Merge branch 'dev' of http://222.212.85.86:8222/bdzl2/bxztApp into dev
@ -34,7 +34,7 @@ import { Field, Popup, Picker } from 'vant'
|
||||
const props = defineProps({
|
||||
// 双向绑定值 (v-model)
|
||||
modelValue: {
|
||||
type: [String, Number],
|
||||
type: [String, Number, Boolean],
|
||||
default: null
|
||||
},
|
||||
// 选项数据,默认格式 [{ label: '显示名', value: '值' }]
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
<EmptyBox v-if="!loading && list.length === 0" :placeholder="emptyText" />
|
||||
</div>
|
||||
|
||||
<van-button type="primary" class="footer-btn" icon="plus" @click="handleAdd"> 冰雪填报 </van-button>
|
||||
<van-button type="primary" class="footer-btn" @click="handleAdd"> 灾害填报 </van-button>
|
||||
|
||||
<!-- 筛选组件:v-model 绑定选中的值,visible 控制显示隐藏 -->
|
||||
<TagFilter
|
||||
@ -56,7 +56,7 @@ import CardItem from '@/components/CardItem.vue'
|
||||
import EmptyBox from '@/components/EmptyBox.vue'
|
||||
import CurrentSite from '@/components/CurrentSite.vue'
|
||||
import TagFilter from '@/components/TagFilter.vue'
|
||||
import mockDataJSON from './mockData.json'
|
||||
import { request } from "@shared/utils/request";
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@ -111,54 +111,21 @@ const getDisasterList = async (keyword = '', disasterType = 'all') => {
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
// TODO: 替换为实际的后端接口地址
|
||||
// const response = await fetch('/api/disaster/list', {
|
||||
// method: 'POST',
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json'
|
||||
// },
|
||||
// body: JSON.stringify({
|
||||
// keyword: keyword.trim(),
|
||||
// disasterType: disasterType === 'all' ? '' : disasterType
|
||||
// })
|
||||
// })
|
||||
// const result = await response.json()
|
||||
// if (result.code === 200) {
|
||||
// list.value = result.data
|
||||
// } else {
|
||||
// showToast(result.message || '获取数据失败')
|
||||
// list.value = []
|
||||
// }
|
||||
|
||||
// ========== 模拟数据 ==========
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
const mockData = mockDataJSON
|
||||
|
||||
let filteredData = [...mockData]
|
||||
|
||||
if (keyword) {
|
||||
filteredData = filteredData.filter((item) =>
|
||||
item.title.toLowerCase().includes(keyword.toLowerCase())
|
||||
)
|
||||
const result = await request({
|
||||
url: '/snow-ops-platform/water-damage/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
keyword: keyword.trim(),
|
||||
disasterType: disasterType === 'all' ? '' : disasterType
|
||||
}
|
||||
|
||||
if (disasterType !== 'all') {
|
||||
filteredData = filteredData.filter((item) =>
|
||||
item.disasterType === disasterType
|
||||
)
|
||||
}
|
||||
|
||||
list.value = filteredData
|
||||
|
||||
if (keyword && filteredData.length === 0) {
|
||||
emptyText.value = '未搜索到相关灾毁信息'
|
||||
} else if (disasterType !== 'all' && filteredData.length === 0) {
|
||||
const typeLabel = disasterTypes.find(t => t.value === disasterType)?.label || disasterType
|
||||
emptyText.value = `暂无${typeLabel}类型灾毁信息`
|
||||
})
|
||||
if (result?.data?.records) {
|
||||
list.value = result.data.records
|
||||
} else {
|
||||
emptyText.value = '暂无相关灾毁信息'
|
||||
showToast(result.message || '获取数据失败')
|
||||
list.value = []
|
||||
}
|
||||
// ========== 模拟数据结束 ==========
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取灾毁列表失败:', error)
|
||||
showToast('获取数据失败,请稍后重试')
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
<WaterDisaster
|
||||
v-if="eventType === 'water'"
|
||||
ref="waterDisasterRef"
|
||||
v-model="waterDisasterData"
|
||||
/>
|
||||
|
||||
<!-- 冰雪灾害表单(待实现) -->
|
||||
@ -31,13 +30,15 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { showToast, showSuccessToast, showFailToast } from 'vant'
|
||||
import PageContainer from '@/components/PageContainer.vue'
|
||||
import CurrentSite from '@/components/CurrentSite.vue'
|
||||
import PanelItem from '@/components/PanelItem.vue'
|
||||
import WaterDisaster from './WaterDisaster.vue'
|
||||
import WaterDisaster from './WaterDisaster/WaterDisaster.vue'
|
||||
import { request } from "@shared/utils/request";
|
||||
import mockFormData from './waterDisasterFormData.json'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@ -45,7 +46,7 @@ const router = useRouter()
|
||||
const eventType = ref('water')
|
||||
|
||||
// 表单数据
|
||||
const waterDisasterData = ref({})
|
||||
const formData = ref(mockFormData)
|
||||
const waterDisasterRef = ref(null)
|
||||
const submitting = ref(false)
|
||||
|
||||
@ -73,12 +74,16 @@ const handleSubmit = async () => {
|
||||
|
||||
// 添加事件类型和站点信息
|
||||
const submitData = {
|
||||
eventType: eventType.value,
|
||||
...formData,
|
||||
// 可以在这里添加站点信息等其他数据
|
||||
}
|
||||
|
||||
console.log('提交数据:', submitData)
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/water-damage/addOrUpdate',
|
||||
method: 'post',
|
||||
data: submitData
|
||||
})
|
||||
|
||||
|
||||
// 模拟提交接口
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
@ -95,6 +100,10 @@ const handleSubmit = async () => {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
waterDisasterRef.value.initFormData(formData.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -1,532 +0,0 @@
|
||||
<template>
|
||||
<div class="water-disaster">
|
||||
<!-- 基本信息 -->
|
||||
<PanelItem title="基本信息">
|
||||
<van-form>
|
||||
<!-- 路况类别 -->
|
||||
<BasePicker v-model="formData.roadCondition" :options="roadConditionOptions" label="路况类别" placeholder="请选择" />
|
||||
|
||||
<!-- 是否阻断 -->
|
||||
<BasePicker v-model="formData.isBlocked" :options="blockedOptions" label="是否阻断" placeholder="请选择" />
|
||||
|
||||
<!-- 抢修进度 -->
|
||||
<BasePicker v-model="formData.repairProgress" :options="repairProgressOptions" label="抢修进度" placeholder="请选择" />
|
||||
|
||||
<!-- 水毁处数 -->
|
||||
<van-field v-model="formData.waterDamageCount" label="水毁处数" placeholder="请填写" type="number" />
|
||||
|
||||
<!-- 阻断里程 -->
|
||||
<van-field v-model="formData.blockedMileage" label="阻断里程" placeholder="请填写" type="digit">
|
||||
<template #button>
|
||||
<span class="field-unit">公里</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<!-- 发生时间 -->
|
||||
<BaseDatePicker v-model="formData.occurTime" label="发生时间" placeholder="请选择时间" :columnsType="['year', 'month', 'day', 'hour', 'minute']" />
|
||||
<div class="calibrate-time-btn" @click="calibrateTime">
|
||||
<van-icon name="replay" />
|
||||
<span>校准时间</span>
|
||||
</div>
|
||||
|
||||
<!-- 线路编号 -->
|
||||
<van-field v-model="formData.lineCode" label="线路编号" placeholder="请填写" />
|
||||
|
||||
<!-- 起点桩号 -->
|
||||
<van-field v-model="formData.startPileNo" label="起点桩号(K)" placeholder="请填写" />
|
||||
|
||||
<!-- 起点桩经纬度 -->
|
||||
<div class="coordinate-row">
|
||||
<van-field v-model="formData.startLongitude" label="起点桩经度" placeholder="经度" class="coordinate-field" />
|
||||
<van-field v-model="formData.startLatitude" label="起点桩纬度" placeholder="纬度" class="coordinate-field" />
|
||||
</div>
|
||||
<div class="calibrate-coord-btn" @click="calibrateStartCoord">
|
||||
<van-icon name="location-o" />
|
||||
<span>校准经纬度</span>
|
||||
</div>
|
||||
|
||||
<!-- 止点桩号 -->
|
||||
<van-field v-model="formData.endPileNo" label="止点桩号(K)" placeholder="请填写" />
|
||||
|
||||
<!-- 止点桩经纬度 -->
|
||||
<div class="coordinate-row">
|
||||
<van-field v-model="formData.endLongitude" label="止点桩经度" placeholder="经度" class="coordinate-field" />
|
||||
<van-field v-model="formData.endLatitude" label="止点桩纬度" placeholder="纬度" class="coordinate-field" />
|
||||
</div>
|
||||
<div class="calibrate-coord-btn" @click="calibrateEndCoord">
|
||||
<van-icon name="location-o" />
|
||||
<span>校准经纬度</span>
|
||||
</div>
|
||||
|
||||
<!-- 路况位置 -->
|
||||
<van-field v-model="formData.roadLocation" label="路况位置" placeholder="请填写" />
|
||||
|
||||
<!-- 阻断点小地名 -->
|
||||
<van-field v-model="formData.smallPlaceName" label="阻断点小地名" placeholder="请填写" />
|
||||
</van-form>
|
||||
</PanelItem>
|
||||
|
||||
<!-- 处置情况 -->
|
||||
<PanelItem title="处置情况">
|
||||
<div class="disposal-measures">
|
||||
<span class="measures-label">处置措施</span>
|
||||
<div class="measures-options">
|
||||
<van-checkbox-group v-model="formData.disposalMeasures" direction="horizontal">
|
||||
<van-checkbox name="halfClose">半幅封闭</van-checkbox>
|
||||
<van-checkbox name="fullClose">全副封闭</van-checkbox>
|
||||
<van-checkbox name="bypass">便道通行</van-checkbox>
|
||||
<van-checkbox name="normal">正常通行</van-checkbox>
|
||||
</van-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 预计恢复时间 -->
|
||||
<BaseDatePicker v-model="formData.estimatedRecoverTime" label="预计恢复时间" placeholder="请选择时间" :min-date="minDate" :max-date="maxDate" type="datetime" />
|
||||
|
||||
<!-- 实际恢复时间 -->
|
||||
<BaseDatePicker v-model="formData.actualRecoverTime" label="实际恢复时间" placeholder="请选择时间" :min-date="minDate" :max-date="maxDate" type="datetime" />
|
||||
</PanelItem>
|
||||
|
||||
<!-- 人员车辆 -->
|
||||
<PanelItem title="人员车辆">
|
||||
<van-form>
|
||||
<van-field v-model="formData.injuredCount" label="受伤人员" placeholder="请填写" type="number">
|
||||
<template #button>
|
||||
<span class="field-unit">个</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.deathCount" label="死亡人员" placeholder="请填写" type="number">
|
||||
<template #button>
|
||||
<span class="field-unit">个</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.strandedPeople" label="滞留人员" placeholder="请填写" type="number">
|
||||
<template #button>
|
||||
<span class="field-unit">个</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.damagedVehicles" label="损坏车辆" placeholder="请填写" type="number">
|
||||
<template #button>
|
||||
<span class="field-unit">辆</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.strandedVehicles" label="滞留车辆" placeholder="请填写" type="number">
|
||||
<template #button>
|
||||
<span class="field-unit">辆</span>
|
||||
</template>
|
||||
</van-field>
|
||||
</van-form>
|
||||
</PanelItem>
|
||||
|
||||
<!-- 灾毁损失 -->
|
||||
<PanelItem title="灾毁损失">
|
||||
<div class="loss-row">
|
||||
<span class="loss-label">塌方及损失</span>
|
||||
<span class="loss-value">{{ formData.collapseLoss }}万/万元</span>
|
||||
</div>
|
||||
<van-button size="small" block type="primary" plain @click="showLossDialog = true">添加损失</van-button>
|
||||
<van-field v-model="formData.handlingSituation" label="处理情况" placeholder="请填写(选填)" />
|
||||
<van-field v-model="formData.totalLossAmount" label="损失总金额" placeholder="请填写(选填)" type="digit">
|
||||
<template #button>
|
||||
<span class="field-unit">万元</span>
|
||||
</template>
|
||||
</van-field>
|
||||
</PanelItem>
|
||||
|
||||
<PanelItem>
|
||||
<van-field v-model="formData.machineryInput" label="已投机械" placeholder="请填写" type="digit">
|
||||
<template #button>
|
||||
<span class="field-unit">台/班</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.laborInput" label="已投入力" placeholder="请填写" type="number">
|
||||
<template #button>
|
||||
<span class="field-unit">人次</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.fundsInput" label="已投资金" placeholder="请填写" type="digit">
|
||||
<template #button>
|
||||
<span class="field-unit">万元</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.siteDescription" label="现场描述" placeholder="请填写" type="textarea" rows="2" autosize />
|
||||
|
||||
<van-field label="附件">
|
||||
<template #input>
|
||||
</template>
|
||||
</van-field>
|
||||
</PanelItem>
|
||||
|
||||
<!-- 附件 -->
|
||||
<!-- <PanelItem title="附件">
|
||||
<div class="attachment-tip">图片只能上传jpg/png文件,且不超过500kb;视频仅支持20s内的视频</div>
|
||||
<div class="upload-area">
|
||||
<van-uploader
|
||||
v-model="formData.imageFiles"
|
||||
:after-read="afterImageRead"
|
||||
accept="image/jpeg,image/png"
|
||||
:max-size="500 * 1024"
|
||||
@oversize="onOversize"
|
||||
multiple
|
||||
:max-count="9"
|
||||
>
|
||||
<div class="upload-btn">
|
||||
<van-icon name="photo-o" size="24" />
|
||||
<span>上传图片</span>
|
||||
</div>
|
||||
</van-uploader>
|
||||
<van-uploader v-model="formData.videoFile" :after-read="afterVideoRead" accept="video/*" :max-size="20 * 1024 * 1024" @oversize="onVideoOversize">
|
||||
<div class="upload-btn">
|
||||
<van-icon name="video-o" size="24" />
|
||||
<span>上传视频</span>
|
||||
</div>
|
||||
</van-uploader>
|
||||
</div>
|
||||
<div v-if="formData.videoFile.length > 0 && formData.videoFile[0].content" class="video-preview">
|
||||
<video :src="formData.videoFile[0].content" controls style="width: 100%; max-height: 200px"></video>
|
||||
</div>
|
||||
</PanelItem> -->
|
||||
|
||||
<!-- 损失计算弹窗 -->
|
||||
<van-dialog v-model:show="showLossDialog" title="添加塌方损失" show-cancel-button @confirm="confirmLoss" @cancel="showLossDialog = false">
|
||||
<div class="loss-dialog-content">
|
||||
<van-field v-model="lossForm.length" label="长度(m)" type="number" placeholder="请输入长度" />
|
||||
<van-field v-model="lossForm.width" label="宽度(m)" type="number" placeholder="请输入宽度" />
|
||||
<van-field v-model="lossForm.height" label="高度(m)" type="number" placeholder="请输入高度" />
|
||||
<van-field v-model="lossForm.unitPrice" label="单价(元/m³)" type="number" placeholder="请输入单价" />
|
||||
<div class="loss-calc-result">预估塌方量:{{ calculatedVolume }} m³</div>
|
||||
<div class="loss-calc-result">预估损失:{{ calculatedLoss }} 万元</div>
|
||||
</div>
|
||||
</van-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { showToast, showFailToast } from 'vant'
|
||||
import PanelItem from '@/components/PanelItem.vue'
|
||||
import BasePicker from '@/components/BasePicker.vue'
|
||||
import BaseDatePicker from '@/components/BaseDatePicker.vue'
|
||||
|
||||
// 定义 props
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
// 定义 emits
|
||||
const emit = defineEmits(['update:modelValue', 'submit'])
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
roadCondition: '',
|
||||
isBlocked: '',
|
||||
repairProgress: '',
|
||||
waterDamageCount: '',
|
||||
blockedMileage: '',
|
||||
occurTime: '',
|
||||
lineCode: '',
|
||||
startPileNo: '',
|
||||
startLongitude: '',
|
||||
startLatitude: '',
|
||||
endPileNo: '',
|
||||
endLongitude: '',
|
||||
endLatitude: '',
|
||||
roadLocation: '',
|
||||
smallPlaceName: '',
|
||||
disposalMeasures: [],
|
||||
estimatedRecoverTime: '',
|
||||
actualRecoverTime: '',
|
||||
injuredCount: '',
|
||||
deathCount: '',
|
||||
strandedPeople: '',
|
||||
damagedVehicles: '',
|
||||
strandedVehicles: '',
|
||||
collapseLoss: '0',
|
||||
handlingSituation: '',
|
||||
totalLossAmount: '',
|
||||
machineryInput: '',
|
||||
laborInput: '',
|
||||
fundsInput: '',
|
||||
siteDescription: '',
|
||||
imageFiles: [],
|
||||
videoFile: []
|
||||
})
|
||||
|
||||
// 弹窗显示状态
|
||||
const showLossDialog = ref(false)
|
||||
|
||||
// BasePicker 选项数据
|
||||
const roadConditionOptions = [
|
||||
{ label: '高速公路', value: '高速公路' },
|
||||
{ label: '国道', value: '国道' },
|
||||
{ label: '省道', value: '省道' },
|
||||
{ label: '县道', value: '县道' },
|
||||
{ label: '乡道', value: '乡道' },
|
||||
{ label: '村道', value: '村道' }
|
||||
]
|
||||
|
||||
const blockedOptions = [
|
||||
{ label: '是', value: '是' },
|
||||
{ label: '否', value: '否' }
|
||||
]
|
||||
|
||||
const repairProgressOptions = [
|
||||
{ label: '未开始', value: '未开始' },
|
||||
{ label: '进行中', value: '进行中' },
|
||||
{ label: '已抢通', value: '已抢通' },
|
||||
{ label: '已修复', value: '已修复' }
|
||||
]
|
||||
|
||||
// 时间选择器范围
|
||||
const minDate = new Date(2020, 0, 1)
|
||||
const maxDate = new Date(2030, 11, 31)
|
||||
|
||||
// 损失计算表单
|
||||
const lossForm = reactive({
|
||||
length: '',
|
||||
width: '',
|
||||
height: '',
|
||||
unitPrice: ''
|
||||
})
|
||||
|
||||
// 计算塌方量
|
||||
const calculatedVolume = computed(() => {
|
||||
const l = parseFloat(lossForm.length) || 0
|
||||
const w = parseFloat(lossForm.width) || 0
|
||||
const h = parseFloat(lossForm.height) || 0
|
||||
return (l * w * h).toFixed(2)
|
||||
})
|
||||
|
||||
// 计算损失金额(万元)
|
||||
const calculatedLoss = computed(() => {
|
||||
const volume = parseFloat(calculatedVolume.value) || 0
|
||||
const price = parseFloat(lossForm.unitPrice) || 0
|
||||
const lossYuan = volume * price
|
||||
return (lossYuan / 10000).toFixed(2)
|
||||
})
|
||||
|
||||
// 监听父组件传入的数据
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
if (newVal && Object.keys(newVal).length > 0) {
|
||||
Object.assign(formData, newVal)
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
|
||||
// 监听表单数据变化,同步到父组件
|
||||
watch(
|
||||
formData,
|
||||
() => {
|
||||
emit('update:modelValue', { ...formData })
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
// 校准时间
|
||||
const calibrateTime = () => {
|
||||
const now = new Date()
|
||||
const formatted = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`
|
||||
formData.occurTime = formatted
|
||||
showToast('时间已校准为当前时间')
|
||||
}
|
||||
|
||||
// 校准起点经纬度
|
||||
const calibrateStartCoord = () => {
|
||||
formData.startLongitude = '108.41763025'
|
||||
formData.startLatitude = '108.41763025'
|
||||
showToast('起点经纬度已校准')
|
||||
}
|
||||
|
||||
// 校准止点经纬度
|
||||
const calibrateEndCoord = () => {
|
||||
formData.endLongitude = '108.41763025'
|
||||
formData.endLatitude = '108.41763025'
|
||||
showToast('止点经纬度已校准')
|
||||
}
|
||||
|
||||
// 确认损失计算
|
||||
const confirmLoss = () => {
|
||||
const lossValue = calculatedLoss.value
|
||||
if (parseFloat(lossValue) > 0) {
|
||||
formData.collapseLoss = lossValue
|
||||
if (formData.totalLossAmount) {
|
||||
const currentTotal = parseFloat(formData.totalLossAmount) || 0
|
||||
formData.totalLossAmount = (currentTotal + parseFloat(lossValue)).toFixed(2)
|
||||
} else {
|
||||
formData.totalLossAmount = lossValue
|
||||
}
|
||||
} else {
|
||||
showToast('请填写有效的长宽高和单价')
|
||||
}
|
||||
lossForm.length = ''
|
||||
lossForm.width = ''
|
||||
lossForm.height = ''
|
||||
lossForm.unitPrice = ''
|
||||
showLossDialog.value = false
|
||||
}
|
||||
|
||||
// 图片上传处理
|
||||
const afterImageRead = (file) => {
|
||||
console.log('图片上传:', file)
|
||||
}
|
||||
|
||||
const onOversize = () => {
|
||||
showFailToast('图片大小不能超过500KB')
|
||||
}
|
||||
|
||||
const afterVideoRead = (file) => {
|
||||
console.log('视频上传:', file)
|
||||
}
|
||||
|
||||
const onVideoOversize = () => {
|
||||
showFailToast('视频大小不能超过20MB')
|
||||
}
|
||||
|
||||
// 暴露验证方法
|
||||
const validate = () => {
|
||||
if (!formData.occurTime) {
|
||||
showToast('请填写发生时间')
|
||||
return false
|
||||
}
|
||||
if (!formData.lineCode) {
|
||||
showToast('请填写线路编号')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取表单数据
|
||||
const getFormData = () => {
|
||||
return { ...formData }
|
||||
}
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
validate,
|
||||
getFormData
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.water-disaster {
|
||||
|
||||
.coordinate-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
.coordinate-field {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.calibrate-time-btn,
|
||||
.calibrate-coord-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 12px;
|
||||
color: #1989fa;
|
||||
margin: 8px 0 8px 12px;
|
||||
padding: 4px 8px;
|
||||
background: #f0f7ff;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.field-unit {
|
||||
color: #969799;
|
||||
font-size: 14px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.disposal-measures {
|
||||
margin-bottom: 16px;
|
||||
.measures-label {
|
||||
font-size: 14px;
|
||||
color: #323233;
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.measures-options {
|
||||
:deep(.van-checkbox-group) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
}
|
||||
:deep(.van-checkbox) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loss-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #f8f9fa;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
margin: 12px 0;
|
||||
.loss-label {
|
||||
font-size: 14px;
|
||||
color: #323233;
|
||||
}
|
||||
.loss-value {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #ee0a24;
|
||||
}
|
||||
}
|
||||
|
||||
.attachment-tip {
|
||||
font-size: 12px;
|
||||
color: #969799;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
.upload-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: #f8f9fa;
|
||||
border: 1px dashed #dcdee0;
|
||||
border-radius: 8px;
|
||||
gap: 4px;
|
||||
font-size: 12px;
|
||||
color: #969799;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.video-preview {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.loss-dialog-content {
|
||||
padding: 8px 16px 16px;
|
||||
.loss-calc-result {
|
||||
font-size: 14px;
|
||||
color: #1989fa;
|
||||
margin-top: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.van-field__label) {
|
||||
width: 90px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<!-- 损失计算弹窗 -->
|
||||
<van-dialog
|
||||
v-model:show="visible"
|
||||
title="塌方损失信息"
|
||||
show-cancel-button
|
||||
@confirm="confirm"
|
||||
@cancel="cancelLoss"
|
||||
confirm-button-text="确定"
|
||||
cancel-button-text="取消"
|
||||
>
|
||||
<div class="loss-dialog-content">
|
||||
<!-- 塌方长 -->
|
||||
<van-field v-model="formData.length" label="塌方长" placeholder="请填写长度" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">米</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<!-- 塌方宽 -->
|
||||
<van-field v-model="formData.width" label="塌方宽" placeholder="请填写宽度" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">米</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<!-- 塌方高 -->
|
||||
<van-field v-model="formData.height" label="塌方高" placeholder="请填写高度" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">米</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<!-- 单价 (0-2000元) -->
|
||||
<van-field v-model="formData.unitPrice" label="单价(0-2000元)" placeholder="请填写单价" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">元</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<van-field v-model="formData.totalPrice" label="塌方损失金额" placeholder="请填写金额" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">元</span>
|
||||
</template>
|
||||
</van-field>
|
||||
</div>
|
||||
</van-dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref, reactive, watch, computed } from 'vue'
|
||||
import { showToast } from 'vant'
|
||||
|
||||
// 弹窗显示状态
|
||||
const visible = ref(false)
|
||||
|
||||
// 损失计算表单
|
||||
const formData = ref({
|
||||
length: '',
|
||||
width: '',
|
||||
height: '',
|
||||
unitPrice: ''
|
||||
})
|
||||
|
||||
const totalPrice = computed(() => {
|
||||
const l = parseFloat(formData.value.length)
|
||||
const w = parseFloat(formData.value.width)
|
||||
const h = parseFloat(formData.value.height)
|
||||
const price = parseFloat(formData.value.unitPrice)
|
||||
if (isNaN(l) || l <= 0) {
|
||||
return 0
|
||||
}
|
||||
if (isNaN(w) || w <= 0) {
|
||||
return 0
|
||||
}
|
||||
if (isNaN(h) || h <= 0) {
|
||||
return 0
|
||||
}
|
||||
if (isNaN(price) || price < 0) {
|
||||
return 0
|
||||
}
|
||||
if (price > 2000) {
|
||||
return 0
|
||||
}
|
||||
return (l * w * h * price)
|
||||
})
|
||||
|
||||
watch(totalPrice, ()=>{
|
||||
formData.value.totalPrice = totalPrice.value
|
||||
})
|
||||
// 显示弹窗
|
||||
const show = () => {
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
// 验证表单数据
|
||||
const validateForm = () => {
|
||||
const l = parseFloat(formData.length)
|
||||
const w = parseFloat(formData.width)
|
||||
const h = parseFloat(formData.height)
|
||||
const price = parseFloat(formData.unitPrice)
|
||||
|
||||
if (isNaN(l) || l <= 0) {
|
||||
showToast('请填写有效的塌方长度')
|
||||
return false
|
||||
}
|
||||
if (isNaN(w) || w <= 0) {
|
||||
showToast('请填写有效的塌方宽度')
|
||||
return false
|
||||
}
|
||||
if (isNaN(h) || h <= 0) {
|
||||
showToast('请填写有效的塌方高度')
|
||||
return false
|
||||
}
|
||||
if (isNaN(price) || price < 0) {
|
||||
showToast('请填写有效的单价')
|
||||
return false
|
||||
}
|
||||
if (price > 2000) {
|
||||
showToast('单价不能超过2000元')
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// 确认损失计算
|
||||
const confirm = () => {
|
||||
if(!formData.value.totalPrice) {
|
||||
showToast('请填写损失金额')
|
||||
return
|
||||
}
|
||||
emit('confirm', formData.value.totalPrice)
|
||||
// 重置表单
|
||||
resetForm()
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
// 取消操作
|
||||
const cancelLoss = () => {
|
||||
resetForm()
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
formData.value.length = ''
|
||||
formData.value.width = ''
|
||||
formData.value.height = ''
|
||||
formData.value.unitPrice = ''
|
||||
formData.value.totalPrice
|
||||
}
|
||||
// 定义事件
|
||||
const emit = defineEmits(['confirm'])
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div class="loss-list">
|
||||
<template v-for="item in modelValue">
|
||||
<van-field v-model="item.totalAmount" :label="getItemLabel(item)" placeholder="请填写" type="digit" @click="cubeCalculateDialog.show()">
|
||||
<template #button>
|
||||
<span class="field-unit">方/万元</span>
|
||||
</template>
|
||||
</van-field>
|
||||
</template>
|
||||
<van-button size="small" block type="primary" plain @click="addLoss">添加损失</van-button>
|
||||
<CubeCalculateDialog ref="cubeCalculateDialog" />
|
||||
<LossPicker ref="lossPicker" :options="options" @confirm="confirmAddLoss" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import CubeCalculateDialog from './CubeCalculateDialog.vue'
|
||||
import { request } from '@shared/utils/request'
|
||||
import LossPicker from './LossPicker.vue'
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const lossPicker = ref(null)
|
||||
|
||||
const options = ref({})
|
||||
// 添加损失项
|
||||
const addLoss = () => {
|
||||
lossPicker.value?.show()
|
||||
}
|
||||
|
||||
const confirmAddLoss = (item) => {
|
||||
emit('update:modelValue', [...props.modelValue, item])
|
||||
}
|
||||
|
||||
const cubeCalculateDialog = ref(null)
|
||||
|
||||
const getItemLabel = (item) => {
|
||||
const loss = options.value.loss?.find((loss) => loss.value === item.lossTypeId)
|
||||
return loss?.text
|
||||
}
|
||||
|
||||
const getLossDict = async (params) => {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/water-damage/loss/typeAndInfo',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
options.value.loss = res.data.records.map((item)=>{
|
||||
return {
|
||||
text: item.lossTypeName,
|
||||
value: item.lossTypeId,
|
||||
item
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await getLossDict()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.field-unit {
|
||||
color: #969799;
|
||||
font-size: 14px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.loss-dialog-content {
|
||||
padding: 16px;
|
||||
|
||||
:deep(.van-field) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.calculation-preview {
|
||||
background-color: #f7f8fa;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
margin-top: 12px;
|
||||
|
||||
.preview-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.preview-label {
|
||||
color: #646566;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.preview-value {
|
||||
color: #ee0a24;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<van-popup v-model:show="showPicker" position="bottom" round>
|
||||
<van-picker :columns="columns" :title="pickerTitle" show-toolbar @confirm="onConfirm" @cancel="showPicker = false" />
|
||||
</van-popup>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref, computed } from 'vue'
|
||||
|
||||
const emit = defineEmits(['confirm'])
|
||||
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const pickerTitle = ref("请选择损失类型")
|
||||
|
||||
|
||||
const columns = computed(() => {
|
||||
return props.options.loss || []
|
||||
})
|
||||
|
||||
const showPicker = ref(false)
|
||||
|
||||
const show = () => {
|
||||
showPicker.value = true
|
||||
}
|
||||
|
||||
const clsoe = () => {
|
||||
showPicker.value = false
|
||||
}
|
||||
|
||||
const onConfirm = ({ selectedValues, selectedOptions }) => {
|
||||
|
||||
emit('confirm', selectedOptions[0].item)
|
||||
showPicker.value = false
|
||||
}
|
||||
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
clsoe
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
@ -0,0 +1,524 @@
|
||||
<template>
|
||||
<div class="water-disaster">
|
||||
<!-- 基本信息 -->
|
||||
<PanelItem title="基本信息">
|
||||
<van-form>
|
||||
<!-- 路况类别 -->
|
||||
<BasePicker v-model="formData.roadConditionType" :options="roadConditionOptions" label="路况类别" placeholder="请选择" />
|
||||
|
||||
<!-- 是否阻断 (event.isBlocked) -->
|
||||
<BasePicker v-model="formData.event.isBlocked" :options="blockedOptions" label="是否阻断" placeholder="请选择" />
|
||||
|
||||
<!-- 抢修进度 (event.repairProgress) -->
|
||||
<BasePicker v-model="formData.event.repairProgress" :options="repairProgressOptions" label="抢修进度" placeholder="请选择" />
|
||||
|
||||
<!-- 水毁处数 (event.damageCount) -->
|
||||
<van-field v-model="formData.event.damageCount" label="水毁处数" placeholder="请填写" type="number" />
|
||||
|
||||
<!-- 阻断里程 (event.blockedMileage) -->
|
||||
<van-field v-model="formData.event.blockedMileage" label="阻断里程" placeholder="请填写" type="digit">
|
||||
<template #button>
|
||||
<span class="field-unit">公里</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<!-- 发生时间 (顶层 occurTime) -->
|
||||
<BaseDatePicker v-model="formData.occurTime" label="发生时间" placeholder="请选择时间" :columnsType="['year', 'month', 'day', 'hour', 'minute']" />
|
||||
<div class="calibrate-time-btn" @click="calibrateTime">
|
||||
<van-icon name="replay" />
|
||||
<span>校准时间</span>
|
||||
</div>
|
||||
|
||||
<!-- 线路编号 (顶层 routeNo) -->
|
||||
<van-field v-model="formData.routeNo" label="线路编号" placeholder="请填写" />
|
||||
|
||||
<!-- 起点桩号 (event.startStakeNo) -->
|
||||
<van-field v-model="formData.event.startStakeNo" label="起点桩号(K)" placeholder="请填写" />
|
||||
|
||||
<!-- 起点桩经纬度 (event.startStakeLng / startStakeLat) -->
|
||||
<div class="coordinate-row">
|
||||
<van-field v-model="formData.event.startStakeLng" label="起点桩经度" placeholder="经度" class="coordinate-field" />
|
||||
<van-field v-model="formData.event.startStakeLat" label="起点桩纬度" placeholder="纬度" class="coordinate-field" />
|
||||
</div>
|
||||
<div class="calibrate-coord-btn" @click="calibrateStartCoord">
|
||||
<van-icon name="location-o" />
|
||||
<span>校准经纬度</span>
|
||||
</div>
|
||||
|
||||
<!-- 止点桩号 (event.endStakeNo) -->
|
||||
<van-field v-model="formData.event.endStakeNo" label="止点桩号(K)" placeholder="请填写" />
|
||||
|
||||
<!-- 止点桩经纬度 (event.endStakeLng / endStakeLat) -->
|
||||
<div class="coordinate-row">
|
||||
<van-field v-model="formData.event.endStakeLng" label="止点桩经度" placeholder="经度" class="coordinate-field" />
|
||||
<van-field v-model="formData.event.endStakeLat" label="止点桩纬度" placeholder="纬度" class="coordinate-field" />
|
||||
</div>
|
||||
<div class="calibrate-coord-btn" @click="calibrateEndCoord">
|
||||
<van-icon name="location-o" />
|
||||
<span>校准经纬度</span>
|
||||
</div>
|
||||
|
||||
<!-- 路况位置 (event.endStakeNo) -->
|
||||
<van-field v-model="formData.occurLocation" label="路况位置" placeholder="请填写" />
|
||||
|
||||
<!-- 阻断点小地名 (event.blockedPointName) -->
|
||||
<van-field v-model="formData.event.blockedPointName" label="阻断点小地名" placeholder="请填写" />
|
||||
</van-form>
|
||||
</PanelItem>
|
||||
|
||||
<!-- 处置情况 (report) -->
|
||||
<PanelItem title="处置情况">
|
||||
<div class="disposal-measures">
|
||||
<span class="measures-label">处置措施</span>
|
||||
<div class="measures-options">
|
||||
<van-checkbox-group v-model="disposalMeasuresArray" direction="horizontal">
|
||||
<van-checkbox name="halfClose">半幅封闭</van-checkbox>
|
||||
<van-checkbox name="fullClose">全副封闭</van-checkbox>
|
||||
<van-checkbox name="bypass">便道通行</van-checkbox>
|
||||
<van-checkbox name="normal">正常通行</van-checkbox>
|
||||
</van-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 预计恢复时间 (report.expectRecoverTime) -->
|
||||
<BaseDatePicker v-model="formData.report.expectRecoverTime" label="预计恢复时间" placeholder="请选择时间" :min-date="minDate" :max-date="maxDate" type="datetime" />
|
||||
|
||||
<!-- 实际恢复时间 (report.actualRecoverTime) -->
|
||||
<BaseDatePicker v-model="formData.report.actualRecoverTime" label="实际恢复时间" placeholder="请选择时间" :min-date="minDate" :max-date="maxDate" type="datetime" />
|
||||
</PanelItem>
|
||||
|
||||
<!-- 人员车辆 (report) -->
|
||||
<PanelItem title="人员车辆">
|
||||
<van-form>
|
||||
<van-field v-model="formData.report.injuredCount" label="受伤人员" placeholder="请填写" type="number">
|
||||
<template #button>
|
||||
<span class="field-unit">人</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.report.deadCount" label="死亡人员" placeholder="请填写" type="number">
|
||||
<template #button>
|
||||
<span class="field-unit">人</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.report.strandedPersonCount" label="滞留人员" placeholder="请填写" type="number">
|
||||
<template #button>
|
||||
<span class="field-unit">人</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.report.damagedVehicleCount" label="损坏车辆" placeholder="请填写" type="number">
|
||||
<template #button>
|
||||
<span class="field-unit">辆</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.report.strandedVehicleCount" label="滞留车辆" placeholder="请填写" type="number">
|
||||
<template #button>
|
||||
<span class="field-unit">辆</span>
|
||||
</template>
|
||||
</van-field>
|
||||
</van-form>
|
||||
</PanelItem>
|
||||
|
||||
<!-- 灾毁损失 (lossList) -->
|
||||
<PanelItem title="灾毁损失">
|
||||
<LossList v-model="formData.lossList" />
|
||||
<van-field v-model="formData.report.remark" label="处理情况" placeholder="请填写(选填)" />
|
||||
<van-field v-model="formData.report.totalLossAmount" label="损失总金额" placeholder="请填写(选填)" type="digit">
|
||||
<template #button>
|
||||
<span class="field-unit">万元</span>
|
||||
</template>
|
||||
</van-field>
|
||||
</PanelItem>
|
||||
|
||||
<!-- 投入资源 (report) -->
|
||||
<PanelItem>
|
||||
<van-field v-model="formData.report.investedMachinery" label="已投机械" placeholder="请填写" type="digit">
|
||||
<template #button>
|
||||
<span class="field-unit">台/班</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.report.investedManpower" label="已投入力" placeholder="请填写" type="number">
|
||||
<template #button>
|
||||
<span class="field-unit">人次</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.report.investedFunds" label="已投资金" placeholder="请填写" type="digit">
|
||||
<template #button>
|
||||
<span class="field-unit">万元</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.report.siteDescription" label="现场描述" placeholder="请填写" type="textarea" rows="2" autosize />
|
||||
</PanelItem>
|
||||
|
||||
<!-- 附件 (fileList) -->
|
||||
<!-- <PanelItem title="附件">
|
||||
<div class="attachment-tip">图片只能上传jpg/png文件,且不超过500kb;视频仅支持20s内的视频</div>
|
||||
<div class="upload-area">
|
||||
<van-uploader v-model="imageFileList" :after-read="afterImageRead" accept="image/jpeg,image/png" :max-size="500 * 1024" @oversize="onOversize" multiple :max-count="9">
|
||||
<div class="upload-btn">
|
||||
<van-icon name="photo-o" size="24" />
|
||||
<span>上传图片</span>
|
||||
</div>
|
||||
</van-uploader>
|
||||
<van-uploader v-model="videoFileList" :after-read="afterVideoRead" accept="video/*" :max-size="20 * 1024 * 1024" @oversize="onVideoOversize">
|
||||
<div class="upload-btn">
|
||||
<van-icon name="video-o" size="24" />
|
||||
<span>上传视频</span>
|
||||
</div>
|
||||
</van-uploader>
|
||||
</div>
|
||||
<div v-if="videoFileList.length > 0 && videoFileList[0].content" class="video-preview">
|
||||
<video :src="videoFileList[0].content" controls style="width: 100%; max-height: 200px"></video>
|
||||
</div>
|
||||
</PanelItem> -->
|
||||
|
||||
<PanelItem>
|
||||
<!-- 是否需要恢复重建 (event.needsRecovery) -->
|
||||
<BasePicker v-model="formData.event.needsRecovery" :options="needsRecoveryOptions" label="是否需要恢复重建" placeholder="请选择" />
|
||||
<!-- 恢复重建预估费用 (event.estimatedRecoveryCost) -->
|
||||
<van-field v-model="formData.event.estimatedRecoveryCost" label="恢复重建预估费用" placeholder="请填写" type="digit">
|
||||
<template #button>
|
||||
<span class="field-unit">万元</span>
|
||||
</template>
|
||||
</van-field>
|
||||
</PanelItem>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { showToast, showFailToast } from 'vant'
|
||||
import PanelItem from '@/components/PanelItem.vue'
|
||||
import BasePicker from '@/components/BasePicker.vue'
|
||||
import BaseDatePicker from '@/components/BaseDatePicker.vue'
|
||||
import LossList from './LossList.vue'
|
||||
|
||||
|
||||
// 处置措施数组(用于多选框组,需要转换为逗号分隔的字符串)
|
||||
const disposalMeasuresArray = ref([])
|
||||
|
||||
// 附件列表
|
||||
const imageFileList = ref([])
|
||||
const videoFileList = ref([])
|
||||
|
||||
// 表单数据 - 按 Request 接口结构定义
|
||||
const formData = reactive({
|
||||
// 顶层字段
|
||||
occurLocation: '', // 发生地点
|
||||
occurTime: '', // 发生时间
|
||||
roadConditionType: '', // 路况类别
|
||||
routeNo: '', // 线路编号
|
||||
|
||||
// event 对象
|
||||
event: {
|
||||
blockedMileage: '', // 阻断里程
|
||||
blockedPointName: '', // 阻断点小地名
|
||||
contactPerson: '', // 联系人
|
||||
contactPhone: '', // 联系电话
|
||||
damageCount: '', // 水毁处数
|
||||
district: '', // 上报区县
|
||||
endStakeLat: '', // 止点纬度
|
||||
endStakeLng: '', // 止点经度
|
||||
endStakeNo: '', // 止点桩号
|
||||
estimatedRecoveryCost: '', // 恢复重建预估费用
|
||||
inspectionMileage: '', // 巡查里程
|
||||
isBlocked: '', // 是否阻断
|
||||
needsRecovery: '', // 是否需要恢复重建
|
||||
repairProgress: '', // 抢修进度
|
||||
reporterUnit: '', // 填报单位
|
||||
startStakeLat: '', // 起点纬度
|
||||
startStakeLng: '', // 起点经度
|
||||
startStakeNo: '' // 起点桩号
|
||||
},
|
||||
|
||||
// report 对象
|
||||
report: {
|
||||
actualRecoverTime: '', // 实际恢复时间
|
||||
damagedVehicleCount: '', // 损坏车辆
|
||||
deadCount: '', // 死亡人员
|
||||
disposalMeasures: '', // 处置措施(逗号分隔)
|
||||
expectRecoverTime: '', // 预计恢复时间
|
||||
injuredCount: '', // 受伤人员
|
||||
investedFunds: '', // 已投资金
|
||||
investedMachinery: '', // 已投机械
|
||||
investedManpower: '', // 已投人力
|
||||
remark: '', // 处理情况/备注
|
||||
siteDescription: '', // 现场描述
|
||||
strandedPersonCount: '', // 滞留人员
|
||||
strandedVehicleCount: '', // 滞留车辆
|
||||
totalLossAmount: '' // 损失总金额
|
||||
},
|
||||
|
||||
// lossList 数组
|
||||
lossList: [],
|
||||
|
||||
// fileList 数组
|
||||
fileList: []
|
||||
})
|
||||
|
||||
// 监听处置措施数组变化,转换为逗号分隔的字符串存到 report.disposalMeasures
|
||||
watch(
|
||||
disposalMeasuresArray,
|
||||
(newVal) => {
|
||||
formData.report.disposalMeasures = newVal.join(',')
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
// 监听附件变化,同步到 fileList
|
||||
watch(
|
||||
imageFileList,
|
||||
(newVal) => {
|
||||
// 转换为接口需要的格式
|
||||
formData.fileList = [
|
||||
...imageFileList.value.map((f) => ({
|
||||
fileName: f.file?.name || '',
|
||||
fileSize: f.file?.size || 0,
|
||||
fileType: 1, // 1-图片
|
||||
fileUrl: f.content || ''
|
||||
})),
|
||||
...videoFileList.value.map((f) => ({
|
||||
fileName: f.file?.name || '',
|
||||
fileSize: f.file?.size || 0,
|
||||
fileType: 2, // 2-视频
|
||||
fileUrl: f.content || ''
|
||||
}))
|
||||
]
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
videoFileList,
|
||||
(newVal) => {
|
||||
formData.fileList = [
|
||||
...imageFileList.value.map((f) => ({
|
||||
fileName: f.file?.name || '',
|
||||
fileSize: f.file?.size || 0,
|
||||
fileType: 1,
|
||||
fileUrl: f.content || ''
|
||||
})),
|
||||
...newVal.map((f) => ({
|
||||
fileName: f.file?.name || '',
|
||||
fileSize: f.file?.size || 0,
|
||||
fileType: 2,
|
||||
fileUrl: f.content || ''
|
||||
}))
|
||||
]
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
// 从 report.disposalMeasures 初始化处置措施数组
|
||||
watch(
|
||||
() => formData.report.disposalMeasures,
|
||||
(newVal) => {
|
||||
if (newVal && typeof newVal === 'string') {
|
||||
disposalMeasuresArray.value = newVal.split(',').filter(Boolean)
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
// BasePicker 选项数据
|
||||
const roadConditionOptions = [
|
||||
{ label: '高速公路', value: '高速公路' },
|
||||
{ label: '国道', value: '国道' },
|
||||
{ label: '省道', value: '省道' },
|
||||
{ label: '县道', value: '县道' },
|
||||
{ label: '乡道', value: '乡道' },
|
||||
{ label: '村道', value: '村道' }
|
||||
]
|
||||
|
||||
const blockedOptions = [
|
||||
{ label: '是', value: true },
|
||||
{ label: '否', value: false }
|
||||
]
|
||||
|
||||
const repairProgressOptions = [
|
||||
{ label: '未抢修', value: '未抢修' },
|
||||
{ label: '抢修中', value: '抢修中' },
|
||||
{ label: '已完成', value: '已完成' },
|
||||
]
|
||||
|
||||
const needsRecoveryOptions = [
|
||||
{ label: '是', value: true },
|
||||
{ label: '否', value: false }
|
||||
]
|
||||
|
||||
// 时间选择器范围
|
||||
const minDate = new Date(2020, 0, 1)
|
||||
const maxDate = new Date(2030, 11, 31)
|
||||
|
||||
const initFormData = (newVal) => {
|
||||
if (newVal && Object.keys(newVal).length > 0) {
|
||||
// 深度合并数据
|
||||
Object.assign(formData, {
|
||||
occurLocation: newVal.occurLocation || '',
|
||||
occurTime: newVal.occurTime || '',
|
||||
roadConditionType: newVal.roadConditionType || '',
|
||||
routeNo: newVal.routeNo || '',
|
||||
event: { ...formData.event, ...(newVal.event || {}) },
|
||||
report: { ...formData.report, ...(newVal.report || {}) },
|
||||
lossList: newVal.lossList || [],
|
||||
fileList: newVal.fileList || []
|
||||
})
|
||||
|
||||
// 初始化处置措施数组
|
||||
if (newVal.report?.disposalMeasures) {
|
||||
disposalMeasuresArray.value = newVal.report.disposalMeasures.split(',').filter(Boolean)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 校准时间
|
||||
const calibrateTime = () => {
|
||||
const now = new Date()
|
||||
const formatted = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`
|
||||
formData.occurTime = formatted
|
||||
showToast('时间已校准为当前时间')
|
||||
}
|
||||
|
||||
// 校准起点经纬度
|
||||
const calibrateStartCoord = () => {
|
||||
formData.event.startStakeLng = '108.41763025'
|
||||
formData.event.startStakeLat = '108.41763025'
|
||||
showToast('起点经纬度已校准')
|
||||
}
|
||||
|
||||
// 校准止点经纬度
|
||||
const calibrateEndCoord = () => {
|
||||
formData.event.endStakeLng = '108.41763025'
|
||||
formData.event.endStakeLat = '108.41763025'
|
||||
showToast('止点经纬度已校准')
|
||||
}
|
||||
|
||||
// 图片上传处理
|
||||
const afterImageRead = (file) => {
|
||||
console.log('图片上传:', file)
|
||||
}
|
||||
|
||||
const onOversize = () => {
|
||||
showFailToast('图片大小不能超过500KB')
|
||||
}
|
||||
|
||||
const afterVideoRead = (file) => {
|
||||
console.log('视频上传:', file)
|
||||
}
|
||||
|
||||
const onVideoOversize = () => {
|
||||
showFailToast('视频大小不能超过20MB')
|
||||
}
|
||||
|
||||
// 暴露验证方法
|
||||
const validate = () => {
|
||||
if (!formData.occurTime) {
|
||||
showToast('请填写发生时间')
|
||||
return false
|
||||
}
|
||||
if (!formData.routeNo) {
|
||||
showToast('请填写线路编号')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取表单数据
|
||||
const getFormData = () => {
|
||||
return { ...formData }
|
||||
}
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
validate,
|
||||
initFormData,
|
||||
getFormData
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.water-disaster {
|
||||
.coordinate-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
.coordinate-field {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.calibrate-time-btn,
|
||||
.calibrate-coord-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 12px;
|
||||
color: #1989fa;
|
||||
margin: 8px 0 8px 12px;
|
||||
padding: 4px 8px;
|
||||
background: #f0f7ff;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.field-unit {
|
||||
color: #969799;
|
||||
font-size: 14px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.disposal-measures {
|
||||
margin-bottom: 16px;
|
||||
.measures-label {
|
||||
font-size: 14px;
|
||||
color: #323233;
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.measures-options {
|
||||
:deep(.van-checkbox-group) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
}
|
||||
:deep(.van-checkbox) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.attachment-tip {
|
||||
font-size: 12px;
|
||||
color: #969799;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
.upload-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: #f8f9fa;
|
||||
border: 1px dashed #dcdee0;
|
||||
border-radius: 8px;
|
||||
gap: 4px;
|
||||
font-size: 12px;
|
||||
color: #969799;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.video-preview {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
:deep(.van-field__label) {
|
||||
width: 110px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,63 @@
|
||||
{
|
||||
"occurLocation": "G108国道 K2250+300处",
|
||||
"occurTime": "2024-07-15 14:30:00",
|
||||
"roadConditionType": "国道",
|
||||
"routeNo": "G108",
|
||||
"event": {
|
||||
"blockedMileage": 1.5,
|
||||
"blockedPointName": "磨盘山隧道口",
|
||||
"contactPerson": "张明",
|
||||
"contactPhone": "13812345678",
|
||||
"damageCount": 3,
|
||||
"district": "武侯区",
|
||||
"endStakeLat": "30.658712",
|
||||
"endStakeLng": "104.082356",
|
||||
"endStakeNo": "K2251+200",
|
||||
"estimatedRecoveryCost": 120.5,
|
||||
"inspectionMileage": 25.6,
|
||||
"isBlocked": true,
|
||||
"needsRecovery": true,
|
||||
"repairProgress": "抢修中",
|
||||
"reporterUnit": "武侯区交通运输局",
|
||||
"startStakeLat": "30.652145",
|
||||
"startStakeLng": "104.075632",
|
||||
"startStakeNo": "K2250+300"
|
||||
},
|
||||
"report": {
|
||||
"damagedVehicleCount": 2,
|
||||
"strandedPersonCount": 12,
|
||||
"deadCount": 0,
|
||||
"strandedVehicleCount": 12,
|
||||
"disposalMeasures": "halfClose,bypass",
|
||||
"actualRecoverTime": "2024-07-17 12:00:00",
|
||||
"expectRecoverTime": "2024-07-18 18:00:00",
|
||||
"injuredCount": 1,
|
||||
"investedFunds": 35.8,
|
||||
"investedMachinery": 6,
|
||||
"investedManpower": 45,
|
||||
"remark": "已组织抢险队伍进行抢通,便道已修建完成",
|
||||
"siteDescription": "因持续强降雨导致山体滑坡,掩埋路面约50米,边坡垮塌严重",
|
||||
"totalLossAmount": 85.6
|
||||
},
|
||||
"lossList": [
|
||||
{
|
||||
"length": 50,
|
||||
"width": 8.5,
|
||||
"height": 2.5,
|
||||
"unitPrice": 380,
|
||||
"totalAmount": 38.9,
|
||||
"lossCategory": "路面损毁",
|
||||
"remark": "沥青路面严重损坏"
|
||||
},
|
||||
{
|
||||
"length": 30,
|
||||
"width": 2.5,
|
||||
"height": 6,
|
||||
"unitPrice": 520,
|
||||
"totalAmount": 23.4,
|
||||
"lossCategory": "挡墙损毁",
|
||||
"remark": "浆砌片石挡墙垮塌"
|
||||
}
|
||||
],
|
||||
"fileList": []
|
||||
}
|
||||
BIN
packages/screen/src/assets/MaMap_img/区县icon@2x.png
Normal file
|
After Width: | Height: | Size: 836 B |
BIN
packages/screen/src/assets/MaMap_img/区县弹窗背景@2x.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
packages/screen/src/assets/MaMap_img/蓝色@2x (1).png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
packages/screen/src/assets/MaMap_img/蓝色@2x1.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
packages/screen/src/assets/MaMap_img/队伍icon定位@2x.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
packages/screen/src/assets/MaMap_img/隧洞icon定位@2x.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
packages/screen/src/assets/MaMap_img/项目@2x.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
packages/screen/src/assets/xiangying/无回应@2x.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
packages/screen/src/assets/xiangying/有回应@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
packages/screen/src/assets/xiangying/未选中1@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
packages/screen/src/assets/xiangying/未选中2@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
packages/screen/src/assets/xiangying/未选中3@2x.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
packages/screen/src/assets/xiangying/未选中4@2x.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
packages/screen/src/assets/xiangying/未选中bg@2x.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
packages/screen/src/assets/xiangying/选中@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
packages/screen/src/assets/xiangying/选中bg@2x.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
@ -17,7 +17,7 @@
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">影响区域</span>
|
||||
<el-select v-model="filterForm.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-select :teleported="false" v-model="filterForm.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in regionOptions"
|
||||
:key="item.value"
|
||||
@ -28,7 +28,7 @@
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">类型</span>
|
||||
<el-select v-model="filterForm.type" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-select :teleported="false" v-model="filterForm.type" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
:key="item.value"
|
||||
@ -39,7 +39,7 @@
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">管控措施</span>
|
||||
<el-select v-model="filterForm.controlMeasure" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-select :teleported="false" v-model="filterForm.controlMeasure" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in controlMeasureOptions"
|
||||
:key="item.value"
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">影响区域</span>
|
||||
<el-select v-model="filterForm.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-select :teleported="false" v-model="filterForm.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in regionOptions"
|
||||
:key="item.value"
|
||||
@ -29,7 +29,7 @@
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">驻地风险等级</span>
|
||||
<el-select v-model="filterForm.riskLevel" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-select :teleported="false" v-model="filterForm.riskLevel" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-option
|
||||
v-for="item in riskLevelOptions"
|
||||
:key="item.value"
|
||||
|
||||
@ -18,7 +18,14 @@
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">影响区域</span>
|
||||
<el-select v-model="filterForm.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.region"
|
||||
placeholder="请选择"
|
||||
popper-class="custom-select-popper"
|
||||
:popper-append-to-body="false"
|
||||
class="filter-select"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in regionOptions"
|
||||
:key="item.value"
|
||||
@ -29,7 +36,12 @@
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">类型</span>
|
||||
<el-select v-model="filterForm.type" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.type"
|
||||
placeholder="请选择"
|
||||
class="filter-select"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
:key="item.value"
|
||||
@ -75,13 +87,13 @@ const tableHeight = ref(300);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: 'id', label: '序号', width: '50' },
|
||||
{ prop: 'district', label: '区县/镇街', width: '100' },
|
||||
{ prop: 'name', label: '姓名', width: '80' },
|
||||
{ prop: 'phone', label: '电话', width: '120' },
|
||||
{ prop: 'type', label: '类型', width: '100' },
|
||||
{ prop: 'role', label: '角色', width: '140' },
|
||||
{ prop: 'dispatchTime', label: '调度时间', width: '160' },
|
||||
{ prop: "id", label: "序号", width: "60px" },
|
||||
{ prop: "district", label: "区县/镇街", width: "120px" },
|
||||
{ prop: "name", label: "姓名", width: "80px" },
|
||||
{ prop: "phone", label: "电话", width: "120px" },
|
||||
{ prop: "type", label: "类型", width: "120px" },
|
||||
{ prop: "role", label: "角色", width: "120px" },
|
||||
{ prop: "dispatchTime", label: "调度时间", width: "160px" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
@ -178,22 +190,19 @@ watch(
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.filter-row {
|
||||
// 筛选区域样式
|
||||
.filter-row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
.filter-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
@ -229,6 +238,5 @@ watch(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -18,7 +18,12 @@
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">影响区域</span>
|
||||
<el-select v-model="filterForm.region" placeholder="请选择" class="filter-select" clearable>
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.region"
|
||||
placeholder="请选择"
|
||||
class="filter-select"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in regionOptions"
|
||||
:key="item.value"
|
||||
@ -32,7 +37,9 @@
|
||||
|
||||
<!-- 调度数列插槽 -->
|
||||
<template #dispatchCount="{ row }">
|
||||
<span class="dispatch-count" @click="handleDispatchClick(row)">{{ row.dispatchCount }}</span>
|
||||
<span class="dispatch-count" @click="handleDispatchClick(row)">{{
|
||||
row.dispatchCount
|
||||
}}</span>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
@ -52,8 +59,8 @@ const props = defineProps({
|
||||
|
||||
const emit = defineEmits({
|
||||
"update:visible": (value) => typeof value === "boolean",
|
||||
"close": () => true,
|
||||
"dispatchClick": (item) => item !== undefined
|
||||
close: () => true,
|
||||
dispatchClick: (item) => item !== undefined,
|
||||
});
|
||||
|
||||
// 筛选表单
|
||||
@ -69,10 +76,10 @@ const tableHeight = ref(300);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: 'id', label: '序号', width: '60' },
|
||||
{ prop: 'region', label: '影响区域', width: '120' },
|
||||
{ prop: 'dispatchCount', label: '调度数', width: '100', slot: 'dispatchCount' },
|
||||
{ prop: 'lastDispatchTime', label: '最近调度时间', width: '160' },
|
||||
{ prop: "id", label: "序号", width: "" },
|
||||
{ prop: "region", label: "影响区域", width: "" },
|
||||
{ prop: "dispatchCount", label: "调度数", width: "", slot: "dispatchCount" },
|
||||
{ prop: "lastDispatchTime", label: "最近调度时间", width: "" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
@ -164,7 +171,7 @@ watch(
|
||||
filterForm.value.region = "";
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
|
||||
@ -18,21 +18,80 @@
|
||||
<template #header>
|
||||
<!-- 统计卡片 -->
|
||||
<div class="stats-cards">
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响桥梁</div>
|
||||
<div class="stat-value">2933</div>
|
||||
<div
|
||||
@click="handleClick('0')"
|
||||
class="stat-card"
|
||||
:style="{
|
||||
backgroundImage: `url(${cardType === '0' ? selectedIcon : unselectedIcon})`,
|
||||
backgroundSize: '100% 100%',
|
||||
backgroundPosition: 'center',
|
||||
}"
|
||||
>
|
||||
<div class="stat-icon"><img :src="Icon0" alt="" /></div>
|
||||
<div class="stat-content">
|
||||
<span class="stat-label">影响桥梁</span>
|
||||
<span class="stat-value">(1430)</span>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响边坡</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响隧道</div>
|
||||
<div class="stat-value">2933</div>
|
||||
<div
|
||||
@click="handleClick('1')"
|
||||
class="stat-card"
|
||||
:style="{
|
||||
backgroundImage: `url(${cardType === '1' ? selectedIcon : unselectedIcon})`,
|
||||
backgroundSize: '100% 100%',
|
||||
backgroundPosition: 'center',
|
||||
}"
|
||||
>
|
||||
<div class="stat-icon"><img :src="Icon1" alt="" /></div>
|
||||
<div class="stat-content">
|
||||
<span class="stat-label">影响边坡</span>
|
||||
<span class="stat-value">(933)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@click="handleClick('2')"
|
||||
class="stat-card"
|
||||
:style="{
|
||||
backgroundImage: `url(${cardType === '2' ? selectedIcon : unselectedIcon})`,
|
||||
backgroundSize: '100% 100%',
|
||||
backgroundPosition: 'center',
|
||||
}"
|
||||
>
|
||||
<div class="stat-icon"><img :src="Icon2" alt="" /></div>
|
||||
<div class="stat-content">
|
||||
<span class="stat-label">影响隧道</span>
|
||||
<span class="stat-value">(1033)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@click="handleClick('3')"
|
||||
class="stat-card"
|
||||
:style="{
|
||||
backgroundImage: `url(${cardType === '3' ? selectedIcon : unselectedIcon})`,
|
||||
backgroundSize: '100% 100%',
|
||||
backgroundPosition: 'center',
|
||||
}"
|
||||
>
|
||||
<div class="stat-icon"><img :src="Icon3" alt="" /></div>
|
||||
<div class="stat-content">
|
||||
<span class="stat-label">影响项目</span>
|
||||
<span class="stat-value">(832)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@click="handleClick('4')"
|
||||
class="stat-card"
|
||||
:style="{
|
||||
backgroundImage: `url(${cardType === '4' ? selectedIcon : unselectedIcon})`,
|
||||
backgroundSize: '100% 100%',
|
||||
backgroundPosition: 'center',
|
||||
}"
|
||||
>
|
||||
<div class="stat-icon"><img :src="Icon4" alt="" /></div>
|
||||
<div class="stat-content">
|
||||
<span class="stat-label">影响路段</span>
|
||||
<span class="stat-value">(832)</span>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响项目</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -41,7 +100,12 @@
|
||||
<template #filter>
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.pointType" size="small" placeholder="影响点类型" class="filter-select">
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.pointType"
|
||||
size="small"
|
||||
placeholder="影响点类型"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in pointTypeOptions"
|
||||
:key="option.value"
|
||||
@ -51,7 +115,12 @@
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.pointLevel" size="small" placeholder="影响点等级" class="filter-select">
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.pointLevel"
|
||||
size="small"
|
||||
placeholder="影响点等级"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in pointLevelOptions"
|
||||
:key="option.value"
|
||||
@ -61,7 +130,12 @@
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select v-model="filterForm.region" size="small" placeholder="影响区域" class="filter-select">
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.region"
|
||||
size="small"
|
||||
placeholder="影响区域"
|
||||
class="filter-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in regionOptionsWithAll"
|
||||
:key="option.value"
|
||||
@ -80,7 +154,9 @@
|
||||
|
||||
<!-- 影响点等级列插槽 -->
|
||||
<template #pointLevel="{ row }">
|
||||
<span class="level-tag" :class="row.levelClass">{{ row.pointLevel }}</span>
|
||||
<span class="level-tag" :class="row.levelClass">{{
|
||||
row.pointLevel
|
||||
}}</span>
|
||||
</template>
|
||||
|
||||
<!-- 交通主管部门负责人列插槽 -->
|
||||
@ -125,9 +201,24 @@
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
||||
import { pointTypeOptions, pointLevelOptions, regionOptionsWithAll } from "../component/index.js";
|
||||
import {
|
||||
pointTypeOptions,
|
||||
pointLevelOptions,
|
||||
regionOptionsWithAll,
|
||||
} from "../component/index.js";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
import respondedIcon from "../../../assets/xiangying/有回应@2x.png";
|
||||
import notRespondedIcon from "../../../assets/xiangying/无回应@2x.png";
|
||||
import selectedIcon from "../../../assets/xiangying/选中bg@2x.png";
|
||||
import unselectedIcon from "../../../assets/xiangying/未选中bg@2x.png";
|
||||
|
||||
import Icon0 from "../../../assets/xiangying/选中@2x.png";
|
||||
import Icon1 from "../../../assets/xiangying/未选中1@2x.png";
|
||||
import Icon2 from "../../../assets/xiangying/未选中2@2x.png";
|
||||
import Icon3 from "../../../assets/xiangying/未选中3@2x.png";
|
||||
import Icon4 from "../../../assets/xiangying/未选中4@2x.png";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
@ -146,16 +237,26 @@ const filterForm = ref({
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: "id", label: "序号", width: "50px" },
|
||||
{ prop: "region", label: "影响区域", width: "80px" },
|
||||
{ prop: "pointType", label: "影响点类型", width: "80px" },
|
||||
{ prop: "pointLocation", label: "影响点位置", width: "180px" },
|
||||
{ prop: "pointLevel", label: "影响点等级", width: "90px", slot: "pointLevel" },
|
||||
{ prop: "trafficDept", label: "交通主管部门负责人", width: "130px", slot: "trafficDept" },
|
||||
{ prop: "roadOrg", label: "公路机构责任人", width: "110px", slot: "roadOrg" },
|
||||
{ prop: "maintenance", label: "养护站负责人", width: "110px", slot: "maintenance" },
|
||||
{ prop: "roadKeeper", label: "护路员", width: "100px", slot: "roadKeeper" },
|
||||
{ prop: "operation", label: "操作", width: "60px", slot: "operation" },
|
||||
{ prop: "id", label: "序号", width: "" },
|
||||
{ prop: "region", label: "影响区域", width: "" },
|
||||
{ prop: "pointType", label: "影响点类型", width: "" },
|
||||
{ prop: "pointLocation", label: "影响点位置", width: "" },
|
||||
{ prop: "pointLevel", label: "影响点等级", width: "", slot: "pointLevel" },
|
||||
{
|
||||
prop: "trafficDept",
|
||||
label: "交通主管部门负责人",
|
||||
width: "",
|
||||
slot: "trafficDept",
|
||||
},
|
||||
{ prop: "roadOrg", label: "公路机构责任人", width: "", slot: "roadOrg" },
|
||||
{
|
||||
prop: "maintenance",
|
||||
label: "养护站负责人",
|
||||
width: "",
|
||||
slot: "maintenance",
|
||||
},
|
||||
{ prop: "roadKeeper", label: "护路员", width: "", slot: "roadKeeper" },
|
||||
{ prop: "operation", label: "操作", width: "", slot: "operation" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
@ -198,6 +299,12 @@ const tableData = ref([
|
||||
},
|
||||
]);
|
||||
|
||||
const cardType = ref("");
|
||||
// 点击卡片切换
|
||||
const handleClick = (type) => {
|
||||
cardType.value = type;
|
||||
};
|
||||
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
@ -266,7 +373,7 @@ watch(
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
@ -276,8 +383,6 @@ watch(
|
||||
@return calc($px / 1920 * 100vw);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 统计卡片
|
||||
.stats-cards {
|
||||
display: grid;
|
||||
@ -285,7 +390,11 @@ watch(
|
||||
gap: vw(16);
|
||||
|
||||
.stat-card {
|
||||
background: linear-gradient(135deg, rgba(30, 70, 120, 0.6) 0%, rgba(20, 50, 90, 0.8) 100%);
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(30, 70, 120, 0.6) 0%,
|
||||
rgba(20, 50, 90, 0.8) 100%
|
||||
);
|
||||
border: vw(2) solid rgba(64, 169, 255, 0.4);
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
@ -315,7 +424,6 @@ watch(
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
@ -425,4 +533,58 @@ watch(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 统计卡片
|
||||
.stats-cards {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
|
||||
.stat-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
|
||||
&:hover {
|
||||
background: rgba(30, 70, 120, 0.9);
|
||||
border-color: rgba(64, 169, 255, 0.6);
|
||||
box-shadow: 0 0 15px rgba(64, 169, 255, 0.3);
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
font-size: 18px;
|
||||
color: #40a9ff;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:z-index="1000"
|
||||
:max-width="700"
|
||||
:max-width="1000"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@close="handleClose"
|
||||
@ -97,12 +97,12 @@ const stats = ref({
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: "id", label: "序号", width: "60px" },
|
||||
{ prop: "district", label: "区县/镇街", width: "120px" },
|
||||
{ prop: "name", label: "姓名", width: "100px" },
|
||||
{ prop: "phone", label: "电话", width: "120px" },
|
||||
{ prop: "role", label: "角色", width: "200px" },
|
||||
{ prop: "position", label: "职务", width: "100px" },
|
||||
{ prop: "id", label: "序号", width: "" },
|
||||
{ prop: "district", label: "区县/镇街", width: "" },
|
||||
{ prop: "name", label: "姓名", width: "" },
|
||||
{ prop: "phone", label: "电话", width: "" },
|
||||
{ prop: "role", label: "角色", width: "" },
|
||||
{ prop: "position", label: "职务", width: "" },
|
||||
{ prop: "operation", label: "操作", width: "120px", slot: "operation" },
|
||||
]);
|
||||
|
||||
|
||||
@ -18,25 +18,80 @@
|
||||
<template #header>
|
||||
<!-- 统计卡片 -->
|
||||
<div class="stats-cards">
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响桥梁</div>
|
||||
<div class="stat-value">2933</div>
|
||||
<div
|
||||
@click="handleClick('0')"
|
||||
class="stat-card"
|
||||
:style="{
|
||||
backgroundImage: `url(${cardType === '0' ? selectedIcon : unselectedIcon})`,
|
||||
backgroundSize: '100% 100%',
|
||||
backgroundPosition: 'center',
|
||||
}"
|
||||
>
|
||||
<div class="stat-icon"><img :src="Icon0" alt="" /></div>
|
||||
<div class="stat-content">
|
||||
<span class="stat-label">影响桥梁</span>
|
||||
<span class="stat-value">(1430)</span>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响边坡</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响隧道</div>
|
||||
<div class="stat-value">2933</div>
|
||||
<div
|
||||
@click="handleClick('1')"
|
||||
class="stat-card"
|
||||
:style="{
|
||||
backgroundImage: `url(${cardType === '1' ? selectedIcon : unselectedIcon})`,
|
||||
backgroundSize: '100% 100%',
|
||||
backgroundPosition: 'center',
|
||||
}"
|
||||
>
|
||||
<div class="stat-icon"><img :src="Icon1" alt="" /></div>
|
||||
<div class="stat-content">
|
||||
<span class="stat-label">影响边坡</span>
|
||||
<span class="stat-value">(933)</span>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响项目</div>
|
||||
<div class="stat-value">2933</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">影响路段</div>
|
||||
<div class="stat-value">2432</div>
|
||||
<div
|
||||
@click="handleClick('2')"
|
||||
class="stat-card"
|
||||
:style="{
|
||||
backgroundImage: `url(${cardType === '2' ? selectedIcon : unselectedIcon})`,
|
||||
backgroundSize: '100% 100%',
|
||||
backgroundPosition: 'center',
|
||||
}"
|
||||
>
|
||||
<div class="stat-icon"><img :src="Icon2" alt="" /></div>
|
||||
<div class="stat-content">
|
||||
<span class="stat-label">影响隧道</span>
|
||||
<span class="stat-value">(1033)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@click="handleClick('3')"
|
||||
class="stat-card"
|
||||
:style="{
|
||||
backgroundImage: `url(${cardType === '3' ? selectedIcon : unselectedIcon})`,
|
||||
backgroundSize: '100% 100%',
|
||||
backgroundPosition: 'center',
|
||||
}"
|
||||
>
|
||||
<div class="stat-icon"><img :src="Icon3" alt="" /></div>
|
||||
<div class="stat-content">
|
||||
<span class="stat-label">影响项目</span>
|
||||
<span class="stat-value">(832)</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@click="handleClick('4')"
|
||||
class="stat-card"
|
||||
:style="{
|
||||
backgroundImage: `url(${cardType === '4' ? selectedIcon : unselectedIcon})`,
|
||||
backgroundSize: '100% 100%',
|
||||
backgroundPosition: 'center',
|
||||
}"
|
||||
>
|
||||
<div class="stat-icon"><img :src="Icon4" alt="" /></div>
|
||||
<div class="stat-content">
|
||||
<span class="stat-label">影响路段</span>
|
||||
<span class="stat-value">(832)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -44,8 +99,8 @@
|
||||
<!-- 筛选区域 -->
|
||||
<template #filter>
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
<!-- <div class="filter-item">
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.pointType"
|
||||
placeholder="影响点类型"
|
||||
class="filter-select"
|
||||
@ -57,9 +112,10 @@
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
<span class="filter-label">影响点等级</span>
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.pointLevel"
|
||||
placeholder="影响点等级"
|
||||
class="filter-select"
|
||||
@ -73,7 +129,8 @@
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
<span class="filter-label">是否回应</span>
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.isResponded"
|
||||
placeholder="是否回应"
|
||||
class="filter-select"
|
||||
@ -91,13 +148,26 @@
|
||||
|
||||
<!-- 影响点等级列插槽 -->
|
||||
<template #pointLevel="{ row }">
|
||||
<span class="level-tag" :class="row.levelClass">{{ row.pointLevel }}</span>
|
||||
<span class="level-tag" :class="row.levelClass">{{
|
||||
row.pointLevel
|
||||
}}</span>
|
||||
</template>
|
||||
|
||||
<!-- 交通主管部门负责人列插槽 -->
|
||||
<template #trafficDept="{ row }">
|
||||
<div class="person-info">
|
||||
<span class="person-name">{{ row.trafficDept.name }}</span>
|
||||
<div class="person-name center">
|
||||
<span style="margin-right: 5px">{{ row.trafficDept.name }}</span>
|
||||
<img
|
||||
class="response-icon"
|
||||
:src="
|
||||
row.trafficDept.isResponded
|
||||
? row.trafficDept.img
|
||||
: row.trafficDept.img
|
||||
"
|
||||
alt
|
||||
/>
|
||||
</div>
|
||||
<span class="person-phone">{{ row.trafficDept.phone }}</span>
|
||||
</div>
|
||||
</template>
|
||||
@ -128,7 +198,9 @@
|
||||
|
||||
<!-- 回应状态列插槽 -->
|
||||
<template #responseStatus="{ row }">
|
||||
<span class="response-status" :class="row.responseClass">{{ row.responseStatus }}</span>
|
||||
<span class="response-status" :class="row.responseClass">{{
|
||||
row.responseStatus
|
||||
}}</span>
|
||||
</template>
|
||||
|
||||
<!-- 最新催告时间列插槽 -->
|
||||
@ -149,9 +221,24 @@
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
||||
import { pointTypeOptions, pointLevelOptions, isRespondedOptions } from "../component/index.js";
|
||||
import {
|
||||
pointTypeOptions,
|
||||
pointLevelOptions,
|
||||
isRespondedOptions,
|
||||
} from "../component/index.js";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
import respondedIcon from "../../../assets/xiangying/有回应@2x.png";
|
||||
import notRespondedIcon from "../../../assets/xiangying/无回应@2x.png";
|
||||
import selectedIcon from "../../../assets/xiangying/选中bg@2x.png";
|
||||
import unselectedIcon from "../../../assets/xiangying/未选中bg@2x.png";
|
||||
|
||||
import Icon0 from "../../../assets/xiangying/选中@2x.png";
|
||||
import Icon1 from "../../../assets/xiangying/未选中1@2x.png";
|
||||
import Icon2 from "../../../assets/xiangying/未选中2@2x.png";
|
||||
import Icon3 from "../../../assets/xiangying/未选中3@2x.png";
|
||||
import Icon4 from "../../../assets/xiangying/未选中4@2x.png";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
@ -168,18 +255,40 @@ const filterForm = ref({
|
||||
isResponded: "",
|
||||
});
|
||||
|
||||
const cardType = ref("0");
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: "id", label: "序号", width: "50px" },
|
||||
{ prop: "pointType", label: "影响点类型", width: "80px" },
|
||||
{ prop: "pointLocation", label: "影响点位置", width: "150px" },
|
||||
{ prop: "pointLevel", label: "影响点等级", width: "90px", slot: "pointLevel" },
|
||||
{
|
||||
prop: "pointLevel",
|
||||
label: "影响点等级",
|
||||
width: "90px",
|
||||
slot: "pointLevel",
|
||||
},
|
||||
{ prop: "checkCount", label: "查次数", width: "60px" },
|
||||
{ prop: "trafficDept", label: "交通主管部门负责人", width: "120px", slot: "trafficDept" },
|
||||
{
|
||||
prop: "trafficDept",
|
||||
label: "交通主管部门负责人",
|
||||
width: "120px",
|
||||
slot: "trafficDept",
|
||||
},
|
||||
{ prop: "roadOrg", label: "公路机构责任人", width: "110px", slot: "roadOrg" },
|
||||
{ prop: "maintenance", label: "养护站负责人", width: "110px", slot: "maintenance" },
|
||||
{
|
||||
prop: "maintenance",
|
||||
label: "养护站负责人",
|
||||
width: "110px",
|
||||
slot: "maintenance",
|
||||
},
|
||||
{ prop: "roadKeeper", label: "护路员", width: "80px", slot: "roadKeeper" },
|
||||
{ prop: "responseStatus", label: "回应状态", width: "70px", slot: "responseStatus" },
|
||||
{
|
||||
prop: "responseStatus",
|
||||
label: "回应状态",
|
||||
width: "70px",
|
||||
slot: "responseStatus",
|
||||
},
|
||||
{ prop: "urgeTime", label: "最新催告时间", width: "110px", slot: "urgeTime" },
|
||||
{ prop: "operation", label: "操作", width: "50px", slot: "operation" },
|
||||
]);
|
||||
@ -193,10 +302,30 @@ const tableData = ref([
|
||||
pointLevel: "一般隐患",
|
||||
levelClass: "level-normal",
|
||||
checkCount: 2,
|
||||
trafficDept: { name: "罗宸", phone: "17623865172" },
|
||||
roadOrg: { name: "李海平", phone: "1372386532" },
|
||||
maintenance: { name: "苏祖兵", phone: "13594331090" },
|
||||
roadKeeper: { name: "凌承礼", phone: "1592393704" },
|
||||
trafficDept: {
|
||||
name: "罗宸",
|
||||
phone: "17623865172",
|
||||
img: respondedIcon,
|
||||
isResponded: true,
|
||||
},
|
||||
roadOrg: {
|
||||
name: "李海平",
|
||||
phone: "1372386532",
|
||||
img: notRespondedIcon,
|
||||
isResponded: false,
|
||||
},
|
||||
maintenance: {
|
||||
name: "苏祖兵",
|
||||
phone: "13594331090",
|
||||
img: notRespondedIcon,
|
||||
isResponded: false,
|
||||
},
|
||||
roadKeeper: {
|
||||
name: "凌承礼",
|
||||
phone: "1592393704",
|
||||
img: respondedIcon,
|
||||
isResponded: true,
|
||||
},
|
||||
responseStatus: "已回应",
|
||||
responseClass: "status-responded",
|
||||
urgeTime: { date: "2026-03-28", time: "12:30:00" },
|
||||
@ -231,6 +360,11 @@ const handleClose = () => {
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击卡片切换
|
||||
const handleClick = (type) => {
|
||||
cardType.value = type;
|
||||
};
|
||||
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 查看详情
|
||||
@ -268,20 +402,25 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.filter-row {
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
margin-bottom: 20px;
|
||||
|
||||
.filter-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.filter-label {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.filter-select {
|
||||
width: 150px;
|
||||
|
||||
@ -334,6 +473,10 @@ watch(
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
.response-icon {
|
||||
width: 30px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.person-name {
|
||||
font-size: 12px;
|
||||
@ -406,42 +549,54 @@ watch(
|
||||
|
||||
// 统计卡片
|
||||
.stats-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
|
||||
.stat-card {
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(30, 70, 120, 0.6) 0%,
|
||||
rgba(20, 50, 90, 0.8) 100%
|
||||
);
|
||||
border: 2px solid rgba(64, 169, 255, 0.4);
|
||||
border-radius: 8px;
|
||||
padding: 8px 20px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(64, 169, 255, 0.8);
|
||||
box-shadow: 0 0 20px rgba(64, 169, 255, 0.3);
|
||||
transform: translateY(-2px);
|
||||
background: rgba(30, 70, 120, 0.9);
|
||||
border-color: rgba(64, 169, 255, 0.6);
|
||||
box-shadow: 0 0 15px rgba(64, 169, 255, 0.3);
|
||||
}
|
||||
|
||||
.stat-icon {
|
||||
font-size: 18px;
|
||||
color: #40a9ff;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-bottom: 8px;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 28px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #40a9ff;
|
||||
text-shadow: 0 0 10px rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,203 @@
|
||||
<template>
|
||||
<teleport to="body">
|
||||
<div
|
||||
v-if="visible"
|
||||
class="center-card-dialog-overlay"
|
||||
:style="{ zIndex: zIndex }"
|
||||
@click.self="handleClose"
|
||||
>
|
||||
<div class="center-card-dialog" :style="dialogStyle">
|
||||
<!-- 头部区域 -->
|
||||
<div class="dialog-header" @click="handleDetail">
|
||||
<div class="header-left">
|
||||
<el-icon class="location-icon"><Location /></el-icon>
|
||||
<span class="dialog-title">潼南</span>
|
||||
</div>
|
||||
<el-icon class="arrow-icon"><ArrowRight /></el-icon>
|
||||
</div>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="dialog-content">
|
||||
<div class="info-item">
|
||||
<span class="info-label">人数:</span>
|
||||
<span class="info-value">{{ value }}</span>
|
||||
<span class="info-unit">人</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">路段:</span>
|
||||
<span class="info-value">{{ roadCount }}</span>
|
||||
<span class="info-unit">条</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
import { ArrowRight, Location } from "@element-plus/icons-vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: "",
|
||||
},
|
||||
roadCount: {
|
||||
type: [String, Number],
|
||||
default: "128",
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
default: 1000,
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: "200px",
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "detail"]);
|
||||
|
||||
const dialogStyle = computed(() => ({
|
||||
width: props.width,
|
||||
}));
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击详情
|
||||
const handleDetail = () => {
|
||||
emit("detail");
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 视频屏幕自适应 - 基于视口宽度动态调整
|
||||
@function vw($px) {
|
||||
@return calc($px / 1920 * 100vw);
|
||||
}
|
||||
|
||||
.center-card-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.center-card-dialog {
|
||||
position: relative;
|
||||
background-image: url("../../../assets/MaMap_img/区县弹窗背景@2x.png");
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
min-width: vw(200);
|
||||
padding: vw(12) vw(16);
|
||||
|
||||
// 头部区域
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
margin-bottom: vw(8);
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: vw(6);
|
||||
|
||||
.location-icon {
|
||||
font-size: vw(16);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
font-size: vw(16);
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
font-size: vw(14);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
// 内容区域
|
||||
.dialog-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: vw(20);
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: vw(4);
|
||||
|
||||
.info-label {
|
||||
font-size: vw(13);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: vw(14);
|
||||
font-weight: 600;
|
||||
color: #40a9ff;
|
||||
}
|
||||
|
||||
.info-unit {
|
||||
font-size: vw(12);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 进入动画
|
||||
.center-card-dialog-overlay {
|
||||
.center-card-dialog {
|
||||
animation: dialogIn 0.3s ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dialogIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.9) translateY(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
// 退出动画
|
||||
.center-card-dialog-overlay.v-leave-active {
|
||||
.center-card-dialog {
|
||||
animation: dialogOut 0.2s ease-in;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dialogOut {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scale(0.9) translateY(-20px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,88 +1,47 @@
|
||||
<template>
|
||||
<div v-if="visible" class="tongnan-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="tongnan-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">潼南基本信息表</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header">
|
||||
<div
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
class="th"
|
||||
:style="{ width: column.width, flex: column.flex || 'none' }"
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="潼南基本信息表"
|
||||
:table-data="tableData"
|
||||
:table-columns="tableColumns"
|
||||
:table-height="320"
|
||||
:total="total"
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:z-index="2100"
|
||||
:max-width="1000"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@close="handleClose"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item, index) in tableData"
|
||||
:key="item.id"
|
||||
class="table-row"
|
||||
:class="{ 'row-even': index % 2 === 1 }"
|
||||
>
|
||||
<div class="td" style="width: 60px">{{ item.id }}</div>
|
||||
<div class="td" style="width: 140px">{{ item.region }}</div>
|
||||
<div class="td" style="width: 100px">{{ item.name }}</div>
|
||||
<div class="td" style="width: 120px">{{ item.phone }}</div>
|
||||
<div class="td" style="width: 180px">
|
||||
<el-tooltip :content="item.stationName" placement="top" :show-after="500">
|
||||
<span class="station-name-text" @click="handleStationNameClick(item)">{{ item.stationName }}</span>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="td" style="flex: 1">{{ item.type }}</div>
|
||||
<div class="td" style="width: 140px">
|
||||
<!-- 操作列插槽 -->
|
||||
<template #operation="{ row }">
|
||||
<div class="action-btns">
|
||||
<div class="action-btn" @click="handleVideo(item)" title="视频">
|
||||
<div class="action-btn" @click="handleVideo(row)" title="视频">
|
||||
<el-icon><VideoCamera /></el-icon>
|
||||
</div>
|
||||
<div class="action-btn" @click="handleVoice(item)" title="语音">
|
||||
<div class="action-btn" @click="handleVoice(row)" title="语音">
|
||||
<el-icon><Microphone /></el-icon>
|
||||
</div>
|
||||
<div class="action-btn" @click="handleCall(item)" title="电话">
|
||||
<div class="action-btn" @click="handleCall(row)" title="电话">
|
||||
<el-icon><Phone /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<span class="total">共{{ total }}条数据</span>
|
||||
<div class="page-btns">
|
||||
<div class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">
|
||||
<el-icon><ArrowLeft /></el-icon>
|
||||
</div>
|
||||
<div
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
class="page-btn"
|
||||
:class="{ active: currentPage === page }"
|
||||
@click="goToPage(page)"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
<div class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 驻地名称列插槽 -->
|
||||
<template #stationName="{ row }">
|
||||
<el-tooltip :content="row.stationName" placement="top" :show-after="500">
|
||||
<span class="station-name-text" @click="handleStationNameClick(row)">{{ row.stationName }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, VideoCamera, Microphone, Phone, ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
||||
import { VideoCamera, Microphone, Phone } from "@element-plus/icons-vue";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -95,13 +54,13 @@ const emit = defineEmits(["update:visible", "close", "video", "voice", "call", "
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "60px" },
|
||||
{ label: "区县/镇街", width: "140px" },
|
||||
{ label: "姓名", width: "100px" },
|
||||
{ label: "电话", width: "120px" },
|
||||
{ label: "驻地名称", width: "180px" },
|
||||
{ label: "类型", flex: "1" },
|
||||
{ label: "调度", width: "140px" },
|
||||
{ prop: "id", label: "序号", width: "60px" },
|
||||
{ prop: "region", label: "区县/镇街", width: "140px" },
|
||||
{ prop: "name", label: "姓名", width: "100px" },
|
||||
{ prop: "phone", label: "电话", width: "120px" },
|
||||
{ prop: "stationName", label: "驻地名称", width: "180px", slot: "stationName" },
|
||||
{ prop: "type", label: "类型", width: "auto" },
|
||||
{ prop: "operation", label: "调度", width: "140px", slot: "operation" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
@ -110,7 +69,7 @@ const tableData = ref([
|
||||
id: 1,
|
||||
region: "沙坪坝区",
|
||||
name: "赵海浪",
|
||||
phone: "1862352068",
|
||||
phone: "18623520688",
|
||||
stationName: "沙坪坝区S545茅山峡公路桥新建工程(渝黔铁路扩能改造工程)项目经理部",
|
||||
type: "交通主管部门",
|
||||
},
|
||||
@ -118,7 +77,7 @@ const tableData = ref([
|
||||
id: 2,
|
||||
region: "沙坪坝区",
|
||||
name: "府效能",
|
||||
phone: "1862352068",
|
||||
phone: "18623520688",
|
||||
stationName: "沙坪坝区S545茅山峡公路桥新建工程(渝黔铁路扩能改造工程)项目经理部",
|
||||
type: "公路机构",
|
||||
},
|
||||
@ -126,7 +85,7 @@ const tableData = ref([
|
||||
id: 3,
|
||||
region: "万州区柏梓镇",
|
||||
name: "王鑫",
|
||||
phone: "1862352068",
|
||||
phone: "18623520688",
|
||||
stationName: "万州区项目经理部",
|
||||
type: "公路机构",
|
||||
},
|
||||
@ -134,7 +93,7 @@ const tableData = ref([
|
||||
id: 4,
|
||||
region: "万州区柏梓镇",
|
||||
name: "王鑫",
|
||||
phone: "1862352068",
|
||||
phone: "18623520688",
|
||||
stationName: "万州区项目经理部",
|
||||
type: "公路机构",
|
||||
},
|
||||
@ -169,10 +128,7 @@ const handleClose = () => {
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 操作按钮
|
||||
const handleVideo = (item) => {
|
||||
@ -192,22 +148,14 @@ const handleStationNameClick = (item) => {
|
||||
emit("stationNameClick", item);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
// 分页事件处理
|
||||
const handleSizeChange = (size) => {
|
||||
pageSize.value = size;
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPage = (page) => {
|
||||
const handleCurrentChange = (page) => {
|
||||
currentPage.value = page;
|
||||
fetchData();
|
||||
};
|
||||
@ -231,126 +179,8 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tongnan-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2100;
|
||||
}
|
||||
|
||||
.tongnan-dialog {
|
||||
width: 80vw;
|
||||
max-width: 1000px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
padding: 12px 16px;
|
||||
|
||||
.th {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 14px 16px;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&.row-even {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
|
||||
.td {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
|
||||
.station-name-text {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 180px;
|
||||
color: #40a9ff;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-shadow: 0 0 8px rgba(105, 192, 255, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.action-btns {
|
||||
// 操作按钮样式
|
||||
.action-btns {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
@ -375,77 +205,22 @@ watch(
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
|
||||
.total {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.page-btns {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.page-btn {
|
||||
min-width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
// 驻地名称样式
|
||||
.station-name-text {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 180px;
|
||||
color: #40a9ff;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.disabled):not(.active) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
&:hover {
|
||||
color: #69c0ff;
|
||||
text-shadow: 0 0 8px rgba(105, 192, 255, 0.6);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,77 +1,29 @@
|
||||
<template>
|
||||
<div v-if="visible" class="responsible-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="responsible-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">潼南建设项目责任人明细</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header">
|
||||
<div
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
class="th"
|
||||
:style="{ width: column.width, flex: column.flex || 'none' }"
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="潼南建设项目责任人明细"
|
||||
:table-data="tableData"
|
||||
:table-columns="tableColumns"
|
||||
:table-height="400"
|
||||
:total="total"
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:z-index="1000"
|
||||
:max-width="1100"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@close="handleClose"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item, index) in tableData"
|
||||
:key="item.id"
|
||||
class="table-row"
|
||||
:class="{ 'row-even': index % 2 === 1 }"
|
||||
>
|
||||
<div class="td" style="width: 60px">{{ item.id }}</div>
|
||||
<div class="td" style="width: 100px">{{ item.region }}</div>
|
||||
<div class="td" style="width: 70px">{{ item.totalCount }}</div>
|
||||
<div class="td" style="width: 70px">{{ item.whistleblower }}</div>
|
||||
<div class="td" style="width: 130px">{{ item.constructionUnit }}</div>
|
||||
<div class="td" style="width: 130px">{{ item.contractorUnit }}</div>
|
||||
<div class="td" style="width: 120px">{{ item.stationed }}</div>
|
||||
<div class="td" style="width: 120px">{{ item.districtLevel }}</div>
|
||||
<div class="td" style="width: 120px">{{ item.cityLevel }}</div>
|
||||
<div class="td" style="width: 60px">
|
||||
<span class="detail-link" @click="handleDetail(item)">详情</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<span class="total">共{{ total }}条数据</span>
|
||||
<div class="page-btns">
|
||||
<div class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">
|
||||
<el-icon><ArrowLeft /></el-icon>
|
||||
</div>
|
||||
<div
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
class="page-btn"
|
||||
:class="{ active: currentPage === page }"
|
||||
@click="goToPage(page)"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
<div class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">
|
||||
<el-icon><ArrowRight /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 操作列插槽 -->
|
||||
<template #operation="{ row }">
|
||||
<span class="detail-link" @click="handleDetail(row)">详情</span>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -84,16 +36,16 @@ const emit = defineEmits(["update:visible", "close", "detail"]);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "60px" },
|
||||
{ label: "区县/镇街", width: "100px" },
|
||||
{ label: "总人数", width: "70px" },
|
||||
{ label: "吹哨人", width: "70px" },
|
||||
{ label: "建设单位包保责任人", width: "130px" },
|
||||
{ label: "施工单位包保责任人", width: "130px" },
|
||||
{ label: "驻地包保责任人", width: "120px" },
|
||||
{ label: "区县级包保责任人", width: "120px" },
|
||||
{ label: "市级包保责任人", width: "120px" },
|
||||
{ label: "操作", width: "60px" },
|
||||
{ prop: "id", label: "序号", width: "" },
|
||||
{ prop: "region", label: "区县/镇街", width: "" },
|
||||
{ prop: "totalCount", label: "总人数", width: "" },
|
||||
{ prop: "whistleblower", label: "吹哨人", width: "" },
|
||||
{ prop: "constructionUnit", label: "建设单位包保责任人", width: "" },
|
||||
{ prop: "contractorUnit", label: "施工单位包保责任人", width: "" },
|
||||
{ prop: "stationed", label: "驻地包保责任人", width: "" },
|
||||
{ prop: "districtLevel", label: "区县级包保责任人", width: "" },
|
||||
{ prop: "cityLevel", label: "市级包保责任人", width: "" },
|
||||
{ prop: "operation", label: "操作", width: "60px", slot: "operation" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
@ -151,32 +103,21 @@ const handleClose = () => {
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = (item) => {
|
||||
emit("detail", item);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
// 分页事件处理
|
||||
const handleSizeChange = (size) => {
|
||||
pageSize.value = size;
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPage = (page) => {
|
||||
const handleCurrentChange = (page) => {
|
||||
currentPage.value = page;
|
||||
fetchData();
|
||||
};
|
||||
@ -200,110 +141,8 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.responsible-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.responsible-dialog {
|
||||
width: 80vw;
|
||||
max-width: 1100px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
padding: 12px 16px;
|
||||
|
||||
.th {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
max-height: 40vh;
|
||||
overflow-y: auto;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 14px 16px;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&.row-even {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
|
||||
.td {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
|
||||
.detail-link {
|
||||
// 详情链接样式
|
||||
.detail-link {
|
||||
color: #40a9ff;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
@ -312,77 +151,5 @@ watch(
|
||||
color: #69c0ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
|
||||
.total {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.page-btns {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.page-btn {
|
||||
min-width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.disabled):not(.active) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,74 +1,29 @@
|
||||
<template>
|
||||
<div v-if="visible" class="team-dialog-overlay" @click="handleOverlayClick">
|
||||
<div class="team-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">潼南护路团队成员</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<div class="table-header">
|
||||
<div
|
||||
v-for="(column, index) in tableColumns"
|
||||
:key="index"
|
||||
class="th"
|
||||
:style="{ width: column.width, flex: column.flex || 'none' }"
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="潼南护路团队成员"
|
||||
:table-data="tableData"
|
||||
:table-columns="tableColumns"
|
||||
:table-height="400"
|
||||
:total="total"
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:z-index="2000"
|
||||
:max-width="900"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@close="handleClose"
|
||||
>
|
||||
{{ column.label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-body">
|
||||
<div
|
||||
v-for="(item, index) in tableData"
|
||||
:key="item.id"
|
||||
class="table-row"
|
||||
:class="{ 'row-even': index % 2 === 1 }"
|
||||
>
|
||||
<div class="td" style="width: 60px">{{ item.id }}</div>
|
||||
<div class="td" style="width: 100px">{{ item.district }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.totalCount }}</div>
|
||||
<div class="td" style="width: 140px">{{ item.trafficDept }}</div>
|
||||
<div class="td" style="width: 120px">{{ item.roadOrg }}</div>
|
||||
<div class="td" style="width: 140px">{{ item.maintenance }}</div>
|
||||
<div class="td" style="width: 80px">{{ item.roadKeeper }}</div>
|
||||
<div class="td" style="flex: 1">
|
||||
<span class="view-link" @click="handleView(item)">查看</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<div class="page-btn" :class="{ disabled: currentPage === 1 }" @click="prevPage">
|
||||
上一个
|
||||
</div>
|
||||
<div class="page-numbers">
|
||||
<div
|
||||
v-for="page in visiblePages"
|
||||
:key="page"
|
||||
class="page-num"
|
||||
:class="{ active: currentPage === page }"
|
||||
@click="goToPage(page)"
|
||||
>
|
||||
{{ page }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-btn" :class="{ disabled: currentPage === totalPages }" @click="nextPage">
|
||||
下一个
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 操作列插槽 -->
|
||||
<template #operation="{ row }">
|
||||
<span class="view-link" @click="handleView(row)">查看</span>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -81,14 +36,14 @@ const emit = defineEmits(["update:visible", "close", "view"]);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "60px" },
|
||||
{ label: "区县", width: "100px" },
|
||||
{ label: "总人数", width: "80px" },
|
||||
{ label: "交通主管部门责任人", width: "140px" },
|
||||
{ label: "公路机构责任人", width: "120px" },
|
||||
{ label: "养护站道班责任人", width: "140px" },
|
||||
{ label: "护路员", width: "80px" },
|
||||
{ label: "操作", flex: "1" },
|
||||
{ prop: "id", label: "序号", width: "60px" },
|
||||
{ prop: "district", label: "区县", width: "100px" },
|
||||
{ prop: "totalCount", label: "总人数", width: "80px" },
|
||||
{ prop: "trafficDept", label: "交通主管部门责任人", width: "140px" },
|
||||
{ prop: "roadOrg", label: "公路机构责任人", width: "120px" },
|
||||
{ prop: "maintenance", label: "养护站道班责任人", width: "140px" },
|
||||
{ prop: "roadKeeper", label: "护路员", width: "80px" },
|
||||
{ prop: "operation", label: "操作", width: "auto", slot: "operation" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
@ -160,32 +115,21 @@ const handleClose = () => {
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 查看详情
|
||||
const handleView = (item) => {
|
||||
emit("view", item);
|
||||
};
|
||||
|
||||
// 分页操作
|
||||
const prevPage = () => {
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value--;
|
||||
// 分页事件处理
|
||||
const handleSizeChange = (size) => {
|
||||
pageSize.value = size;
|
||||
currentPage.value = 1;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage.value < totalPages.value) {
|
||||
currentPage.value++;
|
||||
fetchData();
|
||||
}
|
||||
};
|
||||
|
||||
const goToPage = (page) => {
|
||||
const handleCurrentChange = (page) => {
|
||||
currentPage.value = page;
|
||||
fetchData();
|
||||
};
|
||||
@ -209,111 +153,8 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.team-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.team-dialog {
|
||||
width: 80vw;
|
||||
max-width: 900px;
|
||||
background: linear-gradient(135deg, rgba(20, 50, 90, 0.95) 0%, rgba(10, 30, 60, 0.98) 100%);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(90deg, transparent 0%, rgba(64, 169, 255, 0.2) 20%, rgba(64, 169, 255, 0.2) 80%, transparent 100%);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
padding: 12px 16px;
|
||||
|
||||
.th {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
max-height: 40vh;
|
||||
overflow-y: auto;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
padding: 14px 16px;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&.row-even {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
|
||||
.td {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
text-align: center;
|
||||
|
||||
// 查看链接
|
||||
.view-link {
|
||||
// 查看链接样式
|
||||
.view-link {
|
||||
color: #40a9ff;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
@ -323,88 +164,5 @@ watch(
|
||||
color: #69c0ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
|
||||
.page-btn {
|
||||
padding: 6px 16px;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.page-numbers {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.page-num {
|
||||
min-width: 28px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.active) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.5);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条样式
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(180deg, #40a9ff 0%, #1890ff 100%);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(180deg, #69c0ff 0%, #40a9ff 100%);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,27 +1,21 @@
|
||||
<template>
|
||||
<div class="tunnel-info-dialog" v-if="visible">
|
||||
<!-- 四个角的装饰 -->
|
||||
<div class="corner corner-top-left"></div>
|
||||
<div class="corner corner-top-right"></div>
|
||||
<div class="corner corner-bottom-left"></div>
|
||||
<div class="corner corner-bottom-right"></div>
|
||||
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">
|
||||
<span class="title-text">{{ rescueTeamData.title }}</span>
|
||||
<img
|
||||
class="title-icon"
|
||||
src="../../../assets/RiskWarning_img/图标_media_dvr@2x.png"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<!-- <div class="close-btn" @click="closeDialog">
|
||||
<span class="close-icon">×</span>
|
||||
</div> -->
|
||||
<div class="close-btn" style="pointer-events: auto" @click="closeDialog">
|
||||
<el-icon color="#5DD7F6"><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
:title="rescueTeamData.title"
|
||||
:table-data="[]"
|
||||
:table-columns="[]"
|
||||
:table-height="0"
|
||||
:total="0"
|
||||
:current-page="1"
|
||||
:page-size="10"
|
||||
:z-index="1000"
|
||||
:max-width="400"
|
||||
:show-filter="false"
|
||||
:show-pagination="false"
|
||||
@close="handleClose"
|
||||
>
|
||||
<!-- 标题栏下方自定义插槽 -->
|
||||
<template #header>
|
||||
<div class="dialog-content">
|
||||
<div class="info-item" v-for="(item, index) in rescueTeamData.items" :key="index">
|
||||
<label class="info-label">{{ item.label }}:</label>
|
||||
@ -37,14 +31,15 @@
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, defineEmits } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@ -145,132 +140,33 @@ defineExpose({
|
||||
rescueTeamData,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["close"]);
|
||||
const emit = defineEmits(["update:visible", "close"]);
|
||||
|
||||
const closeDialog = () => {
|
||||
const handleClose = () => {
|
||||
emit("update:visible", false);
|
||||
emit("close");
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 视频屏幕自适应 - 基于视口宽度动态调整
|
||||
@function vw($px) {
|
||||
@return calc($px / 1920 * 100vw);
|
||||
}
|
||||
.tunnel-info-dialog {
|
||||
max-width: vw(300);
|
||||
width: vw(300);
|
||||
max-height: vw(600);
|
||||
overflow-y: auto;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
background: rgba(64, 169, 255, 0.2);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||
backdrop-filter: blur(10px);
|
||||
position: fixed;
|
||||
top: 20%;
|
||||
left: 45%;
|
||||
z-index: 1000;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
// 四个角的装饰
|
||||
.corner {
|
||||
position: absolute;
|
||||
width: vw(20);
|
||||
height: vw(20);
|
||||
border: 1px solid #40a9ff;
|
||||
pointer-events: none;
|
||||
|
||||
&.corner-top-left {
|
||||
top: 0;
|
||||
left: 0;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.corner-top-right {
|
||||
top: 0;
|
||||
right: 0;
|
||||
border-left: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.corner-bottom-left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
&.corner-bottom-right {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-left: none;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: vw(16) vw(20);
|
||||
border-bottom: 1px solid rgba(64, 169, 255, 0.2);
|
||||
|
||||
.header-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: vw(10);
|
||||
|
||||
.title-text {
|
||||
font-size: vw(16);
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
width: vw(24);
|
||||
height: vw(24);
|
||||
}
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
.close-icon {
|
||||
font-size: vw(24);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.close-icon {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-content {
|
||||
padding: vw(16) vw(20);
|
||||
// 信息项样式
|
||||
.dialog-content {
|
||||
padding: 16px 20px;
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: vw(8) 0;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid rgba(64, 169, 255, 0.1);
|
||||
|
||||
.info-label {
|
||||
font-size: vw(14);
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
flex: 0 0 vw(100);
|
||||
flex: 0 0 100px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: vw(14);
|
||||
font-size: 14px;
|
||||
color: #4fecff;
|
||||
flex: 1;
|
||||
}
|
||||
@ -279,16 +175,20 @@ const closeDialog = () => {
|
||||
.info-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 图片样式
|
||||
.dialog-imgs {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: vw(6);
|
||||
padding: vw(16) vw(20);
|
||||
gap: 6px;
|
||||
padding: 16px 20px;
|
||||
|
||||
.dialog-img {
|
||||
width: vw(75);
|
||||
height: vw(75);
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,23 +1,24 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="visible"
|
||||
class="warning-dialog-overlay"
|
||||
@click="handleOverlayClick"
|
||||
<base-dialog
|
||||
v-model:visible="props.visible"
|
||||
title="响应情况"
|
||||
:table-data="tableData"
|
||||
:table-columns="tableColumns"
|
||||
:table-height="300"
|
||||
:total="total"
|
||||
:current-page="currentPage"
|
||||
:page-size="pageSize"
|
||||
:z-index="1000"
|
||||
:max-width="1000"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@close="handleClose"
|
||||
>
|
||||
<div class="warning-dialog" @click.stop>
|
||||
<!-- 标题栏 -->
|
||||
<div class="dialog-header">
|
||||
<div class="header-title">响应情况</div>
|
||||
<div class="close-btn" @click="handleClose">
|
||||
<el-icon><Close /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-section">
|
||||
<!-- 筛选区域插槽 -->
|
||||
<template #filter>
|
||||
<div class="filter-row">
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.warningLevel"
|
||||
placeholder="预警等级"
|
||||
class="filter-select"
|
||||
@ -31,7 +32,7 @@
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.region"
|
||||
placeholder="影响区域"
|
||||
class="filter-select"
|
||||
@ -45,7 +46,7 @@
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.isEnded"
|
||||
placeholder="是否结束"
|
||||
class="filter-select"
|
||||
@ -59,10 +60,11 @@
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<el-select
|
||||
<el-select :teleported="false"
|
||||
v-model="filterForm.isResponded"
|
||||
placeholder="是否回应"
|
||||
class="filter-select"
|
||||
|
||||
>
|
||||
<el-option
|
||||
v-for="option in isRespondedOptions"
|
||||
@ -79,60 +81,24 @@
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section">
|
||||
<el-table
|
||||
:data="tableData"
|
||||
:height="tableHeight"
|
||||
style="width: 100%"
|
||||
:header-cell-style="headerCellStyle"
|
||||
:cell-style="cellStyle"
|
||||
size="small"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="60" />
|
||||
<el-table-column prop="weatherSource" label="气象来源" width="80" />
|
||||
<el-table-column prop="warningLevel" label="预警等级" width="100">
|
||||
<template #default="{ row }">
|
||||
<!-- 预警等级列插槽 -->
|
||||
<template #warningLevel="{ row }">
|
||||
<span class="warning-level" :class="row.levelClass">{{ row.warningLevel }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="region" label="影响区域" width="100" />
|
||||
<el-table-column prop="warningTime" label="预警时间" width="160" />
|
||||
<el-table-column prop="endTime" label="结束时间" width="160" />
|
||||
<el-table-column prop="impactPoints" label="影响点数量" width="100" />
|
||||
<el-table-column prop="called" label="已叫应" width="80">
|
||||
<template #default="{ row }">
|
||||
|
||||
<!-- 已叫应列插槽 -->
|
||||
<template #called="{ row }">
|
||||
<span class="clickable-cell" @click="handleCalledClick(row)">{{ row.called }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="responded" label="已回应" width="80" />
|
||||
<el-table-column prop="notResponded" label="未回应" width="80" />
|
||||
<el-table-column prop="urged" label="已催告" width="80" />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination">
|
||||
<el-pagination
|
||||
v-model:current-page="currentPage"
|
||||
v-model:page-size="pageSize"
|
||||
:page-sizes="[10, 20, 30, 40]"
|
||||
:total="total"
|
||||
background
|
||||
layout="prev, pager, next, jumper, ->, total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</base-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { Close, Search, ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
|
||||
import { Search } from "@element-plus/icons-vue";
|
||||
import baseDialog from "../component/baseDialog.vue";
|
||||
import {
|
||||
warningLevelOptions,
|
||||
regionOptionsWithAll,
|
||||
@ -159,17 +125,17 @@ const filterForm = ref({
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ label: "序号", width: "60px" },
|
||||
{ label: "气象来源", width: "80px" },
|
||||
{ label: "预警等级", width: "100px" },
|
||||
{ label: "影响区域", width: "100px" },
|
||||
{ label: "预警时间", width: "160px" },
|
||||
{ label: "结束时间", width: "160px" },
|
||||
{ label: "影响点数量", width: "100px" },
|
||||
{ label: "已叫应", width: "80px" },
|
||||
{ label: "已回应", width: "80px" },
|
||||
{ label: "未回应", width: "80px" },
|
||||
{ label: "已催告", width: "80px" },
|
||||
{ prop: "id", label: "序号", width: "" },
|
||||
{ prop: "weatherSource", label: "气象来源", width: "" },
|
||||
{ prop: "warningLevel", label: "预警等级", width: "", slot: "warningLevel" },
|
||||
{ prop: "region", label: "影响区域", width: "" },
|
||||
{ prop: "warningTime", label: "预警时间", width: "" },
|
||||
{ prop: "endTime", label: "结束时间", width: "" },
|
||||
{ prop: "impactPoints", label: "影响点数量", width: "" },
|
||||
{ prop: "called", label: "已叫应", width: "", slot: "called" },
|
||||
{ prop: "responded", label: "已回应", width: "" },
|
||||
{ prop: "notResponded", label: "未回应", width: "" },
|
||||
{ prop: "urged", label: "已催告", width: "" },
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
@ -245,10 +211,7 @@ const handleClose = () => {
|
||||
emit("close");
|
||||
};
|
||||
|
||||
// 点击遮罩关闭
|
||||
const handleOverlayClick = () => {
|
||||
handleClose();
|
||||
};
|
||||
// 点击遮罩关闭已由base-dialog组件处理
|
||||
|
||||
// 点击已叫应
|
||||
const handleCalledClick = () => {
|
||||
@ -292,88 +255,15 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.warning-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.warning-dialog {
|
||||
width: 80vw;
|
||||
max-width: 1000px;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
rgba(20, 50, 90, 0.95) 0%,
|
||||
rgba(10, 30, 60, 0.98) 100%
|
||||
);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
// 标题栏
|
||||
.dialog-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.header-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
padding: 8px 40px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent 0%,
|
||||
rgba(64, 169, 255, 0.2) 20%,
|
||||
rgba(64, 169, 255, 0.2) 80%,
|
||||
transparent 100%
|
||||
);
|
||||
border-bottom: 2px solid #40a9ff;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.filter-row {
|
||||
// 筛选区域样式
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
.filter-item {
|
||||
.filter-select {
|
||||
width: 120px;
|
||||
|
||||
@ -419,61 +309,10 @@ watch(
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
background-color: rgba(30, 70, 120, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20px;
|
||||
|
||||
:deep(.el-table) {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
|
||||
.el-table__header-wrapper {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.el-table__body-wrapper {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.el-table__row {
|
||||
background-color: transparent;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&:nth-child(even) {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.el-table__cell {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
border: none;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.el-table__header .el-table__cell {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
border: none;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.warning-level {
|
||||
// 预警等级样式
|
||||
.warning-level {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 4px;
|
||||
@ -503,9 +342,10 @@ watch(
|
||||
color: #40a9ff;
|
||||
border: 1px solid rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.clickable-cell {
|
||||
// 可点击单元格样式
|
||||
.clickable-cell {
|
||||
cursor: pointer;
|
||||
color: #40a9ff;
|
||||
font-weight: 500;
|
||||
@ -515,82 +355,6 @@ watch(
|
||||
color: #69c0ff;
|
||||
text-shadow: 0 0 8px rgba(105, 192, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
|
||||
:deep(.el-pagination) {
|
||||
.el-pagination__total {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.el-pagination__sizes .el-input__inner {
|
||||
color: #fff;
|
||||
background-color: rgba(30, 70, 120, 0.4);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.el-pagination__btn {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.is-disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__item {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.is-disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__jump .el-input__inner {
|
||||
color: #fff;
|
||||
background-color: rgba(30, 70, 120, 0.4);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏滚动条
|
||||
:deep(.el-table__body-wrapper::-webkit-scrollbar) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:deep(.el-table__body-wrapper) {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
// 下拉菜单样式
|
||||
|
||||
@ -20,9 +20,10 @@
|
||||
<el-select
|
||||
v-model="filterForm.warningLevel"
|
||||
placeholder="请选择"
|
||||
class="filter-select"
|
||||
class="filter-select el-select"
|
||||
clearable
|
||||
size="small"
|
||||
:teleported="false"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in warningLevelOptions"
|
||||
@ -40,6 +41,7 @@
|
||||
class="filter-select"
|
||||
clearable
|
||||
size="small"
|
||||
:teleported="false"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in regionOptions"
|
||||
@ -50,13 +52,14 @@
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">是否结束</span>
|
||||
<span class="filter-label">是否失效</span>
|
||||
<el-select
|
||||
v-model="filterForm.isEnded"
|
||||
placeholder="请选择"
|
||||
class="filter-select"
|
||||
clearable
|
||||
size="small"
|
||||
:teleported="false"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in isEndedOptions"
|
||||
@ -66,18 +69,30 @@
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<div class="filter-item">
|
||||
<span class="filter-label">生效时间</span>
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
size="small"
|
||||
popper-class="custom-date-picker"
|
||||
:teleported="false"
|
||||
:prefix-icon="Calendar"
|
||||
@change="handleDateChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 预警等级列插槽 -->
|
||||
<template #warningLevel="{ row }">
|
||||
<span
|
||||
:class="[
|
||||
'warning-level-tag',
|
||||
getWarningClass(row.warningLevel),
|
||||
]"
|
||||
>{{ row.warningLevel }}</span
|
||||
>
|
||||
<span :class="['warning-level-tag', getWarningClass(row.warningLevel)]">{{
|
||||
row.warningLevel
|
||||
}}</span>
|
||||
</template>
|
||||
|
||||
<!-- 影响点数量列插槽 -->
|
||||
@ -106,6 +121,14 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
// 日期范围器
|
||||
const dateRange = ref([]);
|
||||
|
||||
// 处理日期范围变化
|
||||
const handleDateChange = (val) => {
|
||||
filterForm.value.dateRange = val;
|
||||
};
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "impactClick"]);
|
||||
|
||||
// 筛选表单
|
||||
@ -130,13 +153,23 @@ const tableHeight = ref(300);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = ref([
|
||||
{ prop: 'index', label: '序号', width: '60' },
|
||||
{ prop: 'warningLevel', label: '预警等级', width: '100', slot: 'warningLevel' },
|
||||
{ prop: 'weatherType', label: '气象类型', width: '100' },
|
||||
{ prop: 'region', label: '行政区域', width: '100' },
|
||||
{ prop: 'warningTime', label: '预警时间', width: '160' },
|
||||
{ prop: 'endTime', label: '结束时间', width: '160' },
|
||||
{ prop: 'impactCount', label: '影响点数量', width: '100', slot: 'impactCount' },
|
||||
{ prop: "index", label: "序号", width: "" },
|
||||
{
|
||||
prop: "warningLevel",
|
||||
label: "预警等级",
|
||||
width: "",
|
||||
slot: "warningLevel",
|
||||
},
|
||||
{ prop: "weatherType", label: "气象类型", width: "" },
|
||||
{ prop: "region", label: "影响区域", width: "" },
|
||||
{ prop: "warningTime", label: "生效时间", width: "" },
|
||||
{ prop: "endTime", label: "失效时间", width: "" },
|
||||
{
|
||||
prop: "impactCount",
|
||||
label: "影响点数量",
|
||||
width: "",
|
||||
slot: "impactCount",
|
||||
},
|
||||
]);
|
||||
|
||||
// 表格数据
|
||||
@ -182,7 +215,8 @@ const tableData = ref([
|
||||
impactCount: 2,
|
||||
},
|
||||
]);
|
||||
|
||||
tableData.value.push(...tableData.value);
|
||||
tableData.value.push(...tableData.value);
|
||||
// 分页
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
@ -240,20 +274,8 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
padding: 0 24px;
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
// 筛选区域样式
|
||||
.filter-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
@ -290,105 +312,10 @@ watch(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.date-range-picker {
|
||||
:deep(.el-input__wrapper) {
|
||||
background-color: rgba(30, 70, 120, 0.4);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
box-shadow: none;
|
||||
border-radius: 4px;
|
||||
width: 210px !important;
|
||||
|
||||
.el-input__inner {
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
background: transparent;
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.el-input__suffix {
|
||||
.el-icon {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-range-input) {
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-range-separator) {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
padding: 0 24px;
|
||||
|
||||
:deep(.el-table) {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
|
||||
.el-table__header-wrapper {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.el-table__body-wrapper {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.el-table__row {
|
||||
width: 100% !important;
|
||||
background-color: transparent;
|
||||
transition: background-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
}
|
||||
|
||||
&:nth-child(even) {
|
||||
background-color: rgba(30, 70, 120, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.el-table__cell {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
border: none;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
.el-table__header {
|
||||
width: 100% !important;
|
||||
}
|
||||
.el-table__header .el-table__cell {
|
||||
background-color: #1c4979;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
text-align: center;
|
||||
border: none;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
// 预警等级标签
|
||||
.warning-level-tag {
|
||||
// 预警等级标签
|
||||
.warning-level-tag {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 4px;
|
||||
@ -418,10 +345,10 @@ watch(
|
||||
color: #40a9ff;
|
||||
border: 1px solid rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 影响点数量
|
||||
.impact-count {
|
||||
// 影响点数量
|
||||
.impact-count {
|
||||
color: #ff4d4f;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
@ -431,138 +358,52 @@ watch(
|
||||
color: #ff7875;
|
||||
text-shadow: 0 0 8px rgba(255, 77, 79, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 筛选区域
|
||||
.filter-section {
|
||||
margin-bottom: vw(20);
|
||||
|
||||
// 分页
|
||||
.pagination {
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
padding: 12px;
|
||||
|
||||
:deep(.el-pagination) {
|
||||
.el-pagination__total {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: 13px;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.el-pagination__sizes .el-input__inner {
|
||||
color: #fff;
|
||||
.filter-item {
|
||||
.filter-select {
|
||||
width: vw(150);
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
background-color: rgba(30, 70, 120, 0.4);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
font-size: 13px;
|
||||
}
|
||||
box-shadow: none;
|
||||
border-radius: vw(4);
|
||||
|
||||
.el-pagination__btn {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.is-disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__item {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
background-color: rgba(64, 169, 255, 0.1);
|
||||
border: 1px solid rgba(64, 169, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover:not(.is-disabled) {
|
||||
background-color: rgba(64, 169, 255, 0.2);
|
||||
border-color: rgba(64, 169, 255, 0.4);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background-color: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
.el-input__inner {
|
||||
color: #fff;
|
||||
font-size: vw(13);
|
||||
|
||||
&::placeholder {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__jump .el-input__inner {
|
||||
color: #fff;
|
||||
background-color: rgba(30, 70, 120, 0.4);
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.el-table__body) {
|
||||
width: 100% !important;
|
||||
}
|
||||
// 隐藏滚动条
|
||||
:deep(.el-table__body-wrapper::-webkit-scrollbar) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:deep(.el-table__body-wrapper) {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
// 日期选择器弹出面板深色主题
|
||||
.el-picker-panel {
|
||||
background: rgba(20, 50, 90, 0.98) !important;
|
||||
border: 1px solid rgba(64, 169, 255, 0.3) !important;
|
||||
|
||||
.el-picker-panel__content {
|
||||
color: #fff;
|
||||
|
||||
.el-date-table th {
|
||||
.el-input__suffix {
|
||||
.el-icon {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
border-bottom-color: rgba(64, 169, 255, 0.3);
|
||||
}
|
||||
|
||||
.el-date-table td {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
|
||||
&.selected .el-date-table-cell {
|
||||
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
|
||||
}
|
||||
|
||||
&.today span {
|
||||
color: #40a9ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&.in-range,
|
||||
&.start-date,
|
||||
&.end-date {
|
||||
background: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-picker-panel__footer {
|
||||
border-top: 1px solid rgba(64, 169, 255, 0.3);
|
||||
|
||||
.el-button {
|
||||
background: rgba(30, 70, 120, 0.4);
|
||||
border-color: rgba(64, 169, 255, 0.3);
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background: rgba(64, 169, 255, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.el-button--primary {
|
||||
.search-btn {
|
||||
background: linear-gradient(135deg, #40a9ff 0%, #1890ff 100%);
|
||||
border: none;
|
||||
border-radius: vw(4);
|
||||
padding: 0 vw(24);
|
||||
height: vw(32);
|
||||
font-size: vw(13);
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(135deg, #69c0ff 0%, #40a9ff 100%);
|
||||
@ -571,7 +412,9 @@ watch(
|
||||
}
|
||||
}
|
||||
|
||||
.el-table--fit .el-table__inner-wrapper:before {
|
||||
width: 0% !important;
|
||||
:deep(.el-range-editor.el-input__wrapper) {
|
||||
width: 240px !important;
|
||||
height: 30px !important;
|
||||
background-color: #122C46 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -9,12 +9,21 @@
|
||||
<span class="error-text">{{ error }}</span>
|
||||
<button class="retry-btn" @click="loadMapData">重试</button>
|
||||
</div>
|
||||
<TongnanCenterCardDialog
|
||||
ref="tongnanCenterCardDialog"
|
||||
:visible.sync="visible"
|
||||
:value="value"
|
||||
:z-index="zIndex"
|
||||
:width="width"
|
||||
></TongnanCenterCardDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
import axios from 'axios';
|
||||
import axios from "axios";
|
||||
import { request } from "@/utils/request";
|
||||
import TongnanCenterCardDialog from "@/views/RiskWarning/Dialog/tongnanCenterCardDialog.vue";
|
||||
|
||||
const mapContainer = ref(null);
|
||||
const loading = ref(false);
|
||||
@ -29,6 +38,163 @@ const emit = defineEmits(["districtClick"]);
|
||||
const selectedDistrict = ref(null);
|
||||
let selectedLayer = null;
|
||||
|
||||
// 受影响对象数据
|
||||
const affectedCountyData = ref({
|
||||
byName: {},
|
||||
sortedList: [],
|
||||
});
|
||||
|
||||
// 获取受影响对象数据
|
||||
const getAffectedCountyData = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: "snow-ops-platform/weather-warning/affected-county",
|
||||
method: "GET",
|
||||
params: {
|
||||
start: "2025-03-03 12:33:00",
|
||||
end: "2025-07-30 12:33:00",
|
||||
},
|
||||
});
|
||||
console.log("受影响对象数据:", res);
|
||||
if (res.code === "00000" && res.data) {
|
||||
// 统计各区县预警数量
|
||||
const warningStats = countWarningsByCounty(res.data);
|
||||
console.log("区县预警统计:", warningStats);
|
||||
affectedCountyData.value = warningStats;
|
||||
loadMapData();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取受影响对象数据失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 确定主要预警颜色(出现最多的预警等级)
|
||||
const getMainWarningColor = (levels) => {
|
||||
if (!levels || Object.keys(levels).length === 0) return "#1890ff"; // 默认蓝色
|
||||
|
||||
// 预警等级优先级:红色 > 橙色 > 黄色 > 蓝色
|
||||
const priority = ["红色", "橙色", "黄色", "蓝色"];
|
||||
|
||||
// 按数量排序
|
||||
const sortedLevels = Object.entries(levels)
|
||||
.map(([level, count]) => ({ level, count }))
|
||||
.sort((a, b) => b.count - a.count);
|
||||
|
||||
// 如果有多个等级数量相同,按优先级排序
|
||||
const maxCount = sortedLevels[0].count;
|
||||
const maxLevels = sortedLevels.filter((item) => item.count === maxCount);
|
||||
|
||||
if (maxLevels.length === 1) {
|
||||
return getColorByLevel(maxLevels[0].level);
|
||||
} else {
|
||||
// 按优先级选择
|
||||
for (const level of priority) {
|
||||
if (maxLevels.some((item) => item.level === level)) {
|
||||
return getColorByLevel(level);
|
||||
}
|
||||
}
|
||||
return getColorByLevel(maxLevels[0].level);
|
||||
}
|
||||
};
|
||||
|
||||
// 根据预警等级获取颜色
|
||||
const getColorByLevel = (level) => {
|
||||
const colorMap = {
|
||||
红色预警: "#FF4D4F",
|
||||
橙色预警: "#EC7345",
|
||||
黄色预警: "#FBC23C",
|
||||
蓝色预警: "#3799FC",
|
||||
未知: "#1890ff",
|
||||
};
|
||||
return colorMap[level] || "#1890ff";
|
||||
};
|
||||
|
||||
// 统计各区县的预警数量(按预警等级区分)
|
||||
const countWarningsByCounty = (data) => {
|
||||
if (!data || !Array.isArray(data)) return {};
|
||||
|
||||
const stats = {};
|
||||
data.forEach((item) => {
|
||||
// 根据实际数据结构调整字段名
|
||||
const rawCountyName =
|
||||
item.countyName || item.name || item.qxmc || item.gl1Qxmc;
|
||||
const riskLevel =
|
||||
item.riskLevel || item.level || item.warningLevel || item.gl1Yjdj;
|
||||
|
||||
// 简化区县名称
|
||||
const countyName = simplifyDistrictName(rawCountyName);
|
||||
|
||||
if (countyName) {
|
||||
if (!stats[countyName]) {
|
||||
stats[countyName] = {
|
||||
total: 0,
|
||||
levels: {},
|
||||
};
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
stats[countyName].total += 1;
|
||||
|
||||
// 按预警等级统计
|
||||
const level = riskLevel || "未知";
|
||||
if (stats[countyName].levels[level]) {
|
||||
stats[countyName].levels[level] += 1;
|
||||
} else {
|
||||
stats[countyName].levels[level] = 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 合并渝北区和江北区为两江新区
|
||||
if (stats["渝北区"] || stats["江北区"]) {
|
||||
const yubeiData = stats["渝北区"] || {
|
||||
total: 0,
|
||||
levels: {},
|
||||
};
|
||||
const jiangbeiData = stats["江北区"] || {
|
||||
total: 0,
|
||||
levels: {},
|
||||
};
|
||||
|
||||
// 合并总数
|
||||
const total = yubeiData.total + jiangbeiData.total;
|
||||
|
||||
// 合并各等级预警数量
|
||||
const levels = { ...yubeiData.levels };
|
||||
Object.entries(jiangbeiData.levels).forEach(([level, count]) => {
|
||||
if (levels[level]) {
|
||||
levels[level] += count;
|
||||
} else {
|
||||
levels[level] = count;
|
||||
}
|
||||
});
|
||||
|
||||
// 创建两江新区数据
|
||||
stats["两江新区"] = {
|
||||
total,
|
||||
levels,
|
||||
};
|
||||
|
||||
// 删除渝北区和江北区
|
||||
delete stats["渝北区"];
|
||||
delete stats["江北区"];
|
||||
}
|
||||
|
||||
// 转换为数组格式并按总数排序(数量从大到小)
|
||||
const sortedList = Object.entries(stats)
|
||||
.map(([name, data]) => ({
|
||||
name,
|
||||
total: data.total,
|
||||
levels: data.levels,
|
||||
}))
|
||||
.sort((a, b) => b.total - a.total);
|
||||
|
||||
return {
|
||||
byName: stats, // 对象格式:{ 区县名: { total: 总数, levels: { 等级: 数量 } } }
|
||||
sortedList: sortedList, // 数组格式:[{ name: 区县名, total: 总数, levels: { 等级: 数量 } }]
|
||||
};
|
||||
};
|
||||
|
||||
// 重庆地图 GeoJSON API 地址 - 使用最新版本
|
||||
const GEOJSON_URL =
|
||||
"https://geo.datav.aliyun.com/areas_v3/bound/500000_full.json";
|
||||
@ -43,30 +209,29 @@ const loadMapData = async () => {
|
||||
|
||||
// 检查URL参数中是否有Map=dev
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const isDev = urlParams.get('Map') === 'dev';
|
||||
const isDev = urlParams.get("Map") === "dev";
|
||||
|
||||
let geoJsonData;
|
||||
|
||||
if (isDev) {
|
||||
// 本地测试用
|
||||
const response = await fetch(GEOJSON_URL)
|
||||
const response = await fetch(GEOJSON_URL);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
geoJsonData = await response.json()
|
||||
geoJsonData = await response.json();
|
||||
} else {
|
||||
// 部署用
|
||||
const response = await axios.get('/aliyun-geo/bound/500000_full.json');
|
||||
const response = await axios.get("/aliyun-geo/bound/500000_full.json");
|
||||
geoJsonData = response.data;
|
||||
if (!geoJsonData) {
|
||||
throw new Error('地图数据为空');
|
||||
throw new Error("地图数据为空");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// // 处理行政区划变更:渝北区和江北区合并为两江新区
|
||||
processDistrictMerge(geoJsonData);
|
||||
initMap(geoJsonData)
|
||||
initMap(geoJsonData);
|
||||
} catch (err) {
|
||||
console.error("加载地图数据失败:", err);
|
||||
error.value = "地图数据加载失败,请检查网络连接";
|
||||
@ -151,6 +316,17 @@ const getCentroid = (coordinates) => {
|
||||
return count > 0 ? [sumLat / count, sumLng / count] : null;
|
||||
};
|
||||
|
||||
// 简化区县名称
|
||||
const simplifyDistrictName = (name) => {
|
||||
const nameMap = {
|
||||
酉阳土家族苗族自治县: "酉阳县",
|
||||
秀山土家族苗族自治县: "秀山县",
|
||||
彭水苗族土家族自治县: "彭水县",
|
||||
石柱土家族自治县: "石柱县",
|
||||
};
|
||||
return nameMap[name] || name;
|
||||
};
|
||||
|
||||
// 初始化地图
|
||||
const initMap = (geoJsonData) => {
|
||||
if (!mapContainer.value) return;
|
||||
@ -164,7 +340,7 @@ const initMap = (geoJsonData) => {
|
||||
// 创建地图实例
|
||||
mapInstance = new window.L.Map(mapContainer.value, {
|
||||
center: [29.563, 106.551], // 重庆中心坐标
|
||||
zoom: 7,
|
||||
zoom: 6,
|
||||
minZoom: 6,
|
||||
maxZoom: 18,
|
||||
zoomControl: false,
|
||||
@ -185,72 +361,80 @@ const initMap = (geoJsonData) => {
|
||||
|
||||
// 添加 GeoJSON 图层
|
||||
geoJsonLayer = new window.L.GeoJSON(geoJsonData, {
|
||||
style: (feature) => ({
|
||||
fillColor: "#1890ff",
|
||||
style: (feature) => {
|
||||
const districtName = feature.properties.name;
|
||||
let fillColor = "#132C44"; // 默认
|
||||
// 如果有预警统计数据,应用主要预警颜色
|
||||
if (
|
||||
affectedCountyData.value &&
|
||||
affectedCountyData.value.byName &&
|
||||
affectedCountyData.value.byName[districtName]
|
||||
) {
|
||||
const districtData = affectedCountyData.value.byName[districtName];
|
||||
console.log(districtData.levels);
|
||||
fillColor = getMainWarningColor(districtData.levels);
|
||||
}
|
||||
|
||||
return {
|
||||
fillColor: fillColor,
|
||||
weight: 1.5,
|
||||
opacity: 0.6,
|
||||
color: "#40a9ff",
|
||||
fillOpacity: 0.15,
|
||||
}),
|
||||
fillOpacity: 1,
|
||||
};
|
||||
},
|
||||
onEachFeature: (feature, layer) => {
|
||||
if (feature.properties && feature.properties.name) {
|
||||
// 区县点击事件
|
||||
layer.on("click", (e) => {
|
||||
// 清除之前选中的样式
|
||||
if (selectedLayer) {
|
||||
selectedLayer.setStyle({
|
||||
fillColor: "#1890ff",
|
||||
fillOpacity: 0.15,
|
||||
weight: 1.5,
|
||||
color: "#40a9ff",
|
||||
});
|
||||
}
|
||||
|
||||
// 设置当前选中样式
|
||||
layer.setStyle({
|
||||
fillColor: "#ff4d4f",
|
||||
fillOpacity: 0.6,
|
||||
weight: 2.5,
|
||||
color: "#ff7875",
|
||||
});
|
||||
|
||||
selectedLayer = layer;
|
||||
selectedDistrict.value = feature.properties.name;
|
||||
|
||||
// 触发事件
|
||||
emit("districtClick", {
|
||||
name: feature.properties.name,
|
||||
feature: feature,
|
||||
latlng: e.latlng,
|
||||
});
|
||||
|
||||
// 平滑移动到点击位置
|
||||
mapInstance.panTo(e.latlng, { animate: true, duration: 0.5 });
|
||||
});
|
||||
|
||||
// layer.on("click", (e) => {
|
||||
// // 清除之前选中的样式
|
||||
// if (selectedLayer) {
|
||||
// selectedLayer.setStyle({
|
||||
// fillColor: "#1890ff",
|
||||
// fillOpacity: 0.15,
|
||||
// weight: 1.5,
|
||||
// color: "#40a9ff",
|
||||
// });
|
||||
// }
|
||||
// // 设置当前选中样式
|
||||
// layer.setStyle({
|
||||
// fillColor: "#ff4d4f",
|
||||
// fillOpacity: 0.6,
|
||||
// weight: 2.5,
|
||||
// color: "#ff7875",
|
||||
// });
|
||||
// selectedLayer = layer;
|
||||
// selectedDistrict.value = feature.properties.name;
|
||||
// // 触发事件
|
||||
// emit("districtClick", {
|
||||
// name: feature.properties.name,
|
||||
// feature: feature,
|
||||
// latlng: e.latlng,
|
||||
// });
|
||||
// // 平滑移动到点击位置
|
||||
// mapInstance.panTo(e.latlng, { animate: true, duration: 0.5 });
|
||||
// });
|
||||
// 鼠标悬停效果
|
||||
layer.on("mouseover", () => {
|
||||
layer.setStyle({
|
||||
fillColor: "#1890ff",
|
||||
fillOpacity: 0.4,
|
||||
weight: 2,
|
||||
color: "#69c0ff",
|
||||
});
|
||||
});
|
||||
|
||||
layer.on("mouseout", () => {
|
||||
layer.setStyle({
|
||||
fillColor: "#1890ff",
|
||||
fillOpacity: 0.15,
|
||||
weight: 1.5,
|
||||
color: "#40a9ff",
|
||||
});
|
||||
});
|
||||
|
||||
// layer.on("mouseover", () => {
|
||||
// layer.setStyle({
|
||||
// fillColor: "#1890ff",
|
||||
// fillOpacity: 0.4,
|
||||
// weight: 2,
|
||||
// color: "#69c0ff",
|
||||
// });
|
||||
// });
|
||||
// layer.on("mouseout", () => {
|
||||
// layer.setStyle({
|
||||
// fillColor: "#1890ff",
|
||||
// fillOpacity: 0.15,
|
||||
// weight: 1.5,
|
||||
// color: "#40a9ff",
|
||||
// });
|
||||
// });
|
||||
// 添加 popup
|
||||
layer.bindPopup(`<div class="map-popup">
|
||||
<strong>${feature.properties.name}</strong>
|
||||
</div>`);
|
||||
// layer.bindPopup(`<div class="map-popup">
|
||||
// <strong>${feature.properties.name}</strong>
|
||||
// </div>`);
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -270,51 +454,52 @@ const initMap = (geoJsonData) => {
|
||||
}
|
||||
|
||||
if (centroid) {
|
||||
const displayName = simplifyDistrictName(feature.properties.name);
|
||||
const label = window.L.divIcon({
|
||||
className: "district-label",
|
||||
html: `<div class="label-content">${feature.properties.name}</div>`,
|
||||
html: `<div class="label-content">${displayName}</div>`,
|
||||
iconSize: [80, 30],
|
||||
iconAnchor: [40, 15],
|
||||
});
|
||||
|
||||
const marker = window.L.marker(centroid, { icon: label });
|
||||
marker.on("click", (e) => {
|
||||
// 清除之前选中的样式
|
||||
if (selectedLayer) {
|
||||
selectedLayer.setStyle({
|
||||
fillColor: "#1E3A8A",
|
||||
fillOpacity: 0.3,
|
||||
weight: 2,
|
||||
});
|
||||
}
|
||||
// marker.on("click", (e) => {
|
||||
// // 清除之前选中的样式
|
||||
// if (selectedLayer) {
|
||||
// selectedLayer.setStyle({
|
||||
// fillColor: "#1E3A8A",
|
||||
// fillOpacity: 0.3,
|
||||
// weight: 2,
|
||||
// });
|
||||
// }
|
||||
|
||||
// 找到对应的区县图层并设置样式
|
||||
geoJsonLayer.eachLayer((layer) => {
|
||||
if (
|
||||
layer.feature &&
|
||||
layer.feature.properties.name === feature.properties.name
|
||||
) {
|
||||
layer.setStyle({
|
||||
fillColor: "#ff4d4f",
|
||||
fillOpacity: 0.6,
|
||||
weight: 2.5,
|
||||
color: "#ff7875",
|
||||
});
|
||||
selectedLayer = layer;
|
||||
selectedDistrict.value = feature.properties.name;
|
||||
}
|
||||
});
|
||||
// // 找到对应的区县图层并设置样式
|
||||
// geoJsonLayer.eachLayer((layer) => {
|
||||
// if (
|
||||
// layer.feature &&
|
||||
// layer.feature.properties.name === feature.properties.name
|
||||
// ) {
|
||||
// layer.setStyle({
|
||||
// fillColor: "#ff4d4f",
|
||||
// fillOpacity: 0.6,
|
||||
// weight: 2.5,
|
||||
// color: "#ff7875",
|
||||
// });
|
||||
// selectedLayer = layer;
|
||||
// selectedDistrict.value = feature.properties.name;
|
||||
// }
|
||||
// });
|
||||
|
||||
// 触发事件
|
||||
emit("districtClick", {
|
||||
name: feature.properties.name,
|
||||
feature: feature,
|
||||
latlng: e.latlng,
|
||||
});
|
||||
// // 触发事件
|
||||
// emit("districtClick", {
|
||||
// name: feature.properties.name,
|
||||
// feature: feature,
|
||||
// latlng: e.latlng,
|
||||
// });
|
||||
|
||||
// 平滑移动到点击位置
|
||||
mapInstance.panTo(e.latlng, { animate: true, duration: 0.5 });
|
||||
});
|
||||
// // 平滑移动到点击位置
|
||||
// mapInstance.panTo(e.latlng, { animate: true, duration: 0.5 });
|
||||
// });
|
||||
mapInstance.addLayer(marker);
|
||||
}
|
||||
}
|
||||
@ -330,6 +515,9 @@ const initMap = (geoJsonData) => {
|
||||
|
||||
// 组件挂载时加载地图
|
||||
onMounted(() => {
|
||||
// 获取受影响对象数据
|
||||
getAffectedCountyData();
|
||||
|
||||
// 检查 Leaflet 是否已加载
|
||||
if (typeof window.L === "undefined") {
|
||||
// 动态加载 Leaflet CSS 和 JS
|
||||
|
||||
@ -5,7 +5,11 @@
|
||||
:style="{ zIndex: props.zIndex }"
|
||||
@click="handleOverlayClick"
|
||||
>
|
||||
<div class="base-dialog" @click.stop :style="{ maxWidth: `${props.maxWidth}px` }">
|
||||
<div
|
||||
class="base-dialog"
|
||||
@click.stop
|
||||
:style="{ maxWidth: `${props.maxWidth}px` }"
|
||||
>
|
||||
<!-- 四个角的装饰 -->
|
||||
<div class="corner corner-top-left"></div>
|
||||
<div class="corner corner-top-right"></div>
|
||||
@ -29,7 +33,6 @@
|
||||
<div class="filter-section" v-if="props.showFilter">
|
||||
<slot name="filter"></slot>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-section" v-if="props.tableData.length > 0">
|
||||
<el-table
|
||||
@ -45,6 +48,8 @@
|
||||
:key="column.prop"
|
||||
:prop="column.prop"
|
||||
:label="column.label"
|
||||
:width="column.width"
|
||||
:min-width="column.width === 'auto' ? '100px' : undefined"
|
||||
>
|
||||
<template v-if="column.slot" #default="{ row }">
|
||||
<slot :name="column.slot" :row="row"></slot>
|
||||
@ -54,13 +59,15 @@
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination" v-if="props.showPagination && props.tableData.length > 0">
|
||||
<div
|
||||
class="pagination"
|
||||
v-if="props.showPagination && props.tableData.length > 0"
|
||||
>
|
||||
<el-pagination
|
||||
:current-page="props.currentPage"
|
||||
:page-size="props.pageSize"
|
||||
:page-sizes="props.pageSizes"
|
||||
:total="props.total"
|
||||
background
|
||||
layout="prev, pager, next, jumper, ->, total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@ -73,7 +80,6 @@
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import { ElTable, ElTableColumn, ElPagination } from "element-plus";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -130,7 +136,14 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "close", "size-change", "current-change", "update:current-page", "update:page-size"]);
|
||||
const emit = defineEmits([
|
||||
"update:visible",
|
||||
"close",
|
||||
"size-change",
|
||||
"current-change",
|
||||
"update:current-page",
|
||||
"update:page-size",
|
||||
]);
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
@ -202,7 +215,7 @@ const cellStyle = () => {
|
||||
justify-content: center;
|
||||
}
|
||||
:deep(.el-table--small) {
|
||||
background: #16334E;
|
||||
background: #16334e;
|
||||
}
|
||||
|
||||
.base-dialog {
|
||||
@ -310,13 +323,20 @@ const cellStyle = () => {
|
||||
.filter-section {
|
||||
margin-bottom: 16px;
|
||||
padding: 0 24px;
|
||||
:deep(.el-select__wrapper) {
|
||||
background: #122c46 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 表格区域
|
||||
.table-section {
|
||||
width: 100%;
|
||||
padding: 0 24px;
|
||||
background: #16334E
|
||||
background: #16334e;
|
||||
}
|
||||
|
||||
:deep(.el-table__inner-wrapper:before) {
|
||||
width: 0% !important;
|
||||
}
|
||||
|
||||
// 分页
|
||||
@ -324,53 +344,128 @@ const cellStyle = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
padding: 12px;
|
||||
background: #16334E;
|
||||
|
||||
padding: 12px 24px;
|
||||
:deep(.btn-prev) {
|
||||
background: #19334b !important;
|
||||
color: #fff;
|
||||
border: 1px solid #1f4f80;
|
||||
}
|
||||
:deep(.btn-next) {
|
||||
background: #19334b !important;
|
||||
color: #fff;
|
||||
border: 1px solid #1f4f80;
|
||||
}
|
||||
:deep(.number) {
|
||||
background: #19334b !important;
|
||||
color: #2d90e3;
|
||||
border: 1px solid #2d90e3;
|
||||
}
|
||||
:deep(.el-pagination) {
|
||||
background: #16334E;
|
||||
|
||||
.el-pagination__total {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
background: #16334e !important;
|
||||
gap: 10px;
|
||||
}
|
||||
:deep(.el-pager) {
|
||||
background: #16334e !important;
|
||||
gap: 10px;
|
||||
}
|
||||
:deep(.el-input__wrapper) {
|
||||
background: #16334e !important;
|
||||
.el-input__inner {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__sizes .el-input__inner {
|
||||
background: #16334E;
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
:deep(.el-pagination__jump) {
|
||||
color: #fff !important;
|
||||
}
|
||||
:deep(.el-pagination__total) {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 下拉
|
||||
.el-select {
|
||||
.el-select__wrapper {
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 0 1px #c5c5c5 inset;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
background: #122c46;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-pagination__btn {
|
||||
background: #16334E;
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
|
||||
&:hover:not(.is-disabled) {
|
||||
background: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
.el-select__wrapper.is-hovering,
|
||||
.el-select__wrapper.is-focused {
|
||||
box-shadow: 0 0 0 1px #3380ec inset;
|
||||
// filter: brightness(1.3);
|
||||
}
|
||||
}
|
||||
:deep(.el-select__placeholder) {
|
||||
font-weight: 400;
|
||||
color: #40a9ff !important;
|
||||
}
|
||||
// 下拉选项浮窗
|
||||
.el-popper {
|
||||
// 下拉选项
|
||||
.el-select-dropdown {
|
||||
background: #122c46;
|
||||
|
||||
.el-pagination__item {
|
||||
background: #16334E;
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
|
||||
&:hover:not(.is-disabled) {
|
||||
background: rgba(64, 169, 255, 0.2);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background: #40a9ff;
|
||||
border-color: #40a9ff;
|
||||
}
|
||||
}
|
||||
|
||||
.el-pagination__jump .el-input__inner {
|
||||
background: #16334E;
|
||||
border: 1px solid rgba(64, 169, 255, 0.3);
|
||||
.el-select-dropdown__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
background-color: #122c46;
|
||||
text-stroke: 0px #3a6fbf;
|
||||
-webkit-text-stroke: 0px #3a6fbf;
|
||||
height: 40px;
|
||||
|
||||
&.is-hovering {
|
||||
background: #0f2e6d;
|
||||
font-weight: bold;
|
||||
color: #7bc8ef;
|
||||
text-stroke: 0px #7bc8ef;
|
||||
font-style: normal;
|
||||
text-transform: none;
|
||||
-webkit-text-stroke: 0px #7bc8ef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 修改小三角箭头的背景色和边框 */
|
||||
:deep(.el-popper__arrow::before) {
|
||||
background-color: #122c46 !important;
|
||||
}
|
||||
:deep(.custom-select-popper) {
|
||||
background-color: #122c46 !important; /* 整体背景色 */
|
||||
border: 1px solid #122c46 !important; /* 边框颜色 */
|
||||
border-radius: 8px !important; /* 圆角 */
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important; /* 阴影 */
|
||||
}
|
||||
|
||||
/* 覆盖下拉框的白色边框 */
|
||||
:deep(.el-popper.is-light .el-popper__arrow::before) {
|
||||
background-color: #122c46 !important;
|
||||
border-color: #122c46 !important;
|
||||
}
|
||||
|
||||
:deep(.el-select-dropdown) {
|
||||
border: 1px solid #122c46 !important;
|
||||
background-color: #122c46 !important;
|
||||
}
|
||||
|
||||
:deep(.el-popper[data-popper-placement^="bottom"]) {
|
||||
border: 1px solid #122c46 !important;
|
||||
}
|
||||
|
||||
:deep(.el-popper[data-popper-placement^="top"]) {
|
||||
border: 1px solid #122c46 !important;
|
||||
}
|
||||
|
||||
:deep(.el-popper__arrow) {
|
||||
border-color: #122c46 !important;
|
||||
}
|
||||
|
||||
:deep(.el-popper__arrow::after) {
|
||||
border-color: #122c46 !important;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,224 @@
|
||||
/* ========================================
|
||||
el-date-picker 自定义主题样式
|
||||
背景色: #122C45
|
||||
文字色: #FFFFFF
|
||||
主题色/选中背景色: #289DFF
|
||||
======================================== */
|
||||
|
||||
/* 防止样式被覆盖,提高优先级 */
|
||||
.custom-date-picker {
|
||||
/* 弹出框整体背景色 */
|
||||
background-color: #122C45 !important;
|
||||
/* 弹出框边框(主题色) */
|
||||
border: 1px solid #289DFF !important;
|
||||
/* 可选:阴影效果 */
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.3) !important;
|
||||
}
|
||||
.el-date-editor .el-range-input {
|
||||
color: #289DFF !important;
|
||||
}
|
||||
/* ========== 1. 顶部栏(年月切换区域) ========== */
|
||||
.custom-date-picker .el-date-picker__header,
|
||||
.custom-date-picker .el-picker-panel__header {
|
||||
background-color: #122C45 !important;
|
||||
border-bottom: 1px solid rgba(40, 157, 255, 0.3) !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-date-picker__header-label,
|
||||
.custom-date-picker .el-picker-panel__header-label {
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-picker-panel__icon-btn {
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-picker-panel__icon-btn:hover {
|
||||
color: #289DFF !important;
|
||||
}
|
||||
|
||||
/* 年份/月份快速选择面板 */
|
||||
.custom-date-picker .el-year-table td .el-year-table__cell__text,
|
||||
.custom-date-picker .el-month-table td .el-month-table__cell__text {
|
||||
color: #FFFFFF !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-year-table td .el-year-table__cell__text:hover,
|
||||
.custom-date-picker .el-month-table td .el-month-table__cell__text:hover {
|
||||
color: #289DFF !important;
|
||||
background-color: rgba(40, 157, 255, 0.2) !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-year-table td.current .el-year-table__cell__text,
|
||||
.custom-date-picker .el-month-table td.current .el-month-table__cell__text {
|
||||
background-color: #289DFF !important;
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
|
||||
/* ========== 2. 星期栏 ========== */
|
||||
.custom-date-picker .el-date-table th,
|
||||
.custom-date-picker .el-date-table__header th {
|
||||
color: #289DFF !important;
|
||||
background-color: #122C45 !important;
|
||||
border-bottom: 1px solid rgba(40, 157, 255, 0.3) !important;
|
||||
}
|
||||
|
||||
/* ========== 3. 日期单元格(默认状态) ========== */
|
||||
.custom-date-picker .el-date-table td .el-date-table-cell__text {
|
||||
color: #FFFFFF !important;
|
||||
background-color: transparent !important;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-date-table td .el-date-table-cell__text:hover {
|
||||
color: #289DFF !important;
|
||||
background-color: rgba(40, 157, 255, 0.2) !important;
|
||||
}
|
||||
|
||||
/* ========== 4. 选中状态(核心样式) ========== */
|
||||
.custom-date-picker .el-date-table td.current .el-date-table-cell__text {
|
||||
background-color: #289DFF !important;
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
|
||||
/* ========== 5. 今天按钮样式 ========== */
|
||||
.custom-date-picker .el-date-table td.today .el-date-table-cell__text {
|
||||
color: #289DFF !important;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-date-table td.today.current .el-date-table-cell__text {
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
|
||||
/* ========== 6. 其他月份日期(灰色显示) ========== */
|
||||
.custom-date-picker .el-date-table td.next-month .el-date-table-cell__text,
|
||||
.custom-date-picker .el-date-table td.prev-month .el-date-table-cell__text {
|
||||
color: rgba(255, 255, 255, 0.35) !important;
|
||||
}
|
||||
|
||||
/* ========== 7. 禁用日期样式 ========== */
|
||||
.custom-date-picker .el-date-table td.disabled .el-date-table-cell__text {
|
||||
color: rgba(255, 255, 255, 0.2) !important;
|
||||
background-color: rgba(0, 0, 0, 0.2) !important;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* ========== 8. 底部按钮区域 ========== */
|
||||
.custom-date-picker .el-picker-panel__footer {
|
||||
background-color: #122C45 !important;
|
||||
border-top: 1px solid rgba(40, 157, 255, 0.3) !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-button--text {
|
||||
color: #289DFF !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-button--text:hover {
|
||||
color: #66ccff !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-button--primary {
|
||||
background-color: #289DFF !important;
|
||||
border-color: #289DFF !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-button--primary:hover {
|
||||
background-color: #1a7acc !important;
|
||||
border-color: #1a7acc !important;
|
||||
}
|
||||
|
||||
/* ========== 9. 小三角箭头 ========== */
|
||||
/* Element Plus 版本 */
|
||||
.custom-date-picker .el-popper__arrow::before {
|
||||
background-color: #122C45 !important;
|
||||
border: 1px solid #289DFF !important;
|
||||
}
|
||||
|
||||
/* Element UI 版本 */
|
||||
.custom-date-picker .popper__arrow {
|
||||
border-bottom-color: #122C45 !important;
|
||||
}
|
||||
.custom-date-picker .popper__arrow::after {
|
||||
border-bottom-color: #122C45 !important;
|
||||
}
|
||||
|
||||
/* ========== 10. 范围选择器样式 ========== */
|
||||
/* 范围选择器整体背景 */
|
||||
.custom-date-picker.el-picker-panel--date-range {
|
||||
background-color: #122C45 !important;
|
||||
}
|
||||
|
||||
/* 范围选择左右面板 */
|
||||
.custom-date-picker .el-date-range-picker__content {
|
||||
background-color: #122C45 !important;
|
||||
}
|
||||
|
||||
/* 范围选择头部 */
|
||||
.custom-date-picker .el-date-range-picker__header {
|
||||
color: #FFFFFF !important;
|
||||
background-color: #122C45 !important;
|
||||
}
|
||||
|
||||
/* 范围选择 - 起始日期 */
|
||||
.custom-date-picker .el-date-table td.start-date .el-date-table-cell__text,
|
||||
.custom-date-picker .el-date-table td.end-date .el-date-table-cell__text {
|
||||
background-color: #289DFF !important;
|
||||
color: #FFFFFF !important;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* 范围选择 - 中间区间 */
|
||||
.custom-date-picker .el-date-table td.in-range .el-date-table-cell__text {
|
||||
background-color: rgba(40, 157, 255, 0.25) !important;
|
||||
color: #FFFFFF !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* 范围选择 - 区间悬停效果 */
|
||||
.custom-date-picker .el-date-table td.in-range .el-date-table-cell__text:hover {
|
||||
background-color: rgba(40, 157, 255, 0.4) !important;
|
||||
}
|
||||
|
||||
/* ========== 11. 滚动条样式 ========== */
|
||||
.custom-date-picker .el-scrollbar__bar {
|
||||
background-color: rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-scrollbar__thumb {
|
||||
background-color: #289DFF !important;
|
||||
}
|
||||
|
||||
/* ========== 12. 时间选择器样式(如有) ========== */
|
||||
.custom-date-picker .el-time-spinner__item {
|
||||
color: #FFFFFF !important;
|
||||
background-color: #122C45 !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-time-spinner__item:hover {
|
||||
background-color: rgba(40, 157, 255, 0.2) !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-time-spinner__item.active {
|
||||
background-color: #289DFF !important;
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
|
||||
/* ========== 13. 快捷选项样式 ========== */
|
||||
.custom-date-picker .el-picker-panel__shortcut {
|
||||
color: #FFFFFF !important;
|
||||
background-color: #122C45 !important;
|
||||
}
|
||||
|
||||
.custom-date-picker .el-picker-panel__shortcut:hover {
|
||||
background-color: rgba(40, 157, 255, 0.2) !important;
|
||||
color: #289DFF !important;
|
||||
}
|
||||
.el-range__icon{
|
||||
color: #289DFF !important;
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
// 下拉
|
||||
.el-select {
|
||||
.el-select__wrapper {
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 0 1px #c5c5c5 inset;
|
||||
height: 30px !important;
|
||||
line-height: 30px !important;
|
||||
background: #122c46;
|
||||
|
||||
.is-transparent {
|
||||
background: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
color: #fff !important;
|
||||
|
||||
}
|
||||
|
||||
.el-select__placeholder {
|
||||
color: #16D9E0;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.el-select__placeholder {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.el-select__wrapper.is-hovering,
|
||||
.el-select__wrapper.is-focused {
|
||||
box-shadow: 0 0 0 1px #3380ec inset;
|
||||
// filter: brightness(1.3);
|
||||
}
|
||||
}
|
||||
|
||||
// 下拉选项浮窗
|
||||
.el-popper {
|
||||
border-radius: 6px;
|
||||
|
||||
// 下拉选项
|
||||
.el-select-dropdown {
|
||||
background: #122c46;
|
||||
|
||||
.el-select-dropdown__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
background-color: #122c46;
|
||||
text-stroke: 0px #16D9E0;
|
||||
-webkit-text-stroke: 0px #16D9E0;
|
||||
height: 40px;
|
||||
|
||||
&.is-hovering {
|
||||
background: #0f2e6d;
|
||||
font-weight: bold;
|
||||
color: #7bc8ef;
|
||||
text-stroke: 0px #7bc8ef;
|
||||
font-style: normal;
|
||||
text-transform: none;
|
||||
-webkit-text-stroke: 0px #7bc8ef;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -26,7 +26,7 @@
|
||||
<div class="corner corner-bottom-right"></div>
|
||||
<!-- 中心数据展示卡片 -->
|
||||
<div class="center-info-card-container">
|
||||
<div
|
||||
<!-- <div
|
||||
class="center-info-card"
|
||||
@click="openDialog('tongnanResponsible')"
|
||||
v-if="showCenterCard.type === 'first'"
|
||||
@ -44,7 +44,7 @@
|
||||
<span class="info-unit">处</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div
|
||||
class="center-info-card"
|
||||
@ -280,6 +280,9 @@ import tongnanTeamDialog from "./Dialog/tongnanTeamDialog.vue";
|
||||
import warningSituationDialog from "./Dialog/warningSituationDialog.vue";
|
||||
import tunnelInfoDialog from "./Dialog/tunnelInfoDialog.vue";
|
||||
|
||||
import './component/el-select.scss'
|
||||
import './component/date-picker-theme.scss'
|
||||
|
||||
// 弹窗显示状态
|
||||
const dialogVisible = ref({
|
||||
responseSituation: false,
|
||||
@ -616,4 +619,31 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 下拉选项浮窗
|
||||
.el-popper {
|
||||
// 下拉选项
|
||||
.el-select-dropdown {
|
||||
background: #122c46;
|
||||
.el-select-dropdown__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
background-color: #122c46;
|
||||
text-stroke: 0px #3a6fbf;
|
||||
-webkit-text-stroke: 0px #3a6fbf;
|
||||
height: 40px;
|
||||
|
||||
&.is-hovering {
|
||||
background: #0f2e6d;
|
||||
font-weight: bold;
|
||||
color: #7bc8ef;
|
||||
text-stroke: 0px #7bc8ef;
|
||||
font-style: normal;
|
||||
text-transform: none;
|
||||
-webkit-text-stroke: 0px #7bc8ef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -188,7 +188,7 @@ import imgHelp from "../../assets/RiskWarning_img/响应图标5@2x.png";
|
||||
import imgCheck from "../../assets/RiskWarning_img/抽查人数icon@2x.png";
|
||||
|
||||
// 注入兄弟组件通信机制
|
||||
const setRefreshLeftData = inject('setRefreshLeftData');
|
||||
const setRefreshLeftData = inject("setRefreshLeftData");
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@ -287,7 +287,7 @@ const weatherWarningData = ref([
|
||||
|
||||
// 影响点数据
|
||||
const impactData = ref([
|
||||
{ name: "路段", count: 830 },
|
||||
{ name: "路段", count: 0 },
|
||||
{ name: "桥梁", count: 312 },
|
||||
{ name: "隧道", count: 405 },
|
||||
{ name: "边坡", count: 634 },
|
||||
@ -377,7 +377,23 @@ const districtLoadLoad = async () => {
|
||||
if (res.code == "00000") {
|
||||
const data = res.data;
|
||||
if (data) {
|
||||
districtData.value = data;
|
||||
// 根据路段、桥梁、隧道、边坡、项目的总数进行排序(数值越大越靠前)
|
||||
const sortedData = data.sort((a, b) => {
|
||||
const totalA =
|
||||
(a.roadSectionCount || 0) +
|
||||
(a.bridgeCount || 0) +
|
||||
(a.tunnelCount || 0) +
|
||||
(a.slopeCount || 0) +
|
||||
(a.projectCount || 0);
|
||||
const totalB =
|
||||
(b.roadSectionCount || 0) +
|
||||
(b.bridgeCount || 0) +
|
||||
(b.tunnelCount || 0) +
|
||||
(b.slopeCount || 0) +
|
||||
(b.projectCount || 0);
|
||||
return totalB - totalA; // 降序排列,数值大的在前
|
||||
});
|
||||
districtData.value = sortedData;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@ -497,6 +513,7 @@ const totalValue = computed(() => {
|
||||
// 计算每个柱子的高度百分比
|
||||
const getBarHeight = (value) => {
|
||||
const actualValue = value.count || value.value;
|
||||
if (!actualValue || actualValue == 0) return "0";
|
||||
// 确保最小高度为10%,最大高度为100%
|
||||
const height = (actualValue / totalValue.value) * 200;
|
||||
// 确保高度差异明显,至少有5%的差异
|
||||
@ -517,19 +534,7 @@ const tableHeight = computed(() => {
|
||||
});
|
||||
|
||||
// 区县数据
|
||||
const districtData = ref([
|
||||
{ extension: "江北区", road: 1, bridge: 1, tunnel: 1, slope: 8, project: 11 },
|
||||
{ extension: "南岸区", road: 1, bridge: 2, tunnel: 2, slope: 6, project: 12 },
|
||||
{
|
||||
extension: "九龙坡区",
|
||||
road: 2,
|
||||
bridge: 1,
|
||||
tunnel: 1,
|
||||
slope: 9,
|
||||
project: 9,
|
||||
},
|
||||
{ extension: "万州区", road: 1, bridge: 2, tunnel: 2, slope: 11, project: 7 },
|
||||
]);
|
||||
const districtData = ref([]);
|
||||
|
||||
// 响应调度统计数据
|
||||
const responseStats = ref([
|
||||
@ -941,8 +946,17 @@ const cellStyle = () => ({
|
||||
|
||||
// 区县统计表格
|
||||
.district-table-section {
|
||||
height: vw(100);
|
||||
height: vw(150);
|
||||
overflow: hidden;
|
||||
:deep(.el-table__empty-block) {
|
||||
max-height: 40px !important;
|
||||
.el-table__empty-text {
|
||||
line-height: 30px !important;
|
||||
}
|
||||
}
|
||||
:deep(.el-table__empty-block) {
|
||||
min-height: 40px !important;
|
||||
}
|
||||
|
||||
:deep(.el-table) {
|
||||
background: transparent;
|
||||
@ -968,7 +982,7 @@ const cellStyle = () => ({
|
||||
.el-table__body-wrapper {
|
||||
background: transparent;
|
||||
overflow-y: auto;
|
||||
max-height: calc(#{vw(100)} - #{vw(40)}); /* 减去表头高度 */
|
||||
max-height: calc(#{vw(150)} - #{vw(0)}); /* 减去表头高度 */
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
|
||||
|
||||
@ -27,12 +27,8 @@
|
||||
<!-- 管控路段数 -->
|
||||
<div class="control-section">
|
||||
<div class="control-title display jc_sb ai_center">
|
||||
<div class="f1">
|
||||
管控路段数 <span class="control-num">2</span>
|
||||
</div>
|
||||
<div class="f1">
|
||||
管控项目 <span class="control-num">2</span>
|
||||
</div>
|
||||
<div class="f1">管控路段数 <span class="control-num">2</span></div>
|
||||
<div class="f1">管控项目 <span class="control-num">2</span></div>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<div class="control-grid">
|
||||
@ -196,27 +192,12 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from "vue";
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
|
||||
import SectionHeader from "./component/sectionHeader.vue";
|
||||
import { Calendar } from "@element-plus/icons-vue";
|
||||
|
||||
const emit = defineEmits(["openClearanceSituation", "openControlSituation"]);
|
||||
|
||||
// 点击管控项
|
||||
const handleControlClick = (item) => {
|
||||
if (item.label === "封闭管控数") {
|
||||
emit("openClearanceSituation");
|
||||
} else if (item.label === "关闭驻地数") {
|
||||
emit("openControlSituation");
|
||||
}
|
||||
};
|
||||
|
||||
// 点击阻断情况
|
||||
const handleBlockClick = () => {
|
||||
emit("openClearanceSituation");
|
||||
};
|
||||
|
||||
import icon1 from "../../assets/RiskWarning_img/icon1@2x.png";
|
||||
import icon2 from "../../assets/RiskWarning_img/icon2@2x.png";
|
||||
import icon3 from "../../assets/RiskWarning_img/icon3@2x.png";
|
||||
@ -234,40 +215,159 @@ import icon62 from "../../assets/RiskWarning_img/路径62@2x.png";
|
||||
import icon621 from "../../assets/RiskWarning_img/路径62@2x (1).png";
|
||||
import icon622 from "../../assets/RiskWarning_img/路径62@2x (2).png";
|
||||
|
||||
const emit = defineEmits(["openClearanceSituation", "openControlSituation"]);
|
||||
|
||||
// 组件挂载时获取数据
|
||||
onMounted(() => {
|
||||
getYhYjllList();
|
||||
getYhYjllListMaterials();
|
||||
});
|
||||
|
||||
// 获取应急力量列表数据
|
||||
const getYhYjllList = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: "/snow-ops-platform/yhYjll/list",
|
||||
method: "GET",
|
||||
params: {
|
||||
// longitude: 114.305556,
|
||||
// latitude: 22.624722,
|
||||
// maxDistance: 10 // 1000km
|
||||
},
|
||||
});
|
||||
console.log(res);
|
||||
if (res.code == "00000") {
|
||||
let gl1Rysls = 0; // 人员数
|
||||
let gl1Yjllmcs = 0; // 队伍数
|
||||
res.data.forEach((item) => {
|
||||
gl1Yjllmcs = gl1Yjllmcs + 1;
|
||||
gl1Rysls = Number(item.gl1Rysl) + gl1Rysls;
|
||||
});
|
||||
if (gl1Rysls > 10000) {
|
||||
gl1Rysls = (gl1Rysls / 10000).toFixed(2);
|
||||
resourceData.value[1].unit = "万人";
|
||||
} else {
|
||||
resourceData.value[1].value = gl1Rysls;
|
||||
resourceData.value[1].unit = "人";
|
||||
}
|
||||
resourceData.value[0].value = gl1Yjllmcs;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取应急力量列表失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 根据类型获取图标
|
||||
const getIconByType = (type) => {
|
||||
const iconMap = {
|
||||
1: icon1, // 队伍
|
||||
2: icon2, // 人员
|
||||
3: icon3, // 装备
|
||||
4: icon4, // 物资
|
||||
};
|
||||
return iconMap[type] || icon1;
|
||||
};
|
||||
|
||||
// 获取物资列表数据
|
||||
const getYhYjllListMaterials = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: "/snow-ops-platform/yhYjll/listMaterials",
|
||||
method: "GET",
|
||||
params: {},
|
||||
});
|
||||
console.log("物资列表:", res);
|
||||
if (res.code == "00000" && res.data) {
|
||||
let equipment = 0; // 装备数
|
||||
let materials = 0; // 物资数
|
||||
|
||||
res.data.forEach((item) => {
|
||||
if (item.gl1Wzlx == 1) {
|
||||
equipment = equipment + extractAndSumNumbers(item.gl1Wzsl);
|
||||
} else if (item.gl1Wzlx == 2) {
|
||||
materials = materials + extractAndSumNumbers(item.gl1Wzsl);
|
||||
}
|
||||
});
|
||||
if (materials > 10000) {
|
||||
resourceData.value[3].value = (materials / 10000).toFixed(2);
|
||||
resourceData.value[3].unit = "万件";
|
||||
} else {
|
||||
resourceData.value[3].value = materials;
|
||||
resourceData.value[3].unit = "件";
|
||||
}
|
||||
|
||||
console.log(equipment, materials);
|
||||
// 更新物资数据
|
||||
resourceData.value[2].value = equipment || "0";
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取物资列表失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 从字符串中提取数字并相加
|
||||
const extractAndSumNumbers = (value) => {
|
||||
// 如果是数字,直接返回
|
||||
if (typeof value === "number") {
|
||||
return value;
|
||||
}
|
||||
// 如果不是字符串,返回 0
|
||||
if (!value || typeof value !== "string") return 0;
|
||||
// 匹配所有数字(包括小数)
|
||||
const numbers = value.match(/\d+\.?\d*/g);
|
||||
if (!numbers) return 0;
|
||||
// 将提取的数字相加
|
||||
return numbers.reduce((sum, num) => sum + Number(num), 0);
|
||||
};
|
||||
|
||||
// 点击管控项
|
||||
const handleControlClick = (item) => {
|
||||
if (item.label === "封闭管控数") {
|
||||
emit("openClearanceSituation");
|
||||
} else if (item.label === "关闭驻地数") {
|
||||
emit("openControlSituation");
|
||||
}
|
||||
};
|
||||
|
||||
// 点击阻断情况
|
||||
const handleBlockClick = () => {
|
||||
emit("openClearanceSituation");
|
||||
};
|
||||
|
||||
// 日期范围选择器
|
||||
const dateRange = ref([]);
|
||||
|
||||
// 资源数据(队伍、人员、装备、物资)
|
||||
const resourceData = [
|
||||
const resourceData = ref([
|
||||
{
|
||||
label: "全市普通公路抢险队伍",
|
||||
value: "39",
|
||||
value: "",
|
||||
unit: "支",
|
||||
iconClass: "icon-team",
|
||||
img: icon1,
|
||||
},
|
||||
{
|
||||
label: "人员",
|
||||
value: "1612",
|
||||
value: "",
|
||||
unit: "人",
|
||||
iconClass: "icon-person",
|
||||
img: icon2,
|
||||
},
|
||||
{
|
||||
label: "储备装备",
|
||||
value: "1157",
|
||||
value: "",
|
||||
unit: "台",
|
||||
iconClass: "icon-equip",
|
||||
img: icon3,
|
||||
},
|
||||
{
|
||||
label: "物资",
|
||||
value: "41.5",
|
||||
unit: "万件",
|
||||
value: "",
|
||||
unit: "件",
|
||||
iconClass: "icon-material",
|
||||
img: icon4,
|
||||
},
|
||||
];
|
||||
]);
|
||||
|
||||
// 管控路段数据
|
||||
const controlData1 = [
|
||||
@ -397,7 +497,7 @@ const majorEvent = "0";
|
||||
height: vw(16);
|
||||
min-width: 14px;
|
||||
min-height: 14px;
|
||||
background: linear-gradient(135deg, #18F2F9 0%, #1890ff 100%);
|
||||
background: linear-gradient(135deg, #18f2f9 0%, #1890ff 100%);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -480,7 +580,7 @@ const majorEvent = "0";
|
||||
.resource-value {
|
||||
font-size: vw(16);
|
||||
font-weight: bold;
|
||||
color: #18F2F9;
|
||||
color: #18f2f9;
|
||||
|
||||
.unit {
|
||||
font-size: vw(14);
|
||||
@ -506,7 +606,7 @@ const majorEvent = "0";
|
||||
.control-num {
|
||||
font-size: vw(16);
|
||||
|
||||
color: #18F2F9;
|
||||
color: #18f2f9;
|
||||
font-weight: bold;
|
||||
margin-left: vw(5);
|
||||
}
|
||||
@ -535,14 +635,13 @@ const majorEvent = "0";
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(64, 169, 255, 0.15);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.control-value {
|
||||
font-size: vw(18);
|
||||
font-weight: bold;
|
||||
color: #18F2F9;
|
||||
color: #18f2f9;
|
||||
// margin-bottom: vw(4);
|
||||
}
|
||||
|
||||
@ -572,7 +671,7 @@ const majorEvent = "0";
|
||||
.patrol-mileage {
|
||||
font-size: vw(16);
|
||||
font-weight: bold;
|
||||
color: #4FECFF;
|
||||
color: #4fecff;
|
||||
}
|
||||
}
|
||||
|
||||
@ -593,7 +692,7 @@ const majorEvent = "0";
|
||||
.patrol-value {
|
||||
font-size: vw(18);
|
||||
font-weight: bold;
|
||||
color: #4FECFF;
|
||||
color: #4fecff;
|
||||
margin-bottom: vw(4);
|
||||
text-align: left;
|
||||
margin-left: vw(5);
|
||||
@ -723,7 +822,7 @@ const majorEvent = "0";
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
transparent 0%,
|
||||
#18F2F9 50%,
|
||||
#18f2f9 50%,
|
||||
transparent 100%
|
||||
);
|
||||
// margin: 0 auto;
|
||||
@ -744,7 +843,7 @@ const majorEvent = "0";
|
||||
margin-bottom: vw(6);
|
||||
|
||||
.current {
|
||||
color: #18F2F9;
|
||||
color: #18f2f9;
|
||||
}
|
||||
|
||||
.separator {
|
||||
@ -820,7 +919,7 @@ const majorEvent = "0";
|
||||
}
|
||||
|
||||
&.blue .damage-value {
|
||||
color: #18F2F9;
|
||||
color: #18f2f9;
|
||||
.unit {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
@ -94,6 +94,8 @@ export default defineConfig(({ command, mode }) => {
|
||||
proxy: {
|
||||
'/snow-ops-platform': {
|
||||
target: 'http://192.168.110.16:8661/',
|
||||
// target: 'http://8.137.54.85:8661/', //测试环境
|
||||
// target: 'http://192.168.110.36:8661/', //张启生本地环境
|
||||
changeOrigin: true,
|
||||
},
|
||||
}
|
||||
|
||||