This commit is contained in:
huangchenhao 2026-05-08 17:19:55 +08:00
commit f518081cb6
17 changed files with 738 additions and 586 deletions

View File

@ -21,7 +21,11 @@
<div class="panel left-panel">
<div class="panel-title">气象预警信息</div>
<div class="panel-content">
<div class="warning-content-container">{{ warningData.warningContent }}</div>
<div class="warning-content-container">
<div>{{ warningData.warningContent }}</div>
<div>生效时间:2025-11-13 00:31:30.0</div>
<div>失效时间:2025-11-14 06:00:00.0</div>
</div>
</div>
</div>

View File

@ -26,57 +26,47 @@
:popper-append-to-body="false"
class="filter-select"
clearable
@change="fetchData"
>
<el-option
v-for="item in regionOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<el-option v-for="item in regionOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div class="filter-item">
<!-- <div class="filter-item">
<span class="filter-label">类型</span>
<el-select
:teleported="false"
v-model="filterForm.type"
placeholder="请选择"
class="filter-select"
clearable
>
<el-option
v-for="item in typeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<el-select :teleported="false" v-model="filterForm.type" placeholder="请选择" class="filter-select" clearable @change="fetchData">
<el-option v-for="item in typeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div> -->
</div>
</template>
</base-dialog>
</template>
<script setup>
import { ref, computed, watch } from 'vue';
import { Close } from '@element-plus/icons-vue';
import { regionOptions, typeOptions } from '../component/index.js';
import BaseDialog from '../component/baseDialog.vue';
import { ref, computed, watch } from 'vue'
import { Close } from '@element-plus/icons-vue'
import { regionOptions, typeOptions, formatDateTime } from '../component/index.js'
import BaseDialog from '../component/baseDialog.vue'
import { request } from '@/utils/request'
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
});
dispatchDateRange: {
type: Array,
default: () => [],
},
})
const emit = defineEmits(['update:visible', 'close']);
const emit = defineEmits(['update:visible', 'close'])
//
const filterForm = ref({
region: '',
type: '',
});
})
//
// index.js
@ -85,7 +75,7 @@ const filterForm = ref({
// index.js
//
const tableHeight = ref(300);
const tableHeight = ref(300)
//
const tableColumns = ref([
@ -96,104 +86,137 @@ const tableColumns = ref([
{ prop: 'type', label: '类型', width: '120px' },
{ prop: 'role', label: '角色', width: '120px' },
{ prop: 'dispatchTime', label: '调度时间', width: '160px' },
]);
])
//
const tableData = ref([
{
id: 1,
district: '柏梓镇',
name: '赵海浪',
phone: '18623520681',
type: '交通主管部门',
role: '一般人员(路长履职)',
dispatchTime: '2025-08-11 04:53:42',
},
{
id: 2,
district: '柏梓镇',
name: '赵海浪',
phone: '18623520681',
type: '公路机构',
role: '一般人员(路长履职)',
dispatchTime: '2025-08-11 04:53:42',
},
{
id: 3,
district: '万州区',
name: '王鑫',
phone: '18623520682',
type: '养护站',
role: '站长',
dispatchTime: '2025-08-10 14:30:00',
},
{
id: 4,
district: '沙坪坝区',
name: '李华',
phone: '18623520683',
type: '护路员',
role: '一般人员',
dispatchTime: '2025-08-09 09:15:30',
},
]);
const tableData = ref([])
//
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(36);
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(36)
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
const totalPages = computed(() => Math.ceil(total.value / pageSize.value))
const visiblePages = computed(() => {
const pages = [];
const maxVisible = 5;
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
let end = Math.min(totalPages.value, start + maxVisible - 1);
const pages = []
const maxVisible = 5
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2))
let end = Math.min(totalPages.value, start + maxVisible - 1)
if (end - start + 1 < maxVisible) {
start = Math.max(1, end - maxVisible + 1);
start = Math.max(1, end - maxVisible + 1)
}
for (let i = start; i <= end; i++) {
pages.push(i);
pages.push(i)
}
return pages;
});
return pages
})
//
const handleClose = () => {
emit('update:visible', false);
emit('close');
};
emit('update:visible', false)
emit('close')
}
//
const handleSizeChange = val => {
pageSize.value = val;
fetchData();
};
const handleSizeChange = (val) => {
pageSize.value = val
fetchData()
}
const handleCurrentChange = val => {
currentPage.value = val;
fetchData();
};
const handleCurrentChange = (val) => {
currentPage.value = val
fetchData()
}
//
const fetchData = () => {
console.log('获取第', currentPage.value, '页数据');
// API
};
const fetchData = async () => {
try {
const res = await request({
url: '/snow-ops-platform/weather-warning/scheduling-county-record',
method: 'GET',
params: {
offset: (currentPage.value - 1) * pageSize.value,
limit: pageSize.value,
start: formatDateTime(props.dispatchDateRange?.[0]),
end: formatDateTime(props.dispatchDateRange?.[1]),
countyId: filterForm.value.region,
},
})
if (res.total > 0 && res.data) {
const data = res.data
tableData.value = data.map((item, index) => {
// command JSON
let commandData = {}
try {
if (item.command) {
commandData = JSON.parse(item.command)
}
} catch (e) {
console.error('解析 command 字段失败:', e)
}
// type
const typeMap = {
'phone-based-confirmation': '电话确认',
'video-conference': '视频会议',
'scheduling-county': '调度区县',
}
const district = regionOptions.value.find((option) => option.value === item.countyId)?.label || '-'
return {
id: (currentPage.value - 1) * pageSize.value + index + 1,
district: district,
name: commandData.userName || '-',
phone: commandData.userPhone || '-',
type: commandData.type || '-',
role: commandData.role || '一般人员',
dispatchTime: item.createdAt || '-',
}
})
total.value = res.total
} else {
tableData.value = []
total.value = 0
}
} catch (error) {
console.error('获取调度区县详情数据失败:', error)
}
}
// visible
watch(
() => props.visible,
newVal => {
(newVal) => {
if (newVal) {
currentPage.value = 1;
fetchData();
filterForm.value.region = ''
filterForm.value.type = ''
tableData.value = []
total.value = 0
currentPage.value = 1
fetchData()
}
},
)
// dispatchDateRange
watch(
() => props.dispatchDateRange,
() => {
if (props.visible) {
filterForm.value.region = ''
filterForm.value.type = ''
tableData.value = []
total.value = 0
currentPage.value = 1
fetchData()
}
);
},
{ deep: true },
)
</script>
<style lang="scss" scoped>

View File

