Merge branch 'dev' of http://222.212.85.86:8222/bdzl2/bxztApp into dev
This commit is contained in:
commit
11882c188c
47
packages/screen/src/component/DynamicDetail/BlockItem.vue
Normal file
47
packages/screen/src/component/DynamicDetail/BlockItem.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div class="block-item">
|
||||
<slot v-if="title" name="header">
|
||||
<div class="header">
|
||||
<div class="header-title">{{ title }}</div>
|
||||
<div class="header-extra" v-if="$slots.headerExtra">
|
||||
<slot name="headerExtra"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</slot>
|
||||
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
})
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.block-item {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
& + .block-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.header-title {
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
color: #4a4a4a;
|
||||
line-height: 16px;
|
||||
}
|
||||
</style>
|
||||
65
packages/screen/src/component/DynamicDetail/DynamicData.vue
Normal file
65
packages/screen/src/component/DynamicDetail/DynamicData.vue
Normal file
@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<div class="dynamic-data">
|
||||
<span class="info-label">{{ config.label }}:</span>
|
||||
<span class="info-value">{{ getModelValue() || '-' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref, inject, toRaw } from 'vue'
|
||||
|
||||
const formData = inject('formData')
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const getModelValue = () => {
|
||||
if (props.config.value !== null && props.config.value !== undefined && props.config.value !== '') return props.config.value
|
||||
if (typeof props.config.value == 'function') return props.config.value(formData.value)
|
||||
|
||||
if (!props.config.prop) {
|
||||
console.error('请配置prop属性', toRaw(props.config))
|
||||
return null
|
||||
}
|
||||
const keys = props.config.prop?.split('.')
|
||||
let current = formData.value
|
||||
for (const key of keys) {
|
||||
if (typeof current != 'object' || !current[key]) return null
|
||||
current = current[key]
|
||||
}
|
||||
|
||||
return current
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.dynamic-data {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
line-height: 1.5;
|
||||
|
||||
& + .dynamic-data {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
&.margin {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
flex: 1;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div class="dynamic-detail">
|
||||
<template v-for="(config, configIndex) in configList" :key="configIndex">
|
||||
<DynamicDetailItem :config="config" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, watch, ref, provide, computed } from 'vue'
|
||||
import DynamicDetailItem from './DynamicDetailItem.vue'
|
||||
const props = defineProps({
|
||||
configList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
})
|
||||
const computedModelValue = computed(() => {
|
||||
return props.modelValue
|
||||
})
|
||||
provide('formData', computedModelValue)
|
||||
|
||||
const formRef = ref(null)
|
||||
|
||||
// 获得默认表单值
|
||||
const getDefaultFormValue = () => {
|
||||
const form = {}
|
||||
props.formConfig.forEach((config) => {
|
||||
form[config.name] = config.default !== undefined ? config.default : ''
|
||||
})
|
||||
return form
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
getDefaultFormValue,
|
||||
formComponent: formRef.value
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.form-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<template v-if="isShow() && !config.slot && checkLayout(config)">
|
||||
<DynamicLayout :config="config">
|
||||
<DynamicDetailItem v-for="(item, index) in config.children" :key="index" :config="item" />
|
||||
</DynamicLayout>
|
||||
</template>
|
||||
<template v-if="isShow() && !config.slot && !checkLayout(config)">
|
||||
<el-col class="col-item" :span="config.span">
|
||||
<DynamicData style="width: 100%" :config="config" />
|
||||
</el-col>
|
||||
</template>
|
||||
<template v-if="isShow() && config.slot">
|
||||
<slot />
|
||||
</template>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref , inject} from 'vue'
|
||||
import DynamicLayout from './DynamicLayout.vue'
|
||||
import DynamicData from './DynamicData.vue'
|
||||
|
||||
const layoutTypes = ['card', 'block', 'row']
|
||||
const checkLayout = (config) => {
|
||||
return layoutTypes.includes(config?.type)
|
||||
}
|
||||
|
||||
const formData = inject('formData')
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const isShow = () => {
|
||||
if(props.config.show === false) return false
|
||||
if(typeof props.config.show === 'function') return props.config.show(formData)
|
||||
return true
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.col-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<template v-if="config.type == 'card'">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="section-header">
|
||||
<span class="section-title">{{ config.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<slot />
|
||||
</el-card>
|
||||
</template>
|
||||
<template v-else-if="config.type == 'block'">
|
||||
<BlockItem :title="config.label">
|
||||
<slot />
|
||||
</BlockItem>
|
||||
</template>
|
||||
<template v-else-if="config.type == 'row'">
|
||||
<el-row v-bind="config.componentProps">
|
||||
<slot />
|
||||
</el-row>
|
||||
</template>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import BlockItem from './BlockItem.vue';
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
47
packages/screen/src/component/DynamicForm/BlockItem.vue
Normal file
47
packages/screen/src/component/DynamicForm/BlockItem.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div class="block-item">
|
||||
<slot v-if="title" name="header">
|
||||
<div class="header">
|
||||
<div class="header-title">{{ title }}</div>
|
||||
<div class="header-extra" v-if="$slots.headerExtra">
|
||||
<slot name="headerExtra"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</slot>
|
||||
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
})
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.block-item {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
& + .block-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.header-title {
|
||||
font-weight: 500;
|
||||
font-size: 15px;
|
||||
color: #4a4a4a;
|
||||
line-height: 16px;
|
||||
}
|
||||
</style>
|
||||
111
packages/screen/src/component/DynamicForm/DynamicControl.vue
Normal file
111
packages/screen/src/component/DynamicForm/DynamicControl.vue
Normal file
@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div class="dynamic-control">
|
||||
<template v-if="config.type == 'input'">
|
||||
<el-input
|
||||
style="width: 100%"
|
||||
:modelValue="getModelValue()"
|
||||
@update:modelValue="changeModelValue"
|
||||
:placeholder="config.componentProps?.placeholder"
|
||||
:clearable="true"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-if="config.type == 'inputNumber'">
|
||||
<el-input-number
|
||||
style="width: 100%"
|
||||
:modelValue="getModelValue()"
|
||||
@update:modelValue="changeModelValue"
|
||||
:placeholder="config.componentProps?.placeholder"
|
||||
:clearable="true"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-if="config.type == 'radio'">
|
||||
<el-radio-group
|
||||
style="width: 100%"
|
||||
:modelValue="getModelValue()"
|
||||
@update:modelValue="changeModelValue"
|
||||
:placeholder="config.componentProps?.placeholder"
|
||||
>
|
||||
<el-radio v-for="(option, i) in config.options" :value="option.value">{{
|
||||
option.label
|
||||
}}</el-radio>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
|
||||
<template v-if="config.type == 'select'">
|
||||
<el-select
|
||||
style="width: 100%"
|
||||
:modelValue="getModelValue()"
|
||||
@update:modelValue="changeModelValue"
|
||||
:placeholder="config.componentProps?.placeholder"
|
||||
>
|
||||
<el-option
|
||||
v-for="(option, i) in config.options"
|
||||
:key="i"
|
||||
:label="option.label"
|
||||
:value="option.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
<template v-if="config.type == 'date'">
|
||||
<el-date-picker
|
||||
style="width: 100%"
|
||||
:modelValue="getModelValue()"
|
||||
type="date"
|
||||
@update:modelValue="changeModelValue"
|
||||
:placeholder="config.componentProps?.placeholder"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref, inject, toRaw } from 'vue'
|
||||
|
||||
const formData = inject('formData')
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
})
|
||||
|
||||
const getModelValue = () => {
|
||||
if(!props.config.prop) {
|
||||
console.error('请配置prop属性', toRaw(props.config))
|
||||
return null
|
||||
}
|
||||
const keys = props.config.prop?.split('.')
|
||||
let current = formData.value
|
||||
for (const key of keys) {
|
||||
if (typeof current != 'object' || !current[key]) return null
|
||||
current = current[key]
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
const changeModelValue = (value) => {
|
||||
if(!props.config.prop) {
|
||||
return null
|
||||
}
|
||||
// 1. 将路径字符串 'event.name' 按 '.' 拆分成数组
|
||||
const keys = props.config.prop?.split('.')
|
||||
|
||||
// 2. 一直遍历到倒数第一个属性,确保中间路径上的对象都存在
|
||||
let current = formData.value
|
||||
for (let i = 0; i < keys.length - 1; i++) {
|
||||
const key = keys[i]
|
||||
// 如果中间层不存在,就自动创建一个空对象
|
||||
if (!current[key] || typeof current[key] !== 'object') {
|
||||
current[key] = {}
|
||||
}
|
||||
current = current[key]
|
||||
}
|
||||
|
||||
// 3. 在最后一层进行赋值
|
||||
current[keys[keys.length - 1]] = value
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
@ -1,91 +1,52 @@
|
||||
<template>
|
||||
<div class="dynamic-form">
|
||||
<el-form class="form-wrapper" :model="modelValue" ref="formRef">
|
||||
<el-form-item v-for="(config, index) in formConfig" :key="index" :prop="config['prop']"
|
||||
:label="config['label']" :rules="config['rules']" label-position="right">
|
||||
|
||||
<template v-if="config.type == 'input'">
|
||||
<el-input :modelValue="modelValue[config.name]"
|
||||
@update:modelValue="(event) => changeValue(config, event)"
|
||||
:placeholder="config.componentProps?.placeholder" :clearable="true" />
|
||||
</template>
|
||||
|
||||
|
||||
<template v-if="config.type == 'inputNumber'">
|
||||
<el-input-number :modelValue="modelValue[config.name]"
|
||||
@update:modelValue="(event) => changeValue(config, event)"
|
||||
:placeholder="config.componentProps?.placeholder" :clearable="true" />
|
||||
</template>
|
||||
|
||||
|
||||
<template v-if="config.type == 'radio'">
|
||||
<el-radio-group :modelValue="modelValue[config.name]"
|
||||
@update:modelValue="(event) => changeValue(config, event)"
|
||||
:placeholder="config.componentProps?.placeholder">
|
||||
<el-radio v-for="(option, i) in config.options" :value="option.value">{{ option.label
|
||||
}}</el-radio>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
|
||||
|
||||
<template v-if="config.type == 'select'">
|
||||
<el-select :modelValue="modelValue[config.name]"
|
||||
@update:modelValue="(event) => changeValue(config, event)"
|
||||
:placeholder="config.componentProps?.placeholder">
|
||||
<el-option v-for="(option, i) in config.options" :key="i" :label="option.label"
|
||||
:value="option.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
<template v-if="config.type == 'date'">
|
||||
<el-date-picker :modelValue="modelValue[config.name]" type="date"
|
||||
@update:modelValue="(event) => changeValue(config, event)"
|
||||
:placeholder="config.componentProps?.placeholder" />
|
||||
</template>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="dynamic-form">
|
||||
<el-form class="form-wrapper" :model="modelValue" ref="formRef">
|
||||
<template v-for="(config, configIndex) in configList" :key="configIndex">
|
||||
<DynamicFormItem :config="config" />
|
||||
</template>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, watch, ref } from 'vue';
|
||||
import { onMounted, watch, ref, provide } from 'vue'
|
||||
import DynamicFormItem from './DynamicFormItem.vue'
|
||||
const props = defineProps({
|
||||
formConfig: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => { }
|
||||
}
|
||||
configList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const computedModelValue = computed(() => {
|
||||
return props.modelValue
|
||||
})
|
||||
|
||||
provide('formData', computedModelValue)
|
||||
|
||||
const formRef = ref(null)
|
||||
const changeValue = (config, value) => {
|
||||
const form = { ...props.modelValue }
|
||||
form[config.name] = value
|
||||
emit('update:modelValue', form)
|
||||
}
|
||||
|
||||
// 获得默认表单值
|
||||
const getDefaultFormValue = () => {
|
||||
const form = {}
|
||||
props.formConfig.forEach(config => {
|
||||
form[config.name] = config.default !== undefined ? config.default : ''
|
||||
})
|
||||
return form
|
||||
const form = {}
|
||||
props.formConfig.forEach((config) => {
|
||||
form[config.name] = config.default !== undefined ? config.default : ''
|
||||
})
|
||||
return form
|
||||
}
|
||||
|
||||
|
||||
defineExpose({
|
||||
getDefaultFormValue,
|
||||
formComponent: formRef.value,
|
||||
getDefaultFormValue,
|
||||
formComponent: formRef.value
|
||||
})
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.form-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<template v-if="!config.slot && checkLayout(config)">
|
||||
<DynamicLayout :config="config">
|
||||
<DynamicFormItem v-for="(item, index) in config.children" :key="index" :config="item" />
|
||||
</DynamicLayout>
|
||||
</template>
|
||||
<template v-if="!config.slot && !checkLayout(config)">
|
||||
<el-col :span="config.span">
|
||||
<el-form-item :label="config.label" :prop="config.prop">
|
||||
<DynamicControl style="width: 100%" :config="config" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</template>
|
||||
<template v-if="config.slot">
|
||||
<slot />
|
||||
</template>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import DynamicLayout from './DynamicLayout.vue';
|
||||
import DynamicControl from './DynamicControl.vue';
|
||||
|
||||
const layoutTypes = ['card', 'block', 'row']
|
||||
const checkLayout = (config) => {
|
||||
return layoutTypes.includes(config?.type)
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
</style>
|
||||
39
packages/screen/src/component/DynamicForm/DynamicLayout.vue
Normal file
39
packages/screen/src/component/DynamicForm/DynamicLayout.vue
Normal file
@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<template v-if="config.type == 'card'">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="section-header">
|
||||
<span class="section-title">{{ config.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<slot />
|
||||
</el-card>
|
||||
</template>
|
||||
<template v-else-if="config.type == 'block'">
|
||||
<BlockItem :title="config.label">
|
||||
<slot />
|
||||
</BlockItem>
|
||||
</template>
|
||||
<template v-else-if="config.type == 'row'">
|
||||
<el-row v-bind="config.componentProps">
|
||||
<slot />
|
||||
</el-row>
|
||||
</template>
|
||||
<template v-else-if="config.type == 'col'">
|
||||
<el-col v-bind="config.componentProps">
|
||||
<slot />
|
||||
</el-col>
|
||||
</template>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import BlockItem from './BlockItem.vue';
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
@ -258,6 +258,7 @@ const routes = [
|
||||
component: () => import('../views/DisasterManagement/IceDisasterReport/IceDisasterReportPC.vue'),
|
||||
meta: {
|
||||
title: '冰雪灾害上报',
|
||||
parentRoute: 'disasterManagement',
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
@ -266,6 +267,7 @@ const routes = [
|
||||
component: () => import('../views/DisasterManagement/IceDisasterDetail/IceDisasterDetailPC.vue'),
|
||||
meta: {
|
||||
title: '冰雪灾害详情',
|
||||
parentRoute: 'disasterManagement',
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
@ -274,6 +276,7 @@ const routes = [
|
||||
component: () => import('../views/DisasterManagement/WaterDisasterReport/WaterDisasterReportPC.vue'),
|
||||
meta: {
|
||||
title: '水毁灾害上报',
|
||||
parentRoute: 'disasterManagement',
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
@ -283,6 +286,7 @@ const routes = [
|
||||
component: () => import('../views/DisasterManagement/WaterDisasterDetail/WaterDisasterDetailPC.vue'),
|
||||
meta: {
|
||||
title: '水毁事件详情',
|
||||
parentRoute: 'disasterManagement',
|
||||
breadcrumb: true
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,7 +323,7 @@ const handleDetail = (row) => {
|
||||
router.push({ path: '/waterDisasterDetail', query: { id: row.id } })
|
||||
}
|
||||
if (row.disasterType == 'ICE_SNOW') {
|
||||
router.push({ path: '/iceDisasterDetail', query: { id: row.id } })
|
||||
router.push({ path: '/iceDisasterDetail', query: { id: row.relationId } })
|
||||
}
|
||||
}
|
||||
|
||||
@ -333,7 +333,7 @@ const handleEdit = (row) => {
|
||||
router.push({ path: '/waterDisasterDetail', query: { id: row.id, mode: 'edit' } })
|
||||
}
|
||||
if (row.disasterType == 'ICE_SNOW') {
|
||||
router.push({ path: '/iceDisasterDetail', query: { id: row.id, mode: 'edit' } })
|
||||
router.push({ path: '/iceDisasterDetail', query: { id: row.relationId, mode: 'edit' } })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,238 +1,13 @@
|
||||
<template>
|
||||
<div class="web-detail-container">
|
||||
<!-- 页面头部 -->
|
||||
<div class="page-header">
|
||||
<div class="header-left">
|
||||
<el-button :icon="ArrowLeft" @click="handleClickBack">返回</el-button>
|
||||
<h2 class="page-title">冰雪事件详情</h2>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<el-tag :type="getEventStatusType()" size="large">
|
||||
{{ getEventStatusText() }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-container">
|
||||
<div class="left-panel">
|
||||
<!-- 基本信息卡片 -->
|
||||
<el-card class="info-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">基本信息</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">事件类型:</span>
|
||||
<span class="info-value">冰雪事件</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">路况类别:</span>
|
||||
<span class="info-value">{{ detailData.roadConditionType || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">是否阻断:</span>
|
||||
<span class="info-value">{{ detailData.event?.isBlocked ? '是' : '否' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">抢险进度:</span>
|
||||
<span class="info-value">{{ detailData.event?.repairProgress || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">处理措施:</span>
|
||||
<span class="info-value">{{ getBaseDisposalMeasures() }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">水毁处数:</span>
|
||||
<span class="info-value">{{ detailData.event?.damageCount || 0 }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">阻断里程:</span>
|
||||
<span class="info-value">{{ detailData.event?.blockedMileage ? detailData.event.blockedMileage + '公里' : '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">地点路线:</span>
|
||||
<span class="info-value">{{ detailData.occurLocation || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">起点桩号:</span>
|
||||
<span class="info-value">{{ detailData.event?.startStakeNo || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">止点桩号:</span>
|
||||
<span class="info-value">{{ detailData.event?.endStakeNo || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">路况位置:</span>
|
||||
<span class="info-value">{{ detailData.event?.blockedPointName || detailData.occurLocation || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">阻断点小地名:</span>
|
||||
<span class="info-value">{{ detailData.event?.blockedPointName || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">所属区县:</span>
|
||||
<span class="info-value">{{ detailData.event?.district || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">发生时间:</span>
|
||||
<span class="info-value">{{ detailData.occurTime || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">是否恢复重建:</span>
|
||||
<span class="info-value">{{ detailData.event?.needsRecovery ? '是' : '否' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="16" v-if="detailData.event?.needsRecovery">
|
||||
<div class="info-item">
|
||||
<span class="info-label">恢复重建预估费用:</span>
|
||||
<span class="info-value">{{ detailData.event?.estimatedRecoveryCost ? detailData.event.estimatedRecoveryCost + '万元' : '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<!-- 填报信息卡片 -->
|
||||
<el-card class="info-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">填报信息</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-if="hasReportData">
|
||||
<div v-for="(report, index) in allReports" :key="index" class="report-section">
|
||||
<div class="report-header">
|
||||
<span class="report-title">{{ report?.title }}</span>
|
||||
<span class="report-meta">时间:{{ report.reportTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="content-wrapper">
|
||||
<div class="basic-info-wrapper">
|
||||
<div class="info-list">
|
||||
<div class="info-item">
|
||||
<span class="info-label">现场描述:</span>
|
||||
<span class="info-value">{{ report.siteDescription || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">处置措施:</span>
|
||||
<span class="info-value">{{ report.disposalMeasures || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">实际恢复时间:</span>
|
||||
<span class="info-value">{{ report.actualRecoverTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">预计恢复时间:</span>
|
||||
<span class="info-value">{{ report.expectRecoverTime || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<span class="info-label">填报人:</span>
|
||||
<span class="info-value">{{ report.reporterName ? report.reporterName : '-' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<span class="info-label">联系电话:</span>
|
||||
<span class="info-value">{{ report.phone ? report.phone : '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="file-list">
|
||||
<FileUpload v-model="report.fileList" :readonly="!isEdit" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detal-info-wrapper">
|
||||
<template v-if="report.showDetail">
|
||||
<LossListDetail :modelValue="report.lossList" :col-span="8" />
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8">
|
||||
<div class="info-item margin">
|
||||
<span class="info-label">投入机械:</span>
|
||||
<span class="info-value">{{ report.investedMachinery ? report.investedMachinery + '台/班' : '-'}}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item margin">
|
||||
<span class="info-label">投入人力:</span>
|
||||
<span class="info-value">{{ report.investedManpower ? report.investedManpower + '人次' : '-'}}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item margin">
|
||||
<span class="info-label">投入资金:</span>
|
||||
<span class="info-value">{{ report.investedFunds ? report.investedFunds + '万元' : '-'}}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-button style="margin-top: 30px" type="primary" link @click="report.showDetail = !report.showDetail">
|
||||
{{ report.showDetail ? '点击关闭详情' : '点击查看详情' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else description="暂无填报信息" :image-size="100" />
|
||||
</el-card>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<!-- <div class="footer-buttons">
|
||||
<el-button type="primary" size="large" @click="handleContinueReport" class="footer-btn"> 续报 </el-button>
|
||||
</div> -->
|
||||
<DynamicDetail v-model="detailData" :config-list="detailConfig" />
|
||||
</div>
|
||||
<div class="right-panel" v-if="isEdit">
|
||||
<!-- <div class="right-panel" v-if="isEdit">
|
||||
<ContinueReport ref="continueReport" @refresh="getDisasterDetail" />
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -245,6 +20,8 @@ import { ArrowLeft, Picture, VideoCamera } from '@element-plus/icons-vue'
|
||||
import ContinueReport from './IceDisasterContinueReportPC.vue'
|
||||
import { request } from '@shared/utils/request'
|
||||
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
||||
import detailConfig from './detailConfig'
|
||||
import DynamicDetail from '@/component/DynamicDetail/DynamicDetail.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
@ -291,57 +68,6 @@ const hasReportData = computed(() => {
|
||||
return allReports.value.length > 0
|
||||
})
|
||||
|
||||
// 获取事件状态文本
|
||||
const getEventStatusText = () => {
|
||||
return eventStatus.value === 1 ? '已解除' : '未解除'
|
||||
}
|
||||
|
||||
// 获取事件状态类型
|
||||
const getEventStatusType = () => {
|
||||
return eventStatus.value === 1 ? 'success' : 'danger'
|
||||
}
|
||||
|
||||
const getBaseDisposalMeasures = () => {
|
||||
const firstItem = allReports.value[0]
|
||||
if (!firstItem) return '-'
|
||||
return formatDisposalMeasures(firstItem.disposalMeasures || '') || '-'
|
||||
}
|
||||
|
||||
// 格式化处置措施
|
||||
const formatDisposalMeasures = (measures) => {
|
||||
if (!measures) return ''
|
||||
const measureMap = {
|
||||
半幅封闭: '半幅封闭',
|
||||
全副封闭: '全副封闭',
|
||||
便道通行: '便道通行',
|
||||
正常通行: '正常通行'
|
||||
}
|
||||
return measures
|
||||
.split(',')
|
||||
.map((m) => measureMap[m.trim()] || m.trim())
|
||||
.join('、')
|
||||
}
|
||||
|
||||
// 获取损失描述
|
||||
const getLossDescription = (report) => {
|
||||
const lossList = report?.lossList
|
||||
if (!lossList || lossList.length === 0) return '-'
|
||||
|
||||
const totalVolume = lossList.reduce((sum, loss) => {
|
||||
const volume = (loss.length || 0) * (loss.width || 0) * (loss.height || 0)
|
||||
return sum + volume
|
||||
}, 0)
|
||||
|
||||
const totalAmount = lossList.reduce((sum, loss) => sum + (loss.totalAmount || 0), 0)
|
||||
|
||||
return `${totalVolume}方,共损失${totalAmount}万元`
|
||||
}
|
||||
|
||||
// 获取车辆滞留文本
|
||||
const getVehicleStrandedText = (report) => {
|
||||
const count = report?.strandedVehicleCount || 0
|
||||
return count > 0 ? `有车滞留,共${count}辆` : '无车滞留'
|
||||
}
|
||||
|
||||
// 获取灾毁详情
|
||||
const getDisasterDetail = async () => {
|
||||
@ -353,9 +79,8 @@ const getDisasterDetail = async () => {
|
||||
|
||||
try {
|
||||
const result = await request({
|
||||
url: `/snow-ops-platform/water-damage/getById`,
|
||||
url: `/snow-ops-platform/event/getById?id=${route.query.id}`,
|
||||
method: 'get',
|
||||
params: { id }
|
||||
})
|
||||
|
||||
if (result?.data) {
|
||||
@ -601,6 +326,5 @@ onMounted(() => {
|
||||
overflow: hidden;
|
||||
}
|
||||
.file-list {
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -0,0 +1,111 @@
|
||||
export default [
|
||||
{
|
||||
type: 'card',
|
||||
label: '基础信息',
|
||||
children: [
|
||||
{
|
||||
type: 'row',
|
||||
children: [
|
||||
{
|
||||
span: 8,
|
||||
label: '事件类型',
|
||||
value: '冰雪事件',
|
||||
},
|
||||
{
|
||||
span: 8,
|
||||
label: '路况类别',
|
||||
prop: 'event.routeNo'
|
||||
},
|
||||
{
|
||||
span: 8,
|
||||
label: '处理措施',
|
||||
prop: 'event.disposalMeasures'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'row',
|
||||
children: [
|
||||
{
|
||||
span: 8,
|
||||
label: '地点路线',
|
||||
prop: 'event.occurLocation'
|
||||
},
|
||||
{
|
||||
span: 8,
|
||||
label: '起点桩号',
|
||||
prop: 'event.startStakeNo'
|
||||
},
|
||||
{
|
||||
span: 8,
|
||||
label: '止点桩号',
|
||||
prop: 'event.endStakeNo'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'row',
|
||||
children: [
|
||||
{
|
||||
span: 8,
|
||||
label: '路况位置',
|
||||
prop: 'event.occurLocation'
|
||||
},
|
||||
{
|
||||
span: 8,
|
||||
label: '阻断点小地名',
|
||||
prop: 'event.occurLocation'
|
||||
},
|
||||
{
|
||||
span: 8,
|
||||
label: '地点路线',
|
||||
prop: 'event.occurLocation'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'row',
|
||||
children: [
|
||||
{
|
||||
span: 24,
|
||||
label: '受灾里程',
|
||||
prop: 'event.disasterMileage'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'row',
|
||||
children: [
|
||||
{
|
||||
span: 8,
|
||||
label: '所属区县',
|
||||
prop: 'event.district'
|
||||
},
|
||||
{
|
||||
span: 8,
|
||||
label: '发现时间',
|
||||
prop: 'event.occurTime'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'row',
|
||||
children: [
|
||||
{
|
||||
span: 8,
|
||||
label: '是否需要恢复重建',
|
||||
prop: 'event.actualRecoverTime'
|
||||
},
|
||||
{
|
||||
show: (formData) => {
|
||||
return formData.event?.actualRecoverTime
|
||||
},
|
||||
span: 8,
|
||||
label: '恢复重建预估费用(万元)',
|
||||
prop: 'event.estimatedRecoveryCost'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<div class="disaster-form-page">
|
||||
<el-page-header style="margin-bottom: 10px;" @back="router.go(-1)" class="page-header">
|
||||
<template #content>
|
||||
<span class="title">{{ '冰雪灾害填报' }}</span>
|
||||
</template>
|
||||
</el-page-header>
|
||||
|
||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="140px" class="disaster-form" @submit.prevent>
|
||||
<!-- 基本信息区块 -->
|
||||
<el-card class="form-section" shadow="never">
|
||||
|
||||
@ -149,7 +149,7 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
// Emits 定义
|
||||
const emit = defineEmits(['input', 'change', 'submit'])
|
||||
const emit = defineEmits(['input', 'change'])
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
@ -293,14 +293,6 @@ const calibrateTime = () => {
|
||||
|
||||
// 表单验证
|
||||
const validate = () => {
|
||||
if (!formData.occurTime) {
|
||||
ElMessage.warning('请填写发生时间')
|
||||
return false
|
||||
}
|
||||
if (!formData.routeNo) {
|
||||
ElMessage.warning('请填写线路编号')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -354,13 +346,6 @@ const resetForm = () => {
|
||||
disposalMeasureValue.value = ''
|
||||
}
|
||||
|
||||
// 提交方法
|
||||
const submit = () => {
|
||||
if (validate()) {
|
||||
emit('submit', getFormData())
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
// 验证表单
|
||||
if (!validate()) {
|
||||
|
||||
@ -1,17 +1,5 @@
|
||||
<template>
|
||||
<div class="web-detail-container">
|
||||
<!-- 页面头部 -->
|
||||
<div class="page-header">
|
||||
<div class="header-left">
|
||||
<el-button :icon="ArrowLeft" @click="handleClickBack">返回</el-button>
|
||||
<h2 class="page-title">水毁事件详情</h2>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<el-tag :type="getEventStatusType()" size="large">
|
||||
{{ getEventStatusText() }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-container">
|
||||
<div class="left-panel">
|
||||
@ -293,16 +281,6 @@ const hasReportData = computed(() => {
|
||||
return allReports.value.length > 0
|
||||
})
|
||||
|
||||
// 获取事件状态文本
|
||||
const getEventStatusText = () => {
|
||||
return eventStatus.value === 1 ? '已解除' : '未解除'
|
||||
}
|
||||
|
||||
// 获取事件状态类型
|
||||
const getEventStatusType = () => {
|
||||
return eventStatus.value === 1 ? 'success' : 'danger'
|
||||
}
|
||||
|
||||
const getBaseDisposalMeasures = () => {
|
||||
const firstItem = allReports.value[0]
|
||||
if (!firstItem) return '-'
|
||||
|
||||
@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<div class="disaster-form-page">
|
||||
<el-page-header style="margin-bottom: 10px;" @back="router.go(-1)" class="page-header">
|
||||
<template #content>
|
||||
<span class="title">{{ '水毁灾害填报' }}</span>
|
||||
</template>
|
||||
</el-page-header>
|
||||
|
||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="140px" class="disaster-form" @submit.prevent>
|
||||
<!-- 基本信息区块 -->
|
||||
<el-card class="form-section" shadow="never">
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
<div
|
||||
v-for="(item, index) in impactData"
|
||||
:key="index"
|
||||
@click="handleClick(index)"
|
||||
@click="handleClick(index, item)"
|
||||
class="stat-card"
|
||||
:style="{
|
||||
backgroundImage: `url(${cardType == index ? selectedIcon : unselectedIcon})`,
|
||||
@ -350,11 +350,11 @@ const tableColumns = ref(bridgeColumns);
|
||||
const tableData = ref([]);
|
||||
// 影响点数据
|
||||
const impactData = ref([
|
||||
{ name: "影响桥梁", count: 0, icon: Icon0 },
|
||||
{ name: "影响边坡", count: 0, icon: Icon1 },
|
||||
{ name: "影响隧道", count: 0, icon: Icon2 },
|
||||
{ name: "影响项目", count: 0, icon: Icon3 },
|
||||
{ name: "影响路段", count: 0, icon: Icon4 },
|
||||
{ name: "影响路段", count: 0, icon: Icon4, type: "路段" },
|
||||
{ name: "影响桥梁", count: 0, icon: Icon0, type: "桥梁" },
|
||||
{ name: "影响隧道", count: 0, icon: Icon2, type: "隧道" },
|
||||
{ name: "影响边坡", count: 0, icon: Icon1, type: "边坡" },
|
||||
{ name: "影响项目", count: 0, icon: Icon3, type: "项目" },
|
||||
]);
|
||||
// 顶部卡片数据
|
||||
const loadBarChartData = async () => {
|
||||
@ -401,6 +401,7 @@ const loadBarChartData = async () => {
|
||||
};
|
||||
|
||||
const cardType = ref("0");
|
||||
const cardTypeVal = ref("路段");
|
||||
|
||||
// 根据 cardType 获取对应的表格列配置
|
||||
const getColumnsByType = (type) => {
|
||||
@ -417,11 +418,11 @@ const getColumnsByType = (type) => {
|
||||
// 根据 cardType 获取对应的 API 路径
|
||||
const getApiUrlByType = (type) => {
|
||||
const urlMap = {
|
||||
0: "/snow-ops-platform/weather-warning/affected-object/bridge",
|
||||
1: "/snow-ops-platform/weather-warning/affected-object/slope",
|
||||
2: "/snow-ops-platform/weather-warning/affected-object/tunnel",
|
||||
3: "/snow-ops-platform/weather-warning/affected-object/project",
|
||||
4: "/snow-ops-platform/weather-warning/affected-object/road-section",
|
||||
桥梁: "/snow-ops-platform/weather-warning/affected-object/bridge",
|
||||
边坡: "/snow-ops-platform/weather-warning/affected-object/slope",
|
||||
隧道: "/snow-ops-platform/weather-warning/affected-object/tunnel",
|
||||
项目: "/snow-ops-platform/weather-warning/affected-object/project",
|
||||
路段: "/snow-ops-platform/weather-warning/affected-object/road-section",
|
||||
};
|
||||
return (
|
||||
urlMap[type] || "/snow-ops-platform/weather-warning/affected-object/bridge"
|
||||
@ -429,9 +430,10 @@ const getApiUrlByType = (type) => {
|
||||
};
|
||||
|
||||
// 点击卡片切换
|
||||
const handleClick = (type) => {
|
||||
const handleClick = (index, item) => {
|
||||
tableData.value = [];
|
||||
cardType.value = type + "";
|
||||
cardType.value = index + "";
|
||||
cardTypeVal.value = item.type;
|
||||
// 切换表格列配置
|
||||
tableColumns.value = getColumnsByType(cardType.value);
|
||||
// 重置分页并获取数据
|
||||
@ -507,15 +509,6 @@ const getTimeParams = () => {
|
||||
};
|
||||
// 处理数据为统一格式
|
||||
const processUnifiedData = (item, type) => {
|
||||
// 根据类型获取影响点类型名称
|
||||
const typeMap = {
|
||||
0: "桥梁",
|
||||
1: "边坡",
|
||||
2: "隧道",
|
||||
3: "项目",
|
||||
4: "路段",
|
||||
};
|
||||
|
||||
// 获取等级样式类
|
||||
const getLevelClass = (level) => {
|
||||
const levelMap = {
|
||||
@ -551,7 +544,7 @@ const processUnifiedData = (item, type) => {
|
||||
item.ADMINISTRATIVE_REGION ||
|
||||
"-",
|
||||
// 影响点类型
|
||||
pointType: typeMap[type] || "-",
|
||||
pointType: impactData.value[type].type || "-",
|
||||
// 影响点位置(根据类型取不同字段)
|
||||
pointLocation:
|
||||
item.GL1_QLMC ||
|
||||
@ -604,7 +597,7 @@ const processUnifiedData = (item, type) => {
|
||||
};
|
||||
|
||||
// 桥梁类型特殊处理(根据BASE_GLQL桥梁信息表字典)
|
||||
if (type === "0") {
|
||||
if (cardTypeVal.value === "桥梁") {
|
||||
return {
|
||||
...baseData,
|
||||
// 影响区域 - 使用区县名称
|
||||
@ -645,7 +638,7 @@ const processUnifiedData = (item, type) => {
|
||||
}
|
||||
|
||||
// 隧道类型特殊处理(根据BASE_GLSD隧道信息表字典)
|
||||
if (type === "2") {
|
||||
if (cardTypeVal.value === "隧道") {
|
||||
return {
|
||||
...baseData,
|
||||
// 影响区域 - 使用区县名称
|
||||
@ -686,7 +679,7 @@ const processUnifiedData = (item, type) => {
|
||||
}
|
||||
|
||||
// 路段类型特殊处理(根据BASE_XJLD路线信息表字典)
|
||||
if (type === "4") {
|
||||
if (cardTypeVal.value === "路段") {
|
||||
return {
|
||||
...baseData,
|
||||
// 影响区域 - 使用区县名称
|
||||
@ -725,7 +718,7 @@ const processUnifiedData = (item, type) => {
|
||||
}
|
||||
|
||||
// 项目类型特殊处理(根据SQL字段映射)
|
||||
if (type === "3") {
|
||||
if (cardTypeVal.value === "项目") {
|
||||
return {
|
||||
...baseData,
|
||||
// 影响区域 - 使用COUNTY字段
|
||||
@ -801,31 +794,41 @@ const fetchData = async () => {
|
||||
const timeParams = getTimeParams();
|
||||
|
||||
// 根据 cardType 获取对应的 API URL
|
||||
const apiUrl = getApiUrlByType(cardType.value);
|
||||
const apiUrl = getApiUrlByType(cardTypeVal.value);
|
||||
|
||||
const res = await request({
|
||||
url: apiUrl,
|
||||
method: "GET",
|
||||
params: timeParams,
|
||||
});
|
||||
|
||||
if (res.code === "00000" && res.data) {
|
||||
// 处理返回数据
|
||||
const allData = res.data;
|
||||
total.value = allData.length || 0;
|
||||
|
||||
// 客户端分页:计算当前页的数据范围
|
||||
const startIndex = (currentPage.value - 1) * pageSize.value;
|
||||
const endIndex = startIndex + pageSize.value;
|
||||
const currentPageData = allData.slice(startIndex, endIndex);
|
||||
|
||||
tableData.value = currentPageData.map((item, index) => ({
|
||||
...processDataByType(item, cardType.value),
|
||||
id: startIndex + index + 1,
|
||||
}));
|
||||
// 路段存在分页功能了,需要处理返回数据
|
||||
if (cardTypeVal.value == "路段") {
|
||||
if (res.data) {
|
||||
tableData.value = res.data.map((item, index) => ({
|
||||
...processDataByType(item, cardType.value),
|
||||
id: index + 1,
|
||||
}));
|
||||
total.value = res.total || 0;
|
||||
}
|
||||
} else {
|
||||
tableData.value = [];
|
||||
total.value = 0;
|
||||
if (res.code === "00000" && res.data) {
|
||||
// 处理返回数据
|
||||
const allData = res.data;
|
||||
total.value = allData.length || 0;
|
||||
|
||||
// 客户端分页:计算当前页的数据范围
|
||||
const startIndex = (currentPage.value - 1) * pageSize.value;
|
||||
const endIndex = startIndex + pageSize.value;
|
||||
const currentPageData = allData.slice(startIndex, endIndex);
|
||||
|
||||
tableData.value = currentPageData.map((item, index) => ({
|
||||
...processDataByType(item, cardType.value),
|
||||
id: startIndex + index + 1,
|
||||
}));
|
||||
} else {
|
||||
tableData.value = [];
|
||||
total.value = 0;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取影响点数据失败:", error);
|
||||
|
||||
@ -123,31 +123,36 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
warningitem: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "impactClick"]);
|
||||
|
||||
// 初始化日期范围(当月)
|
||||
const getDefaultDateRange = () => {
|
||||
const now = new Date();
|
||||
const start = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
const end = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59);
|
||||
return [start, end];
|
||||
};
|
||||
|
||||
// 日期范围器
|
||||
const dateRange = ref(getDefaultDateRange());
|
||||
|
||||
const dateRange = ref([]);
|
||||
onMounted(() => {
|
||||
filterForm.value = {
|
||||
riskLeve: "",
|
||||
countyName: "",
|
||||
isEnded: "",
|
||||
dateRange: dateRange.value,
|
||||
};
|
||||
fetchWarningData();
|
||||
// 如果弹窗初始就是打开状态,则初始化数据
|
||||
if (props.visible) {
|
||||
initDialogData();
|
||||
}
|
||||
});
|
||||
|
||||
// 监听 warningitem 变化,当弹窗重新打开时更新筛选条件
|
||||
watch(
|
||||
() => props.warningitem,
|
||||
(newVal) => {
|
||||
console.log("warningitem 变化:", newVal);
|
||||
if (newVal && Object.keys(newVal).length > 0) {
|
||||
filterForm.value.riskLeve = newVal.label || "";
|
||||
currentPage.value = 1;
|
||||
}
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
// 监听注入的日期范围变化
|
||||
watch(
|
||||
() => getdateRange.value,
|
||||
@ -156,11 +161,9 @@ watch(
|
||||
if (newVal && newVal.length === 2) {
|
||||
dateRange.value = newVal;
|
||||
filterForm.value.dateRange = newVal;
|
||||
// 重新获取数据
|
||||
fetchWarningData();
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
// 筛选表单
|
||||
@ -230,7 +233,7 @@ const fetchWarningData = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const params = {
|
||||
offset: currentPage.value,
|
||||
offset: (currentPage.value - 1) * pageSize.value,
|
||||
limit: pageSize.value,
|
||||
start: "",
|
||||
end: "",
|
||||
@ -335,31 +338,88 @@ const handleImpactClick = (item) => {
|
||||
// 分页操作
|
||||
const handleSizeChange = (val) => {
|
||||
pageSize.value = val;
|
||||
console.log("分页大小变化:", val);
|
||||
currentPage.value = 1;
|
||||
fetchWarningData();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (val) => {
|
||||
console.log("当前页码变化:", val);
|
||||
currentPage.value = val;
|
||||
fetchWarningData();
|
||||
};
|
||||
|
||||
// 初始化弹窗数据
|
||||
const initDialogData = () => {
|
||||
// 设置日期范围
|
||||
if (getdateRange.value && getdateRange.value.length === 2) {
|
||||
dateRange.value = getdateRange.value;
|
||||
}
|
||||
|
||||
// 如果有 warningitem 则设置筛选条件
|
||||
if (props.warningitem && Object.keys(props.warningitem).length > 0) {
|
||||
filterForm.value = {
|
||||
riskLeve: props.warningitem.label || "",
|
||||
countyName: props.warningitem.countyName || "",
|
||||
isEnded: "",
|
||||
dateRange: dateRange.value,
|
||||
};
|
||||
} else {
|
||||
filterForm.value = {
|
||||
riskLeve: "",
|
||||
countyName: "",
|
||||
isEnded: "",
|
||||
dateRange: dateRange.value,
|
||||
};
|
||||
}
|
||||
|
||||
// 重置页码并获取数据
|
||||
currentPage.value = 1;
|
||||
console.log("初始化筛选条件:", filterForm.value);
|
||||
fetchWarningData();
|
||||
};
|
||||
|
||||
// 重置数据
|
||||
const resetData = () => {
|
||||
// 清空表格数据
|
||||
tableData.value = [];
|
||||
total.value = 0;
|
||||
currentPage.value = 1;
|
||||
// 清空筛选条件
|
||||
filterForm.value = {
|
||||
riskLeve: "",
|
||||
countyName: "",
|
||||
isEnded: "",
|
||||
dateRange: [],
|
||||
};
|
||||
// 清空日期范围
|
||||
dateRange.value = [];
|
||||
};
|
||||
|
||||
// 监听visible变化
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
currentPage.value = 1;
|
||||
fetchWarningData();
|
||||
// 弹窗打开时,初始化数据
|
||||
initDialogData();
|
||||
} else {
|
||||
// 弹窗关闭时,清空页面数据
|
||||
resetData();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// 监听筛选条件变化
|
||||
// 监听筛选条件变化(手动修改时触发,初始化时不触发)
|
||||
watch(
|
||||
() => filterForm.value,
|
||||
() => {
|
||||
currentPage.value = 1;
|
||||
fetchWarningData();
|
||||
(newVal, oldVal) => {
|
||||
console.log("筛选条件变化:===========", newVal, oldVal);
|
||||
// 只在旧值存在且不为空对象时触发(排除初始化情况)
|
||||
if (oldVal && Object.keys(oldVal).length > 0) {
|
||||
currentPage.value = 1;
|
||||
fetchWarningData();
|
||||
}
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
@ -230,7 +230,7 @@ const showCountyCardsOnMap = (dataList) => {
|
||||
// 调用处理函数
|
||||
handleCenterCardItemClick(item);
|
||||
// 移动地图到该位置
|
||||
mapInstance.setView(center, 10);
|
||||
// mapInstance.setView(center, 10);
|
||||
// 触发点击事件
|
||||
emit("districtClick", {
|
||||
name: countyName,
|
||||
@ -248,10 +248,10 @@ const showCountyCardsOnMap = (dataList) => {
|
||||
});
|
||||
|
||||
// 调整地图视角以显示所有卡片
|
||||
if (countyCardMarkers.length > 0) {
|
||||
const group = new window.L.featureGroup(countyCardMarkers);
|
||||
mapInstance.fitBounds(group.getBounds().pad(0.2));
|
||||
}
|
||||
// if (countyCardMarkers.length > 0) {
|
||||
// const group = new window.L.featureGroup(countyCardMarkers);
|
||||
// mapInstance.fitBounds(group.getBounds().pad(0.2));
|
||||
// }
|
||||
};
|
||||
|
||||
// 获取公路类型文本
|
||||
@ -312,13 +312,13 @@ const getTimeParams = (type) => {
|
||||
let start = "";
|
||||
let end = "";
|
||||
if (props.dateRange && props.dateRange.length === 2) {
|
||||
start = formatDateTime(props.dateRange[0]) || "";
|
||||
end = formatDateTime(props.dateRange[1]) || "";
|
||||
start = formatDateTime(props.dateRange[0]) || "";
|
||||
end = formatDateTime(props.dateRange[1]) || "";
|
||||
}
|
||||
// 添加路段等级参数
|
||||
if(props.roadItem && type === "road"){
|
||||
// end = props.roadItem.endTime || "";
|
||||
}
|
||||
// if(props.roadItem && type === "road"){
|
||||
// // end = props.roadItem.endTime || "";
|
||||
// }
|
||||
return {
|
||||
start: start,
|
||||
end: end,
|
||||
@ -370,7 +370,7 @@ const getAffectedBridgeData = async () => {
|
||||
method: "GET",
|
||||
params: timeParams,
|
||||
});
|
||||
if (res.code === "00000" && res.data) {
|
||||
if (res.data) {
|
||||
res.data.forEach((item) => {
|
||||
item.COORDINATE_POINT = [item.GL1_QLJD, item.GL1_QLWD];
|
||||
if (
|
||||
@ -382,8 +382,7 @@ const getAffectedBridgeData = async () => {
|
||||
}
|
||||
});
|
||||
}
|
||||
// affectedBridgeData.value = res.data;
|
||||
|
||||
console.log("受影响桥梁数据:", affectedBridgeData.value);
|
||||
addProjectMarkers(affectedBridgeData.value, bridgeIcon, "bridge");
|
||||
} catch (error) {
|
||||
console.error("获取受影响桥梁数据失败:", error);
|
||||
@ -391,8 +390,6 @@ const getAffectedBridgeData = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const affectedTunnelData = ref([]);
|
||||
|
||||
const tunnelInfoDialogRef = ref(null);
|
||||
// 获取受影响隧道数据
|
||||
const getAffectedTunnelData = async () => {
|
||||
@ -403,7 +400,6 @@ const getAffectedTunnelData = async () => {
|
||||
method: "GET",
|
||||
params: timeParams,
|
||||
});
|
||||
console.log("受影响隧道数据:", res);
|
||||
if (res.code === "00000" && res.data) {
|
||||
res.data.forEach((item) => {
|
||||
item.COORDINATE_POINT = [
|
||||
@ -414,9 +410,7 @@ const getAffectedTunnelData = async () => {
|
||||
tunnelInfoDialogRef.value.push(item);
|
||||
}
|
||||
});
|
||||
// tunnelInfoDialogRef.value = res.data;
|
||||
console.log("受影响隧道数据:", res.data);
|
||||
|
||||
console.log("受影响隧道数据:", tunnelInfoDialogRef.value);
|
||||
addProjectMarkers(tunnelInfoDialogRef.value, tunnelIcon2, "tunnel");
|
||||
}
|
||||
return [];
|
||||
@ -426,9 +420,8 @@ const getAffectedTunnelData = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const affectedProjectData = ref([]);
|
||||
|
||||
// 获取受影响项目数据
|
||||
const affectedProjectData = ref([]);
|
||||
const getAffectedProjectData = async () => {
|
||||
try {
|
||||
const timeParams = getTimeParams();
|
||||
@ -469,25 +462,24 @@ const getAffectedProjectData = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const affectedRoadSectionData = ref([]);
|
||||
// 获取受影响路段数据
|
||||
const affectedRoadSectionData = ref([]);
|
||||
const getAffectedRoadSectionData = async () => {
|
||||
try {
|
||||
const timeParams = getTimeParams(road);
|
||||
const timeParams = getTimeParams();
|
||||
const res = await request({
|
||||
url: "/snow-ops-platform/weather-warning/affected-object/road-section",
|
||||
method: "GET",
|
||||
params: timeParams,
|
||||
});
|
||||
console.log("受影响路段数据:", res);
|
||||
if (res.code === "00000" && res.data) {
|
||||
if (res.data) {
|
||||
res.data.forEach((item) => {
|
||||
item.COORDINATE_POINT = JSON.parse(item.STARTPOINT);
|
||||
});
|
||||
affectedRoadSectionData.value = res.data;
|
||||
// 在地图上添加项目标记
|
||||
console.log("开始添加项目标记...");
|
||||
|
||||
console.log("受影响路段数据:", affectedRoadSectionData.value);
|
||||
addProjectMarkers(affectedRoadSectionData.value, tunnelLineIcon, "road");
|
||||
}
|
||||
return [];
|
||||
@ -568,8 +560,8 @@ const addProjectMarkers = (data, iconUrl, type = "project") => {
|
||||
return;
|
||||
}
|
||||
|
||||
// // 清除之前的标记
|
||||
// clearProjectMarkers();
|
||||
// 清除之前的标记
|
||||
clearProjectMarkers();
|
||||
|
||||
// 创建自定义图标
|
||||
const projectIconObj = window.L.icon({
|
||||
@ -1171,7 +1163,7 @@ const locateToDistrict = (countyName) => {
|
||||
const center = bounds.getCenter();
|
||||
|
||||
// 移动地图到该中心点并放大
|
||||
mapInstance.setView(center, 10);
|
||||
// mapInstance.setView(center, 10);
|
||||
|
||||
// 高亮显示该区县
|
||||
if (selectedLayer) {
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
<div class="left">
|
||||
<left
|
||||
:dateRange="getdateRange"
|
||||
@warningClick="handleWarningClick"
|
||||
@openImpactDetail="openDialog('impactPoint')"
|
||||
@openWarningInfo="openDialog('warningInfo')"
|
||||
@openImpactPoint="openDialog('impactPoint')"
|
||||
@ -61,7 +62,7 @@
|
||||
ref="chongqingMapRef"
|
||||
:activeitem="activeitem"
|
||||
:dateRange="getdateRange"
|
||||
:roadItem="roadItem"
|
||||
:roadItem="roadItem"
|
||||
@districtClick="handleDistrictClick"
|
||||
/>
|
||||
</div>
|
||||
@ -212,6 +213,7 @@
|
||||
<!-- 预警情况对话框 -->
|
||||
<warningSituationDialog
|
||||
v-model:visible="dialogVisible.warningSituation"
|
||||
:warningitem="warningitem"
|
||||
@close="closeDialog('warningSituation')"
|
||||
@impactClick="openDialog('impactPoint')"
|
||||
@impactClickItem="handleImpactClickItem"
|
||||
@ -356,6 +358,12 @@ const closeDialog = (dialogName) => {
|
||||
console.log("关闭弹窗", dialogName);
|
||||
dialogVisible.value[dialogName] = false;
|
||||
};
|
||||
// 处理气象预警点击
|
||||
const warningitem = ref({});
|
||||
const handleWarningClick = (item) => {
|
||||
console.log("气象预警点击:", item);
|
||||
warningitem.value = item;
|
||||
};
|
||||
|
||||
// 确认对话框配置
|
||||
const confirmConfig = ref({
|
||||
|
||||
@ -229,6 +229,7 @@ const emit = defineEmits([
|
||||
"openDispatchDistrict",
|
||||
"openImpactDetail",
|
||||
"showCenterCard",
|
||||
"warningClick",
|
||||
]);
|
||||
|
||||
// 点击统计项
|
||||
@ -244,7 +245,10 @@ const handleStatClick = (item) => {
|
||||
|
||||
// 点击气象预警卡片
|
||||
const handleWarningCardClick = (item) => {
|
||||
console.log("item:", item);
|
||||
emit("openWarningSituation", item);
|
||||
// 传递日期范围
|
||||
emit("warningClick", item);
|
||||
};
|
||||
|
||||
// 点击影响点明细
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user