@ -18,19 +18,8 @@
<div class="filter-row">
<div class="filter-item">
<span class="filter-label">影响区域</span>
<el-select
:teleported="false"
v-model="filterForm.region"
placeholder="请选择"
class="filter-select"
clearable
>
<el-option
v-for="item in regionOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<el-select :teleported="false" v-model="filterForm.region" placeholder="请选择" class="filter-select" clearable @change="fetchData">
<el-option v-for="item in regionOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
@ -44,34 +33,47 @@
</template>
<script setup>
import { ref, computed, watch } from 'vue';
import { Close } from '@element-plus/icons-vue';
import { regionOptions } from '../component/index.js';
import BaseDialog from '../component/baseDialog.vue';
import { ref, computed, watch } from 'vue'
import { Close } from '@element-plus/icons-vue'
import { regionOptions, formatDateTime } from '../component/index.js'
import BaseDialog from '../component/baseDialog.vue'
import { request } from '@/utils/request'
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
});
dispatchDateRange: {
type: Array,
default: () => [],
},
})
watch(
() => props.dispatchDateRange,
(newVal) => {
console.log(newVal, '调度日期范围')
fetchData()
},
)
const emit = defineEmits({
'update:visible': value => typeof value === 'boolean',
'update:visible': (value) => typeof value === 'boolean',
close: () => true,
dispatchClick: item => item !== undefined,
});
dispatchClick: (item) => item !== undefined,
})
//
const filterForm = ref({
region: '',
});
})
//
// index.js
//
const tableHeight = ref(300);
const tableHeight = ref(300)
//
const tableColumns = ref([
@ -79,99 +81,106 @@ const tableColumns = ref([
{ prop: 'region', label: '影响区域', width: '' },
{ prop: 'dispatchCount', label: '调度数', width: '', slot: 'dispatchCount' },
{ prop: 'lastDispatchTime', label: '最近调度时间', width: '' },
]);
])
//
const tableData = ref([
{
id: 1,
region: '重庆市',
dispatchCount: 1,
lastDispatchTime: '2025-08-11 04:53:42',
},
{
id: 2,
region: '万州区',
dispatchCount: 1,
lastDispatchTime: '2025-08-11 04:53:42',
},
{
id: 3,
region: '沙坪坝区',
dispatchCount: 3,
lastDispatchTime: '2025-08-10 16:20:15',
},
{
id: 4,
region: '渝中区',
dispatchCount: 2,
lastDispatchTime: '2025-08-09 11:45:30',
},
]);
const tableData = ref([])
//
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(36);
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(36)
const totalPages = computed(() => Math.ceil(total.value / pageSize.value));
const totalPages = computed(() => Math.ceil(total.value / pageSize.value))
const visiblePages = computed(() => {
const pages = [];
const maxVisible = 5;
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2));
let end = Math.min(totalPages.value, start + maxVisible - 1);
const pages = []
const maxVisible = 5
let start = Math.max(1, currentPage.value - Math.floor(maxVisible / 2))
let end = Math.min(totalPages.value, start + maxVisible - 1)
if (end - start + 1 < maxVisible) {
start = Math.max(1, end - maxVisible + 1);
start = Math.max(1, end - maxVisible + 1)
}
for (let i = start; i <= end; i++) {
pages.push(i);
pages.push(i)
}
return pages;
});
return pages
})
//
const handleClose = () => {
emit('update:visible', false);
emit('close');
};
emit('update:visible', false)
emit('close')
}
//
const handleDispatchClick = item => {
emit('dispatchClick', item);
};
const handleDispatchClick = (item) => {
emit('dispatchClick', item)
}
//
const handleSizeChange = val => {
pageSize.value = val;
fetchData();
};
const handleSizeChange = (val) => {
pageSize.value = val
fetchData()
}
const handleCurrentChange = val => {
currentPage.value = val;
fetchData();
};
const handleCurrentChange = (val) => {
currentPage.value = val
fetchData()
}
const handleFilterChange = () => {
currentPage.value = 1
fetchData()
}
//
const fetchData = () => {
console.log('获取第', currentPage.value, '页数据');
// API
};
const fetchData = async () => {
try {
const res = await request({
url: '/snow-ops-platform/weather-warning/scheduling-county',
method: 'GET',
params: {
start: formatDateTime(props.dispatchDateRange?.[0]),
end: formatDateTime(props.dispatchDateRange?.[1]),
countyId: filterForm.value.region,
offset: (currentPage.value - 1) * pageSize.value,
limit: pageSize.value,
},
})
if (res.total > 0 && res.data) {
const data = res.data
tableData.value = data.map((item, index) => {
const region = item.qxmc || regionOptions.value.find((option) => option.value === item.countyId)?.label || '-'
return {
id: (currentPage.value - 1) * pageSize.value + index + 1,
region: region,
dispatchCount: item.count || 0,
lastDispatchTime: item.lastTime || '-',
}
})
total.value = res.total
} else {
tableData.value = []
total.value = 0
}
} catch (error) {
console.error('获取调度区县数据失败:', error)
}
}
// visible
watch(
() => props.visible,
newVal => {
if (newVal) {
currentPage.value = 1;
(newVal) => {
currentPage.value = 1
//
filterForm.value.region = '';
fetchData();
}
}
);
filterForm.value.region = ''
fetchData()
},
)
</script>
<style lang="scss" scoped>

View File

@ -139,12 +139,7 @@
<span class="timeline-value highlight">{{ item.sceneDesc }}</span>
</div>
<div class="timeline-images" v-if="item.images && item.images.length > 0">
<div
v-for="(img, imgIndex) in item.images"
:key="imgIndex"
class="timeline-image"
@click="previewImage(img)"
>
<div v-for="(img, imgIndex) in item.images" :key="imgIndex" class="timeline-image" @click="previewImage(img)">
<img :src="img" alt="现场图片" />
</div>
</div>
@ -168,11 +163,11 @@
</template>
<script setup>
import { ref, watch, onMounted } from 'vue';
import { Close } from '@element-plus/icons-vue';
import baseDialog from '../component/baseDialog.vue';
import { request } from '@/utils/request';
import { formatDateTime } from '../component/index.js';
import { ref, watch, onMounted } from 'vue'
import { Close } from '@element-plus/icons-vue'
import baseDialog from '../component/baseDialog.vue'
import { request } from '@/utils/request'
import { formatDateTime } from '../component/index.js'
const props = defineProps({
visible: {
@ -183,11 +178,11 @@ const props = defineProps({
type: Object,
default: () => ({}),
},
});
})
onMounted(() => {
console.log('props.eventData', props.eventData);
});
const emit = defineEmits(['update:visible', 'close']);
console.log('props.eventData', props.eventData)
})
const emit = defineEmits(['update:visible', 'close'])
//
const eventInfo = ref({
@ -201,55 +196,56 @@ const eventInfo = ref({
roadPosition: '',
stakeRange: '',
discoverTime: '',
});
})
//
const feedbackList = ref([]);
const feedbackList = ref([])
//
const fetchEventDetail = async () => {
try {
const gl1SjId = props.eventData?.gl1SjId;
const gl1SjId = props.eventData?.gl1SjId
if (!gl1SjId) {
console.warn('gl1SjId 不存在');
return;
console.warn('gl1SjId 不存在')
return
}
const res = await request({
url: '/snow-ops-platform/sm-event/detail-by-sjid',
// url: '/snow-ops-platform/sm-event/detail-by-sjid',
url: '/snow-ops-platform/sm-event/detail',
method: 'GET',
params: {
sjid: gl1SjId + '',
// sjid: '00092c5f0c054c67b0ad00071dd94630',
gl1SjId: gl1SjId + '',
// gl1SjId: '2fd1225c892a4e9396f006fe8ebaac53',
},
});
})
if (res && res.code === '00000') {
// - API
const data = res.data || {};
const data = res.data || {}
eventInfo.value = {
// eventType:
eventType: data.eventType || '-',
eventType: data.gl1Sjlx || '-',
// eventLevel: ->
roadConditionType: data.eventLevel || '-',
roadConditionType: data.gl1Lklx || '-',
// isBlocked: eventDesc
isBlocked: data.eventDesc?.includes('阻断') ? '是' : '否',
// district: ->
reportCounty: data.district || '-',
reportCounty: data.qxmc || '-',
// detailAddress: ->
blockLocation: data.detailAddress || '-',
blockLocation: data.gl1Wz || '-',
// eventNo: -> 线
routeCode: data.eventNo || '-',
routeCode: data.gl1Lxbh || '-',
// eventDesc: ->
handleMeasure: data.eventDesc || '-',
handleMeasure: data.gl1Clcs || '-',
// detailAddress: ->
roadPosition: data.detailAddress || '-',
// stakeRange
stakeRange: formatStakeRangeFromData(data),
roadPosition: data.gl1Lxmc || '-',
// stakeRange
stakeRange: data.gl1Qdzh + '-' + data.gl1Zdzh || '-',
// occurTime: ->
discoverTime: formatDateTime(data.occurTime) || '-',
};
console.log('eventInfo', eventInfo.value);
discoverTime: data.gl1Fxsj || '-',
}
console.log('eventInfo', eventInfo.value)
// - API
if (data.handleList && Array.isArray(data.handleList)) {
feedbackList.value = data.handleList.map((item, index) => ({
@ -257,84 +253,85 @@ const fetchEventDetail = async () => {
isFirst: index === 0,
reportType: index === 0 ? '首报' : '续报',
// disposeTime:
reportTime: formatDateTime(item.disposeTime) || '-',
reportTime: formatDateTime(item.gl1Cjsj) || '-',
// handleMeasure: disposeDesc
handleMeasure: item.disposeDesc?.substring(0, 10) || '-',
handleMeasure: item.gl1Clcs || '-',
// expectStartTime:
estimatedRecoverTime: formatDateTime(item.expectStartTime) || '-',
estimatedRecoverTime: formatDateTime(item.gl1Yjhfsj) || '-',
// actualStartTime:
actualRecoverTime: formatDateTime(item.actualStartTime) || '-',
actualRecoverTime: formatDateTime(item.gl1Sjhfsj) || '-',
// disposer:
reporter: item.disposer || '-',
reporter: item.gl1Lxrxm || '-',
// contactPhone:
contactPhone: item.contactPhone || '-',
contactPhone: item.gl1Lxdh || '-',
// disposeDesc:
sceneDesc: item.disposeDesc || '-',
}));
sceneDesc: item.gl1Xcqkms || '-',
images: item.gl1Zjtp ? [item.gl1Zjtp] : [],
}))
} else {
feedbackList.value = [];
feedbackList.value = []
}
}
} catch (error) {
console.error('获取事件详情失败:', error);
console.error('获取事件详情失败:', error)
}
}
};
//
const formatRoadPosition = data => {
const parts = [];
if (data.gl1Qxmc) parts.push(data.gl1Qxmc);
if (data.gl1Zddxdm) parts.push(data.gl1Zddxdm);
if (data.gl1Lxbh) parts.push(data.gl1Lxbh);
return parts.length > 0 ? parts.join('') : '-';
};
const formatRoadPosition = (data) => {
const parts = []
if (data.gl1Qxmc) parts.push(data.gl1Qxmc)
if (data.gl1Zddxdm) parts.push(data.gl1Zddxdm)
if (data.gl1Lxbh) parts.push(data.gl1Lxbh)
return parts.length > 0 ? parts.join('') : '-'
}
//
const formatStakeRange = data => {
const start = data.gl1Qdzh || '';
const end = data.gl1Zdzh || '';
if (start && end) return `${start}-${end}`;
if (start) return start;
if (end) return end;
return '-';
};
const formatStakeRange = (data) => {
const start = data.gl1Qdzh || ''
const end = data.gl1Zdzh || ''
if (start && end) return `${start}-${end}`
if (start) return start
if (end) return end
return '-'
}
// API- APIdetailAddress'-'
const formatStakeRangeFromData = data => {
const formatStakeRangeFromData = (data) => {
// APIdetailAddress'-'
// API
return '-';
};
return '-'
}
//
const previewVisible = ref(false);
const previewImageUrl = ref('');
const previewVisible = ref(false)
const previewImageUrl = ref('')
const previewImage = url => {
previewImageUrl.value = url;
previewVisible.value = true;
};
const previewImage = (url) => {
previewImageUrl.value = url
previewVisible.value = true
}
const closePreview = () => {
previewVisible.value = false;
previewImageUrl.value = '';
};
previewVisible.value = false
previewImageUrl.value = ''
}
//
const handleClose = () => {
emit('update:visible', false);
emit('close');
};
emit('update:visible', false)
emit('close')
}
// eventData
watch(
() => props.visible,
newVal => {
(newVal) => {
if (newVal) {
fetchEventDetail();
fetchEventDetail()
}
}
);
},
)
</script>
<style lang="scss" scoped>

View File

@ -62,12 +62,7 @@
</div>
<!-- 图片预览组件 -->
<el-image-viewer
v-if="previewVisible"
:url-list="hazardData.photos"
:initial-index="previewIndex"
@close="previewVisible = false"
/>
<el-image-viewer v-if="previewVisible" :url-list="hazardData.photos" :initial-index="previewIndex" @close="previewVisible = false" />
<!-- 风险描述 -->
<div class="info-block">
@ -97,13 +92,13 @@
<span class="responsibility-phone">{{ hazardData.trafficDept.phone }}</span>
<span class="responsibility-frequency">{{ hazardData.trafficDept.frequency }}</span>
<div class="action-btns">
<div class="action-btn" @click="handleVideo(hazardData.trafficDept)" title="视频">
<div class="action-btn" @click="handleVideo(hazardData.trafficDept, '交通主管部门责任人')" title="视频">
<el-icon><VideoCamera /></el-icon>
</div>
<div class="action-btn" @click="handleVoice(hazardData.trafficDept)" title="语音">
<div class="action-btn" @click="handleVoice(hazardData.trafficDept, '交通主管部门责任人')" title="语音">
<el-icon><Microphone /></el-icon>
</div>
<div class="action-btn" @click="handleCall(hazardData.trafficDept)" title="电话">
<div class="action-btn" @click="handleCall(hazardData.trafficDept, '交通主管部门责任人')" title="电话">
<el-icon><Phone /></el-icon>
</div>
</div>
@ -115,13 +110,13 @@
<span class="responsibility-phone">{{ hazardData.roadOrg.phone }}</span>
<span class="responsibility-frequency">{{ hazardData.roadOrg.frequency }}</span>
<div class="action-btns">
<div class="action-btn" @click="handleVideo(hazardData.roadOrg)" title="视频">
<div class="action-btn" @click="handleVideo(hazardData.roadOrg, '公路机构责任人')" title="视频">
<el-icon><VideoCamera /></el-icon>
</div>
<div class="action-btn" @click="handleVoice(hazardData.roadOrg)" title="语音">
<div class="action-btn" @click="handleVoice(hazardData.roadOrg, '公路机构责任人')" title="语音">
<el-icon><Microphone /></el-icon>
</div>
<div class="action-btn" @click="handleCall(hazardData.roadOrg)" title="电话">
<div class="action-btn" @click="handleCall(hazardData.roadOrg, '公路机构责任人')" title="电话">
<el-icon><Phone /></el-icon>
</div>
</div>
@ -133,13 +128,13 @@
<span class="responsibility-phone">{{ hazardData.maintenance.phone }}</span>
<span class="responsibility-frequency">{{ hazardData.maintenance.frequency }}</span>
<div class="action-btns">
<div class="action-btn" @click="handleVideo(hazardData.maintenance)" title="视频">
<div class="action-btn" @click="handleVideo(hazardData.maintenance, '养护站责任人')" title="视频">
<el-icon><VideoCamera /></el-icon>
</div>
<div class="action-btn" @click="handleVoice(hazardData.maintenance)" title="语音">
<div class="action-btn" @click="handleVoice(hazardData.maintenance, '养护站责任人')" title="语音">
<el-icon><Microphone /></el-icon>
</div>
<div class="action-btn" @click="handleCall(hazardData.maintenance)" title="电话">
<div class="action-btn" @click="handleCall(hazardData.maintenance, '养护站责任人')" title="电话">
<el-icon><Phone /></el-icon>
</div>
</div>
@ -156,13 +151,13 @@
<span class="responsibility-name" style="width: 100px">{{ hazardData.roadKeeper.phone }}</span>
<span class="responsibility-frequency">{{ hazardData.roadKeeper.frequency }}</span>
<div class="action-btns">
<div class="action-btn" @click="handleVideo(hazardData.roadKeeper)" title="视频">
<div class="action-btn" @click="handleVideo(hazardData.roadKeeper, '护路员')" title="视频">
<el-icon><VideoCamera /></el-icon>
</div>
<div class="action-btn" @click="handleVoice(hazardData.roadKeeper)" title="语音">
<div class="action-btn" @click="handleVoice(hazardData.roadKeeper, '护路员')" title="语音">
<el-icon><Microphone /></el-icon>
</div>
<div class="action-btn" @click="handleCall(hazardData.roadKeeper)" title="电话">
<div class="action-btn" @click="handleCall(hazardData.roadKeeper, '护路员')" title="电话">
<el-icon><Phone /></el-icon>
</div>
</div>
@ -332,11 +327,13 @@ const previewPhoto = (index) => {
}
//
const handleVideo = (item) => {
const handleVideo = (item, type) => {
console.log('视频通话:', item)
let videoParams = {
...item,
id: hazardData.value.id,
type: type,
role: getRolefn(type),
}
openVideoConference(videoParams)
// emit('video', {
@ -346,11 +343,13 @@ const handleVideo = (item) => {
}
//
const handleVoice = (item) => {
const handleVoice = (item, type) => {
console.log('语音通话:', item)
let voiceParams = {
...item,
id: hazardData.value.id,
type: type,
role: getRolefn(type),
}
openVoiceConference(voiceParams)
// emit('voice', {
@ -360,14 +359,28 @@ const handleVoice = (item) => {
}
//
const handleCall = (item) => {
const handleCall = (item, type) => {
console.log('拨打电话:', item)
emit('call', {
...item,
id: hazardData.value.id,
type: type,
role: getRolefn(type),
})
}
const getRolefn = (item) => {
if (item == '交通主管部门责任人') {
return '责任人'
} else if (item == '公路机构责任人') {
return '责任人'
} else if (item == '养护站责任人') {
return '站长'
} else if (item == '护路员') {
return '一般人员'
} else {
return '-'
}
}
// visible
watch(
() => props.visible,

View File

@ -26,12 +26,7 @@
clearable
@change="handleFilterChange"
>
<el-option
v-for="item in districtOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<el-option v-for="item in regionOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
@ -40,56 +35,32 @@
</template>
<script setup>
import { ref, watch } from 'vue';
import BaseDialog from '../component/baseDialog.vue';
import { request } from '@/utils/request';
import { ref, watch, inject } from 'vue'
import BaseDialog from '../component/baseDialog.vue'
import { request } from '@/utils/request'
import { formatDateTime, regionOptions } from '../component/index'
//
const getdateRange = inject('getdateRange', ref([]))
const props = defineProps({
visible: {
type: Boolean,
default: false,
},
});
dispatchDateRange: {
type: Array,
default: () => [],
},
})
const emit = defineEmits(['update:visible', 'close']);
const emit = defineEmits(['update:visible', 'close'])
//
const filterForm = ref({
district: '',
});
//
const districtOptions = ref([
{ label: '万州区', value: 'wanzhou' },
{ label: '黔江区', value: 'qianjiang' },
{ label: '涪陵区', value: 'fuling' },
{ label: '渝中区', value: 'yuzhong' },
{ label: '大渡口区', value: 'dadukou' },
{ label: '江北区', value: 'jiangbei' },
{ label: '沙坪坝区', value: 'shapingba' },
{ label: '九龙坡区', value: 'jiulongpo' },
{ label: '南岸区', value: 'nanan' },
{ label: '北碚区', value: 'beibei' },
{ label: '渝北区', value: 'yubei' },
{ label: '巴南区', value: 'banan' },
{ label: '长寿区', value: 'changshou' },
{ label: '江津区', value: 'jiangjin' },
{ label: '合川区', value: 'hechuan' },
{ label: '永川区', value: 'yongchuan' },
{ label: '南川区', value: 'nanchuan' },
{ label: '綦江区', value: 'qijiang' },
{ label: '大足区', value: 'dazu' },
{ label: '璧山区', value: 'bishan' },
{ label: '铜梁区', value: 'tongliang' },
{ label: '潼南区', value: 'tongnan' },
{ label: '荣昌区', value: 'rongchang' },
{ label: '开州区', value: 'kaizhou' },
{ label: '梁平区', value: 'liangping' },
{ label: '武隆区', value: 'wulong' },
]);
})
//
const tableHeight = ref(300);
const tableHeight = ref(300)
// -
const tableColumns = ref([
@ -98,80 +69,97 @@ const tableColumns = ref([
{ prop: 'inspectTime', label: '抽查时间' },
{ prop: 'inspectedPerson', label: '被抽查人' },
{ prop: 'contactPhone', label: '联系电话' },
]);
])
//
const tableData = ref([]);
const tableData = ref([])
//
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0);
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(0)
//
const handleClose = () => {
emit('update:visible', false);
emit('close');
};
emit('update:visible', false)
emit('close')
}
//
const handleSizeChange = val => {
pageSize.value = val;
fetchData();
};
const handleSizeChange = (val) => {
pageSize.value = val
fetchData()
}
const handleCurrentChange = val => {
currentPage.value = val;
fetchData();
};
const handleCurrentChange = (val) => {
currentPage.value = val
fetchData()
}
//
const handleFilterChange = () => {
currentPage.value = 1;
fetchData();
};
currentPage.value = 1
fetchData()
}
//
const fetchData = async () => {
try {
const res = await request({
url: '/snow-ops-platform/inspection/personnel-list',
url: '/snow-ops-platform/weather-warning/spot-check',
method: 'GET',
params: {
pageNum: currentPage.value,
pageSize: pageSize.value,
districtCode: filterForm.value.district,
offset: (currentPage.value - 1) * pageSize.value,
limit: pageSize.value,
start: formatDateTime(props.dispatchDateRange?.[0]),
end: formatDateTime(props.dispatchDateRange?.[1]),
countyId: filterForm.value.district,
},
});
})
console.log(res, '抽查人次数据')
if (res.total > 0 && res.data) {
const data = res.data
tableData.value = data.map((item, index) => {
// command JSON
let commandData = {}
try {
if (item.command) {
commandData = JSON.parse(item.command)
}
} catch (e) {
console.error('解析 command 字段失败:', e)
}
const district = regionOptions.value.find((option) => option.value === item.countyId)?.label || '-'
if (res.code === '00000' && res.data) {
const data = res.data;
tableData.value = data.records.map((item, index) => {
return {
id: currentPage.value * pageSize.value - (pageSize.value - index - 1),
district: item.districtName || '-',
inspectTime: item.inspectTime || '-',
inspectedPerson: item.inspectedPerson || '-',
contactPhone: item.contactPhone || '-',
};
});
total.value = data.total;
district: district,
inspectTime: formatDateTime(item.createdAt) || '-',
inspectedPerson: commandData.userName || '-',
contactPhone: commandData.userPhone || '-',
}
})
total.value = data.total
} else {
tableData.value = []
total.value = 0
}
} catch (error) {
console.error('获取抽查人次数据失败:', error);
console.error('获取抽查人次数据失败:', error)
}
}
};
// visible
watch(
() => props.visible,
newVal => {
(newVal) => {
if (newVal) {
currentPage.value = 1;
fetchData();
currentPage.value = 1
fetchData()
}
}
);
},
)
</script>
<style lang="scss" scoped>

View File

@ -65,18 +65,13 @@
</div>
<!-- 照片 -->
<div class="section" v-if="photoList.length > 0">
<div class="section">
<div class="section-title">
<span class="title-icon"></span>
照片
</div>
<div class="photo-list">
<div
v-for="(photo, index) in photoList"
:key="index"
class="photo-item"
@click="previewImage(photo)"
>
<div v-for="(photo, index) in photoList" :key="index" class="photo-item" @click="previewImage(photo)">
<img :src="photo" alt="照片" />
</div>
</div>
@ -117,10 +112,7 @@
</div>
<div class="detail-row">
<span class="detail-label">是否发现问题</span>
<span
class="detail-value"
:class="record.hasProblem ? 'status-yes' : 'status-no'"
>
<span class="detail-value" :class="record.hasProblem ? 'status-yes' : 'status-no'">
{{ record.hasProblem ? '是' : '否' }}
</span>
</div>
@ -145,10 +137,11 @@
</template>
<script setup>
import { ref, watch } from 'vue';
import { Close } from '@element-plus/icons-vue';
import baseDialog from '../component/baseDialog.vue';
import { request } from '@/utils/request';
import { ref, watch } from 'vue'
import { Close } from '@element-plus/icons-vue'
import baseDialog from '../component/baseDialog.vue'
import { request } from '@/utils/request'
import { getImageUrlList } from '../component/index.js'
const props = defineProps({
visible: {
@ -163,9 +156,9 @@ const props = defineProps({
type: Object,
default: () => ({}),
},
});
})
const emit = defineEmits(['update:visible', 'close']);
const emit = defineEmits(['update:visible', 'close'])
//
const basicInfo = ref({
@ -176,18 +169,18 @@ const basicInfo = ref({
location: '',
riskDesc: '',
discoverTime: '',
});
})
watch(
() => props.item,
newVal => {
(newVal) => {
if (newVal) {
//
getAffectedObjectTypeId(props.item);
getAffectedObjectTypeId(props.item)
}
}
);
},
)
//
const photoList = ref([]);
const photoList = ref([])
//
const dynamicRecords = ref([
@ -207,82 +200,79 @@ const dynamicRecords = ref([
// hasProblem: false,
// image: null,
// },
]);
])
//
const getStatusClass = status => {
if (status === '未回应') return 'status-unresponse';
if (status === '已回应') return 'status-response';
return '';
};
const getStatusClass = (status) => {
if (status === '未回应') return 'status-unresponse'
if (status === '已回应') return 'status-response'
return ''
}
//
const previewVisible = ref(false);
const previewImageUrl = ref('');
const previewVisible = ref(false)
const previewImageUrl = ref('')
const previewImage = url => {
previewImageUrl.value = url;
previewVisible.value = true;
};
const previewImage = (url) => {
previewImageUrl.value = url
previewVisible.value = true
}
const closePreview = () => {
previewVisible.value = false;
previewImageUrl.value = '';
};
previewVisible.value = false
previewImageUrl.value = ''
}
//
const handleClose = () => {
emit('update:visible', false);
emit('close');
};
const leveltext = level => {
if (level.includes('一') || level.includes('1')) return '一类';
if (level.includes('二') || level.includes('2')) return '二类';
if (level.includes('三') || level.includes('3')) return '三类';
if (level.includes('四') || level.includes('4')) return '四类';
if (level.includes('五') || level.includes('5')) return '五类';
if (level.includes('9')) return '未评定';
return '未评定';
};
emit('update:visible', false)
emit('close')
}
const leveltext = (level) => {
if (level.includes('一') || level.includes('1')) return '一类'
if (level.includes('二') || level.includes('2')) return '二类'
if (level.includes('三') || level.includes('3')) return '三类'
if (level.includes('四') || level.includes('4')) return '四类'
if (level.includes('五') || level.includes('5')) return '五类'
if (level.includes('9')) return '未评定'
return '未评定'
}
// base-dialog
//
const getAffectedObjectTypeId = data => {
let pointType = props.item.pointType;
const getAffectedObjectTypeId = (data) => {
let pointType = props.item.pointType
basicInfo.value = {}
photoList.value = []
dynamicRecords.value = []
if (!data) {
basicInfo.value = {};
photoList.value = [];
dynamicRecords.value = [];
return;
return
}
if (pointType === '桥梁') {
// -
basicInfo.value = {
district: data.GL1_QXMC || '-', //
level: leveltext(data.GL1_JSZKPJDJ) || '未评定', //
levelClass:
data.GL1_JSZKPJDJ === '一类' || data.GL1_JSZKPJDJ === '二类'
? 'level-normal'
: 'level-serious', //
levelClass: data.GL1_JSZKPJDJ === '一类' || data.GL1_JSZKPJDJ === '二类' ? 'level-normal' : 'level-serious', //
roadCode: data.GL1_LXBH || '-', // 线
location: data.GL1_QLMC || '-', //
riskDesc: data.GL1_DQBH || '-', //
discoverTime: data.GL1_JSZKPDRQ || '-', //
};
}
// - 使
const photos = [];
const photos = []
if (data.GL1_QLZMZFJ) {
photos.push(data.GL1_QLZMZFJ); //
photos.push(data.GL1_QLZMZFJ) //
}
if (data.GL1_QLLMZFJ) {
photos.push(data.GL1_QLLMZFJ); //
photos.push(data.GL1_QLLMZFJ) //
}
if (data.GL1_QLDXZFJ) {
photos.push(data.GL1_QLDXZFJ); //
photos.push(data.GL1_QLDXZFJ) //
}
if (data.GL1_QLZP) {
photos.push(data.GL1_QLZP); //
photos.push(data.GL1_QLZP) //
}
photoList.value = photos.length > 0 ? photos : [];
photoList.value = photos.length > 0 ? photos : []
// - 使
// dynamicRecords.value = [
@ -300,22 +290,19 @@ const getAffectedObjectTypeId = data => {
basicInfo.value = {
district: data.GL1_QXMC || '-', //
level: leveltext(data.GL1_FXDJ) || '未评定', //
levelClass:
data.GL1_FXDJ?.includes('一级') || data.GL1_FXDJ?.includes('二级')
? 'level-normal'
: 'level-serious', //
levelClass: data.GL1_FXDJ?.includes('一级') || data.GL1_FXDJ?.includes('二级') ? 'level-normal' : 'level-serious', //
roadCode: data.GL1_LXBM || '-', // 线
location: data.GL1_BPGC || '-', //
riskDesc: data.GL1_JCSSSZ || '-', //
discoverTime: data.GL1_ZRRXM || '-', //
};
}
// -
const photos = [];
const photos = []
if (data.GL1_ZRLXFS) {
photos.push(data.GL1_ZRLXFS); // URL
photos.push(data.GL1_ZRLXFS) // URL
}
photoList.value = photos.length > 0 ? photos : [];
photoList.value = photos.length > 0 ? photos : []
// -
// dynamicRecords.value = [
@ -333,29 +320,28 @@ const getAffectedObjectTypeId = data => {
basicInfo.value = {
district: data.GL1_QXMC || '-', //
level: leveltext(data.GL1_PDDJ) || '未评定', //
levelClass:
data.GL1_PDDJ === '一级' || data.GL1_PDDJ === '二级' ? 'level-normal' : 'level-serious', //
levelClass: data.GL1_PDDJ === '一级' || data.GL1_PDDJ === '二级' ? 'level-normal' : 'level-serious', //
roadCode: data.GL1_LXBH || '-', // 线
location: data.GL1_SDMC || '-', //
riskDesc: data.GL1_BHMS || '-', //
discoverTime: data.GL1_PDRQ || '-', //
};
}
// - 使
const photos = [];
const photos = []
if (data.GL1_SDJDKFJS) {
photos.push(data.GL1_SDJDKFJS); //
photos.push(data.GL1_SDJDKFJS) //
}
if (data.GL1_SDCDKFJS) {
photos.push(data.GL1_SDCDKFJS); //
photos.push(data.GL1_SDCDKFJS) //
}
if (data.GL1_SDDXZP) {
photos.push(data.GL1_SDDXZP); //
photos.push(data.GL1_SDDXZP) //
}
if (data.GL1_TP) {
photos.push(data.GL1_TP); //
photos.push(data.GL1_TP) //
}
photoList.value = photos.length > 0 ? photos : [];
photoList.value = photos.length > 0 ? photos : []
// -
// dynamicRecords.value = [
@ -371,18 +357,22 @@ const getAffectedObjectTypeId = data => {
} else if (pointType === '路段') {
// -
basicInfo.value = {
district: data.rawData.GL1_QXMC || '-', //
district: data.rawData.COUNTY_NAME || '-', //
level: data.rawData.GL1_FXDJ || '未评定', //
levelClass: data.rawData.GL1_FXDJ, //
roadCode: data.rawData.GL1_LXBH || '-', // 线
location: data.pointLocation, //
riskDesc: data.rawData.GL1_FXMS || '-', //
discoverTime: data.rawData.GL1_SBSJ || '-', //
};
}
const photos = []
// -
photoList.value = [];
if (getImageUrlList(data.item?.RISK_POINT?.GL1_TP).length > 0) {
photos.push(...getImageUrlList(data.item?.RISK_POINT?.GL1_TP || '')) //
}
photoList.value = photos.length > 0 ? photos : []
console.log('照片列表:', photos)
// -
// dynamicRecords.value = [
// {
@ -395,58 +385,58 @@ const getAffectedObjectTypeId = data => {
// },
// ];
}
};
}
//
const getAffectedObjectDetail = async () => {
try {
let id = '';
let apiUrl = '';
const pointType = props.item?.pointType;
let id = ''
let apiUrl = ''
const pointType = props.item?.pointType
if (pointType === '桥梁') {
id = props.item?.rawData?.GL1_ZJ || '';
apiUrl = `/snow-ops-platform/weather-warning/affected-object/bridge/${id}`;
id = props.item?.rawData?.GL1_ZJ || ''
apiUrl = `/snow-ops-platform/weather-warning/affected-object/bridge/${id}`
} else if (pointType === '边坡') {
id = props.item?.rawData?.GL1_ID || '';
apiUrl = `/snow-ops-platform/weather-warning/affected-object/slope/${id}`;
id = props.item?.rawData?.GL1_ID || ''
apiUrl = `/snow-ops-platform/weather-warning/affected-object/slope/${id}`
} else if (pointType === '隧道') {
id = props.item?.rawData?.GL1_ZJ || '';
apiUrl = `/snow-ops-platform/weather-warning/affected-object/tunnel/${id}`;
id = props.item?.rawData?.GL1_ZJ || ''
apiUrl = `/snow-ops-platform/weather-warning/affected-object/tunnel/${id}`
} else if (pointType === '路段') {
id = props.item?.rawData?.GL1ZJ || '';
apiUrl = `/snow-ops-platform/weather-warning/affected-object/road-section/${id}`;
id = props.item?.rawData?.GL1ZJ || ''
apiUrl = `/snow-ops-platform/weather-warning/affected-object/road-section/${id}`
}
if (!id || !apiUrl) {
console.warn('未找到影响点ID或API地址');
return;
console.warn('未找到影响点ID或API地址')
return
}
const res = await request({
url: apiUrl,
method: 'GET',
});
})
console.log('影响点详情数据:', res);
console.log('影响点详情数据:', res)
if (res.code === '00000') {
getAffectedObjectTypeId(res.data || {});
getAffectedObjectTypeId(res.data || {})
}
} catch (error) {
console.error('获取影响点详情数据失败:', error);
console.error('获取影响点详情数据失败:', error)
}
}
};
// visible
watch(
() => props.visible,
newVal => {
(newVal) => {
if (newVal) {
//
// getAffectedObjectDetail();
}
}
);
},
)
</script>
<style lang="scss" scoped>

View File

@ -209,7 +209,6 @@ import Icon3 from '../../../assets/xiangying/未选中3@2x.png'
import Icon4 from '../../../assets/xiangying/未选中4@2x.png'
import { formatDateTime } from '../component/index.js'
onMounted(() => {})
const props = defineProps({
visible: {
type: Boolean,
@ -332,7 +331,7 @@ const impactData = ref([
{ name: '影响桥梁', count: 0, icon: Icon0, type: '桥梁' },
{ name: '影响隧道', count: 0, icon: Icon2, type: '隧道' },
{ name: '影响边坡', count: 0, icon: Icon1, type: '边坡' },
{ name: '影响项目', count: 0, icon: Icon3, type: '驻地' },
{ name: '影响驻地', count: 0, icon: Icon3, type: '驻地' },
])
//
const loadBarChartData = async () => {
@ -367,6 +366,9 @@ const loadBarChartData = async () => {
// name
const convertedData = data.map((item) => {
if (item.extension == '项目') {
item.extension = '驻地'
}
const name = nameMap[item.name] || item.name
return { ...item, name }
})
@ -396,11 +398,6 @@ const getColumnsByType = (type) => {
边坡: roadColumns,
驻地: projectColumns,
}
// { name: '', count: 0, icon: Icon4, type: '' },
// { name: '', count: 0, icon: Icon0, type: '' },
// { name: '', count: 0, icon: Icon2, type: '' },
// { name: '', count: 0, icon: Icon1, type: '' },
// { name: '', count: 0, icon: Icon3, type: '' },
return typeMap[type] || bridgeColumns
}
@ -468,8 +465,8 @@ const handleSearch = () => {
//
const handleDetail = (item) => {
emit('detail', item)
emit('itemClick', item)
emit('detail', { ...item, warningId: props.handleImpactItem.warningId })
emit('itemClick', { ...item, warningId: props.handleImpactItem.warningId })
}
//
@ -489,7 +486,7 @@ const handleFilterChange = () => {
}
//
const getTimeParams = () => {
const getTimeParams = (type) => {
console.log('原始时间范围:', props.handleImpactItem)
let countyId = ''
console.log('区域:', filterForm.value)
@ -498,10 +495,7 @@ const getTimeParams = () => {
countyId = item.value || ''
}
})
return {
// start: `${year}-${month}-01 00:00:00`,
// end: `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`,
let obj = {
start: formatDateTime(props.getdateRange[0] ? props.getdateRange[0] : props.handleImpactItem.dateRange?.[0] || ''),
end: formatDateTime(props.getdateRange[1] ? props.getdateRange[1] : props.handleImpactItem.dateRange?.[1] || ''),
limit: pageSize.value,
@ -510,6 +504,15 @@ const getTimeParams = () => {
riskLevel: filterForm.value.pointLevel || '',
roadTypes: filterForm.value.roadType || '',
}
if (type === '路段' || type === '驻地') {
obj.warningId = props.handleImpactItem.warningId || ''
}
return obj
// {
// // start: `${year}-${month}-01 00:00:00`,
// // end: `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`,
// }
}
//
const processUnifiedData = (item, type) => {
@ -757,7 +760,7 @@ const processDataByType = (item, type) => {
const fetchData = async () => {
console.log('获取第', currentPage.value, '页数据, 类型:', cardType.value)
try {
const timeParams = getTimeParams()
const timeParams = getTimeParams(cardTypeVal.value)
// cardType API URL
const apiUrl = getApiUrlByType(cardTypeVal.value)
@ -816,26 +819,30 @@ watch(
total.value = 0
tableData.value = []
cardType.value = '0'
loadBarChartData()
console.log('影响点情况=========newVal:', newVal)
if (newVal) {
filterForm.value.region = newVal.countyName
currentPage.value = 1
fetchData()
} else {
filterForm.value = {
district: '',
type: '',
roadConditionType: '',
roadType: '',
pointType: '',
}
cardType.value = '0'
}
fetchData()
loadBarChartData()
},
)
// visible
watch(
() => props.visible,
(newVal) => {
tableColumns.value = bridgeColumns
// if (newVal) {
// filterForm.value = {
// pointType: '',
@ -844,9 +851,9 @@ watch(
// }
// tableData.value = []
// cardType.value = '0'
loadBarChartData()
// loadBarChartData()
// currentPage.value = 1
// fetchData()
//
// }
},
)

View File

@ -84,13 +84,11 @@ const props = defineProps({
const emit = defineEmits(['update:visible', 'close'])
//
const nationalRoadMileage = ref(345)
const ruralRoadMileage = ref(4333)
//
const mileageData = ref([
{ name: '国省道', value: 345, icon: IconNational, type: 'national' },
{ name: '农村公路', value: 4333, icon: IconRuralRoad, type: 'rural' },
{ name: '国省道', value: 0, icon: IconNational, type: 'national' },
{ name: '农村公路', value: 0, icon: IconRuralRoad, type: 'rural' },
])
//
@ -183,7 +181,36 @@ const fetchData = async () => {
console.error('获取巡查里程列表数据失败:', error)
}
}
//
const getInspectionStats = async () => {
try {
let params = {
start: '',
end: '',
}
if (props.getdateRange && props.getdateRange.length === 2) {
params.start = formatDateTime(props.getdateRange[0])
params.end = formatDateTime(props.getdateRange[1])
}
const res = await request({
url: '/snow-ops-platform/yhWgxc/weather-warning/inspection-stats',
method: 'GET',
params: params,
})
console.log('巡查统计数据:', res)
if (res.code == '00000' && res.data) {
const data = res.data
//
mileageData.value[0].value = data.nationalProvincialRoadMileage || '0'
mileageData.value[1].value = data.ruralRoadMileage || '0'
} else {
mileageData.value[0].value = '0'
mileageData.value[1].value = '0'
}
} catch (error) {
console.error('获取巡查统计数据失败:', error)
}
}
// visible
watch(
() => props.visible,
@ -193,6 +220,7 @@ watch(
currentPage.value = 1
// fetchStatsData()
fetchData()
getInspectionStats()
},
)
</script>

View File

@ -24,7 +24,7 @@
@click="handleClick(item.type)"
class="stat-card"
:style="{
backgroundImage: `url(${cardType === item.type ? selectedIcon : unselectedIcon})`,
backgroundImage: `url(${cardType == item.type ? selectedIcon : unselectedIcon})`,
backgroundSize: '100% 100%',
backgroundPosition: 'center',
}"
@ -43,13 +43,27 @@
<div class="filter-row">
<div class="filter-item">
<span class="filter-label">影响点等级</span>
<el-select :teleported="false" v-model="filterForm.pointLevel" placeholder="影响点等级" class="filter-select">
<el-select
:teleported="false"
v-model="filterForm.pointLevel"
placeholder="影响点等级"
clearable
class="filter-select"
@change="handleFilterChange"
>
<el-option v-for="option in pointLevelOptions" :key="option.value" :label="option.label" :value="option.value" />
</el-select>
</div>
<div class="filter-item">
<span class="filter-label">是否回应</span>
<el-select :teleported="false" v-model="filterForm.isResponded" placeholder="是否回应" class="filter-select">
<el-select
:teleported="false"
v-model="filterForm.isResponded"
placeholder="是否回应"
clearable
class="filter-select"
@change="handleFilterChange"
>
<el-option v-for="option in isRespondedOptions" :key="option.value" :label="option.label" :value="option.value" />
</el-select>
</div>
@ -67,7 +81,7 @@
<!-- 交通主管部门负责人列插槽 -->
<template #trafficDept="{ row }">
<div class="person-info">
<div class="person-name center">
<div class="person-name center" v-if="row.trafficDept.name != '-'">
<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>
@ -78,7 +92,7 @@
<!-- 公路机构责任人列插槽 -->
<template #roadOrg="{ row }">
<div class="person-info">
<div class="person-name center">
<div class="person-name center" v-if="row.roadOrg.name != '-'">
<span style="margin-right: 5px">{{ row.roadOrg.name }}</span>
<img :src="row.roadOrg.img" class="response-icon" alt="" />
</div>
@ -89,7 +103,7 @@
<!-- 养护站负责人列插槽 -->
<template #maintenance="{ row }">
<div class="person-info">
<div class="person-name center">
<div class="person-name center" v-if="row.maintenance.name != '-'">
<span style="margin-right: 5px">{{ row.maintenance.name }}</span>
<img :src="row.maintenance.img" class="response-icon" alt="" />
</div>
@ -100,7 +114,7 @@
<!-- 护路员列插槽 -->
<template #roadKeeper="{ row }">
<div class="person-info">
<div class="person-name center">
<div class="person-name center" v-if="row.roadKeeper.name != '-'">
<span style="margin-right: 5px">{{ row.roadKeeper.name }}</span>
<img :src="row.roadKeeper.img" class="response-icon" alt="" />
</div>
@ -108,6 +122,17 @@
</div>
</template>
<!-- 路长列插槽 -->
<template #generalStaff="{ row }">
<div class="person-info">
<div class="person-name center" v-if="row.generalStaff.name != '-'">
<span style="margin-right: 5px">{{ row.generalStaff.name }}</span>
<img :src="row.generalStaff.img" class="response-icon" alt="" />
</div>
<span class="person-phone">{{ row.generalStaff.phone }}</span>
</div>
</template>
<!-- 回应状态列插槽 -->
<!-- <template #responseStatusData="{ row }">
<span class="response-status" :class="row.responseClass">{{
@ -286,7 +311,9 @@ const fetchData = async () => {
end: '',
offset: (currentPage.value - 1) * pageSize.value,
limit: pageSize.value,
warningId: props.responseStatusData.warningId,
warningId: props.responseStatusData.warningId || '',
riskLevel: filterForm.value.pointLevel || '',
isResponded: filterForm.value.isResponded,
}
if (props.dispatchDateRange && props.dispatchDateRange.length > 0) {
params.start = formatDateTime(props.dispatchDateRange[0]) || ''
@ -306,6 +333,7 @@ const fetchData = async () => {
const roadKeeperEvent = item.events?.find((e) => e.noticeRoles?.includes('护路员')) || {}
const roadOrgEvent = item.events?.find((e) => e.noticeRoles?.includes('公路机构')) || {}
const maintenanceEvent = item.events?.find((e) => e.noticeRoles?.includes('养护站')) || {}
const generalStaffEvent = item.events?.find((e) => e.noticeRoles?.includes('路长')) || {}
//
const lastNoticeTime = item.events?.[0]?.lastNoticeTime || ''
@ -343,8 +371,10 @@ const fetchData = async () => {
isResponded: roadKeeperEvent.replyState === 'read',
},
generalStaff: {
name: item.GL1_QLGCS || '-',
phone: item.GL1_QLGCSDH || '-',
name: generalStaffEvent.noticeName || '-',
phone: generalStaffEvent.noticePhone || '-',
img: generalStaffEvent.replyState === 'read' ? respondedIcon : notRespondedIcon,
isResponded: generalStaffEvent.replyState === 'read',
},
urgeTime: {
@ -353,7 +383,10 @@ const fetchData = async () => {
},
}
})
total.value = res.data.length
total.value = res.total || 0
}else{
tableData.value = []
total.value = 0
}
} catch (error) {
console.error('获取通知实体数据失败:', error)
@ -386,12 +419,38 @@ const handleSearch = () => {
fetchData()
loadBarChartData()
}
const handleFilterChange = () => {
console.log(filterForm.value)
filterForm.value.pointLevel = filterForm.value.pointLevel || ''
filterForm.value.isResponded = filterForm.value.isResponded
currentPage.value = 1
fetchData()
}
// visible
watch(
() => props.visible,
(newVal) => {
filterForm.value = {
pointType: '',
pointLevel: '',
region: '',
}
tableData.value = []
cardType.value = '路段'
currentPage.value = 1
if (newVal) {
fetchData()
loadBarChartData()
}
},
)
watch(
() => cardType.value,
(newVal) => {
if (newVal) {
tableData.value = []
currentPage.value = 1
fetchData()
loadBarChartData()
@ -404,7 +463,6 @@ watch(
() => props.dispatchDateRange,
() => {
if (props.visible) {
currentPage.value = 1
fetchData()
}
},
@ -413,7 +471,7 @@ watch(
onMounted(() => {
//
loadBarChartData()
// loadBarChartData()
})
</script>

View File

@ -248,10 +248,16 @@ const getLevelClass = (riskLevel) => {
watch(
() => props.visible,
(newVal) => {
if (newVal) {
currentPage.value = 1
filterForm.value.warningLevel = ''
filterForm.value.region = ''
filterForm.value.isEnded = ''
filterForm.value.isResponded = ''
filterForm.value.district = ''
filterForm.value.countyId = ''
tableData.value = []
total.value = 0
fetchData()
}
},
)
@ -261,6 +267,14 @@ watch(
() => {
if (props.visible) {
currentPage.value = 1
filterForm.value.warningLevel = ''
filterForm.value.region = ''
filterForm.value.isEnded = ''
filterForm.value.isResponded = ''
filterForm.value.district = ''
filterForm.value.countyId = ''
tableData.value = []
total.value = 0
fetchData()
}
},

View File

@ -85,7 +85,7 @@ const props = defineProps({
},
})
const emit = defineEmits(['update:visible', 'close', 'impactClick'])
const emit = defineEmits(['update:visible', 'close', 'impactClick', 'impactClickItem'])
//
const dateRange = ref([])
@ -224,6 +224,7 @@ const fetchWarningData = async () => {
endTime: item.endTime || '-',
impactCount: item.affectedCount || 0,
warningId: item.warningId || '',
...item,
}))
} else {
tableData.value = []

View File

@ -17,10 +17,9 @@
:dataList="centerCardDataList"
@close="closeCenterCard"
@itemClick="handleCenterCardItemClick"
@click="handleCenterCardClick"
/>
<hazardPointSituationDialog v-model:visible="hazardPointSituationDialogVisible" :data="{}" @close="closeHazardPointSituationDialog" />
<hazardPointSituationDialog :data="{}" />
</div>
</template>
@ -1738,15 +1737,14 @@ const handleHazardItemClick = async (item, flag) => {
const riskLevel = riskLevelMap[item.label] || ''
await getRiskPointData(riskLevel, item, flag)
}
const flag = ref(true)
// dateRange
watch(
() => props.dateRange,
async (newVal, oldVal) => {
console.log('dateRange 变化:', newVal, oldVal)
//
clearProjectMarkers() //
await clearProjectMarkers() //
await getAffectedCountyData()
},
{ deep: true },
@ -1767,7 +1765,7 @@ watch(
//
onMounted(() => {
//
getAffectedCountyData()
// getAffectedCountyData()
// Leaflet
if (typeof window.L === 'undefined') {
@ -2078,7 +2076,7 @@ defineExpose({
// }
.center-info-card {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
// box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
cursor: pointer;
transition: all 0.3s;

View File

@ -172,36 +172,23 @@ export const formatDateTime = (date) => {
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}
// 记录用户操作日志(使用 fetch keepalive 确保页面切换后请求仍能完成)
export const logUserOperation = (type, command) => {
try {
// 记录用户操作日志
export const logUserOperation = async (type, command) => {
const data = { type, command }
// 使用 fetch 的 keepalive 选项确保页面卸载后请求仍能完成
fetch('/snow-ops-platform/weather-warning/users/logs', {
const res = await request({
url: '/snow-ops-platform/weather-warning/users/logs',
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
keepalive: true, // 关键:确保页面切换后请求仍能完成
data: data,
})
.then((response) => {
console.log('日志请求完成:', response.status)
})
.catch((error) => {
console.error('日志请求失败:', error)
})
console.log('日志已触发发送:', data)
return true
} catch (error) {
console.error('记录操作日志失败:', error)
return false
console.log('日志请求完成:', res)
if (res.code === '00000') {
ElMessage.success('操作日志记录成功')
} else {
ElMessage.error(res.message || '操作日志记录失败')
}
}
// 打开视频会议
export const openVideoConference = async (item) => {
console.log('打开视频会议:', item)
@ -229,6 +216,8 @@ export const openVideoConference = async (item) => {
userName: item.name,
userPhone: item.phone,
id: item.id,
type: item.type,
role: item.role,
userId: userId,
text: '打开视频会议',
}
@ -270,6 +259,8 @@ export const openVoiceConference = async (item) => {
userName: item.name,
userPhone: item.phone,
id: item.id,
role: item.role,
type: item.type,
userId: userId,
text: '打开语音通话',
}
@ -297,6 +288,8 @@ export const opencallConference = async (item) => {
userName: item.name,
userPhone: item.phone,
id: item.id,
role: item.role,
type: item.type,
userId: '',
text: '拨打电话',
}

View File

@ -199,10 +199,15 @@
<controlSituationDialog v-model:visible="dialogVisible.controlSituation" @close="closeDialog('controlSituation')" />
<!-- 调度详情对话框 -->
<dispatchDetailDialog v-model:visible="dialogVisible.dispatchDetail" @close="closeDialog('dispatchDetail')" />
<dispatchDetailDialog
:dispatchDateRange="dispatchDateRange"
v-model:visible="dialogVisible.dispatchDetail"
@close="closeDialog('dispatchDetail')"
/>
<!-- 调度区县情况对话框 -->
<dispatchDistrictDialog
:dispatchDateRange="dispatchDateRange"
v-model:visible="dialogVisible.dispatchDistrict"
@close="closeDialog('dispatchDistrict')"
@dispatchClick="openDialog('dispatchDetail')"
@ -240,7 +245,11 @@
<offlineHelpDialog v-model:visible="dialogVisible.offlineHelp" @close="closeDialog('offlineHelp')" />
<!-- 抽查人次对话框 -->
<imageInspectionDialog v-model:visible="dialogVisible.imageInspection" @close="closeDialog('imageInspection')" />
<imageInspectionDialog
v-model:visible="dialogVisible.imageInspection"
:dispatchDateRange="dispatchDateRange"
@close="closeDialog('imageInspection')"
/>
<!-- 巡查里程对话框 -->
<patrolMileageDialog v-model:visible="dialogVisible.patrolMileage" :getdateRange="getdateRange" @close="closeDialog('patrolMileage')" />
@ -595,6 +604,7 @@ const handleCenterCardClick = (item) => {
title: getCardTitleByType(item.type),
dataList: item.data,
}
if (item.type == 'second') return
chongqingMapRef.value.openCenterCard(cardData)
//
@ -672,6 +682,16 @@ const mapBase = useMapBase(mapStore)
* 组件挂载后初始化地图
*/
onMounted(() => {
// URL token
const urlParams = new URLSearchParams(window.location.search)
const urlToken = urlParams.get('token')
console.log('从 URL 获取的 token:', urlToken)
if (urlToken) {
//
localStorage.setItem('token', urlToken)
sessionStorage.setItem('token', urlToken)
console.log('从 URL 获取并更新 token 成功')
}
//
mapBase.loadBaseData()
fetchRoadConditionOptions() //

View File

@ -148,24 +148,26 @@ const setRefreshLeftData = inject('setRefreshLeftData')
//
const getdateRange = inject('getdateRange', ref([]))
const flag = ref(true)
//
watch(
() => getdateRange.value,
(newVal) => {
console.log('left.vue 日期范围变化:', newVal)
dateRange.value = JSON.parse(JSON.stringify(newVal))
dateRange.value = newVal
// dispatchLoadLoad() //
// scheduleStatisticsByCountyLoad() //
init()
},
{ deep: true },
)
onMounted(() => {
init()
// init()
//
if (setRefreshLeftData) {
setRefreshLeftData(init)
}
// if (setRefreshLeftData) {
// setRefreshLeftData(init)
// }
})
const init = () => {
roadTypeLoad() //
@ -200,11 +202,13 @@ const handleStatClick = (item) => {
emit('openResponseStatus')
emit('dispatchDateRange', dateRange.value)
} else if (item.label === '调度区县数') {
emit('dispatchDateRange', dateRange.value)
emit('openDispatchDistrict')
} else if (item.label === '线下帮扶数') {
emit('openOfflineHelp')
} else if (item.label === '抽查人次') {
emit('openImageInspection')
emit('dispatchDateRange', dateRange.value)
}
}
@ -336,6 +340,7 @@ watch(
(newVal) => {
console.log('left.vue 调度响应变化:', newVal)
dispatchLoadLoad()
scheduleStatisticsByCountyLoad() //
},
{ deep: true },
)
@ -681,37 +686,37 @@ const districtData = ref([])
const responseStats = ref([
{
label: '叫应总数',
value: '15',
value: '0',
iconClass: 'icon-call',
img: imgCall,
},
{
label: '已回应数',
value: '9',
value: '0',
iconClass: 'icon-reply',
img: imgReply,
},
{
label: '回应率',
value: '100%',
value: '0%',
iconClass: 'icon-rate',
img: imgRate,
},
{
label: '调度区县数',
value: '21',
value: '0',
iconClass: 'icon-district',
img: imgDistrict,
},
{
label: '线下帮扶数',
value: '12',
value: '0',
iconClass: 'icon-help',
img: imgHelp,
},
{
label: '抽查人次',
value: '23',
value: '0',
iconClass: 'icon-check',
img: imgCheck,
},

View File

@ -745,18 +745,22 @@ const init = () => {
//
onMounted(() => {
init()
// init()
//
if (setRefreshRightData) {
setRefreshRightData(init)
}
// if (setRefreshRightData) {
// setRefreshRightData(init)
// }
})
const flag = ref(true)
watch(
() => getdateRange.value,
(newVal) => {
(newVal, oldVal) => {
if (flag.value) {
flag.value = false
return
}
dateRange.value = JSON.parse(JSON.stringify(newVal))
console.log('right.vue 日期范围变化:', newVal)
dateRange.value = newVal
init()
},
{ deep: true, immediate: true },