Merge branch 'dev' of http://222.212.85.86:8222/bdzl2/bxztApp into dev
This commit is contained in:
commit
bb103fd196
@ -55,6 +55,7 @@
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { Field, Popup, DatePicker, TimePicker } from 'vant'
|
||||
import { formatDate } from '@shared/utils'
|
||||
|
||||
// Props 定义
|
||||
const props = defineProps({
|
||||
@ -141,6 +142,11 @@ const props = defineProps({
|
||||
return option
|
||||
}
|
||||
},
|
||||
// 返回结果格式化
|
||||
resultFormat: {
|
||||
type: String,
|
||||
default: 'YYYY-MM-DD HH:mm:ss'
|
||||
},
|
||||
// 选项过滤函数
|
||||
filter: {
|
||||
type: Function,
|
||||
@ -350,13 +356,14 @@ const formatTimePart = () => {
|
||||
// 确认选择
|
||||
const onConfirm = () => {
|
||||
let finalValue = formatDatePart()
|
||||
|
||||
if (hasTime.value) {
|
||||
const timePart = formatTimePart()
|
||||
if (timePart) {
|
||||
finalValue += ' ' + timePart
|
||||
}
|
||||
}
|
||||
|
||||
finalValue = formatDate(finalValue)
|
||||
|
||||
emit('update:modelValue', finalValue)
|
||||
emit('change', finalValue)
|
||||
|
||||
@ -31,9 +31,9 @@
|
||||
<span class="info-value">{{ detailData.event?.isBlocked ? '是' : '否' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 抢修进度 -->
|
||||
<!-- 抢险进度 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">抢修进度:</span>
|
||||
<span class="info-label">抢险进度:</span>
|
||||
<span class="info-value">{{ detailData.event?.repairProgress || '-' }}</span>
|
||||
</div>
|
||||
|
||||
@ -72,33 +72,17 @@
|
||||
<span class="info-value">{{ detailData.occurLocation || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 起点桩号及经纬度 -->
|
||||
<!-- 起点桩号 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">起点桩号:</span>
|
||||
<span class="info-value">{{ detailData.event?.startStakeNo || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row sub-row">
|
||||
<span class="info-label">起点桩经度:</span>
|
||||
<span class="info-value">{{ detailData.event?.startStakeLng || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row sub-row">
|
||||
<span class="info-label">起点桩纬度:</span>
|
||||
<span class="info-value">{{ detailData.event?.startStakeLat || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 止点桩号及经纬度 -->
|
||||
<!-- 止点桩号 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">止点桩号:</span>
|
||||
<span class="info-value">{{ detailData.event?.endStakeNo || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row sub-row">
|
||||
<span class="info-label">止点桩经度:</span>
|
||||
<span class="info-value">{{ detailData.event?.endStakeLng || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row sub-row">
|
||||
<span class="info-label">止点桩纬度:</span>
|
||||
<span class="info-value">{{ detailData.event?.endStakeLat || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 路况位置(使用阻断点小地名或发生地点) -->
|
||||
<div class="info-row">
|
||||
@ -165,17 +149,19 @@
|
||||
</div>
|
||||
<div class="report-content">
|
||||
<div class="info-row">
|
||||
<span class="info-label">处置情况:</span>
|
||||
<span class="info-value">{{ formatDisposalMeasures(report.disposalMeasures) || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">塌方及损失:</span>
|
||||
<span class="info-value">{{ getLossDescription(report) }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">路产损失:</span>
|
||||
<span class="info-value">{{ report.totalLossAmount ? report.totalLossAmount + '万元' : '-' }}</span>
|
||||
<span class="info-label">处置措施:</span>
|
||||
<span class="info-value">{{ report.disposalMeasures || '-' }}</span>
|
||||
</div>
|
||||
<template v-for="(lossItem, idx) of report.lossList" :key="idx">
|
||||
<div class="info-row">
|
||||
<span class="info-label">{{ lossItem.lossCategory }}:</span>
|
||||
<span class="info-value">{{ lossItem.totalAmount }}{{ lossItem.unit }}</span>
|
||||
</div>
|
||||
<div class="info-row" v-if="lossItem.lossCategory == '其他损失'">
|
||||
<span class="info-label">其它损失描述:</span>
|
||||
<span class="info-value">{{ lossItem.remark }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="info-row">
|
||||
<span class="info-label">有无车辆滞留:</span>
|
||||
<span class="info-value">{{ getVehicleStrandedText(report) }}</span>
|
||||
@ -197,13 +183,18 @@
|
||||
<span class="info-value">{{ report.siteDescription || '-' }}</span>
|
||||
</div>
|
||||
<!-- 附件 -->
|
||||
<div class="info-row" v-if="report.fileList && report.fileList.length > 0">
|
||||
<div class="info-row column" v-if="report.fileList && report.fileList.length > 0">
|
||||
<span class="info-label">附件:</span>
|
||||
<div class="attachment-list">
|
||||
<div v-for="(file, fileIndex) in report.fileList" :key="fileIndex" class="attachment-item">
|
||||
<van-icon :name="file.fileType === 1 ? 'photo-o' : 'video-o'" />
|
||||
<span class="file-name">{{ file.fileName }}</span>
|
||||
<van-button size="mini" type="primary" plain @click="previewFile(file)">预览</van-button>
|
||||
<div class="preview-image-block" v-if="file.fileType === 1" @click="previewFile(report, file)">
|
||||
<img :src="file.fileUrl" alt="" />
|
||||
</div>
|
||||
<div class="preview-video-block" v-else>
|
||||
<van-icon :name="file.fileType === 1 ? 'photo-o' : 'video-o'" />
|
||||
<span class="file-name">{{ file.fileName }}</span>
|
||||
<!-- <van-button size="mini" type="primary" plain @click="previewFile(report, file)">预览</van-button> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -216,15 +207,19 @@
|
||||
|
||||
<!-- 底部按钮:未解除状态显示续报按钮 -->
|
||||
<div class="footer-buttons">
|
||||
<van-button type="primary" class="footer-btn" @click="handleContinueReport">续报</van-button>
|
||||
<van-button type="primary" class="footer-btn" @click="handleContinueReport">续报</van-button>
|
||||
</div>
|
||||
|
||||
<van-image-preview :startPosition="startPosition" v-model:show="previewImagesVisible" :images="imagesForPreview">
|
||||
<template v-slot:index="{ index }">第{{ index + 1 }}页</template>
|
||||
</van-image-preview>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { showToast } from 'vant'
|
||||
import { showToast, showImagePreview } from 'vant'
|
||||
import PageContainer from '@/components/PageContainer.vue'
|
||||
import PanelItem from '@/components/PanelItem.vue'
|
||||
import CurrentSite from '@/components/CurrentSite.vue'
|
||||
@ -236,10 +231,10 @@ const route = useRoute()
|
||||
|
||||
// 详情数据(对应 Data 接口)
|
||||
const detailData = ref({
|
||||
event: null, // Event 对象
|
||||
reportList: [], // 填报列表(包含首报和续报)
|
||||
fileList: [], // 附件列表
|
||||
lossList: [], // 损失列表
|
||||
event: null, // Event 对象
|
||||
report: [], // 填报列表(包含首报和续报)
|
||||
fileList: [], // 附件列表
|
||||
lossList: [], // 损失列表
|
||||
occurLocation: '',
|
||||
occurTime: '',
|
||||
roadConditionType: '',
|
||||
@ -247,11 +242,17 @@ const detailData = ref({
|
||||
})
|
||||
|
||||
const allReports = computed(() => {
|
||||
const reports = detailData.value.reportList?.map((item, index)=>{
|
||||
item.title = index == 0 ? '首报' : ('续报' + index)
|
||||
return item
|
||||
}) || []
|
||||
return reports.reverse()
|
||||
const reports =
|
||||
detailData.value.report?.map((item, index) => {
|
||||
if (index === detailData.value.report.length - 1) {
|
||||
item.title = '首报'
|
||||
} else {
|
||||
item.title = '续报' + (detailData.value.report.length - 1 - index)
|
||||
}
|
||||
return item
|
||||
}) || []
|
||||
return reports
|
||||
// return reports.reverse()
|
||||
})
|
||||
|
||||
// 是否有填报数据
|
||||
@ -259,7 +260,6 @@ const hasReportData = computed(() => {
|
||||
return allReports.value.length > 0
|
||||
})
|
||||
|
||||
|
||||
// 获取事件状态文本
|
||||
const getEventStatusText = () => {
|
||||
return detailData.eventStatus === 1 ? '已解除' : '未解除'
|
||||
@ -274,10 +274,10 @@ const getEventStatusType = () => {
|
||||
const formatDisposalMeasures = (measures) => {
|
||||
if (!measures) return ''
|
||||
const measureMap = {
|
||||
halfClose: '半幅封闭',
|
||||
fullClose: '全副封闭',
|
||||
bypass: '便道通行',
|
||||
normal: '正常通行'
|
||||
半幅封闭: '半幅封闭',
|
||||
全副封闭: '全副封闭',
|
||||
便道通行: '便道通行',
|
||||
正常通行: '正常通行'
|
||||
}
|
||||
return measures
|
||||
.split(',')
|
||||
@ -303,7 +303,7 @@ const getLossDescription = (report) => {
|
||||
// 获取车辆滞留文本
|
||||
const getVehicleStrandedText = (report) => {
|
||||
const count = report?.strandedVehicleCount || 0
|
||||
return count > 0 ? `有车滞留,共${count}辆` : '无车滞留'
|
||||
return count > 0 ? `有车滞留` : '无车滞留'
|
||||
}
|
||||
|
||||
// 获取灾毁详情
|
||||
@ -326,7 +326,7 @@ const getDisasterDetail = async () => {
|
||||
const data = result.data
|
||||
detailData.value = {
|
||||
event: data.event || null,
|
||||
reportList: data.report || [], // 直接使用 reportList,包含首报和续报
|
||||
report: data.report || [], // 直接使用 report,包含首报和续报
|
||||
fileList: data.fileList || [],
|
||||
lossList: data.lossList || [],
|
||||
occurLocation: data.occurLocation || '',
|
||||
@ -360,11 +360,25 @@ const handleContinueReport = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const isImageFile = (file) => {
|
||||
// 根据url后缀判断
|
||||
const imageExtensions = /\.(jpg|jpeg|png|gif|webp|bmp|svg)$/i
|
||||
if (file.fileUrl && imageExtensions.test(file.fileUrl)) return true
|
||||
// 根据文件类型判断
|
||||
if (file.type && file.type.startsWith('image/')) return true
|
||||
return false
|
||||
}
|
||||
|
||||
const imagesForPreview = ref([])
|
||||
const previewImagesVisible = ref(false)
|
||||
const startPosition = ref(0)
|
||||
|
||||
// 预览附件
|
||||
const previewFile = (file) => {
|
||||
if (file.fileUrl) {
|
||||
window.open(file.fileUrl, '_blank')
|
||||
}
|
||||
const previewFile = (report, file) => {
|
||||
const images = report.fileList.filter((file) => isImageFile(file))
|
||||
imagesForPreview.value = images.map((item) => item.fileUrl)
|
||||
startPosition.value = imagesForPreview.value.indexOf(file.fileUrl)
|
||||
previewImagesVisible.value = true
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@ -391,6 +405,13 @@ onMounted(() => {
|
||||
margin-left: 20px;
|
||||
margin-top: -8px;
|
||||
}
|
||||
|
||||
&.column {
|
||||
flex-direction: column;
|
||||
.info-label {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-label {
|
||||
@ -445,14 +466,17 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.attachment-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex: 1;
|
||||
gap: 10px;
|
||||
overflow: hidden;
|
||||
|
||||
.attachment-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
padding: 8px;
|
||||
background: #f7f8fa;
|
||||
border-radius: 4px;
|
||||
|
||||
@ -467,11 +491,20 @@ onMounted(() => {
|
||||
color: #323233;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.preview-image-block {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-buttons {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
@ -491,4 +524,4 @@ onMounted(() => {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { showToast, Tag as VanTag, Loading as VanLoading, Icon as VanIcon, Button as VanButton } from 'vant'
|
||||
import { showToast, Tag as VanTag, Loading as VanLoading, Icon as VanIcon, Button as VanButton, showImagePreview } from 'vant'
|
||||
import PageContainer from '@/components/PageContainer.vue'
|
||||
import SearchInput from '@/components/SearchInput.vue'
|
||||
import CardItem from '@/components/CardItem.vue'
|
||||
@ -124,7 +124,7 @@ const getDisasterTypeText = (item) => {
|
||||
// 可以根据 roadConditionType、repairProgress 或其他字段来生成类型标签
|
||||
// 这里提供几种可能的映射方式
|
||||
|
||||
// 方式1:根据抢修进度
|
||||
// 方式1:根据抢险进度
|
||||
if (item.repairProgress) {
|
||||
return item.repairProgress
|
||||
}
|
||||
@ -149,8 +149,8 @@ const getShortTypeName = (type) => {
|
||||
'积水': '积水',
|
||||
'积雪': '积雪',
|
||||
'其他': '其他',
|
||||
'未抢修': '待抢修',
|
||||
'抢修中': '抢修中',
|
||||
'未抢险': '待抢险',
|
||||
'抢险中': '抢险中',
|
||||
'已完成': '已完成',
|
||||
'高速公路': '高速',
|
||||
'国道': '国道',
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<CurrentSite />
|
||||
|
||||
<!-- 事件类型 -->
|
||||
<PanelItem title="事件类型" style="margin-bottom: 10px;" v-if="!isContinue">
|
||||
<PanelItem title="事件类型" style="margin-bottom: 10px" v-if="!isContinue">
|
||||
<van-radio-group v-model="eventType" direction="horizontal" class="event-type-group">
|
||||
<van-radio name="water">水毁灾害</van-radio>
|
||||
<van-radio name="ice">冰雪灾害</van-radio>
|
||||
@ -12,20 +12,15 @@
|
||||
</PanelItem>
|
||||
|
||||
<!-- 根据事件类型渲染不同表单 -->
|
||||
<WaterDisaster
|
||||
v-if="eventType === 'water'"
|
||||
ref="waterDisasterRef"
|
||||
/>
|
||||
|
||||
<WaterDisaster v-if="eventType === 'water'" ref="waterDisasterRef" />
|
||||
|
||||
<!-- 冰雪灾害表单(待实现) -->
|
||||
<div v-else class="coming-soon">
|
||||
<van-empty description="冰雪灾害表单开发中..." />
|
||||
</div>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<van-button type="primary" class="footer-btn" @click="handleSubmit" :loading="submitting">
|
||||
提交
|
||||
</van-button>
|
||||
<van-button type="primary" class="footer-btn" @click="handleSubmit" :loading="submitting"> 提交 </van-button>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
@ -37,7 +32,7 @@ import PageContainer from '@/components/PageContainer.vue'
|
||||
import CurrentSite from '@/components/CurrentSite.vue'
|
||||
import PanelItem from '@/components/PanelItem.vue'
|
||||
import WaterDisaster from './WaterDisaster/WaterDisaster.vue'
|
||||
import { request } from "@shared/utils/request";
|
||||
import { request } from '@shared/utils/request'
|
||||
import mockFormData from './waterDisasterFormData.json'
|
||||
|
||||
const router = useRouter()
|
||||
@ -52,7 +47,7 @@ const title = ref(!isContinue ? '灾毁填报' : '灾毁续报')
|
||||
const eventType = ref('water')
|
||||
|
||||
// 表单数据
|
||||
const formData = ref(mockFormData)
|
||||
const formData = ref(route.query.mock ? mockFormData : {})
|
||||
const waterDisasterRef = ref(null)
|
||||
const submitting = ref(false)
|
||||
|
||||
@ -69,7 +64,7 @@ const handleSubmit = async () => {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
submitting.value = true
|
||||
try {
|
||||
// 获取表单数据
|
||||
@ -77,10 +72,10 @@ const handleSubmit = async () => {
|
||||
if (eventType.value === 'water') {
|
||||
formData = waterDisasterRef.value.getFormData()
|
||||
}
|
||||
|
||||
|
||||
// 添加事件类型和站点信息
|
||||
const submitData = {
|
||||
...formData,
|
||||
...formData
|
||||
// 可以在这里添加站点信息等其他数据
|
||||
}
|
||||
|
||||
@ -90,16 +85,24 @@ const handleSubmit = async () => {
|
||||
data: submitData
|
||||
})
|
||||
|
||||
if(res?.code === '00000') {
|
||||
if (res?.code === '00000') {
|
||||
showSuccessToast('提交成功')
|
||||
if (submitData.event.needsRecovery) {
|
||||
router.replace({
|
||||
name: 'RebuildAdd',
|
||||
params: {
|
||||
data: res.data.id
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 提交成功后返回列表页
|
||||
setTimeout(() => {
|
||||
router.replace('/disasterManagement')
|
||||
}, 500)
|
||||
}
|
||||
} else {
|
||||
showFailToast(res.message)
|
||||
}
|
||||
|
||||
// 提交成功后返回列表页
|
||||
setTimeout(() => {
|
||||
router.replace('/disasterManagement')
|
||||
}, 1000)
|
||||
} catch (error) {
|
||||
showFailToast('提交失败,请重试')
|
||||
console.error('提交失败:', error)
|
||||
@ -126,10 +129,10 @@ const getDisasterDetail = async () => {
|
||||
// 接口返回 Data 结构
|
||||
const data = result.data
|
||||
const newFormData = {
|
||||
...data,
|
||||
lossList: null,
|
||||
report: formData.value.report,
|
||||
fileList: null
|
||||
...data,
|
||||
lossList: null,
|
||||
report: formData.value.report,
|
||||
fileList: null
|
||||
}
|
||||
waterDisasterRef.value.initFormData(newFormData)
|
||||
} else {
|
||||
@ -142,7 +145,7 @@ const getDisasterDetail = async () => {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if(route.query?.id) {
|
||||
if (route.query?.id) {
|
||||
getDisasterDetail()
|
||||
} else {
|
||||
waterDisasterRef.value.initFormData(formData.value)
|
||||
@ -189,4 +192,4 @@ onMounted(() => {
|
||||
transform: translateX(-50%) scale(0.98);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<!-- 损失计算弹窗 -->
|
||||
<van-dialog v-model:show="visible" :title="lossItem?.title" show-cancel-button @confirm="confirm" @cancel="cancelLoss" confirm-button-text="确定" cancel-button-text="取消">
|
||||
<div class="loss-dialog-content">
|
||||
<!-- 立方计算 -->
|
||||
<template v-if="lossItem.calc == 'cube'">
|
||||
<van-field v-model="formData.length" :label="lossItem?.itemName + '长'" placeholder="请填写长度" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">米</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<van-field v-model="formData.width" :label="lossItem?.itemName + '宽'" placeholder="请填写宽度" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">米</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<van-field v-model="formData.height" :label="lossItem?.itemName + '高'" placeholder="请填写高度" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">米</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<van-field v-model="formData.unitPrice" label="单价" placeholder="请填写单价" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">元</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<van-field v-model="formData.totalAmount" :label="lossItem?.itemName + '损失金额'" placeholder="请填写金额" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">元</span>
|
||||
</template>
|
||||
</van-field>
|
||||
</template>
|
||||
|
||||
<!-- 长度计算-->
|
||||
<template v-else-if="lossItem.calc == 'length'">
|
||||
<van-field v-model="formData.length" :label="lossItem?.itemName + '长度'" placeholder="请填写长度" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">米</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.unitPrice" label="单价" placeholder="请填写单价" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">元</span>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.totalAmount" :label="lossItem?.itemName + '损失金额'" placeholder="请填写金额" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">元</span>
|
||||
</template>
|
||||
</van-field>
|
||||
</template>
|
||||
</div>
|
||||
</van-dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, ref, reactive, watch, computed } from 'vue'
|
||||
import { showToast } from 'vant'
|
||||
import { getLossItem } from './LossMap'
|
||||
|
||||
// 弹窗显示状态
|
||||
const visible = ref(false)
|
||||
|
||||
// 损失计算表单
|
||||
const formData = ref({
|
||||
length: '',
|
||||
width: '',
|
||||
height: '',
|
||||
unitPrice: ''
|
||||
})
|
||||
|
||||
const lossItem = ref(null)
|
||||
|
||||
// 立方计算
|
||||
const cubeCalc = () => {
|
||||
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
|
||||
}
|
||||
|
||||
// 长度计算
|
||||
const lengthCalc = () => {
|
||||
const l = parseFloat(formData.value.length)
|
||||
const price = parseFloat(formData.value.unitPrice)
|
||||
if (isNaN(l) || l <= 0) {
|
||||
return 0
|
||||
}
|
||||
if (isNaN(price) || price < 0) {
|
||||
return 0
|
||||
}
|
||||
if (price > 2000) {
|
||||
return 0
|
||||
}
|
||||
return l * price
|
||||
}
|
||||
const totalAmount = computed(() => {
|
||||
if(lossItem.value?.calc == 'cube') return cubeCalc()
|
||||
if(lossItem.value?.calc == 'length') return lengthCalc()
|
||||
return 0
|
||||
})
|
||||
|
||||
watch(totalAmount, () => {
|
||||
formData.value.totalAmount = totalAmount.value
|
||||
})
|
||||
// 显示弹窗
|
||||
const show = (item) => {
|
||||
lossItem.value = getLossItem(item.lossTypeCode)
|
||||
|
||||
formData.value.length = item.length
|
||||
formData.value.width = item.width
|
||||
formData.value.height = item.height
|
||||
formData.value.unitPrice = item.unitPrice
|
||||
formData.value.totalAmount = item.totalAmount
|
||||
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.totalAmount) {
|
||||
showToast('请填写损失金额')
|
||||
return
|
||||
}
|
||||
emit('confirm', formData.value)
|
||||
// 重置表单
|
||||
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.totalAmount
|
||||
}
|
||||
// 定义事件
|
||||
const emit = defineEmits(['confirm'])
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
@ -1,172 +0,0 @@
|
||||
<template>
|
||||
<!-- 损失计算弹窗 -->
|
||||
<van-dialog
|
||||
v-model:show="visible"
|
||||
:title="itemName + '损失信息'"
|
||||
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="itemName + '长'" placeholder="请填写长度" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">米</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<!-- 塌方宽 -->
|
||||
<van-field v-model="formData.width" :label="itemName + '宽'" placeholder="请填写宽度" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">米</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<!-- 塌方高 -->
|
||||
<van-field v-model="formData.height" :label="itemName + '高'" 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.totalAmount" :label="itemName + '损失金额'" 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 itemName = ref('')
|
||||
|
||||
const totalAmount = 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(totalAmount, ()=>{
|
||||
formData.value.totalAmount = totalAmount.value
|
||||
})
|
||||
// 显示弹窗
|
||||
const show = (item) => {
|
||||
console.log("🚀 ~ show ~ item:", item)
|
||||
formData.value.length = item.length
|
||||
formData.value.width = item.width
|
||||
formData.value.height = item.height
|
||||
formData.value.unitPrice = item.unitPrice
|
||||
formData.value.totalAmount = item.totalAmount
|
||||
itemName.value = getItemName(item)
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
const getItemName = (item) => {
|
||||
return item.lossTypeName
|
||||
}
|
||||
|
||||
// 验证表单数据
|
||||
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.totalAmount) {
|
||||
showToast('请填写损失金额')
|
||||
return
|
||||
}
|
||||
emit('confirm', formData.value)
|
||||
// 重置表单
|
||||
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.totalAmount
|
||||
}
|
||||
// 定义事件
|
||||
const emit = defineEmits(['confirm'])
|
||||
|
||||
defineExpose({
|
||||
show
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
@ -1,24 +1,34 @@
|
||||
<template>
|
||||
<div class="loss-list">
|
||||
<template v-for="(item, index) in modelValue">
|
||||
<van-field v-model="item.totalAmount" :label="getItemLabel(item)" placeholder="请填写" type="digit" @click="showCalculateDialog(item, index)">
|
||||
<van-field v-if="getLossItem(item.lossTypeCode)" v-model="item.totalAmount" :label="getItemLabel(item)" placeholder="请填写" type="digit" @click="showCalculateDialog(item, index)">
|
||||
<template #button>
|
||||
<span class="field-unit">{{ item.unit }}</span>
|
||||
<van-icon @click.stop="removeItem(index)" class="remove-icon" name="delete-o" />
|
||||
</template>
|
||||
</van-field>
|
||||
<template v-else>
|
||||
<van-field v-model="item.totalAmount" :label="getItemLabel(item)" placeholder="请填写" type="digit">
|
||||
<template #button>
|
||||
<span class="field-unit">{{ item.unit }}</span>
|
||||
<van-icon @click.stop="removeItem(index)" class="remove-icon" name="delete-o" />
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-if="item.lossTypeCode == 'OTHER_LOSS'" v-model="item.remark" label="其它损失描述" placeholder="请填写"></van-field>
|
||||
</template>
|
||||
</template>
|
||||
<van-button size="small" block type="primary" plain @click="addLoss">添加损失</van-button>
|
||||
<CubeCalculateDialog ref="cubeCalculateDialog" @confirm="confirmCalculate" />
|
||||
<LossPicker ref="lossPicker" :options="options" @confirm="confirmAddLoss" />
|
||||
<CalculateDialog ref="cubeCalculateDialog" @confirm="confirmCalculate" />
|
||||
<LossPicker ref="lossPicker" :options="getOptions()" @confirm="confirmAddLoss" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import CubeCalculateDialog from './CubeCalculateDialog.vue'
|
||||
import CalculateDialog from './CalculateDialog.vue'
|
||||
import { request } from '@shared/utils/request'
|
||||
import LossPicker from './LossPicker.vue'
|
||||
import { getLossItem } from './LossMap'
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
@ -33,6 +43,19 @@ const lossPicker = ref(null)
|
||||
|
||||
const options = ref({})
|
||||
|
||||
const getOptions = () => {
|
||||
if(!options.value.loss) return []
|
||||
const filteredOptions = options.value.loss.filter((item) => {
|
||||
for(const valueItem of props.modelValue) {
|
||||
if(item.value === valueItem.lossTypeId) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return filteredOptions
|
||||
}
|
||||
|
||||
const dialogItemIndex = ref(null)
|
||||
|
||||
// 添加损失项
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
|
||||
const lossMap = {
|
||||
COLLAPSE_LOSS: {
|
||||
title: '塌方损失信息',
|
||||
itemName: '塌方',
|
||||
calc: 'cube',
|
||||
},
|
||||
RETAINING_WALL_LOSS: {
|
||||
title: '挡墙损失信息',
|
||||
itemName: '挡墙',
|
||||
calc: 'cube',
|
||||
},
|
||||
ROADBED_LOSS: {
|
||||
title: '路基损失信息',
|
||||
itemName: '路基',
|
||||
calc: 'cube',
|
||||
},
|
||||
PAVEMENT_LOSS: {
|
||||
title: '路面损失信息',
|
||||
itemName: '路面',
|
||||
calc: 'cube',
|
||||
},
|
||||
SLOPE_PROTECTION_LOSS: {
|
||||
title: '护坡损失信息',
|
||||
itemName: '护坡',
|
||||
calc: 'cube',
|
||||
},
|
||||
BRIDGE_LOSS: {
|
||||
title: '桥梁损失信息',
|
||||
itemName: '桥梁',
|
||||
calc: 'cube',
|
||||
},
|
||||
TUNNEL_LOSS: {
|
||||
title: '隧道损失信息',
|
||||
itemName: '隧道',
|
||||
calc: 'length'
|
||||
},
|
||||
CULVERT_LOSS: {
|
||||
title: '涵洞损失信息',
|
||||
itemName: '涵洞',
|
||||
calc: 'length'
|
||||
}
|
||||
}
|
||||
|
||||
export const getLossItem = (code) => {
|
||||
return lossMap[code]
|
||||
}
|
||||
@ -19,7 +19,7 @@ const pickerTitle = ref("请选择损失类型")
|
||||
|
||||
|
||||
const columns = computed(() => {
|
||||
return props.options.loss || []
|
||||
return props.options || []
|
||||
})
|
||||
|
||||
const showPicker = ref(false)
|
||||
|
||||
@ -9,8 +9,8 @@
|
||||
<!-- 是否阻断 (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.repairProgress) -->
|
||||
<BasePicker v-model="formData.event.repairProgress" :options="repairProgressOptions" label="抢险进度" placeholder="请选择" />
|
||||
|
||||
<!-- 水毁处数 (event.damageCount) -->
|
||||
<van-field v-model="formData.event.damageCount" label="水毁处数" placeholder="请填写" type="number" />
|
||||
@ -35,29 +35,9 @@
|
||||
<!-- 起点桩号 (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>
|
||||
|
||||
<!-- 路况位置 (occurLocation) -->
|
||||
<van-field v-model="formData.occurLocation" label="路况位置" placeholder="请填写" />
|
||||
|
||||
@ -72,11 +52,11 @@
|
||||
<span class="measures-label">处置措施</span>
|
||||
<div class="measures-options">
|
||||
<!-- 改为单选,使用 van-radio-group -->
|
||||
<van-radio-group v-model="disposalMeasureValue" direction="horizontal">
|
||||
<van-radio name="halfClose">半幅封闭</van-radio>
|
||||
<van-radio name="fullClose">全副封闭</van-radio>
|
||||
<van-radio name="bypass">便道通行</van-radio>
|
||||
<van-radio name="normal">正常通行</van-radio>
|
||||
<van-radio-group v-model="formData.report.disposalMeasures" direction="horizontal">
|
||||
<van-radio name="半幅封闭">半幅封闭</van-radio>
|
||||
<van-radio name="全副封闭">全副封闭</van-radio>
|
||||
<van-radio name="便道通行">便道通行</van-radio>
|
||||
<van-radio name="正常通行">正常通行</van-radio>
|
||||
</van-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
@ -148,30 +128,12 @@
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field v-model="formData.report.siteDescription" label="现场描述" placeholder="请填写" type="textarea" rows="2" autosize />
|
||||
<van-field label="附件" center>
|
||||
<template #input>
|
||||
<van-uploader accept="video/*,image/*" :modelValue="getFileList()" :after-read="afterRead" multiple :max-count="6" @delete="removeFile" />
|
||||
</template>
|
||||
</van-field>
|
||||
</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="请选择" />
|
||||
@ -186,28 +148,23 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { showToast, showFailToast } from 'vant'
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { showToast, showFailToast, showLoadingToast } 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'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { request } from '@shared/utils/request'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
// 是否为续报
|
||||
const isContinue = computed(() => route.query.isContinue)
|
||||
|
||||
// 处置措施单选值(用于单选组件)
|
||||
const disposalMeasureValue = ref('')
|
||||
|
||||
// 附件列表
|
||||
const imageFileList = ref([])
|
||||
const videoFileList = ref([])
|
||||
|
||||
// 表单数据 - 按 Request 接口结构定义
|
||||
const formData = reactive({
|
||||
// 表单数据 - 按 Request 接口结构定义,使用 ref 包装
|
||||
const formData = ref({
|
||||
// 顶层字段
|
||||
occurLocation: '', // 发生地点
|
||||
occurTime: '', // 发生时间
|
||||
@ -222,17 +179,13 @@ const formData = reactive({
|
||||
contactPhone: '', // 联系电话
|
||||
damageCount: '', // 水毁处数
|
||||
district: '', // 上报区县
|
||||
endStakeLat: '', // 止点纬度
|
||||
endStakeLng: '', // 止点经度
|
||||
endStakeNo: '', // 止点桩号
|
||||
estimatedRecoveryCost: '', // 恢复重建预估费用
|
||||
inspectionMileage: '', // 巡查里程
|
||||
isBlocked: '', // 是否阻断
|
||||
needsRecovery: '', // 是否需要恢复重建
|
||||
repairProgress: '', // 抢修进度
|
||||
repairProgress: '', // 抢险进度
|
||||
reporterUnit: '', // 填报单位
|
||||
startStakeLat: '', // 起点纬度
|
||||
startStakeLng: '', // 起点经度
|
||||
startStakeNo: '' // 起点桩号
|
||||
},
|
||||
|
||||
@ -261,65 +214,16 @@ const formData = reactive({
|
||||
fileList: []
|
||||
})
|
||||
|
||||
// 监听处置措施单选值变化,直接赋值给 report.disposalMeasures
|
||||
watch(disposalMeasureValue, (newVal) => {
|
||||
formData.report.disposalMeasures = newVal
|
||||
})
|
||||
|
||||
// 监听附件变化,同步到 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') {
|
||||
disposalMeasureValue.value = newVal
|
||||
const getFileList = () => {
|
||||
const fileList = formData.value.fileList?.map((item) => {
|
||||
return {
|
||||
url: item.fileUrl,
|
||||
name: item.fileName
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
})
|
||||
|
||||
return fileList
|
||||
}
|
||||
|
||||
// BasePicker 选项数据
|
||||
const roadConditionOptions = [
|
||||
@ -337,9 +241,9 @@ const blockedOptions = [
|
||||
]
|
||||
|
||||
const repairProgressOptions = [
|
||||
{ label: '未抢修', value: '未抢修' },
|
||||
{ label: '抢修中', value: '抢修中' },
|
||||
{ label: '已完成', value: '已完成' },
|
||||
{ label: '未抢险', value: '未抢险' },
|
||||
{ label: '抢险中', value: '抢险中' },
|
||||
{ label: '已完成', value: '已完成' }
|
||||
]
|
||||
|
||||
const needsRecoveryOptions = [
|
||||
@ -353,21 +257,16 @@ const maxDate = new Date(2030, 11, 31)
|
||||
|
||||
const initFormData = (newVal) => {
|
||||
if (newVal && Object.keys(newVal).length > 0) {
|
||||
// 深度合并数据
|
||||
Object.assign(formData, {
|
||||
// 深度合并数据 - 直接替换整个对象
|
||||
formData.value = {
|
||||
occurLocation: newVal.occurLocation || '',
|
||||
occurTime: newVal.occurTime || '',
|
||||
roadConditionType: newVal.roadConditionType || '',
|
||||
routeNo: newVal.routeNo || '',
|
||||
event: { ...formData.event, ...(newVal.event || {}) },
|
||||
report: { ...formData.report, ...(newVal.report || {}) },
|
||||
event: { ...formData.value.event, ...(newVal.event || {}) },
|
||||
report: { ...formData.value.report, ...(newVal.report || {}) },
|
||||
lossList: newVal.lossList || [],
|
||||
fileList: newVal.fileList || []
|
||||
})
|
||||
|
||||
// 初始化处置措施单选值(直接赋值,不再需要 split)
|
||||
if (newVal.report?.disposalMeasures) {
|
||||
disposalMeasureValue.value = newVal.report.disposalMeasures
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -376,24 +275,10 @@ const initFormData = (newVal) => {
|
||||
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
|
||||
formData.value.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)
|
||||
@ -411,22 +296,157 @@ const onVideoOversize = () => {
|
||||
showFailToast('视频大小不能超过20MB')
|
||||
}
|
||||
|
||||
const isImageFile = (file) => {
|
||||
// 根据url后缀判断
|
||||
const imageExtensions = /\.(jpg|jpeg|png|gif|webp|bmp|svg)$/i
|
||||
if (file.fileUrl && imageExtensions.test(file.fileUrl)) return true
|
||||
// 根据文件类型判断
|
||||
if (file.type && file.type.startsWith('image/')) return true
|
||||
return false
|
||||
}
|
||||
|
||||
const isVideoFile = (file) => {
|
||||
// 根据url后缀判断
|
||||
const videoExtensions = /\.(mp4|avi|mov|wmv|flv|mkv)$/i
|
||||
if (file.fileUrl && videoExtensions.test(file.fileUrl)) return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断图片是否可以上传
|
||||
* @param {File} file - 图片文件
|
||||
* @returns {boolean} 是否允许上传
|
||||
*/
|
||||
const isValidImage = (file) => {
|
||||
// 校验文件类型
|
||||
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
|
||||
|
||||
if (!isJpgOrPng) {
|
||||
showFailToast('只能上传 JPG/PNG 格式的图片!')
|
||||
return false
|
||||
}
|
||||
|
||||
// 校验文件大小(500KB = 500 * 1024 bytes)
|
||||
const isLt500k = file.size / 1024 < 500
|
||||
|
||||
if (!isLt500k) {
|
||||
showFailToast(`图片大小不能超过 500KB!当前大小:${(file.size / 1024).toFixed(2)}KB`)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断视频是否可以上传
|
||||
* @param {File} file - 视频文件
|
||||
* @returns {boolean} 是否允许上传
|
||||
*/
|
||||
const isValidVideo = (file) => {
|
||||
// 校验文件类型
|
||||
const allowedTypes = ['video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/webm']
|
||||
const isValidType = allowedTypes.includes(file.type)
|
||||
|
||||
if (!isValidType) {
|
||||
showFailToast('请上传有效的视频文件(MP4、MOV、AVI、WEBM格式)!')
|
||||
return false
|
||||
}
|
||||
|
||||
// 校验文件大小(50MB = 50 * 1024 * 1024 bytes)
|
||||
const maxSize = 50 * 1024 * 1024
|
||||
const isValidSize = file.size <= maxSize
|
||||
|
||||
if (!isValidSize) {
|
||||
showFailToast(`视频大小不能超过 50MB!当前大小:${(file.size / 1024 / 1024).toFixed(2)}MB`)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一的上传前校验
|
||||
* @param {File} file - 上传的文件
|
||||
* @returns {boolean} 是否允许上传
|
||||
*/
|
||||
const checkFile = (file) => {
|
||||
// 判断是否为图片
|
||||
if (file.type.startsWith('image/')) {
|
||||
return isValidImage(file)
|
||||
}
|
||||
|
||||
// 判断是否为视频
|
||||
if (file.type.startsWith('video/')) {
|
||||
return isValidVideo(file)
|
||||
}
|
||||
|
||||
showFailToast('只支持图片和视频文件!')
|
||||
return false
|
||||
}
|
||||
|
||||
const afterRead = async (options) => {
|
||||
const file = options.file
|
||||
if (!checkFile(file)) return
|
||||
const toast = showLoadingToast({
|
||||
message: '上传中...',
|
||||
forbidClick: true,
|
||||
duration: 0 // 设置为0表示不会自动关闭
|
||||
})
|
||||
try {
|
||||
const uploadFormData = new FormData()
|
||||
uploadFormData.append('file', file)
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/file/upload',
|
||||
method: 'post',
|
||||
data: uploadFormData
|
||||
})
|
||||
toast.close()
|
||||
if (res.code === '00000') {
|
||||
const name = file.name
|
||||
let type = isImageFile(file) ? 1 : isVideoFile(file) ? 2 : 3
|
||||
|
||||
const url = res.data
|
||||
const fileData = {
|
||||
fileName: name,
|
||||
fileUrl: url,
|
||||
fileType: type,
|
||||
fileSize: file.size
|
||||
}
|
||||
if (!formData.value.fileList) formData.value.fileList = []
|
||||
formData.value.fileList.push(fileData)
|
||||
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
toast.close()
|
||||
showToast({
|
||||
type: 'fail',
|
||||
message: error.message
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const removeFile = (file, index) => {
|
||||
// 删除文件
|
||||
formData.value.fileList.splice(index, 1)
|
||||
}
|
||||
|
||||
// 暴露验证方法
|
||||
const validate = () => {
|
||||
if (!formData.occurTime) {
|
||||
if (!formData.value.occurTime) {
|
||||
showToast('请填写发生时间')
|
||||
return false
|
||||
}
|
||||
if (!formData.routeNo) {
|
||||
if (!formData.value.routeNo) {
|
||||
showToast('请填写线路编号')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 获取表单数据
|
||||
// 获取表单数据 - 返回 formData.value 的副本
|
||||
const getFormData = () => {
|
||||
return { ...formData }
|
||||
return { ...formData.value }
|
||||
}
|
||||
|
||||
// 暴露方法给父组件
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"title": "G242金铃乡老窖坪发生积雪",
|
||||
"status": "未解除",
|
||||
"occurTime": "2025/10/10 20:29",
|
||||
"estimateRecoverTime": "2025/10/10 20:29",
|
||||
"disasterType": "积雪"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "S521白鹿镇X发生边坡坍塌",
|
||||
"status": "已解除",
|
||||
"occurTime": "2025/10/10 20:29",
|
||||
"estimateRecoverTime": "2025/10/10 20:29",
|
||||
"disasterType": "边坡坍塌"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "彭水S523发生边坡坍塌",
|
||||
"status": "未解除",
|
||||
"occurTime": "2025/10/10 20:29",
|
||||
"estimateRecoverTime": "2025/10/10 20:29",
|
||||
"disasterType": "路基沉陷"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"title": "梁平蟠龙镇G318发生山体滑坡",
|
||||
"status": "已解除",
|
||||
"occurTime": "2025/10/10 20:29",
|
||||
"estimateRecoverTime": "2025/10/10 20:29",
|
||||
"disasterType": "山体滑坡"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"title": "重庆市大足区XX县G201行道树倒塌",
|
||||
"status": "已解除",
|
||||
"occurTime": "2025/10/10 20:29",
|
||||
"estimateRecoverTime": "2025/10/10 20:29",
|
||||
"disasterType": "行道树倒塌"
|
||||
}
|
||||
]
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"occurLocation": "G108国道 K2250+300处",
|
||||
"occurTime": "2024-07-15 14:30:00",
|
||||
"occurTime": null,
|
||||
"roadConditionType": "国道",
|
||||
"routeNo": "G108",
|
||||
"event": {
|
||||
@ -10,17 +10,13 @@
|
||||
"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": "抢修中",
|
||||
"repairProgress": "抢险中",
|
||||
"reporterUnit": "武侯区交通运输局",
|
||||
"startStakeLat": "30.652145",
|
||||
"startStakeLng": "104.075632",
|
||||
"startStakeNo": "K2250+300"
|
||||
},
|
||||
"report": {
|
||||
@ -28,9 +24,9 @@
|
||||
"strandedPersonCount": 12,
|
||||
"deadCount": 0,
|
||||
"strandedVehicleCount": 12,
|
||||
"disposalMeasures": "halfClose,bypass",
|
||||
"actualRecoverTime": "2024-07-17 12:00:00",
|
||||
"expectRecoverTime": "2024-07-18 18:00:00",
|
||||
"disposalMeasures": null,
|
||||
"actualRecoverTime": null,
|
||||
"expectRecoverTime": null,
|
||||
"injuredCount": 1,
|
||||
"investedFunds": 35.8,
|
||||
"investedMachinery": 6,
|
||||
|
||||
@ -1,21 +1,19 @@
|
||||
<template>
|
||||
<div class="breadcrumb-container">
|
||||
<el-breadcrumb separator="/">
|
||||
<el-breadcrumb-item
|
||||
v-for="(item, index) in breadcrumbList"
|
||||
:key="index"
|
||||
:class="{ 'is-link': index < breadcrumbList.length - 1 }"
|
||||
@click="handleBreadcrumbClick(item, index)"
|
||||
>
|
||||
<el-breadcrumb-item v-for="(item, index) in breadcrumbList" :key="index"
|
||||
:class="{ 'is-link': index < breadcrumbList.length - 1 }" @click="handleBreadcrumbClick(item, index)">
|
||||
{{ item.title }}
|
||||
</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
|
||||
|
||||
<!-- 关闭按钮组 -->
|
||||
<div class="breadcrumb-actions" v-if="breadcrumbList.length > 1">
|
||||
<el-dropdown trigger="click" @command="handleCloseAction">
|
||||
<el-button type="text" size="small" class="close-btn">
|
||||
<el-icon><Close /></el-icon>
|
||||
<el-icon>
|
||||
<Close />
|
||||
</el-icon>
|
||||
关闭
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
@ -23,7 +21,8 @@
|
||||
<el-dropdown-item command="close-current">关闭当前页</el-dropdown-item>
|
||||
<el-dropdown-item command="close-other" :disabled="breadcrumbList.length <= 2">关闭其他页</el-dropdown-item>
|
||||
<el-dropdown-item command="close-left" :disabled="currentIndex === 0">关闭左侧</el-dropdown-item>
|
||||
<el-dropdown-item command="close-right" :disabled="currentIndex === breadcrumbList.length - 1">关闭右侧</el-dropdown-item>
|
||||
<el-dropdown-item command="close-right"
|
||||
:disabled="currentIndex === breadcrumbList.length - 1">关闭右侧</el-dropdown-item>
|
||||
<el-dropdown-item command="close-all" :disabled="breadcrumbList.length <= 1">全部关闭</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
@ -37,6 +36,11 @@ import { ref, watch, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { Close } from '@element-plus/icons-vue'
|
||||
|
||||
// 从路由实例获取所有路由配置
|
||||
const router = useRouter()
|
||||
const routes = router.getRoutes()
|
||||
const route = useRoute()
|
||||
|
||||
const props = defineProps({
|
||||
homeTitle: {
|
||||
type: String,
|
||||
@ -46,54 +50,60 @@ const props = defineProps({
|
||||
|
||||
const emit = defineEmits(['breadcrumb-change'])
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
const breadcrumbList = ref([])
|
||||
const currentIndex = ref(0)
|
||||
|
||||
|
||||
// 生成面包屑数据
|
||||
const generateBreadcrumb = () => {
|
||||
const matched = route.matched.filter(item => item.meta && item.meta.breadcrumb !== false)
|
||||
|
||||
// 基础面包屑:首页
|
||||
breadcrumbList.value = [
|
||||
{
|
||||
title: props.homeTitle,
|
||||
path: '/',
|
||||
name: 'Home'
|
||||
// 生成面包屑数据
|
||||
const generateBreadcrumb = () => {
|
||||
const matched = route.matched.filter(item => item.meta && item.meta.breadcrumb !== false)
|
||||
|
||||
// 基础面包屑:首页
|
||||
breadcrumbList.value = [
|
||||
{
|
||||
title: props.homeTitle,
|
||||
path: '/',
|
||||
name: 'Home'
|
||||
}
|
||||
]
|
||||
|
||||
const currentRoute = route.matched[route.matched.length - 1]
|
||||
const currentPath = route.path
|
||||
|
||||
// 如果有父路由配置,自动构建父子结构
|
||||
if (currentRoute && currentRoute.meta && currentRoute.meta.parentRoute) {
|
||||
const parentRouteName = currentRoute.meta.parentRoute
|
||||
|
||||
// 查找父路由信息
|
||||
const parentRoute = routes.find(r => r.name === parentRouteName)
|
||||
if (parentRoute && parentRoute.meta && parentRoute.meta.title) {
|
||||
// 添加父级路由
|
||||
breadcrumbList.value.push({
|
||||
title: parentRoute.meta.title,
|
||||
path: parentRoute.path,
|
||||
name: parentRoute.name,
|
||||
meta: parentRoute.meta
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const currentPath = route.path
|
||||
|
||||
// 特殊处理:驻地台账页面(响应预警的子页面)
|
||||
if (currentPath.includes('/ledgerManagement')) {
|
||||
// 添加响应预警(父级)
|
||||
breadcrumbList.value.push({
|
||||
title: '响应预警',
|
||||
path: '/warningManagement',
|
||||
name: 'warningManagement',
|
||||
meta: { title: '响应预警' }
|
||||
})
|
||||
|
||||
// 添加驻地台账(当前页)
|
||||
breadcrumbList.value.push({
|
||||
title: '驻地台账',
|
||||
path: currentPath,
|
||||
name: 'ledgerManagement',
|
||||
meta: { title: '驻地台账' }
|
||||
})
|
||||
} else {
|
||||
// 普通路由处理
|
||||
|
||||
// 普通路由处理(包括子页面)
|
||||
matched.forEach((record, index) => {
|
||||
// 跳过根路径(已经在上面添加了首页)
|
||||
if (record.path === '/') return
|
||||
|
||||
|
||||
// 如果是子页面且已经有父级,跳过重复添加
|
||||
if (index === matched.length - 1 && currentRoute && currentRoute.meta && currentRoute.meta.parentRoute) {
|
||||
// 检查当前记录是否就是父路由本身,如果是则跳过(因为上面已经添加了)
|
||||
const isParentAlreadyAdded = breadcrumbList.value.some(item => item.name === currentRoute.meta.parentRoute)
|
||||
if (isParentAlreadyAdded && record.name === currentRoute.meta.parentRoute) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (record.meta && record.meta.title) {
|
||||
let fullPath = record.path
|
||||
|
||||
|
||||
// 处理相对路径
|
||||
if (!fullPath.startsWith('/') && index > 0) {
|
||||
const parentPath = breadcrumbList.value[breadcrumbList.value.length - 1]?.path || ''
|
||||
@ -101,7 +111,7 @@ const generateBreadcrumb = () => {
|
||||
fullPath = parentPath + (parentPath.endsWith('/') ? '' : '/') + record.path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
breadcrumbList.value.push({
|
||||
title: record.meta.title,
|
||||
path: fullPath,
|
||||
@ -110,12 +120,11 @@ const generateBreadcrumb = () => {
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 更新当前索引
|
||||
const currentIndexInList = breadcrumbList.value.findIndex(item => item.path === currentPath)
|
||||
currentIndex.value = currentIndexInList >= 0 ? currentIndexInList : breadcrumbList.value.length - 1
|
||||
}
|
||||
|
||||
// 更新当前索引
|
||||
const currentIndexInList = breadcrumbList.value.findIndex(item => item.path === currentPath)
|
||||
currentIndex.value = currentIndexInList >= 0 ? currentIndexInList : breadcrumbList.value.length - 1
|
||||
}
|
||||
|
||||
// 处理面包屑点击
|
||||
const handleBreadcrumbClick = (item, index) => {
|
||||
@ -148,10 +157,10 @@ const handleCloseAction = (command) => {
|
||||
// 关闭当前页
|
||||
const closeCurrentPage = () => {
|
||||
if (breadcrumbList.value.length <= 1) return
|
||||
|
||||
|
||||
const currentPath = route.path
|
||||
const currentIndex = breadcrumbList.value.findIndex(item => item.path === currentPath)
|
||||
|
||||
|
||||
if (currentIndex > 0) {
|
||||
// 跳转到前一个页面
|
||||
const prevPage = breadcrumbList.value[currentIndex - 1]
|
||||
@ -163,16 +172,16 @@ const closeCurrentPage = () => {
|
||||
// 关闭其他页
|
||||
const closeOtherPages = () => {
|
||||
if (breadcrumbList.value.length <= 2) return
|
||||
|
||||
|
||||
const currentPath = route.path
|
||||
const currentItem = breadcrumbList.value.find(item => item.path === currentPath)
|
||||
|
||||
|
||||
if (currentItem) {
|
||||
breadcrumbList.value = [
|
||||
breadcrumbList.value[0], // 保留首页
|
||||
currentItem
|
||||
]
|
||||
|
||||
|
||||
// 触发路由跳转逻辑
|
||||
emit('breadcrumb-change', breadcrumbList.value)
|
||||
}
|
||||
@ -181,15 +190,15 @@ const closeOtherPages = () => {
|
||||
// 关闭左侧页
|
||||
const closeLeftPages = () => {
|
||||
if (currentIndex.value <= 1) return
|
||||
|
||||
|
||||
const currentItem = breadcrumbList.value[currentIndex.value]
|
||||
breadcrumbList.value = [
|
||||
breadcrumbList.value[0], // 保留首页
|
||||
currentItem
|
||||
]
|
||||
|
||||
|
||||
// 如果当前不在首页,需要重新构建路径
|
||||
let targetPath = '/'
|
||||
let targetPath = '/'
|
||||
if (currentItem.path !== '/') {
|
||||
targetPath = currentItem.path
|
||||
}
|
||||
@ -199,9 +208,9 @@ const closeLeftPages = () => {
|
||||
// 关闭右侧页
|
||||
const closeRightPages = () => {
|
||||
if (currentIndex.value >= breadcrumbList.value.length - 1) return
|
||||
|
||||
|
||||
breadcrumbList.value = breadcrumbList.value.slice(0, currentIndex.value + 1)
|
||||
|
||||
|
||||
// 跳转到最后一个保留的页面
|
||||
const lastItem = breadcrumbList.value[breadcrumbList.value.length - 1]
|
||||
router.push(lastItem.path)
|
||||
@ -243,23 +252,23 @@ defineExpose({
|
||||
|
||||
:deep(.el-breadcrumb) {
|
||||
font-size: 14px;
|
||||
|
||||
|
||||
.el-breadcrumb__item {
|
||||
.el-breadcrumb__inner {
|
||||
color: #606266;
|
||||
font-weight: 400;
|
||||
|
||||
|
||||
&.is-link {
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
|
||||
|
||||
&:hover {
|
||||
color: #66b1ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&:last-child .el-breadcrumb__inner {
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
@ -271,7 +280,7 @@ defineExpose({
|
||||
.breadcrumb-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
|
||||
.close-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -281,12 +290,12 @@ defineExpose({
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f7fa;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
|
||||
.el-icon {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
68
packages/screen/src/component/FileUpload/FileUpload.vue
Normal file
68
packages/screen/src/component/FileUpload/FileUpload.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<!-- FileUpload.vue -->
|
||||
<template>
|
||||
<div class="file-upload">
|
||||
<UploadBlock v-if="!readonly" v-model="modelValue" :type="type" :multiple="multiple" :limit="limit" :placeholder="placeholder" :customFileType="fileType" />
|
||||
<PreviewBlock :readonly="readonly" v-model:file-list="modelValue" :type="type" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import UploadBlock from './UploadBlock.vue'
|
||||
import PreviewBlock from './PreviewBlock.vue'
|
||||
|
||||
const modelValue = defineModel('modelValue', {
|
||||
type: Array,
|
||||
default: () => []
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
// 文件类型: 'image' 或其他
|
||||
type: {
|
||||
type: String,
|
||||
default: 'image'
|
||||
},
|
||||
// 上传接口地址
|
||||
action: {
|
||||
type: String
|
||||
},
|
||||
// 上传请求头
|
||||
headers: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
// 是否支持多选
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 最大上传数量
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 9
|
||||
},
|
||||
// 占位提示文字
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 只读模式
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 自定义fileType
|
||||
fileType: {
|
||||
type: Number,
|
||||
default: null,
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'upload-success', 'upload-error', 'remove'])
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.file-upload {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
242
packages/screen/src/component/FileUpload/PreviewBlock.vue
Normal file
242
packages/screen/src/component/FileUpload/PreviewBlock.vue
Normal file
@ -0,0 +1,242 @@
|
||||
<!-- PreviewBlock.vue - 预览模块 -->
|
||||
<template>
|
||||
<div class="preview-block">
|
||||
<div v-if="showFileList && showFileList.length" class="preview-list">
|
||||
<div
|
||||
v-for="file in showFileList"
|
||||
:key="file.uid"
|
||||
class="preview-item"
|
||||
>
|
||||
<!-- 图片类型且为图片文件时显示预览图 -->
|
||||
<div v-if="type === 'image' && isImageFile(file)" class="preview-image">
|
||||
<el-image
|
||||
:src="file.fileUrl"
|
||||
:preview-src-list="getImageUrlList()"
|
||||
fit="cover"
|
||||
:initial-index="getImageIndex(file)"
|
||||
>
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<el-icon><Picture /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</div>
|
||||
<!-- 非图片或非图片类型显示图标 -->
|
||||
<div v-else class="preview-icon">
|
||||
<el-icon :size="40">
|
||||
<component :is="getFileIcon(file)" />
|
||||
</el-icon>
|
||||
</div>
|
||||
|
||||
<!-- <div class="preview-info">
|
||||
<span class="file-name" :title="file.fileName">{{ file.fileName }}</span>
|
||||
<span class="file-size">{{ formatFileSize(file.fileSize) }}</span>
|
||||
</div> -->
|
||||
|
||||
<div class="preview-actions" v-if="!readonly">
|
||||
<el-button
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
circle
|
||||
size="small"
|
||||
@click="handleRemove(file)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div v-else class="preview-empty">
|
||||
<el-empty description="暂无文件" :image-size="80" />
|
||||
</div> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { Picture, Document, VideoCamera, Delete } from '@element-plus/icons-vue'
|
||||
|
||||
const props = defineProps({
|
||||
fileList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'image'
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const showFileList = computed(() => {
|
||||
if(!props.fileList?.length) return []
|
||||
if(props.type == 'image') return props.fileList.filter(file => isImageFile(file))
|
||||
if(props.type == 'video') return props.fileList.filter(file => isVideoFile(file))
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:fileList'])
|
||||
|
||||
// 判断是否为图片文件
|
||||
const isImageFile = (file) => {
|
||||
// 根据url后缀判断
|
||||
const imageExtensions = /\.(jpg|jpeg|png|gif|webp|bmp|svg)$/i
|
||||
if (file.fileUrl && imageExtensions.test(file.fileUrl)) return true
|
||||
// 根据文件类型判断
|
||||
if (file.type && file.type.startsWith('image/')) return true
|
||||
return false
|
||||
}
|
||||
|
||||
const isVideoFile = (file) => {
|
||||
// 根据url后缀判断
|
||||
const videoExtensions = /\.(mp4|avi|mov|wmv|flv|mkv)$/i
|
||||
if (file.fileUrl && videoExtensions.test(file.fileUrl)) return true
|
||||
}
|
||||
|
||||
// 获取所有图片的URL列表(用于预览)
|
||||
const getImageUrlList = () => {
|
||||
return props.fileList
|
||||
.filter(file => isImageFile(file))
|
||||
.map(file => file.fileUrl)
|
||||
}
|
||||
|
||||
// 获取当前图片在预览列表中的索引
|
||||
const getImageIndex = (currentFile) => {
|
||||
const imageUrls = getImageUrlList()
|
||||
return imageUrls.findIndex(url => url === currentFile.fileUrl)
|
||||
}
|
||||
|
||||
// 根据文件类型获取对应图标
|
||||
const getFileIcon = (file) => {
|
||||
const ext = file.fileName?.split('.').pop()?.toLowerCase() || ''
|
||||
|
||||
// 视频文件
|
||||
if (['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv'].includes(ext)) {
|
||||
return VideoCamera
|
||||
}
|
||||
// 音频文件
|
||||
if (['mp3', 'wav', 'flac', 'aac', 'ogg'].includes(ext)) {
|
||||
return VideoCamera
|
||||
}
|
||||
// 默认文档图标
|
||||
return Document
|
||||
}
|
||||
|
||||
// 格式化文件大小
|
||||
const formatFileSize = (size) => {
|
||||
if (!size) return ''
|
||||
if (size < 1024) return size + ' B'
|
||||
if (size < 1024 * 1024) return (size / 1024).toFixed(2) + ' KB'
|
||||
return (size / (1024 * 1024)).toFixed(2) + ' MB'
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
const handleRemove = (file) => {
|
||||
const index = props.fileList.findIndex(item => item.fileUrl === file.fileUrl)
|
||||
emit('update:fileList', [...props.fileList.slice(0, index), ...props.fileList.slice(index + 1)] )
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.preview-block {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.preview-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.preview-item {
|
||||
position: relative;
|
||||
width: 120px;
|
||||
border: 1px solid #ebebeb;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.preview-item:hover {
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.preview-image :deep(.el-image) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.preview-image :deep(.el-image__inner) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.image-slot {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f5f7fa;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.preview-icon {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f5f7fa;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.preview-info {
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #ebebeb;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
display: block;
|
||||
font-size: 10px;
|
||||
color: #909399;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.preview-actions {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.preview-item:hover .preview-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.preview-empty {
|
||||
padding: 40px 0;
|
||||
}
|
||||
</style>
|
||||
148
packages/screen/src/component/FileUpload/UploadBlock.vue
Normal file
148
packages/screen/src/component/FileUpload/UploadBlock.vue
Normal file
@ -0,0 +1,148 @@
|
||||
<!-- UploadBlock.vue -->
|
||||
<template>
|
||||
<div class="upload-block">
|
||||
<el-button type="primary" @click="showFileInput">
|
||||
<el-icon>
|
||||
<Upload />
|
||||
</el-icon>选择文件</el-button>
|
||||
<input class="inner-file" ref="fileRef" type="file" @change="uploadFiles" :accept="getAccept()" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { Upload } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { request } from '@/utils/request'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'image'
|
||||
},
|
||||
headers: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 9
|
||||
},
|
||||
// 占位提示文字
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 自定义fileType
|
||||
customFileType: {
|
||||
type: Number,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const fileRef = ref(null)
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
// 按钮文字
|
||||
const buttonText = computed(() => {
|
||||
return props.placeholder || '点击上传'
|
||||
})
|
||||
|
||||
// 默认提示文字
|
||||
const defaultTip = computed(() => {
|
||||
if (props.type === 'image') {
|
||||
return '支持图片格式,单个文件不超过 10MB'
|
||||
}
|
||||
return '支持文件格式,单个文件不超过 10MB'
|
||||
})
|
||||
|
||||
const showFileInput = () => {
|
||||
fileRef.value.click()
|
||||
}
|
||||
|
||||
// 上传前校验
|
||||
const beforeUpload = (file) => {
|
||||
const isLt10M = file.size / 1024 / 1024 < 10
|
||||
if (!isLt10M) {
|
||||
ElMessage.error('文件大小不能超过 10MB!')
|
||||
return false
|
||||
}
|
||||
|
||||
if (props.type === 'image') {
|
||||
const isImage = file.type.startsWith('image/')
|
||||
if (!isImage) {
|
||||
ElMessage.error('只能上传图片文件!')
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const getAccept = () => {
|
||||
if (props.type === 'image') {
|
||||
return 'image/*'
|
||||
}
|
||||
if (props.type == 'video') {
|
||||
return 'video/*'
|
||||
}
|
||||
return '*/*'
|
||||
}
|
||||
|
||||
const uploadFiles = async (event) => {
|
||||
const file = event.target.files[0]
|
||||
try {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/file/upload',
|
||||
method: 'post',
|
||||
data: formData
|
||||
})
|
||||
if (res.code === '00000') {
|
||||
let fileType = 3
|
||||
const name = file.name
|
||||
if(props.type == 'image') fileType = 1
|
||||
if(props.type == 'video') fileType = 2
|
||||
|
||||
const url = res.data
|
||||
const fileData = {
|
||||
fileName: name,
|
||||
fileUrl: url,
|
||||
fileType: props.customFileType || fileType,
|
||||
fileSize: file.size
|
||||
}
|
||||
emit('update:modelValue', [...props.modelValue, fileData])
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
fileRef.value.value = null
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.upload-block {
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.inner-file {
|
||||
z-index: 0;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
||||
@ -24,7 +24,7 @@
|
||||
<template #footer>
|
||||
<div class="dialog-footer" :class="footerClass">
|
||||
<el-button v-if="onConfirm" class="button" size="large" type="primary" @click="onConfirm"> {{ onConfirmName || '保存' }} </el-button>
|
||||
<el-button class="button" size="large" :type="onCancelType" @click="onCancel"> {{ onCancelName || '取消' }} </el-button>
|
||||
<el-button v-if="onCancel" class="button" size="large" :type="onCancelType" @click="onCancel"> {{ onCancelName || '取消' }} </el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
@ -15,8 +15,8 @@
|
||||
|
||||
<template #footer>
|
||||
<div class="drawer-footer">
|
||||
<el-button @click="onCancel">取消</el-button>
|
||||
<el-button type="primary" @click="onConfirm">确认</el-button>
|
||||
<el-button v-if="props.onCancel" @click="onCancel">取消</el-button>
|
||||
<el-button v-if="props.onConfirm" type="primary" @click="onConfirm">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
|
||||
142
packages/screen/src/component/VideoPreviewDialog.vue
Normal file
142
packages/screen/src/component/VideoPreviewDialog.vue
Normal file
@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
width="80%"
|
||||
:show-close="true"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="true"
|
||||
class="video-preview-dialog"
|
||||
@close="handleClose"
|
||||
>
|
||||
<div class="video-container">
|
||||
<video
|
||||
ref="videoRef"
|
||||
:src="currentVideoUrl"
|
||||
class="video-player"
|
||||
controls
|
||||
autoplay
|
||||
controlslist="nodownload"
|
||||
></video>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="handleClose" type="danger" plain>关闭预览</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, onUnmounted } from 'vue'
|
||||
|
||||
// 当前视频URL
|
||||
const currentVideoUrl = ref('')
|
||||
|
||||
// 弹窗标题
|
||||
const dialogTitle = ref('视频预览')
|
||||
|
||||
// 弹窗显示状态
|
||||
const dialogVisible = ref(false)
|
||||
|
||||
// DOM 引用
|
||||
const videoRef = ref(null)
|
||||
|
||||
// 显示弹窗
|
||||
const show = (options) => {
|
||||
if (!options || !options.url) {
|
||||
console.error('视频URL不能为空')
|
||||
return
|
||||
}
|
||||
|
||||
currentVideoUrl.value = options.url
|
||||
dialogTitle.value = options.title || '视频预览'
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
const close = () => {
|
||||
dialogVisible.value = false
|
||||
// 延迟清空视频URL,避免视频元素销毁时的问题
|
||||
setTimeout(() => {
|
||||
if (!dialogVisible.value) {
|
||||
currentVideoUrl.value = ''
|
||||
dialogTitle.value = '视频预览'
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
// 键盘事件处理
|
||||
const handleKeydown = (event) => {
|
||||
if (event.key === 'Escape' && dialogVisible.value) {
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
||||
// 监听弹窗关闭
|
||||
const handleClose = () => {
|
||||
close()
|
||||
}
|
||||
|
||||
// 监听弹窗显示状态,添加/移除键盘监听
|
||||
watch(dialogVisible, (visible) => {
|
||||
if (visible) {
|
||||
document.addEventListener('keydown', handleKeydown)
|
||||
} else {
|
||||
document.removeEventListener('keydown', handleKeydown)
|
||||
}
|
||||
})
|
||||
|
||||
// 组件卸载时清理
|
||||
onUnmounted(() => {
|
||||
document.removeEventListener('keydown', handleKeydown)
|
||||
})
|
||||
|
||||
// 对外暴露方法
|
||||
defineExpose({
|
||||
show,
|
||||
close
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.video-preview-dialog :deep(.el-dialog) {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.video-preview-dialog :deep(.el-dialog__body) {
|
||||
padding: 0;
|
||||
max-height: 70vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.video-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.video-player {
|
||||
width: 100%;
|
||||
max-height: 70vh;
|
||||
object-fit: contain;
|
||||
outline: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.video-preview-dialog :deep(.el-dialog__footer) {
|
||||
padding: 16px 20px;
|
||||
border-top: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
@ -1,4 +1,3 @@
|
||||
import component from 'element-plus/es/components/tree-select/src/tree-select-option.mjs'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
const routes = [
|
||||
@ -118,17 +117,17 @@ const routes = [
|
||||
},
|
||||
component: () => import('../views/ConstructionDepartment/ConstructionDepartment.vue')
|
||||
},
|
||||
// 响应预警
|
||||
// 响应预警 - 建设处
|
||||
{
|
||||
path: '/warningManagement',
|
||||
name: 'warningManagement',
|
||||
component: () => import('../views/WarningManagement/index.vue'),
|
||||
component: () => import('../views/WarningManagement/construction/index.vue'),
|
||||
meta: {
|
||||
title: '响应预警',
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
// 驻地台账 - 作为独立的页面,但在面包屑中显示为响应预警的子页面
|
||||
// 驻地台账 - 建设处
|
||||
{
|
||||
path: '/ledgerManagement',
|
||||
name: 'ledgerManagement',
|
||||
@ -136,23 +135,88 @@ const routes = [
|
||||
meta: {
|
||||
title: '驻地台账',
|
||||
breadcrumb: true,
|
||||
parentRoute: 'warningManagement' // 用于在面包屑中建立父子关系
|
||||
parentRoute: 'warningManagement'
|
||||
}
|
||||
},
|
||||
// 项目管理
|
||||
// 响应预警 - 区县级
|
||||
{
|
||||
path: '/warningManagement2',
|
||||
name: 'warningManagement2',
|
||||
component: () => import('../views/WarningManagement/district/index.vue'),
|
||||
meta: {
|
||||
title: '响应预警',
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
// 驻地台账 - 区县级
|
||||
{
|
||||
path: '/ledgerManagement2',
|
||||
name: 'ledgerManagement2',
|
||||
component: () => import('../views/LedgerManagement/index.vue'),
|
||||
meta: {
|
||||
title: '驻地台账',
|
||||
breadcrumb: true,
|
||||
parentRoute: 'warningManagement2'
|
||||
}
|
||||
},
|
||||
|
||||
// 项目管理 - 区县
|
||||
{
|
||||
path: '/projectManagement',
|
||||
name: 'projectManagement',
|
||||
component: () => import('../views/ProjectManagement_Rebuild/index.vue'),
|
||||
component: () => import('../views/ProjectManagement_Rebuild/district/index.vue'),
|
||||
meta: {
|
||||
title: '项目管理',
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/projectAdd/:data?',
|
||||
name: 'projectAdd',
|
||||
component: () => import('../views/ProjectManagement_Rebuild/district/projectAddPage.vue'),
|
||||
meta: {
|
||||
title: '项目填报',
|
||||
breadcrumb: true,
|
||||
parentRoute: 'projectManagement'
|
||||
}
|
||||
},
|
||||
// 项目详情 - 区县版本
|
||||
{
|
||||
path: '/projectDetail/:data?',
|
||||
name: 'projectDetail',
|
||||
component: () => import('../views/ProjectManagement_Rebuild/district/projectDetailPage.vue'),
|
||||
meta: {
|
||||
title: '项目详情',
|
||||
breadcrumb: true,
|
||||
parentRoute: 'projectManagement'
|
||||
}
|
||||
},
|
||||
// 项目管理 - 业务部门
|
||||
{
|
||||
path: '/projectManagement2',
|
||||
name: 'projectManagement2',
|
||||
component: () => import('../views/ProjectManagement_Rebuild/business/index.vue'),
|
||||
meta: {
|
||||
title: '项目管理',
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
// 项目详情 - 业务部门版本
|
||||
{
|
||||
path: '/projectDetail2/:data?',
|
||||
name: 'projectDetail2',
|
||||
component: () => import('../views/ProjectManagement_Rebuild/business/projectDetailPage.vue'),
|
||||
meta: {
|
||||
title: '项目详情',
|
||||
breadcrumb: true,
|
||||
parentRoute: 'projectManagement2'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
path: '/disasterManagement',
|
||||
name: 'disasterManagement',
|
||||
component: () => import('../views/DisasterManagement/DisasterManagement.vue'),
|
||||
component: () => import('../views/DisasterManagement/DisasterManagementPC.vue'),
|
||||
meta: {
|
||||
title: '灾害巡检事件',
|
||||
breadcrumb: true
|
||||
@ -161,16 +225,16 @@ const routes = [
|
||||
{
|
||||
path: '/disasterReport',
|
||||
name: 'DisasterReport',
|
||||
component: () => import('../views/DisasterManagement/DisasterReport/DisasterReport.vue'),
|
||||
component: () => import('../views/DisasterManagement/DisasterReport/DisasterReportPC.vue'),
|
||||
meta: {
|
||||
title: '灾毁事件填报',
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
path: '/waterDisasterDetail',
|
||||
name: 'WaterDisasterDetail',
|
||||
component: () => import('../views/DisasterManagement/DisasterDetail/WaterDisasterDetail.vue'),
|
||||
component: () => import('../views/DisasterManagement/DisasterDetail/WaterDisasterDetailPC.vue'),
|
||||
meta: {
|
||||
title: '水毁事件详情',
|
||||
breadcrumb: true
|
||||
|
||||
@ -3,19 +3,19 @@
|
||||
<!-- 合并后的单个卡片 -->
|
||||
<el-card class="form-card" shadow="never">
|
||||
<div slot="header" class="card-header">
|
||||
<span>续保信息</span>
|
||||
<span>续报信息</span>
|
||||
</div>
|
||||
|
||||
<!-- 所有表单项合并到一个区域,每行一个 -->
|
||||
<el-form :model="formData" label-width="120px" size="small">
|
||||
<!-- 处置措施 -->
|
||||
<el-form-item label="处置措施">
|
||||
<el-radio-group v-model="disposalMeasureValue">
|
||||
<el-radio label="halfClose">半幅封闭</el-radio>
|
||||
<el-radio label="fullClose">全副封闭</el-radio>
|
||||
<el-radio label="bypass">便道通行</el-radio>
|
||||
<el-radio label="normal">正常通行</el-radio>
|
||||
</el-radio-group>
|
||||
<el-select v-model="formData.report.disposalMeasures">
|
||||
<el-option label="半幅封闭" value="半幅封闭" />
|
||||
<el-option label="全副封闭" value="全副封闭" />
|
||||
<el-option label="便道通行" value="便道通行" />
|
||||
<el-option label="正常通行" value="正常通行" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 预计恢复时间 -->
|
||||
@ -138,7 +138,7 @@
|
||||
import { ref, reactive, watch, computed } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { request } from '@shared/utils/request'
|
||||
import LossList from '../DisasterReport/LossList.vue'
|
||||
import LossList from '../DisasterReport/WaterDisasterLossListPC.vue'
|
||||
|
||||
// Props 定义
|
||||
const props = defineProps({
|
||||
@ -164,8 +164,6 @@ const formData = reactive({
|
||||
contactPhone: '',
|
||||
damageCount: '',
|
||||
district: '',
|
||||
endStakeLat: '',
|
||||
endStakeLng: '',
|
||||
endStakeNo: '',
|
||||
estimatedRecoveryCost: '',
|
||||
inspectionMileage: '',
|
||||
@ -173,8 +171,6 @@ const formData = reactive({
|
||||
needsRecovery: '',
|
||||
repairProgress: '',
|
||||
reporterUnit: '',
|
||||
startStakeLat: '',
|
||||
startStakeLng: '',
|
||||
startStakeNo: ''
|
||||
},
|
||||
report: {
|
||||
@ -216,8 +212,8 @@ const blockedOptions = [
|
||||
]
|
||||
|
||||
const repairProgressOptions = [
|
||||
{ label: '未抢修', value: '未抢修' },
|
||||
{ label: '抢修中', value: '抢修中' },
|
||||
{ label: '未抢险', value: '未抢险' },
|
||||
{ label: '抢险中', value: '抢险中' },
|
||||
{ label: '已完成', value: '已完成' }
|
||||
]
|
||||
|
||||
@ -295,20 +291,6 @@ const calibrateTime = () => {
|
||||
ElMessage.success('时间已校准为当前时间')
|
||||
}
|
||||
|
||||
// 校准起点经纬度
|
||||
const calibrateStartCoord = () => {
|
||||
formData.event.startStakeLng = '108.41763025'
|
||||
formData.event.startStakeLat = '108.41763025'
|
||||
ElMessage.success('起点经纬度已校准')
|
||||
}
|
||||
|
||||
// 校准止点经纬度
|
||||
const calibrateEndCoord = () => {
|
||||
formData.event.endStakeLng = '108.41763025'
|
||||
formData.event.endStakeLat = '108.41763025'
|
||||
ElMessage.success('止点经纬度已校准')
|
||||
}
|
||||
|
||||
// 表单验证
|
||||
const validate = () => {
|
||||
if (!formData.occurTime) {
|
||||
@ -341,8 +323,6 @@ const resetForm = () => {
|
||||
contactPhone: '',
|
||||
damageCount: '',
|
||||
district: '',
|
||||
endStakeLat: '',
|
||||
endStakeLng: '',
|
||||
endStakeNo: '',
|
||||
estimatedRecoveryCost: '',
|
||||
inspectionMileage: '',
|
||||
@ -350,8 +330,6 @@ const resetForm = () => {
|
||||
needsRecovery: '',
|
||||
repairProgress: '',
|
||||
reporterUnit: '',
|
||||
startStakeLat: '',
|
||||
startStakeLng: '',
|
||||
startStakeNo: ''
|
||||
},
|
||||
report: {
|
||||
@ -426,8 +404,6 @@ defineExpose({
|
||||
getFormData,
|
||||
resetForm,
|
||||
calibrateTime,
|
||||
calibrateStartCoord,
|
||||
calibrateEndCoord
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -47,16 +47,25 @@
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">抢修进度:</span>
|
||||
<span class="info-label">抢险进度:</span>
|
||||
<span class="info-value">{{ detailData.event?.repairProgress || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">处理措施:</span>
|
||||
<span class="info-value">{{ getBaseDisposalMeasures() }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">水毁处数:</span>
|
||||
<span class="info-value">{{ detailData.event?.damageCount || 0 }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">阻断里程:</span>
|
||||
@ -66,66 +75,24 @@
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">发生时间:</span>
|
||||
<span class="info-value">{{ detailData.occurTime || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">线路编号:</span>
|
||||
<span class="info-value">{{ detailData.routeNo || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">地点路线:</span>
|
||||
<span class="info-value">{{ detailData.occurLocation || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">起点桩号:</span>
|
||||
<span class="info-value">{{ detailData.event?.startStakeNo || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">起点桩经度:</span>
|
||||
<span class="info-value">{{ detailData.event?.startStakeLng || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">起点桩纬度:</span>
|
||||
<span class="info-value">{{ detailData.event?.startStakeLat || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">止点桩号:</span>
|
||||
<span class="info-value">{{ detailData.event?.endStakeNo || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">止点桩经度:</span>
|
||||
<span class="info-value">{{ detailData.event?.endStakeLng || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">止点桩纬度:</span>
|
||||
<span class="info-value">{{ detailData.event?.endStakeLat || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
@ -141,55 +108,37 @@
|
||||
<span class="info-value">{{ detailData.event?.blockedPointName || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">上报区县:</span>
|
||||
<span class="info-value">{{ detailData.event?.district || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">巡查里程:</span>
|
||||
<span class="info-value">{{ detailData.event?.inspectionMileage ? detailData.event.inspectionMileage + '公里' : '-' }}</span>
|
||||
<span class="info-label">所属区县:</span>
|
||||
<span class="info-value">{{ detailData.event?.district || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">发生时间:</span>
|
||||
<span class="info-value">{{ detailData.occurTime || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">是否恢复重建:</span>
|
||||
<span class="info-value">{{ detailData.event?.needsRecovery ? '是' : '否' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-col :span="16">
|
||||
<div class="info-item">
|
||||
<span class="info-label">恢复重建预估费用:</span>
|
||||
<span class="info-value">{{ detailData.event?.estimatedRecoveryCost ? detailData.event.estimatedRecoveryCost + '万元' : '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="info-row">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">联系人:</span>
|
||||
<span class="info-value">{{ detailData.event?.contactPerson || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">联系电话:</span>
|
||||
<span class="info-value">{{ detailData.event?.contactPhone || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">填报单位:</span>
|
||||
<span class="info-value">{{ detailData.event?.reporterUnit || '-' }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<!-- 填报信息卡片 -->
|
||||
@ -204,52 +153,71 @@
|
||||
<div v-for="(report, index) in allReports" :key="index" class="report-section">
|
||||
<div class="report-header">
|
||||
<span class="report-title">{{ report?.title }}</span>
|
||||
<span class="report-meta">{{ report.reporterName || '-' }} {{ report.reportTime || '-' }}</span>
|
||||
<span class="report-meta">时间:{{ report.reportTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="content-wrapper">
|
||||
<div class="basic-info-wrapper">
|
||||
<div class="info-list">
|
||||
<div class="info-item">
|
||||
<span class="info-label">现场描述:</span>
|
||||
<span class="info-value">{{ report.siteDescription || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">处置措施:</span>
|
||||
<span class="info-value">{{ report.disposalMeasures || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">实际恢复时间:</span>
|
||||
<span class="info-value">{{ report.actualRecoverTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">预计恢复时间:</span>
|
||||
<span class="info-value">{{ report.expectRecoverTime || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="info-list">
|
||||
<div class="info-item">
|
||||
<span class="info-label">处置情况:</span>
|
||||
<span class="info-value">{{ formatDisposalMeasures(report.disposalMeasures) || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">塌方及损失:</span>
|
||||
<span class="info-value">{{ getLossDescription(report) }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">路产损失:</span>
|
||||
<span class="info-value">{{ report.totalLossAmount ? report.totalLossAmount + '万元' : '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">有无车辆滞留:</span>
|
||||
<span class="info-value">{{ getVehicleStrandedText(report) }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">滞留车辆:</span>
|
||||
<span class="info-value">{{ report.strandedVehicleCount || 0 }}辆</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">预计恢复时间:</span>
|
||||
<span class="info-value">{{ report.expectRecoverTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">实际恢复时间:</span>
|
||||
<span class="info-value">{{ report.actualRecoverTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">现场描述:</span>
|
||||
<span class="info-value">{{ report.siteDescription || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="info-label">填报人:</span>
|
||||
<span class="info-value">{{ report.reporterName ? report.reporterName : '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 附件 -->
|
||||
<div v-if="report.fileList && report.fileList.length > 0" class="info-item attachment-item">
|
||||
<span class="info-label">附件:</span>
|
||||
<div class="attachment-list">
|
||||
<el-link v-for="(file, fileIndex) in report.fileList" :key="fileIndex" :underline="false" @click="previewFile(file)" class="attachment-link">
|
||||
<el-icon><Picture v-if="file.fileType === 1" /><VideoCamera v-else /></el-icon>
|
||||
<span class="file-name">{{ file.fileName }}</span>
|
||||
</el-link>
|
||||
<div class="info-item">
|
||||
<span class="info-label">联系电话:</span>
|
||||
<span class="info-value">{{ report.phone ? report.phone : '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="file-list">
|
||||
<FileUpload v-model="report.fileList" :readonly="!isEdit" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detal-info-wrapper">
|
||||
<template v-if="report.showDetail">
|
||||
<LossListDetail :modelValue="report.lossList" :col-span="8" />
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">已投入机械:</span>
|
||||
<span class="info-value">{{ report.investedMachinery }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">已投入人力:</span>
|
||||
<span class="info-value">{{ report.investedManpower }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="info-item">
|
||||
<span class="info-label">已投入资金:</span>
|
||||
<span class="info-value">{{ report.investedFunds }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-button style="margin-top: 30px" type="primary" link @click="report.showDetail = !report.showDetail">
|
||||
{{ report.showDetail ? '点击关闭详情' : '点击查看详情' }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -274,8 +242,10 @@ import { onMounted, ref, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ArrowLeft, Picture, VideoCamera } from '@element-plus/icons-vue'
|
||||
import ContinueReport from './ContinueReport.vue'
|
||||
import ContinueReport from './WaterDisasterContinueReportPC.vue'
|
||||
import { request } from '@shared/utils/request'
|
||||
import LossListDetail from './WaterDisasterLossListDetailPC.vue'
|
||||
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
||||
import mockData from '../DisasterReport/waterMockJson.json'
|
||||
|
||||
const router = useRouter()
|
||||
@ -307,10 +277,15 @@ const continueReport = ref(null)
|
||||
const allReports = computed(() => {
|
||||
const reports =
|
||||
detailData.value.report?.map((item, index) => {
|
||||
item.title = index === 0 ? '首报' : '续报' + index
|
||||
if (index === detailData.value.report.length - 1) {
|
||||
item.title = '首报'
|
||||
} else {
|
||||
item.title = '续报' + (detailData.value.report.length - 1 - index)
|
||||
}
|
||||
return item
|
||||
}) || []
|
||||
return reports.reverse()
|
||||
return reports
|
||||
// return reports.reverse()
|
||||
})
|
||||
|
||||
// 是否有填报数据
|
||||
@ -328,14 +303,20 @@ const getEventStatusType = () => {
|
||||
return eventStatus.value === 1 ? 'success' : 'danger'
|
||||
}
|
||||
|
||||
const getBaseDisposalMeasures = () => {
|
||||
const firstItem = allReports.value[0]
|
||||
if (!firstItem) return '-'
|
||||
return formatDisposalMeasures(firstItem.disposalMeasures || '') || '-'
|
||||
}
|
||||
|
||||
// 格式化处置措施
|
||||
const formatDisposalMeasures = (measures) => {
|
||||
if (!measures) return ''
|
||||
const measureMap = {
|
||||
halfClose: '半幅封闭',
|
||||
fullClose: '全副封闭',
|
||||
bypass: '便道通行',
|
||||
normal: '正常通行'
|
||||
半幅封闭: '半幅封闭',
|
||||
全副封闭: '全副封闭',
|
||||
便道通行: '便道通行',
|
||||
正常通行: '正常通行'
|
||||
}
|
||||
return measures
|
||||
.split(',')
|
||||
@ -381,6 +362,7 @@ const getDisasterDetail = async () => {
|
||||
|
||||
if (result?.data) {
|
||||
const data = result.data
|
||||
console.log('🚀 ~ getDisasterDetail ~ data:', data)
|
||||
detailData.value = {
|
||||
event: data.event || null,
|
||||
report: data.report || [],
|
||||
@ -397,7 +379,7 @@ const getDisasterDetail = async () => {
|
||||
const newFormData = {
|
||||
...data,
|
||||
lossList: null,
|
||||
report: mockData.report,
|
||||
report: route.query.mock ? mockData.report : {},
|
||||
fileList: null
|
||||
}
|
||||
continueReport.value?.initFormData(newFormData)
|
||||
@ -416,25 +398,6 @@ const handleClickBack = () => {
|
||||
router.push('/disasterManagement')
|
||||
}
|
||||
|
||||
// 续报
|
||||
const handleContinueReport = () => {
|
||||
router.push({
|
||||
path: '/disasterReport',
|
||||
query: {
|
||||
id: route.query.id,
|
||||
eventId: detailData.value.event?.id,
|
||||
isContinue: 'true'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 预览附件
|
||||
const previewFile = (file) => {
|
||||
if (file.fileUrl) {
|
||||
window.open(file.fileUrl, '_blank')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getDisasterDetail()
|
||||
})
|
||||
@ -502,8 +465,12 @@ onMounted(() => {
|
||||
align-items: flex-start;
|
||||
line-height: 1.5;
|
||||
|
||||
& + .info-item {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
width: 120px;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
@ -612,7 +579,26 @@ onMounted(() => {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.right-panel {
|
||||
width: 400px;
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
.content-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.basic-info-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
.detal-info-wrapper {
|
||||
margin-top: 10px;
|
||||
border-top: 1px solid #efefef;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.info-list {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.file-list {
|
||||
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<el-row class="loss-list-detail" :gutter="24">
|
||||
<template v-for="(item, index) in configs" :key="index">
|
||||
<el-col :span="colSpan">
|
||||
<div class="info-item">
|
||||
<span class="info-label">{{ item.lossTypeName }}:</span>
|
||||
<span class="info-value">{{ getValue(item) }}{{ item.unit }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="colSpan" v-if="item.lossTypeCode == 'OTHER_LOSS'">
|
||||
<div class="info-item">
|
||||
<span class="info-label">其它损失描述:</span>
|
||||
<span class="info-value">{{ getRemark(item) }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Delete, Plus } from '@element-plus/icons-vue'
|
||||
import { request } from '@shared/utils/request'
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
colSpan: {
|
||||
type: Number,
|
||||
default: 8
|
||||
}
|
||||
})
|
||||
|
||||
const getValue = (config) => {
|
||||
const value = props.modelValue?.find((v) => v.lossTypeId === config.lossTypeId)
|
||||
if (value == null) props.modelValue?.push({ ...config })
|
||||
return value?.totalAmount || 0
|
||||
}
|
||||
|
||||
const getRemark = (config) => {
|
||||
const value = props.modelValue?.find((v) => v.lossTypeId === config.lossTypeId)
|
||||
if (value == null) props.modelValue?.push({ ...config })
|
||||
return value?.remark || ''
|
||||
}
|
||||
|
||||
const configs = ref([])
|
||||
|
||||
// 获取损失类型字典
|
||||
const getLossDict = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/water-damage/loss/typeAndInfo',
|
||||
method: 'get'
|
||||
})
|
||||
configs.value = res.data?.records
|
||||
} catch (error) {
|
||||
console.error('获取损失类型失败:', error)
|
||||
ElMessage.error('获取损失类型失败')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await getLossDict()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.loss-list-detail {
|
||||
width: 100%;
|
||||
|
||||
.loss-table {
|
||||
margin-bottom: 16px;
|
||||
|
||||
:deep(.el-table) {
|
||||
.amount-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.unit-text {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-button-wrapper {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.calculate-form {
|
||||
padding: 8px 0;
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.calculation-preview {
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
margin-top: 16px;
|
||||
|
||||
.preview-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.preview-label {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.preview-value {
|
||||
color: #f56c6c;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loss-picker-content {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
padding: 8px 0;
|
||||
|
||||
.loss-radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
|
||||
.loss-radio-item {
|
||||
margin: 0;
|
||||
padding: 10px 12px;
|
||||
border-radius: 6px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
:deep(.el-radio__label) {
|
||||
width: calc(100% - 22px);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
line-height: 1.5;
|
||||
margin-top: 10px;
|
||||
|
||||
.info-label {
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
flex: 1;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -22,9 +22,8 @@
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6">
|
||||
<el-form-item label="事件类别">
|
||||
<el-select v-model="filterForm.disasterType" placeholder="请选择" clearable>
|
||||
<el-option label="水毁事件" value="水毁事件" />
|
||||
<el-option label="塌方事件" value="塌方事件" />
|
||||
<el-option label="泥石流" value="泥石流" />
|
||||
<el-option label="水毁事件" value="WATER_DAMAGE" />
|
||||
<el-option label="冰雪灾害" value="ICE_SNOW" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@ -87,20 +86,25 @@
|
||||
{{ scope.$index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="routeNo" label="所属区县" min-width="120" />
|
||||
<el-table-column prop="district" label="所属区县" min-width="120" />
|
||||
<el-table-column prop="routeNo" label="路线编号" min-width="120" />
|
||||
<el-table-column prop="routeName" label="路线名称" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="startPile" label="起点桩号" min-width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="endPile" label="终点桩号" min-width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="startStakeNo" label="起点桩号" min-width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="endStakeNo" label="终点桩号" min-width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="roadConditionLocation" label="路况位置" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="isBlocked" label="是否阻断" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.isBlocked === '是' ? 'danger' : 'success'" size="small">
|
||||
{{ row.isBlocked || '—' }}
|
||||
<el-tag :type="row.blocked === true ? 'danger' : 'success'" size="small">
|
||||
{{ row.blocked === true ? '是' : row.blocked === false ? '否' : '—' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="disasterType" label="事件类型" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="disasterType" label="事件类型" min-width="120" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.disasterType == 'ICE_SNOW'">冰雪灾害</span>
|
||||
<span v-if="row.disasterType == 'WATER_DAMAGE'">水毁灾害</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="roadConditionType" label="路况类别" min-width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="eventStatus" label="事件状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
@ -109,20 +113,20 @@
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="measure" label="处理措施" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="disposalMeasures" label="处理措施" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="occurTime" label="发现时间" width="170" />
|
||||
<el-table-column prop="expectRecoverTime" label="预计恢复时间" width="170" />
|
||||
<el-table-column prop="contactPerson" label="联系人" width="110" />
|
||||
<el-table-column prop="contactPhone" label="联系电话" width="120" />
|
||||
<el-table-column label="图片" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.hasImage" link type="primary" size="small" @click="viewImages(row)">查看</el-button>
|
||||
<el-icon style="font-size: 18px; cursor: pointer;" v-if="row.images && row.images.length > 0" @click="viewImages(row)"><Picture /></el-icon>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="视频" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.hasVideo" link type="primary" size="small" @click="viewVideos(row)">播放</el-button>
|
||||
<el-icon v-if="row.videos && row.videos.length > 0" style="font-size: 18px; cursor: pointer;" @click="viewVideos(row)"><VideoPlay /></el-icon>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -148,6 +152,9 @@
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-image-viewer v-if="showPreviewImage && selectedRow" :url-list="selectedRow.images" show-progress @close="showPreviewImage = false" />
|
||||
<VideoPreviewDialog ref="videoPreviewDialog" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -156,6 +163,8 @@ import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { request } from '@/utils/request'
|
||||
import { Picture, VideoPlay } from '@element-plus/icons-vue'
|
||||
import VideoPreviewDialog from '@/component/VideoPreviewDialog.vue'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@ -171,6 +180,11 @@ const filterForm = reactive({
|
||||
pushStatus: '' // 推送状态
|
||||
})
|
||||
|
||||
const showPreviewImage = ref(false)
|
||||
const selectedRow = ref(null)
|
||||
|
||||
const videoPreviewDialog = ref(null)
|
||||
|
||||
// 日期范围
|
||||
const dateRange = ref(null)
|
||||
|
||||
@ -221,7 +235,7 @@ const fetchData = async () => {
|
||||
|
||||
// 实际接口调用
|
||||
const response = await request({
|
||||
url: '/snow-ops-platform/unified-disaster/list',
|
||||
url: '/snow-ops-platform/unified-disaster/pc/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
@ -313,21 +327,16 @@ const toReport = () => {
|
||||
|
||||
// 查看图片
|
||||
const viewImages = (row) => {
|
||||
if (row.images && row.images.length) {
|
||||
// 打开图片预览
|
||||
ElMessage.info('图片预览功能开发中')
|
||||
} else {
|
||||
ElMessage.info('暂无图片')
|
||||
}
|
||||
selectedRow.value = row
|
||||
showPreviewImage.value = true
|
||||
}
|
||||
|
||||
// 查看视频
|
||||
const viewVideos = (row) => {
|
||||
if (row.videos && row.videos.length) {
|
||||
ElMessage.info('视频播放功能开发中')
|
||||
} else {
|
||||
ElMessage.info('暂无视频')
|
||||
}
|
||||
videoPreviewDialog.value.show({
|
||||
url: row.videos[0],
|
||||
title: row.eventName
|
||||
})
|
||||
}
|
||||
|
||||
// 分页大小改变
|
||||
@ -400,4 +409,4 @@ onMounted(() => {
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
@ -16,7 +16,7 @@ import { useRouter, useRoute } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Upload } from '@element-plus/icons-vue'
|
||||
import { request } from '@/utils/request'
|
||||
import WaterDisasterReport from './WaterDisasterReport.vue'
|
||||
import WaterDisasterReport from './WaterDisasterReportPC.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
@ -35,8 +35,8 @@
|
||||
<BlockItem title="路况事件信息">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="事件类型" prop="roadConditionType">
|
||||
<el-select v-model="formData.roadConditionType" placeholder="请选择" style="width: 100%">
|
||||
<el-form-item label="事件类型">
|
||||
<el-select v-model="eventType" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="水毁事件" value="水毁事件" />
|
||||
<el-option label="冰雪事件" value="冰雪事件" />
|
||||
</el-select>
|
||||
@ -77,8 +77,8 @@
|
||||
</el-col>
|
||||
<!-- 处理措施-->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="处理措施" prop="event.repairProgress">
|
||||
<el-select v-model="formData.event.repairProgress" placeholder="请选择" style="width: 100%">
|
||||
<el-form-item label="处理措施" prop="event.disposalMeasures">
|
||||
<el-select v-model="formData.event.disposalMeasures" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="全幅封闭" value="全幅封闭" />
|
||||
<el-option label="半幅封闭" value="半幅封闭" />
|
||||
<el-option label="正常通行" value="正常通行" />
|
||||
@ -206,35 +206,14 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="图片上传" prop="fileList">
|
||||
<el-upload
|
||||
v-model:file-list="imageFileList"
|
||||
action="#"
|
||||
list-type="picture-card"
|
||||
:auto-upload="false"
|
||||
:limit="9"
|
||||
:on-preview="handlePicturePreview"
|
||||
:on-remove="handlePictureRemove"
|
||||
:before-upload="beforeImageUpload"
|
||||
accept="image/jpeg,image/png"
|
||||
>
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-upload>
|
||||
<div class="upload-tip">只能上传jpg/png格式,且不超过500kb</div>
|
||||
<FileUpload type="image" :limit="9" v-model="formData.fileList" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="视频上传" prop="fileList">
|
||||
<el-upload v-model:file-list="videoFileList" action="#" :auto-upload="false" :limit="1" :before-upload="beforeVideoUpload" accept="video/*">
|
||||
<el-button type="primary"
|
||||
><el-icon><Upload /></el-icon> 选择文件</el-button
|
||||
>
|
||||
</el-upload>
|
||||
<div class="upload-tip">仅支持20s内的视频,不超过20MB</div>
|
||||
<div v-if="videoFileList.length > 0 && videoFileList[0].url" class="video-preview">
|
||||
<video :src="videoFileList[0].url" controls style="width: 100%; max-height: 200px"></video>
|
||||
</div>
|
||||
<FileUpload type="video" :limit="9" v-model="formData.fileList" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@ -307,24 +286,33 @@
|
||||
<!-- 已投入机械 -->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="已投入机械" prop="report.investedMachinery">
|
||||
<el-input-number v-model="formData.report.investedMachinery" :min="0" :precision="1" style="width: 100%" />
|
||||
<span class="unit-suffix">台/班</span>
|
||||
<el-input-number v-model="formData.report.investedMachinery" :min="0" :precision="1" style="width: 100%" placeholder="请填写">
|
||||
<template #suffix>
|
||||
<span class="unit-text">台/班</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 已投入人力 -->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="投入人力" prop="report.investedManpower">
|
||||
<el-input-number v-model="formData.report.investedManpower" :min="0" :step="1" style="width: 100%" />
|
||||
<span class="unit-suffix">人次</span>
|
||||
<el-input-number v-model="formData.report.investedManpower" :min="0" :step="1" style="width: 100%" placeholder="请填写">
|
||||
<template #suffix>
|
||||
<span class="unit-text">人次</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 已投入资金 -->
|
||||
<el-col :span="8">
|
||||
<el-form-item label="已投入资金" prop="report.investedFunds">
|
||||
<el-input-number v-model="formData.report.investedFunds" :min="0" :precision="2" style="width: 100%" />
|
||||
<span class="unit-suffix">万元</span>
|
||||
<el-input-number v-model="formData.report.investedFunds" :min="0" :precision="2" style="width: 100%" placeholder="请填写">
|
||||
<template #suffix>
|
||||
<span class="unit-text">万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
@ -351,7 +339,7 @@
|
||||
<!-- 恢复重建预估费用 -->
|
||||
<el-col :span="8" v-if="!isContinue">
|
||||
<el-form-item label="恢复重建预估费用" prop="event.estimatedRecoveryCost">
|
||||
<el-input-number v-model="formData.event.estimatedRecoveryCost" :min="0" :precision="2" style="width: 100%">
|
||||
<el-input-number v-model="formData.event.estimatedRecoveryCost" :min="0" :precision="2" style="width: 100%" placeholder="请填写">
|
||||
<template #suffix>
|
||||
<span class="unit-text">万元</span>
|
||||
</template>
|
||||
@ -383,9 +371,9 @@ import { ElMessage } from 'element-plus'
|
||||
import { Plus, Upload } from '@element-plus/icons-vue'
|
||||
import mockData from './waterMockJson.json'
|
||||
import { request } from '@/utils/request'
|
||||
import LossList from './LossList.vue'
|
||||
import LossList from './WaterDisasterLossListPC.vue'
|
||||
import BlockItem from '@/component/BlockItem.vue'
|
||||
import { el } from 'element-plus/es/locale/index.mjs'
|
||||
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
@ -402,6 +390,8 @@ const disposalMeasuresArray = ref([])
|
||||
const imageFileList = ref([])
|
||||
const videoFileList = ref([])
|
||||
|
||||
const eventType = ref('水毁事件')
|
||||
|
||||
const formData = reactive({
|
||||
// 顶层字段
|
||||
occurLocation: null, // 发生地点/路况位置
|
||||
@ -417,17 +407,13 @@ const formData = reactive({
|
||||
contactPhone: null, // 联系电话
|
||||
damageCount: null, // 水毁处数
|
||||
district: null, // 上报区县
|
||||
endStakeLat: null, // 止点纬度
|
||||
endStakeLng: null, // 止点经度
|
||||
endStakeNo: null, // 止点桩号
|
||||
estimatedRecoveryCost: null, // 恢复重建预估费用
|
||||
inspectionMileage: null, // 巡查里程
|
||||
isBlocked: null, // 是否阻断
|
||||
needsRecovery: null, // 是否需要恢复重建
|
||||
repairProgress: null, // 抢修进度
|
||||
repairProgress: null, // 抢险进度
|
||||
reporterUnit: null, // 填报单位
|
||||
startStakeLat: null, // 起点纬度
|
||||
startStakeLng: null, // 起点经度
|
||||
startStakeNo: null // 起点桩号
|
||||
},
|
||||
|
||||
@ -635,7 +621,12 @@ const handleSubmit = async () => {
|
||||
|
||||
// 加载编辑数据
|
||||
const loadEditData = async () => {
|
||||
initFormData(mockData)
|
||||
|
||||
if(route.query.mock) {
|
||||
initFormData(mockData)
|
||||
} else {
|
||||
initFormData({})
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@ -10,17 +10,13 @@
|
||||
"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": "抢修中",
|
||||
"repairProgress": "抢险中",
|
||||
"reporterUnit": "武侯区交通运输局",
|
||||
"startStakeLat": "30.652145",
|
||||
"startStakeLng": "104.075632",
|
||||
"startStakeNo": "K2250+300"
|
||||
},
|
||||
"report": {
|
||||
@ -28,7 +24,7 @@
|
||||
"strandedPersonCount": 12,
|
||||
"deadCount": 0,
|
||||
"strandedVehicleCount": 12,
|
||||
"disposalMeasures": "halfClose,bypass",
|
||||
"disposalMeasures": "全幅封闭",
|
||||
"actualRecoverTime": "2024-07-17 12:00:00",
|
||||
"expectRecoverTime": "2024-07-18 18:00:00",
|
||||
"injuredCount": 1,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { h, ref, onMounted, reactive, watch, toRaw, nextTick } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const tableData = ref([]); // 表格数据
|
||||
|
||||
@ -18,7 +19,7 @@ const model = reactive({
|
||||
const form = reactive({
|
||||
});
|
||||
const INIT_FORM = {
|
||||
|
||||
|
||||
};
|
||||
// 抽屉内容
|
||||
const drawer = reactive({
|
||||
@ -35,101 +36,105 @@ const drawerRef = ref(null); // 抽屉实例
|
||||
|
||||
const columns = [
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "county",
|
||||
label: "所属区县",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "projectName",
|
||||
label: "项目名称",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "siteName",
|
||||
label: "驻地名称",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "siteType",
|
||||
label: "驻地类型",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "coordinatePoint",
|
||||
label: "坐标点位",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "subProjectName",
|
||||
label: "所属项目名称",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "projectType",
|
||||
label: "项目类型",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "constructionUnit",
|
||||
label: "建设单位",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "constructionCompany",
|
||||
label: "施工单位",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "siteAddress",
|
||||
label: "驻地地址",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "town",
|
||||
label: "乡镇名称",
|
||||
},
|
||||
{
|
||||
prop: "streetName",
|
||||
label: "街道名称",
|
||||
},
|
||||
{
|
||||
prop: "administrativeRegion",
|
||||
label: "行政区域",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "sitePopulation",
|
||||
label: "驻地人数",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "riskLevel",
|
||||
label: "驻地风险等级",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "buildingType",
|
||||
label: "房建类型",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "relocationStatus",
|
||||
label: "搬迁状态",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "吹哨人/电话",
|
||||
formatter: (row) => `${row.whistleblowerName || ''}/${row.whistleblowerPhone || ''}`,
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "建设单位包保责任人/电话",
|
||||
formatter: (row) => `${row.ownerResponsiblePerson || ''}/${row.ownerResponsiblePhone || ''}`,
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "施工单位包保责任人/电话",
|
||||
formatter: (row) => `${row.constructorResponsiblePerson || ''}/${row.constructorResponsiblePhone || ''}`,
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "驻地包保责任人/电话",
|
||||
formatter: (row) => `${row.siteResponsiblePerson || ''}/${row.siteResponsiblePhone || ''}`,
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "区县级包保责任人/电话",
|
||||
formatter: (row) => `${row.districtResponsiblePerson || ''}/${row.districtResponsiblePhone || ''}`,
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "市级包保责任人/电话",
|
||||
formatter: (row) => `${row.cityResponsiblePerson || ''}/${row.cityResponsiblePhone || ''}`,
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "remarks",
|
||||
label: "备注",
|
||||
},
|
||||
]
|
||||
|
||||
// 过滤条件
|
||||
const filterData = reactive({
|
||||
title: "",
|
||||
type: "",
|
||||
warningLevel: "",
|
||||
})
|
||||
const filterData = reactive({})
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
@ -145,17 +150,33 @@ const pagination = reactive({
|
||||
});
|
||||
|
||||
// 获取列表
|
||||
const getTableData = async (filterData) => {
|
||||
const getTableData = async (filterData = {}) => {
|
||||
try {
|
||||
// 过滤空字符串属性
|
||||
const filteredParams = {};
|
||||
Object.keys(filterData).forEach(key => {
|
||||
if (filterData[key] !== '' && filterData[key] != null) {
|
||||
filteredParams[key] = filterData[key];
|
||||
}
|
||||
});
|
||||
const res = await request({
|
||||
url: '',
|
||||
url: '/snow-ops-platform/site-ledger/list',
|
||||
method: "GET",
|
||||
params: {
|
||||
|
||||
...filteredParams,
|
||||
pageNum: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
}
|
||||
})
|
||||
if (res.code === '00000') {
|
||||
tableData.value = res.data.records
|
||||
pagination.total = res.data.total
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
ElMessage.error(error.message)
|
||||
console.error('获取列表失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,8 +203,31 @@ const warningLevelOptions = [
|
||||
]
|
||||
|
||||
|
||||
const exportExcel = async () => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/site-ledger/export',
|
||||
method: 'GET'
|
||||
})
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default () => {
|
||||
|
||||
onMounted(() => {
|
||||
getTableData();
|
||||
})
|
||||
|
||||
|
||||
watch(filterData, (val) => {
|
||||
getTableData(filterData);
|
||||
}, { deep: true })
|
||||
|
||||
|
||||
return {
|
||||
modelVisible,
|
||||
model,
|
||||
@ -197,5 +241,7 @@ export default () => {
|
||||
filterData,
|
||||
pagination,
|
||||
columns,
|
||||
|
||||
exportExcel,
|
||||
}
|
||||
}
|
||||
@ -1,37 +1,37 @@
|
||||
<template>
|
||||
<div class="root">
|
||||
<div class="search-box">
|
||||
<el-input v-model="script.filterData.title" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-input v-model="script.filterData.projectName" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="项目名称" :suffix-icon="Search" />
|
||||
<el-input v-model="script.filterData.title" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-input v-model="script.filterData.siteName" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="驻地名称" :suffix-icon="Search" />
|
||||
<el-input v-model="script.filterData.title" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-input v-model="script.filterData.constructionUnit" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="建设单位" :suffix-icon="Search" />
|
||||
<el-input v-model="script.filterData.title" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-input v-model="script.filterData.constructionCompany" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="施工单位" :suffix-icon="Search" />
|
||||
<el-select v-model="script.filterData.type" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-select v-model="script.filterData.projectType" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="项目类型" :suffix-icon="ArrowDown" :options="script.typeOptions" clearable />
|
||||
<el-select v-model="script.filterData.warningLevel" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-select v-model="script.filterData.siteType" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="驻地类型" :suffix-icon="ArrowDown" :options="script.warningLevelOptions" clearable />
|
||||
<el-select v-model="script.filterData.warningLevel" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-select v-model="script.filterData.riskLevel" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="驻地风险等级" :suffix-icon="ArrowDown" :options="script.warningLevelOptions" clearable />
|
||||
<el-select v-model="script.filterData.warningLevel" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-select v-model="script.filterData.districtCounty" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="所属区县" :suffix-icon="ArrowDown" :options="script.warningLevelOptions" clearable />
|
||||
<el-input v-model="script.filterData.title" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-input v-model="script.filterData.whistleblowerName" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="吹哨人姓名" :suffix-icon="Search" />
|
||||
<el-input v-model="script.filterData.title" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-input v-model="script.filterData.constructorResponsiblePerson" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="建设单位责任人姓名" :suffix-icon="Search" />
|
||||
<el-input v-model="script.filterData.title" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-input v-model="script.filterData.districtResponsiblePerson" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="区县级责任人姓名" :suffix-icon="Search" />
|
||||
<el-input v-model="script.filterData.title" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-input v-model="script.filterData.cityResponsiblePerson" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="市级责任人姓名" :suffix-icon="Search" />
|
||||
<el-input v-model="script.filterData.title" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-input v-model="script.filterData.ownerResponsiblePerson" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="施工单位责任人姓名" :suffix-icon="Search" />
|
||||
<el-input v-model="script.filterData.title" style="width: 240px; margin-right: 10px" size="large"
|
||||
<el-input v-model="script.filterData.siteResponsiblePerson" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="驻地责任人姓名" :suffix-icon="Search" />
|
||||
</div>
|
||||
<div class="event-box">
|
||||
<el-button type="primary" color="#952DE6" @click="">导出</el-button>
|
||||
<el-button type="primary" color="#952DE6" @click="script.exportExcel">导出</el-button>
|
||||
<el-button type="primary" @click="">导入</el-button>
|
||||
</div>
|
||||
<DynamicTable :dataSource="script.tableData.value" :columns="script.columns" :autoHeight="true"
|
||||
|
||||
@ -0,0 +1,440 @@
|
||||
<template>
|
||||
<div class="detail-container">
|
||||
<el-form ref="formRef" :model="form" label-position="right" label-width="150px"
|
||||
style="max-height: 60vh; overflow-y: auto; padding-right: 50px" :rules="rules">
|
||||
<div class="basic-info">
|
||||
<el-row>
|
||||
<h4 style="margin: 0 0 20px 50px;">基本信息</h4>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="区县名称" prop="区县名称">
|
||||
<el-input disabled v-model="form.districtName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="路线编码" prop="路线编码">
|
||||
<el-input disabled v-model="form.routeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="实施里程" prop="实施里程">
|
||||
<el-input-number disabled v-model="form.implementMileage" :controls="false">
|
||||
<template #suffix>
|
||||
<span>公里</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="塌方及损失" prop="塌方及损失">
|
||||
<el-input-number disabled v-model="form.earthworkLoss" :controls="false">
|
||||
<template #suffix>
|
||||
<span>方/万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="起点桩号" prop="起点桩号">
|
||||
<el-input disabled v-model="form.startStakeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="止点桩号" prop="止点桩号">
|
||||
<el-input disabled v-model="form.endStakeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="路况位置" prop="路况位置">
|
||||
<el-input disabled v-model="form.roadLocation"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="阻断点小地名" prop="阻断点小地名">
|
||||
<el-input disabled v-model="form.blockedPointName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="灾害类型" prop="灾害类型">
|
||||
<el-input disabled v-model="form.disasterType"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="预估费用" prop="预估费用">
|
||||
<el-input-number disabled v-model="form.estimatedCost" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="技术等级" prop="技术等级">
|
||||
<el-select v-model="form.technicalGrade">
|
||||
<el-option
|
||||
v-for="item in [{ value: '三级', label: '三级' }, { value: '二级', label: '二级' }, { value: '一级', label: '一级' }]"
|
||||
:key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="资金来源" prop="资金来源">
|
||||
<el-input v-model="form.fundingSource"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="处置灾毁处数" prop="处置灾毁处数">
|
||||
<el-input-number v-model="form.disposalCount" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="已完工处数" prop="已完工处数">
|
||||
<el-input-number v-model="form.completedCount" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="总投资" prop="总投资">
|
||||
<el-input-number v-model="form.totalInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目费用类型" prop="项目费用类型">
|
||||
<el-radio-group v-model="form.projectExpenseType">
|
||||
<el-radio value="自费重修">自费重修</el-radio>
|
||||
<el-radio value="申报重修">申报重修</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="performance-info">
|
||||
<el-row>
|
||||
<h4 style="margin: 0 0 20px 50px;">实施情况</h4>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="主要建设内容" prop="主要建设内容">
|
||||
<el-input disabled type="textarea" v-model="form.mainConstructionContent" clearable>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="开工或预计开工时间" prop="开工或预计开工时间">
|
||||
<el-date-picker disabled type="date" v-model="form.startTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="完工或预计完工时间" prop="完工或预计完工时间">
|
||||
<el-date-picker disabled type="date" v-model="form.endTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否在部交通统计报表管理系统报送投资" prop="是否在部交通统计报表管理系统报送投资" label-width="300px">
|
||||
<el-radio-group disabled v-model="form.isReportedToMinistry">
|
||||
<el-radio :value="0">是</el-radio>
|
||||
<el-radio :value="1">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="已报送投资额" prop="已报送投资额">
|
||||
<el-input-number disabled v-model="form.reportedInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目实施进度" prop="项目实施进度">
|
||||
<el-select disabled v-model="form.projectProgress">
|
||||
<el-option v-for="item in [
|
||||
{ value: '立项', label: '立项' },
|
||||
{ value: '财政评审', label: '财政评审' },
|
||||
{ value: '开展施工图设计', label: '开展施工图设计' },
|
||||
{ value: '完成施设于批复', label: '完成施设于批复' },
|
||||
]" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位名称" prop="建设单位名称">
|
||||
<el-input disabled v-model="form.constructionUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位联系人" prop="建设单位联系人">
|
||||
<el-input disabled v-model="form.constructionUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位联系人电话" prop="建设单位联系人电话">
|
||||
<el-input disabled v-model="form.constructionUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工单位名称" prop="施工单位名称">
|
||||
<el-input disabled v-model="form.executionUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工单位联系人" prop="施工单位联系人">
|
||||
<el-input disabled v-model="form.executionUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工单位联系电话" prop="施工单位联系电话">
|
||||
<el-input disabled v-model="form.executionUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计单位名称" prop="设计单位名称">
|
||||
<el-input disabled v-model="form.designUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计单位联系人" prop="设计单位联系人">
|
||||
<el-input disabled v-model="form.designUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计单位联系人电话" prop="设计单位联系人电话">
|
||||
<el-input disabled v-model="form.designUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监理单位名称" prop="监理单位名称">
|
||||
<el-input disabled v-model="form.supervisionUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监理单位联系人" prop="监理单位联系人">
|
||||
<el-input disabled v-model="form.supervisionUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监理单位联系电话" prop="监理单位联系电话">
|
||||
<el-input disabled v-model="form.supervisionUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工图批复时间" prop="施工图批复时间">
|
||||
<el-date-picker disabled type="date" v-model="form.designApprovalTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工图设计批复文件(附件)" prop="施工图设计批复文件" label-width="200px">
|
||||
<FileUpload type="image" :limit="9" v-model="form.designApprovalFiles" :fileType=2 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工合同时间" prop="施工合同时间">
|
||||
<el-date-picker disabled type="date" v-model="form.contractTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工合同金额" prop="施工合同金额">
|
||||
<el-input-number disabled v-model="form.contractAmount" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工合同(附件)" prop="施工合同">
|
||||
<FileUpload type="image" :limit="9" v-model="form.contractFiles" :fileType=3 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设完成投资" prop="建设完成投资">
|
||||
<el-input-number disabled v-model="form.completedInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="交竣工验收时间" prop="交竣工验收时间">
|
||||
<el-date-picker disabled type="date" v-model="form.acceptanceTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="交竣工证书(附件)" prop="交竣工证书" label-width="200px">
|
||||
<FileUpload type="image" :limit="9" v-model="form.acceptanceFiles" :fileType=4 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="其他佐证文件" prop="其他佐证文件">
|
||||
<FileUpload type="image" :limit="9" v-model="form.otherFiles" :fileType=6 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="完工项目上传图片(附件)" prop="完工项目上传图片" label-width="200px">
|
||||
<FileUpload type="image" :limit="9" v-model="form.completedFiles" :fileType=5 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, computed } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
||||
|
||||
const formRef = ref(null);
|
||||
defineExpose({ formRef });
|
||||
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
技术等级: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.technicalGrade) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请选择技术等级"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
资金来源: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.fundingSource) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请填写资金来源"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
处置灾毁处数: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.disposalCount) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请填写处置灾毁处数"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
已完工处数: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.completedCount) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请填写已完工处数"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
总投资: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.totalInvestment) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请填写总投资数"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
项目费用类型: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.projectExpenseType) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请选择项目费用类型"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@ -0,0 +1,447 @@
|
||||
import { h, ref, onMounted, reactive, watch, toRaw, nextTick } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import ExamineDialog from "./examineDialog.vue";
|
||||
import RejectDialog from './rejectDialog.vue';
|
||||
|
||||
const tableData = ref([]); // 表格数据
|
||||
const modelVisible = ref(false); // 弹窗状态
|
||||
const drawerVisible = ref(false); // 抽屉状态
|
||||
// 弹窗内容
|
||||
const model = reactive({
|
||||
title: '',
|
||||
content: null,
|
||||
props: {},
|
||||
onCancel: null,
|
||||
onConfirm: null,
|
||||
width: '',
|
||||
footerPosition: null,
|
||||
onCancelType: null,
|
||||
onConfirmName: null,
|
||||
onCancelName: null,
|
||||
tagContent: null,
|
||||
tagType: null,
|
||||
});
|
||||
const form = reactive({
|
||||
});
|
||||
// 抽屉内容
|
||||
const drawer = reactive({
|
||||
title: '',
|
||||
content: null,
|
||||
props: {},
|
||||
onCancel: null,
|
||||
onConfirm: null,
|
||||
direction: 'rtl',
|
||||
size: '50%'
|
||||
});
|
||||
const dialogRef = ref(null); // 弹窗实例
|
||||
const drawerRef = ref(null); // 抽屉实例
|
||||
|
||||
// 第二个弹窗
|
||||
const model2 = reactive({
|
||||
title: '',
|
||||
content: null,
|
||||
props: {},
|
||||
onCancel: null,
|
||||
onConfirm: null,
|
||||
width: '',
|
||||
footerPosition: null,
|
||||
onCancelType: null,
|
||||
onConfirmName: null,
|
||||
onCancelName: null,
|
||||
tagContent: null,
|
||||
tagType: null,
|
||||
});
|
||||
const modelVisible2 = ref(false);
|
||||
const dialogRef2 = ref(null);
|
||||
|
||||
|
||||
|
||||
// 过滤条件
|
||||
const filterData = reactive({
|
||||
})
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
pageSizes: [10, 20, 50],
|
||||
layout: "prev, pager, next, jumper",
|
||||
onChange: (page, pageSize) => {
|
||||
pagination.current = page;
|
||||
pagination.pageSize = pageSize;
|
||||
getTableData(filterData);
|
||||
},
|
||||
});
|
||||
|
||||
// 获取项目列表
|
||||
const getTableData = async (filterData = {}) => {
|
||||
try {
|
||||
// 过滤空字符串属性
|
||||
const filteredParams = {};
|
||||
Object.keys(filterData).forEach(key => {
|
||||
if (filterData[key] !== '' && filterData[key] != null) {
|
||||
filteredParams[key] = filterData[key];
|
||||
}
|
||||
});
|
||||
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/recovery/list',
|
||||
method: "GET",
|
||||
params: {
|
||||
...filteredParams,
|
||||
submitTimeStart: filteredParams?.submitTimeStart ? filteredParams.submitTimeStart + `-01-01 00:00:00` : null,
|
||||
pageNum: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
}
|
||||
})
|
||||
if (res.code === '00000') {
|
||||
tableData.value = res.data.records
|
||||
pagination.total = res.data.total
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('获取项目列表失败');
|
||||
console.error('获取项目列表失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 驳回项目
|
||||
const rejectProject = async () => {
|
||||
try {
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '操作中',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
})
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/recovery/approve',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id: form.id,
|
||||
approveLevel: 2,
|
||||
isPass: false,
|
||||
rejectReason: form.rejectReason,
|
||||
}
|
||||
})
|
||||
loading.close();
|
||||
if (res.code === '00000') {
|
||||
ElMessage.success('操作成功');
|
||||
modelVisible.value = false;
|
||||
modelVisible2.value = false;
|
||||
getTableData(filterData);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('操作失败');
|
||||
console.error('驳回项目失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 审批通过项目
|
||||
const approveProject = async () => {
|
||||
try {
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '操作中',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
})
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/recovery/approve',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id: form.id,
|
||||
approveLevel: 2,
|
||||
isPass: true,
|
||||
}
|
||||
})
|
||||
loading.close();
|
||||
if (res.code === '00000') {
|
||||
ElMessage.success('操作成功');
|
||||
modelVisible.value = false;
|
||||
modelVisible2.value = false;
|
||||
getTableData(filterData);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('操作失败');
|
||||
console.error('审批项目失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取项目详情
|
||||
const getDetailData = async (id) => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: `/snow-ops-platform/recovery/getById`,
|
||||
method: 'GET',
|
||||
params: {
|
||||
id: id,
|
||||
}
|
||||
});
|
||||
if (res.code === '00000') {
|
||||
return res.data;
|
||||
} else {
|
||||
throw new Error(res.message);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('获取项目详情失败');
|
||||
console.error('获取项目详情失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default () => {
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
// 记录访问的项目管理模块
|
||||
onMounted(() => {
|
||||
sessionStorage.setItem('lastVisitedProjectManagement', 'projectManagement2')
|
||||
})
|
||||
|
||||
const columns = [
|
||||
{
|
||||
prop: "districtName",
|
||||
label: "区县",
|
||||
},
|
||||
{
|
||||
prop: "routeNo",
|
||||
label: "路线编码",
|
||||
},
|
||||
// {
|
||||
// prop: "disasterType",
|
||||
// label: "灾害类型",
|
||||
// },
|
||||
{
|
||||
prop: "startStakeNo",
|
||||
label: "起点桩号",
|
||||
},
|
||||
{
|
||||
prop: "endStakeNo",
|
||||
label: "止点桩号",
|
||||
},
|
||||
{
|
||||
prop: "implementMileage",
|
||||
label: "实施里程(公里)",
|
||||
},
|
||||
// {
|
||||
// prop: "technicalGrade",
|
||||
// label: "技术等级",
|
||||
// },
|
||||
{
|
||||
prop: "totalInvestment",
|
||||
label: "总投资金额(万元)",
|
||||
},
|
||||
{
|
||||
prop: "estimatedCost",
|
||||
label: "投资估算(万元)",
|
||||
},
|
||||
{
|
||||
prop: "subsidyAmount",
|
||||
label: "补助金额(万元)",
|
||||
},
|
||||
{
|
||||
prop: "fundingSource",
|
||||
label: "资金来源",
|
||||
},
|
||||
{
|
||||
prop: "startTime",
|
||||
label: "开工或预计开工时间",
|
||||
},
|
||||
{
|
||||
prop: "endTime",
|
||||
label: "完工或预计完工时间",
|
||||
},
|
||||
{
|
||||
prop: "projectProgress",
|
||||
label: "项目进度情况",
|
||||
},
|
||||
// {
|
||||
// prop: "reportStatus",
|
||||
// label: "申报状态",
|
||||
// formatter: (row) => {
|
||||
// const colorMap = {
|
||||
// 0: '#409EFF', // 蓝色 - 未申报
|
||||
// 1: '#67C23A', // 绿色 - 已申报
|
||||
// };
|
||||
// const textMap = {
|
||||
// 0: '未申报',
|
||||
// 1: '已申报',
|
||||
// };
|
||||
// const status = row.reportStatus;
|
||||
// const color = colorMap[status] || '#909399';
|
||||
// const text = textMap[status] || '未知状态';
|
||||
// return h(ElText, { style: { color } }, text);
|
||||
// }
|
||||
// },
|
||||
{
|
||||
prop: "approvalStatus",
|
||||
width: 150,
|
||||
label: "审批状态",
|
||||
formatter: (row) => {
|
||||
const colorMap = {
|
||||
0: '#409EFF', // 蓝色 - 待区县审批
|
||||
1: '#67C23A', // 绿色 - 区县审批通过
|
||||
2: '#F56C6C', // 红色 - 区县审批驳回
|
||||
3: '#67C23A', // 绿色 - 业务部门审批通过
|
||||
4: '#F56C6C', // 红色 - 业务部门审批驳回
|
||||
};
|
||||
const textMap = {
|
||||
0: '待区县审批',
|
||||
1: '区县审批通过(待业务部门审批)',
|
||||
2: '区县审批驳回',
|
||||
3: '业务部门审批通过',
|
||||
4: '业务部门审批驳回',
|
||||
};
|
||||
const status = row.approvalStatus;
|
||||
const color = colorMap[status] || '#909399';
|
||||
const text = textMap[status] || '未知状态';
|
||||
return h(ElText, { style: { color } }, text);
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: "updateTime",
|
||||
label: "更新日期",
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 150,
|
||||
render: (row) => () =>
|
||||
h("div", { class: "action-btns" }, [
|
||||
row.approvalStatus === 1 ? h(
|
||||
ElButton,
|
||||
{
|
||||
type: "primary",
|
||||
link: true,
|
||||
onClick: async () => {
|
||||
openExamineDialog(row);
|
||||
},
|
||||
},
|
||||
() => "审批"
|
||||
) : null,
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
type: "primary",
|
||||
link: true,
|
||||
style: row.approvalStatus === 1 ? "margin-left: 10px;" : "",
|
||||
onClick: async () => {
|
||||
gotoDetaillPage(row);
|
||||
},
|
||||
},
|
||||
() => "详情"
|
||||
),
|
||||
]),
|
||||
},
|
||||
]
|
||||
|
||||
// 打开审批弹窗
|
||||
const openExamineDialog = async (row) => {
|
||||
const data = await getDetailData(row.id)
|
||||
model.title = '项目审批';
|
||||
Object.assign(form, data);
|
||||
model.props = {
|
||||
form: form,
|
||||
};
|
||||
model.content = ExamineDialog;
|
||||
model.onCancel = () => {
|
||||
model2.title = '驳回原因';
|
||||
model2.props = {
|
||||
form: form,
|
||||
}
|
||||
model2.content = RejectDialog;
|
||||
model2.onCancel = () => {
|
||||
modelVisible2.value = false;
|
||||
}
|
||||
model2.onConfirm = async () => {
|
||||
await dialogRef2?.value?.dynamicComponentRef?.formRef.validate().then(async () => {
|
||||
await rejectProject()
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error('请处理表单中的错误项');
|
||||
});
|
||||
|
||||
}
|
||||
model2.width = '30%'
|
||||
model2.footerPosition = 'center'
|
||||
model2.onConfirmName = '确定'
|
||||
model2.onCancelName = '取消'
|
||||
modelVisible2.value = true;
|
||||
};
|
||||
model.onConfirm = async () => {
|
||||
await dialogRef?.value?.dynamicComponentRef?.formRef.validate().then(async () => {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
'确定该项目申请通过恢复重建?',
|
||||
'审批确认',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
);
|
||||
await approveProject();
|
||||
} catch {
|
||||
ElMessage.info('已取消审批');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error('请处理表单中的错误项');
|
||||
});
|
||||
};
|
||||
model.width = "50%"
|
||||
model.footerPosition = 'flex-end'
|
||||
model.onCancelType = 'danger'
|
||||
model.onConfirmName = '审批通过'
|
||||
model.onCancelName = '审批驳回'
|
||||
// model.tagType = 'warning'
|
||||
// model.tagContent = '测试'
|
||||
modelVisible.value = true;
|
||||
}
|
||||
|
||||
// 跳转至详情页面
|
||||
const gotoDetaillPage = (row) => {
|
||||
router.push({
|
||||
name: 'projectDetail2',
|
||||
params: {
|
||||
data: encodeURIComponent(JSON.stringify(row.id))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getTableData();
|
||||
})
|
||||
|
||||
|
||||
watch(filterData, (val) => {
|
||||
getTableData(filterData);
|
||||
}, { deep: true })
|
||||
|
||||
|
||||
return {
|
||||
tableData,
|
||||
filterData,
|
||||
pagination,
|
||||
columns,
|
||||
|
||||
modelVisible,
|
||||
model,
|
||||
drawerVisible,
|
||||
drawer,
|
||||
dialogRef,
|
||||
drawerRef,
|
||||
openExamineDialog,
|
||||
|
||||
model2,
|
||||
modelVisible2,
|
||||
dialogRef2,
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="root">
|
||||
<div class="search-box">
|
||||
<el-date-picker v-model="script.filterData.submitTimeStart" type="year" placeholder="年度" format="YYYY" value-format="YYYY"
|
||||
style="width: 240px; margin-right: 10px" size="large" />
|
||||
<el-date-picker v-model="script.filterData.submitTimeStart" type="year" placeholder="年度" format="YYYY"
|
||||
value-format="YYYY" style="width: 240px; margin-right: 10px" size="large" />
|
||||
<el-input v-model="script.filterData.routeNo" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="路线编码" :suffix-icon="Search" />
|
||||
</div>
|
||||
@ -19,10 +19,16 @@
|
||||
:onConfirm="script.model?.onConfirm" :onCancel="script.model?.onCancel" ref="dialogRef"
|
||||
:width="script.model?.width" :footer-position="script.model?.footerPosition"
|
||||
:onCancelType="script.model?.onCancelType" :onConfirmName="script.model?.onConfirmName"
|
||||
:onCancelName="script.model?.onCancelName"
|
||||
:tagContent="script.model?.tagContent"
|
||||
:tagType="script.model?.tagType"
|
||||
>
|
||||
:onCancelName="script.model?.onCancelName" :tagContent="script.model?.tagContent"
|
||||
:tagType="script.model?.tagType">
|
||||
</MyDialog>
|
||||
<MyDialog v-model="script.modelVisible2.value" :title="script.model2?.title"
|
||||
:dynamicComponent="script.model2?.content" :component-props="script.model2?.props"
|
||||
:onConfirm="script.model2?.onConfirm" :onCancel="script.model2?.onCancel" ref="dialogRef2"
|
||||
:width="script.model2?.width" :footer-position="script.model2?.footerPosition"
|
||||
:onCancelType="script.model2?.onCancelType" :onConfirmName="script.model2?.onConfirmName"
|
||||
:onCancelName="script.model2?.onCancelName" :tagContent="script.model2?.tagContent"
|
||||
:tagType="script.model2?.tagType">
|
||||
</MyDialog>
|
||||
<MyDrawer v-model="script.drawerVisible.value" :title="script.drawer?.title"
|
||||
:dynamicComponent="script.drawer?.content" :component-props="script.drawer?.props"
|
||||
@ -34,13 +40,13 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import DynamicTable from "../../component/DynamicTable";
|
||||
import DynamicTable from "../../../component/DynamicTable/index.js";
|
||||
import { Search } from "@element-plus/icons-vue";
|
||||
import MyDialog from "../../component/MyDialog";
|
||||
import MyDrawer from "../../component/MyDrawer";
|
||||
import MyDialog from "../../../component/MyDialog/index.js";
|
||||
import MyDrawer from "../../../component/MyDrawer/index.js";
|
||||
import scriptFn from "./index.js";
|
||||
const script = scriptFn();
|
||||
const { dialogRef, drawerRef } = script;
|
||||
const { dialogRef, drawerRef, dialogRef2 } = script;
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -0,0 +1,473 @@
|
||||
<template>
|
||||
<div class="root">
|
||||
<div class="form-box">
|
||||
<el-form ref="formRef" :model="form" label-position="right" label-width="150px" style="padding-right: 50px"
|
||||
:rules="rules">
|
||||
<el-row>
|
||||
<el-col :span="20">
|
||||
<h4 style="margin:0 0 20px 50px;">基本信息</h4>
|
||||
</el-col>
|
||||
<el-col :span="4" style="display: flex; justify-content: center;">
|
||||
<el-tag :type="getApprovalStatusType(form.approvalStatus)">{{
|
||||
getApprovalStatusText(form.approvalStatus) }}</el-tag>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="区县名称" prop="区县名称">
|
||||
<el-input disabled v-model="form.districtName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="路线编码" prop="路线编码">
|
||||
<el-input disabled v-model="form.routeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="实施里程" prop="实施里程">
|
||||
<el-input-number disabled v-model="form.implementMileage" :controls="false">
|
||||
<template #suffix>
|
||||
<span>公里</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="塌方及损失" prop="塌方及损失">
|
||||
<el-input-number disabled v-model="form.earthworkLoss" :controls="false">
|
||||
<template #suffix>
|
||||
<span>方/万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="起点桩号" prop="起点桩号">
|
||||
<el-input disabled v-model="form.startStakeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="止点桩号" prop="止点桩号">
|
||||
<el-input disabled v-model="form.endStakeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="路况位置" prop="路况位置">
|
||||
<el-input disabled v-model="form.roadLocation"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="阻断点小地名" prop="阻断点小地名">
|
||||
<el-input disabled v-model="form.blockedPointName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="灾害类型" prop="灾害类型">
|
||||
<el-input disabled v-model="form.disasterType"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="预估费用" prop="预估费用">
|
||||
<el-input-number disabled v-model="form.estimatedCost" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="技术等级" prop="技术等级">
|
||||
<el-select disabled v-model="form.technicalGrade">
|
||||
<el-option
|
||||
v-for="item in [{ value: '三级', label: '三级' }, { value: '二级', label: '二级' }, { value: '一级', label: '一级' }]"
|
||||
:key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="资金来源" prop="资金来源">
|
||||
<el-input disabled v-model="form.fundingSource"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="处置灾毁处数" prop="处置灾毁处数">
|
||||
<el-input-number disabled v-model="form.disposalCount" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="已完工处数" prop="已完工处数">
|
||||
<el-input-number disabled v-model="form.completedCount" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="总投资" prop="总投资">
|
||||
<el-input-number disabled v-model="form.totalInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目费用类型" prop="项目费用类型">
|
||||
<el-radio-group disabled v-model="form.projectExpenseType">
|
||||
<el-radio value="自费重修">自费重修</el-radio>
|
||||
<el-radio value="申报重修">申报重修</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<h4 style="margin:0 0 20px 50px;">实施情况</h4>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="主要建设内容" prop="主要建设内容">
|
||||
<el-input disabled type="textarea" v-model="form.mainConstructionContent" clearable>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="开工或预计开工时间" prop="开工或预计开工时间">
|
||||
<el-date-picker disabled type="date" v-model="form.startTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="完工或预计完工时间" prop="完工或预计完工时间">
|
||||
<el-date-picker disabled type="date" v-model="form.endTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否在部交通统计报表管理系统报送投资" prop="是否在部交通统计报表管理系统报送投资" label-width="300px">
|
||||
<el-radio-group disabled v-model="form.isReportedToMinistry">
|
||||
<el-radio :value="0">是</el-radio>
|
||||
<el-radio :value="1">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="已报送投资额" prop="已报送投资额">
|
||||
<el-input-number disabled v-model="form.reportedInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目实施进度" prop="项目实施进度">
|
||||
<el-select disabled v-model="form.projectProgress">
|
||||
<el-option v-for="item in [
|
||||
{ value: '立项', label: '立项' },
|
||||
{ value: '财政评审', label: '财政评审' },
|
||||
{ value: '开展施工图设计', label: '开展施工图设计' },
|
||||
{ value: '完成施设于批复', label: '完成施设于批复' },
|
||||
]" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位名称" prop="建设单位名称">
|
||||
<el-input disabled v-model="form.constructionUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位联系人" prop="建设单位联系人">
|
||||
<el-input disabled v-model="form.constructionUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位联系人电话" prop="建设单位联系人电话">
|
||||
<el-input disabled v-model="form.constructionUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工单位名称" prop="施工单位名称">
|
||||
<el-input disabled v-model="form.executionUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工单位联系人" prop="施工单位联系人">
|
||||
<el-input disabled v-model="form.executionUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工单位联系电话" prop="施工单位联系电话">
|
||||
<el-input disabled v-model="form.executionUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计单位名称" prop="设计单位名称">
|
||||
<el-input disabled v-model="form.designUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计单位联系人" prop="设计单位联系人">
|
||||
<el-input disabled v-model="form.designUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计单位联系人电话" prop="设计单位联系人电话">
|
||||
<el-input disabled v-model="form.designUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监理单位名称" prop="监理单位名称">
|
||||
<el-input disabled v-model="form.supervisionUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监理单位联系人" prop="监理单位联系人">
|
||||
<el-input disabled v-model="form.supervisionUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监理单位联系电话" prop="监理单位联系电话">
|
||||
<el-input disabled v-model="form.supervisionUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工图批复时间" prop="施工图批复时间">
|
||||
<el-date-picker disabled type="date" v-model="form.designApprovalTime" clearable
|
||||
format="YYYY-MM-DD" value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工图设计批复文件(附件)" prop="施工图设计批复文件" label-width="200px">
|
||||
<FileUpload readonly type="image" :limit="9" v-model="designApprovalFiles" :fileType=2 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工合同时间" prop="施工合同时间">
|
||||
<el-date-picker disabled type="date" v-model="form.contractTime" clearable
|
||||
format="YYYY-MM-DD" value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工合同金额" prop="施工合同金额">
|
||||
<el-input-number disabled v-model="form.contractAmount" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工合同(附件)" prop="施工合同">
|
||||
<FileUpload readonly type="image" :limit="9" v-model="contractFiles" :fileType=3 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设完成投资" prop="建设完成投资">
|
||||
<el-input-number disabled v-model="form.completedInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="交竣工验收时间" prop="交竣工验收时间">
|
||||
<el-date-picker disabled type="date" v-model="form.acceptanceTime" clearable
|
||||
format="YYYY-MM-DD" value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="交竣工证书(附件)" prop="交竣工证书" label-width="200px">
|
||||
<FileUpload readonly type="image" :limit="9" v-model="acceptanceFiles" :fileType=4 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="其他佐证文件" prop="其他佐证文件">
|
||||
<FileUpload readonly type="image" :limit="9" v-model="otherFiles" :fileType=6 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="完工项目上传图片(附件)" prop="完工项目上传图片" label-width="200px">
|
||||
<FileUpload readonly type="image" :limit="9" v-model="completedFiles" :fileType=5 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div v-if="form.rejectReason">
|
||||
<el-row>
|
||||
<h4 style="margin:0 0 20px 50px;">驳回原因</h4>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<span style="margin:0 0 20px 50px;"> {{form.rejectReason}} </span>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="button-box">
|
||||
<el-button type="primary" @click="goback" size="large">返回</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
import { ref, onMounted, watch, reactive, toRaw } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
||||
import { request } from '../../../../../shared/utils/request'
|
||||
import { ElLoading, ElMessage } from 'element-plus'
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const form = ref({})
|
||||
const formRef = ref(null)
|
||||
|
||||
// 附件分类: 1-现场图片/视频 2-施工图设计批复文件 3-施工合同 4-交竣工证书 5-完工项目上传图片 6-其他佐证文件
|
||||
const designApprovalFiles = ref([]) // 施工图设计批复文件
|
||||
const contractFiles = ref([]) // 施工合同
|
||||
const acceptanceFiles = ref([]) // 交竣工证书
|
||||
const completedFiles = ref([]) // 完工项目上传图片
|
||||
const otherFiles = ref([]) // 其他佐证文件
|
||||
|
||||
// 获取审批状态文本
|
||||
const getApprovalStatusText = (status) => {
|
||||
const statusMap = {
|
||||
0: '待区县审批',
|
||||
1: '区县审批通过(待业务部门审批)',
|
||||
2: '区县审批驳回',
|
||||
3: '业务部门审批通过',
|
||||
4: '业务部门审批驳回'
|
||||
}
|
||||
return statusMap[status] || '未知状态'
|
||||
}
|
||||
|
||||
// 获取审批状态标签类型
|
||||
const getApprovalStatusType = (status) => {
|
||||
const typeMap = {
|
||||
0: 'warning', // 待区县审批 - 警告色
|
||||
1: 'primary', // 区县审批通过 - 主要色
|
||||
2: 'danger', // 区县审批驳回 - 危险色
|
||||
3: 'success', // 业务部门审批通过 - 成功色
|
||||
4: 'danger' // 业务部门审批驳回 - 危险色
|
||||
}
|
||||
return typeMap[status] || 'info'
|
||||
}
|
||||
|
||||
|
||||
|
||||
// watch(() => designApprovalFiles.value, (data) => {
|
||||
// console.log('@@@@@', data);
|
||||
// })
|
||||
|
||||
// watch(() => form.value, (data) => {
|
||||
// console.log('@@@@@form', data);
|
||||
// }, { deep: true })
|
||||
|
||||
// 获取详情信息
|
||||
const getDetail = async (id) => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/recovery/getById',
|
||||
method: 'GET',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
if (res.code === '00000') {
|
||||
form.value = res.data
|
||||
designApprovalFiles.value = res.data.designApprovalFiles
|
||||
contractFiles.value = res.data.contractFiles
|
||||
acceptanceFiles.value = res.data.acceptanceFiles
|
||||
completedFiles.value = res.data.completedFiles
|
||||
otherFiles.value = res.data.otherFiles
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message)
|
||||
console.log('error', error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onMounted(async() => {
|
||||
if (route.params.data) {
|
||||
const data = JSON.parse(decodeURIComponent(route.params.data));
|
||||
await getDetail(data)
|
||||
}
|
||||
})
|
||||
|
||||
const goback = () => {
|
||||
router.push({
|
||||
name: 'projectManagement2',
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.root {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.form-box {
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.button-box {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div class="detail-container">
|
||||
<el-form ref="formRef" :model="form" label-position="right" label-width="auto"
|
||||
style="max-height: 60vh; overflow-y: auto;" :rules="rules">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="" prop="驳回原因">
|
||||
<el-input v-model="form.rejectReason"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, computed } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
const formRef = ref(null);
|
||||
defineExpose({ formRef });
|
||||
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
驳回原因: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.rejectReason) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请输入驳回原因"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@ -0,0 +1,225 @@
|
||||
<template>
|
||||
<div class="detail-container">
|
||||
<el-form ref="formRef" :model="form" label-position="right" label-width="150px"
|
||||
style="max-height: 60vh; overflow-y: auto; padding-right: 50px" :rules="rules">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="区县名称" prop="区县名称">
|
||||
<el-input disabled v-model="form.districtName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="路线编码" prop="路线编码">
|
||||
<el-input disabled v-model="form.routeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="实施里程" prop="实施里程">
|
||||
<el-input-number disabled v-model="form.implementMileage" :controls="false">
|
||||
<template #suffix>
|
||||
<span>公里</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="塌方及损失" prop="塌方及损失">
|
||||
<el-input-number disabled v-model="form.earthworkLoss" :controls="false">
|
||||
<template #suffix>
|
||||
<span>方/万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="起点桩号" prop="起点桩号">
|
||||
<el-input disabled v-model="form.startStakeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="止点桩号" prop="止点桩号">
|
||||
<el-input disabled v-model="form.endStakeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="路况位置" prop="路况位置">
|
||||
<el-input disabled v-model="form.roadLocation"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="阻断点小地名" prop="阻断点小地名">
|
||||
<el-input disabled v-model="form.blockedPointName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="灾害类型" prop="灾害类型">
|
||||
<el-input disabled v-model="form.disasterType"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="预估费用" prop="预估费用">
|
||||
<el-input-number disabled v-model="form.estimatedCost" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="技术等级" prop="技术等级">
|
||||
<el-select v-model="form.technicalGrade">
|
||||
<el-option
|
||||
v-for="item in [{ value: '三级', label: '三级' }, { value: '二级', label: '二级' }, { value: '一级', label: '一级' }]"
|
||||
:key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="资金来源" prop="资金来源">
|
||||
<el-input v-model="form.fundingSource"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="处置灾毁处数" prop="处置灾毁处数">
|
||||
<el-input-number v-model="form.disposalCount" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="已完工处数" prop="已完工处数">
|
||||
<el-input-number v-model="form.completedCount" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="总投资" prop="总投资">
|
||||
<el-input-number v-model="form.totalInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目费用类型" prop="项目费用类型">
|
||||
<el-radio-group v-model="form.projectExpenseType">
|
||||
<el-radio value="自费重修">自费重修</el-radio>
|
||||
<el-radio value="申报重修">申报重修</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, computed } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
const formRef = ref(null);
|
||||
defineExpose({ formRef });
|
||||
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
技术等级: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.technicalGrade) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请选择技术等级"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
资金来源: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.fundingSource) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请填写资金来源"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
处置灾毁处数: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.disposalCount) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请填写处置灾毁处数"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
已完工处数: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.completedCount) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请填写已完工处数"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
总投资: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.totalInvestment) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请填写总投资数"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
项目费用类型: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.projectExpenseType) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请选择项目费用类型"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@ -0,0 +1,399 @@
|
||||
import { h, ref, onMounted, reactive, watch, toRaw, nextTick } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import ExamineDialog from "./examineDialog.vue";
|
||||
import RejectDialog from './rejectDialog.vue';
|
||||
import { ElLoading, ElText } from 'element-plus'
|
||||
|
||||
const tableData = ref([]); // 表格数据
|
||||
const modelVisible = ref(false); // 弹窗状态
|
||||
const drawerVisible = ref(false); // 抽屉状态
|
||||
// 弹窗内容
|
||||
const model = reactive({
|
||||
title: '',
|
||||
content: null,
|
||||
props: {},
|
||||
onCancel: null,
|
||||
onConfirm: null,
|
||||
width: '',
|
||||
footerPosition: null,
|
||||
onCancelType: null,
|
||||
onConfirmName: null,
|
||||
onCancelName: null,
|
||||
tagContent: null,
|
||||
tagType: null,
|
||||
});
|
||||
const form = reactive({
|
||||
});
|
||||
// 抽屉内容
|
||||
const drawer = reactive({
|
||||
title: '',
|
||||
content: null,
|
||||
props: {},
|
||||
onCancel: null,
|
||||
onConfirm: null,
|
||||
direction: 'rtl',
|
||||
size: '50%'
|
||||
});
|
||||
const dialogRef = ref(null); // 弹窗实例
|
||||
const drawerRef = ref(null); // 抽屉实例
|
||||
|
||||
// 第二个弹窗
|
||||
const model2 = reactive({
|
||||
title: '',
|
||||
content: null,
|
||||
props: {},
|
||||
onCancel: null,
|
||||
onConfirm: null,
|
||||
width: '',
|
||||
footerPosition: null,
|
||||
onCancelType: null,
|
||||
onConfirmName: null,
|
||||
onCancelName: null,
|
||||
tagContent: null,
|
||||
tagType: null,
|
||||
});
|
||||
const modelVisible2 = ref(false);
|
||||
const dialogRef2 = ref(null);
|
||||
|
||||
|
||||
|
||||
// 过滤条件
|
||||
const filterData = reactive({
|
||||
})
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
pageSizes: [10, 20, 50],
|
||||
layout: "prev, pager, next, jumper",
|
||||
onChange: (page, pageSize) => {
|
||||
pagination.current = page;
|
||||
pagination.pageSize = pageSize;
|
||||
getTableData(filterData);
|
||||
},
|
||||
});
|
||||
|
||||
// 获取项目列表
|
||||
const getTableData = async (filterData = {}) => {
|
||||
try {
|
||||
// 过滤空字符串属性
|
||||
const filteredParams = {};
|
||||
Object.keys(filterData).forEach(key => {
|
||||
if (filterData[key] !== '' && filterData[key] != null) {
|
||||
filteredParams[key] = filterData[key];
|
||||
}
|
||||
});
|
||||
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/recovery/list',
|
||||
method: "GET",
|
||||
params: {
|
||||
...filteredParams,
|
||||
submitTimeStart: filteredParams?.submitTimeStart ? filteredParams.submitTimeStart + `-01-01 00:00:00` : null,
|
||||
pageNum: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
}
|
||||
})
|
||||
if (res.code === '00000') {
|
||||
tableData.value = res.data.records
|
||||
pagination.total = res.data.total;
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('获取项目列表失败');
|
||||
console.error('获取项目列表失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 驳回项目
|
||||
const rejectProject = async () => {
|
||||
try {
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '操作中',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
})
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/recovery/approve',
|
||||
method: 'POST',
|
||||
data: {
|
||||
id: form.id,
|
||||
approveLevel: 1,
|
||||
isPass: false,
|
||||
rejectReason: form.rejectReason,
|
||||
}
|
||||
})
|
||||
loading.close();
|
||||
if (res.code === '00000') {
|
||||
ElMessage.success('操作成功');
|
||||
modelVisible.value = false;
|
||||
modelVisible2.value = false;
|
||||
getTableData(filterData);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('操作失败');
|
||||
console.error('驳回项目失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取项目详情
|
||||
const getDetailData = async (id) => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: `/snow-ops-platform/recovery/getById`,
|
||||
method: 'GET',
|
||||
params: {
|
||||
id: id,
|
||||
}
|
||||
});
|
||||
if (res.code === '00000') {
|
||||
return res.data;
|
||||
} else {
|
||||
throw new Error(res.message);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('获取项目详情失败');
|
||||
console.error('获取项目详情失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default () => {
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
// 记录访问的项目管理模块
|
||||
onMounted(() => {
|
||||
sessionStorage.setItem('lastVisitedProjectManagement', 'projectManagement')
|
||||
})
|
||||
|
||||
const columns = [
|
||||
{
|
||||
prop: "districtName",
|
||||
label: "区县",
|
||||
},
|
||||
{
|
||||
prop: "routeNo",
|
||||
label: "路线编码",
|
||||
},
|
||||
{
|
||||
prop: "disasterType",
|
||||
label: "灾害类型",
|
||||
},
|
||||
{
|
||||
prop: "startStakeNo",
|
||||
label: "起点桩号",
|
||||
},
|
||||
{
|
||||
prop: "endStakeNo",
|
||||
label: "止点桩号",
|
||||
},
|
||||
{
|
||||
prop: "implementMileage",
|
||||
label: "实施里程(公里)",
|
||||
},
|
||||
{
|
||||
prop: "technicalGrade",
|
||||
label: "技术等级",
|
||||
},
|
||||
{
|
||||
prop: "totalInvestment",
|
||||
label: "总投资金额(万元)",
|
||||
},
|
||||
{
|
||||
prop: "estimatedCost",
|
||||
label: "投资估算(万元)",
|
||||
},
|
||||
{
|
||||
prop: "startTime",
|
||||
label: "开工或预计开工时间",
|
||||
},
|
||||
{
|
||||
prop: "endTime",
|
||||
label: "完工或预计完工时间",
|
||||
},
|
||||
{
|
||||
prop: "reportStatus",
|
||||
label: "申报状态",
|
||||
formatter: (row) => {
|
||||
const colorMap = {
|
||||
0: '#409EFF', // 蓝色 - 未申报
|
||||
1: '#67C23A', // 绿色 - 已申报
|
||||
};
|
||||
const textMap = {
|
||||
0: '未申报',
|
||||
1: '已申报',
|
||||
};
|
||||
const status = row.reportStatus;
|
||||
const color = colorMap[status] || '#909399';
|
||||
const text = textMap[status] || '未知状态';
|
||||
return h(ElText, { style: { color } }, text);
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: "approvalStatus",
|
||||
width: 150,
|
||||
label: "审批状态",
|
||||
formatter: (row) => {
|
||||
const colorMap = {
|
||||
0: '#409EFF', // 蓝色 - 待区县审批
|
||||
1: '#67C23A', // 绿色 - 区县审批通过
|
||||
2: '#F56C6C', // 红色 - 区县审批驳回
|
||||
3: '#67C23A', // 绿色 - 业务部门审批通过
|
||||
4: '#F56C6C', // 红色 - 业务部门审批驳回
|
||||
};
|
||||
const textMap = {
|
||||
0: '待区县审批',
|
||||
1: '区县审批通过(待业务部门审批)',
|
||||
2: '区县审批驳回',
|
||||
3: '业务部门审批通过',
|
||||
4: '业务部门审批驳回',
|
||||
};
|
||||
const status = row.approvalStatus;
|
||||
const color = colorMap[status] || '#909399';
|
||||
const text = textMap[status] || '未知状态';
|
||||
return h(ElText, { style: { color } }, text);
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: "updateTime",
|
||||
label: "更新日期",
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 150,
|
||||
render: (row) => () =>
|
||||
h("div", { class: "action-btns" }, [
|
||||
row.approvalStatus === 0 ? h(
|
||||
ElButton,
|
||||
{
|
||||
type: "primary",
|
||||
link: true,
|
||||
onClick: async () => {
|
||||
openExamineDialog(row);
|
||||
},
|
||||
},
|
||||
() => "审批"
|
||||
) : null,
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
type: "primary",
|
||||
link: true,
|
||||
style: row.approvalStatus === 0 ? "margin-left: 10px;" : "",
|
||||
onClick: async () => {
|
||||
gotoDetaillPage(row);
|
||||
},
|
||||
},
|
||||
() => "详情"
|
||||
),
|
||||
]),
|
||||
},
|
||||
]
|
||||
|
||||
// 打开审批弹窗
|
||||
const openExamineDialog = async (row) => {
|
||||
const data = await getDetailData(row.id)
|
||||
model.title = '项目审批';
|
||||
Object.assign(form, data);
|
||||
model.props = {
|
||||
form: form,
|
||||
};
|
||||
model.content = ExamineDialog;
|
||||
model.onCancel = () => {
|
||||
model2.title = '驳回原因';
|
||||
model2.props = {
|
||||
form: form,
|
||||
}
|
||||
model2.content = RejectDialog;
|
||||
model2.onCancel = () => {
|
||||
modelVisible2.value = false;
|
||||
}
|
||||
model2.onConfirm = async () => {
|
||||
await dialogRef2?.value?.dynamicComponentRef?.formRef.validate().then(async () => {
|
||||
await rejectProject()
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error('请处理表单中的错误项');
|
||||
});
|
||||
|
||||
}
|
||||
model2.width = '30%'
|
||||
model2.footerPosition = 'center'
|
||||
model2.onConfirmName = '确定'
|
||||
model2.onCancelName = '取消'
|
||||
modelVisible2.value = true;
|
||||
};
|
||||
model.onConfirm = async () => {
|
||||
await dialogRef?.value?.dynamicComponentRef?.formRef.validate().then(() => {
|
||||
router.push({
|
||||
name: 'projectAdd',
|
||||
params: {
|
||||
data: encodeURIComponent(JSON.stringify(form)),
|
||||
}
|
||||
})
|
||||
modelVisible.value = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error('请处理表单中的错误项');
|
||||
});
|
||||
};
|
||||
model.width = "50%"
|
||||
model.footerPosition = 'flex-end'
|
||||
model.onCancelType = 'danger'
|
||||
model.onConfirmName = '审批通过'
|
||||
model.onCancelName = '审批驳回'
|
||||
// model.tagType = 'warning'
|
||||
// model.tagContent = '测试'
|
||||
modelVisible.value = true;
|
||||
}
|
||||
|
||||
// 跳转至详情页面
|
||||
const gotoDetaillPage = (row) => {
|
||||
router.push({
|
||||
name: 'projectDetail',
|
||||
params: {
|
||||
data: encodeURIComponent(JSON.stringify(row.id))
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getTableData();
|
||||
})
|
||||
|
||||
|
||||
watch(filterData, (val) => {
|
||||
getTableData(filterData);
|
||||
}, { deep: true })
|
||||
|
||||
|
||||
return {
|
||||
tableData,
|
||||
filterData,
|
||||
pagination,
|
||||
columns,
|
||||
|
||||
modelVisible,
|
||||
model,
|
||||
drawerVisible,
|
||||
drawer,
|
||||
dialogRef,
|
||||
drawerRef,
|
||||
openExamineDialog,
|
||||
|
||||
model2,
|
||||
modelVisible2,
|
||||
dialogRef2,
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="root">
|
||||
<div class="search-box">
|
||||
<el-date-picker v-model="script.filterData.submitTimeStart" type="year" placeholder="年度" format="YYYY"
|
||||
value-format="YYYY" style="width: 240px; margin-right: 10px" size="large" />
|
||||
<el-input v-model="script.filterData.routeNo" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="路线编码" :suffix-icon="Search" />
|
||||
</div>
|
||||
<div class="event-box">
|
||||
<el-button type="primary" color="#952DE6" @click="">导出</el-button>
|
||||
</div>
|
||||
<DynamicTable :dataSource="script.tableData.value" :columns="script.columns" :autoHeight="true"
|
||||
:pagination="script.pagination">
|
||||
|
||||
</DynamicTable>
|
||||
<div class="model-box">
|
||||
<MyDialog v-model="script.modelVisible.value" :title="script.model?.title"
|
||||
:dynamicComponent="script.model?.content" :component-props="script.model?.props"
|
||||
:onConfirm="script.model?.onConfirm" :onCancel="script.model?.onCancel" ref="dialogRef"
|
||||
:width="script.model?.width" :footer-position="script.model?.footerPosition"
|
||||
:onCancelType="script.model?.onCancelType" :onConfirmName="script.model?.onConfirmName"
|
||||
:onCancelName="script.model?.onCancelName" :tagContent="script.model?.tagContent"
|
||||
:tagType="script.model?.tagType">
|
||||
</MyDialog>
|
||||
<MyDialog v-model="script.modelVisible2.value" :title="script.model2?.title"
|
||||
:dynamicComponent="script.model2?.content" :component-props="script.model2?.props"
|
||||
:onConfirm="script.model2?.onConfirm" :onCancel="script.model2?.onCancel" ref="dialogRef2"
|
||||
:width="script.model2?.width" :footer-position="script.model2?.footerPosition"
|
||||
:onCancelType="script.model2?.onCancelType" :onConfirmName="script.model2?.onConfirmName"
|
||||
:onCancelName="script.model2?.onCancelName" :tagContent="script.model2?.tagContent"
|
||||
:tagType="script.model2?.tagType">
|
||||
</MyDialog>
|
||||
<MyDrawer v-model="script.drawerVisible.value" :title="script.drawer?.title"
|
||||
:dynamicComponent="script.drawer?.content" :component-props="script.drawer?.props"
|
||||
:onConfirm="script.drawer?.onConfirm" :onCancel="script.drawer?.onCancel" ref="drawerRef"
|
||||
:direction="script.drawer?.direction" :size="script.drawer?.size">
|
||||
</MyDrawer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import DynamicTable from "../../../component/DynamicTable/index.js";
|
||||
import { Search } from "@element-plus/icons-vue";
|
||||
import MyDialog from "../../../component/MyDialog/index.js";
|
||||
import MyDrawer from "../../../component/MyDrawer/index.js";
|
||||
import scriptFn from "./index.js";
|
||||
const script = scriptFn();
|
||||
const { dialogRef, drawerRef, dialogRef2 } = script;
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.root {
|
||||
height: 100%;
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.event-box {
|
||||
margin: 20px 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,453 @@
|
||||
<template>
|
||||
<div class="root">
|
||||
<div class="form-box">
|
||||
<el-form ref="formRef" :model="form" label-position="right" label-width="150px" style="padding-right: 50px"
|
||||
:rules="rules">
|
||||
<el-row>
|
||||
<h4 style="margin:0 0 20px 50px;">基本信息</h4>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="区县名称" prop="区县名称">
|
||||
<el-input disabled v-model="form.districtName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="路线编码" prop="路线编码">
|
||||
<el-input disabled v-model="form.routeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="实施里程" prop="实施里程">
|
||||
<el-input-number disabled v-model="form.implementMileage" :controls="false">
|
||||
<template #suffix>
|
||||
<span>公里</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="塌方及损失" prop="塌方及损失">
|
||||
<el-input-number disabled v-model="form.earthworkLoss" :controls="false">
|
||||
<template #suffix>
|
||||
<span>方/万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="起点桩号" prop="起点桩号">
|
||||
<el-input disabled v-model="form.startStakeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="止点桩号" prop="止点桩号">
|
||||
<el-input disabled v-model="form.endStakeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="路况位置" prop="路况位置">
|
||||
<el-input disabled v-model="form.roadLocation"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="阻断点小地名" prop="阻断点小地名">
|
||||
<el-input disabled v-model="form.blockedPointName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="灾害类型" prop="灾害类型">
|
||||
<el-input disabled v-model="form.disasterType"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="预估费用" prop="预估费用">
|
||||
<el-input-number disabled v-model="form.estimatedCost" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="技术等级" prop="技术等级">
|
||||
<el-select disabled v-model="form.technicalGrade">
|
||||
<el-option
|
||||
v-for="item in [{ value: '三级', label: '三级' }, { value: '二级', label: '二级' }, { value: '一级', label: '一级' }]"
|
||||
:key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="资金来源" prop="资金来源">
|
||||
<el-input disabled v-model="form.fundingSource"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="处置灾毁处数" prop="处置灾毁处数">
|
||||
<el-input-number disabled v-model="form.disposalCount" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="已完工处数" prop="已完工处数">
|
||||
<el-input-number disabled v-model="form.completedCount" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="总投资" prop="总投资">
|
||||
<el-input-number disabled v-model="form.totalInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目费用类型" prop="项目费用类型">
|
||||
<el-radio-group disabled v-model="form.projectExpenseType">
|
||||
<el-radio value="自费重修">自费重修</el-radio>
|
||||
<el-radio value="申报重修">申报重修</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<h4 style="margin:0 0 20px 50px;">实施情况</h4>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="主要建设内容" prop="主要建设内容">
|
||||
<el-input type="textarea" v-model="form.mainConstructionContent" clearable>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="开工或预计开工时间" prop="开工或预计开工时间">
|
||||
<el-date-picker type="date" v-model="form.startTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="完工或预计完工时间" prop="完工或预计完工时间">
|
||||
<el-date-picker type="date" v-model="form.endTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否在部交通统计报表管理系统报送投资" prop="是否在部交通统计报表管理系统报送投资" label-width="300px">
|
||||
<el-radio-group v-model="form.isReportedToMinistry">
|
||||
<el-radio value="0">是</el-radio>
|
||||
<el-radio value="1">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="已报送投资额" prop="已报送投资额">
|
||||
<el-input-number v-model="form.reportedInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目实施进度" prop="项目实施进度">
|
||||
<el-select :disabled="form.projectExpenseType === '申报重修'" v-model="form.projectProgress">
|
||||
<el-option v-for="item in [
|
||||
{ value: '立项', label: '立项' },
|
||||
{ value: '财政评审', label: '财政评审' },
|
||||
{ value: '开展施工图设计', label: '开展施工图设计' },
|
||||
{ value: '完成施设于批复', label: '完成施设于批复' },
|
||||
]" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位名称" prop="建设单位名称">
|
||||
<el-input v-model="form.constructionUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位联系人" prop="建设单位联系人">
|
||||
<el-input v-model="form.constructionUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位联系人电话" prop="建设单位联系人电话">
|
||||
<el-input v-model="form.constructionUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工单位名称" prop="施工单位名称">
|
||||
<el-input v-model="form.executionUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工单位联系人" prop="施工单位联系人">
|
||||
<el-input v-model="form.executionUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工单位联系电话" prop="施工单位联系电话">
|
||||
<el-input v-model="form.executionUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计单位名称" prop="设计单位名称">
|
||||
<el-input v-model="form.designUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计单位联系人" prop="设计单位联系人">
|
||||
<el-input v-model="form.designUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计单位联系人电话" prop="设计单位联系人电话">
|
||||
<el-input v-model="form.designUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监理单位名称" prop="监理单位名称">
|
||||
<el-input v-model="form.supervisionUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监理单位联系人" prop="监理单位联系人">
|
||||
<el-input v-model="form.supervisionUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监理单位联系电话" prop="监理单位联系电话">
|
||||
<el-input v-model="form.supervisionUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工图批复时间" prop="施工图批复时间">
|
||||
<el-date-picker type="date" v-model="form.designApprovalTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工图设计批复文件(附件)" prop="施工图设计批复文件" label-width="200px">
|
||||
<FileUpload type="image" :limit="9" v-model="designApprovalFiles" :fileType=2 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工合同时间" prop="施工合同时间">
|
||||
<el-date-picker type="date" v-model="form.contractTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工合同金额" prop="施工合同金额">
|
||||
<el-input-number v-model="form.contractAmount" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工合同(附件)" prop="施工合同">
|
||||
<FileUpload type="image" :limit="9" v-model="contractFiles" :fileType=3 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设完成投资" prop="建设完成投资">
|
||||
<el-input-number v-model="form.completedInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="交竣工验收时间" prop="交竣工验收时间">
|
||||
<el-date-picker type="date" v-model="form.acceptanceTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="交竣工证书(附件)" prop="交竣工证书" label-width="200px">
|
||||
<FileUpload type="image" :limit="9" v-model="acceptanceFiles" :fileType=4 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="其他佐证文件" prop="其他佐证文件">
|
||||
<FileUpload type="image" :limit="9" v-model="otherFiles" :fileType=6 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="完工项目上传图片(附件)" prop="完工项目上传图片" label-width="200px">
|
||||
<FileUpload type="image" :limit="9" v-model="completedFiles" :fileType=5 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="button-box">
|
||||
<el-button type="primary" @click="submit" size="large">提交</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
import { ref, onMounted, watch, reactive, toRaw } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
||||
import { request } from '../../../../../shared/utils/request'
|
||||
import { ElLoading } from 'element-plus'
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const form = ref({})
|
||||
const formRef = ref(null)
|
||||
|
||||
// 附件分类: 1-现场图片/视频 2-施工图设计批复文件 3-施工合同 4-交竣工证书 5-完工项目上传图片 6-其他佐证文件
|
||||
const designApprovalFiles = ref([]) // 施工图设计批复文件
|
||||
const contractFiles = ref([]) // 施工合同
|
||||
const acceptanceFiles = ref([]) // 交竣工证书
|
||||
const completedFiles = ref([]) // 完工项目上传图片
|
||||
const otherFiles = ref([]) // 其他佐证文件
|
||||
|
||||
|
||||
|
||||
// watch(() => designApprovalFiles.value, (data) => {
|
||||
// console.log('@@@@@', data);
|
||||
// })
|
||||
|
||||
// watch(() => form.value, (data) => {
|
||||
// console.log('@@@@@form', data);
|
||||
// }, { deep: true })
|
||||
|
||||
onMounted(() => {
|
||||
if (route.params.data) {
|
||||
const data = JSON.parse(decodeURIComponent(route.params.data));
|
||||
|
||||
if (data.projectExpenseType === '申报重修') {
|
||||
form.value = {
|
||||
...data,
|
||||
projectProgress: '申报审批'
|
||||
}
|
||||
} else {
|
||||
form.value = data
|
||||
}
|
||||
designApprovalFiles.value = data.designApprovalFiles
|
||||
contractFiles.value = data.contractFiles
|
||||
acceptanceFiles.value = data.acceptanceFiles
|
||||
completedFiles.value = data.completedFiles
|
||||
otherFiles.value = data.otherFiles
|
||||
}
|
||||
})
|
||||
|
||||
const submit = async () => {
|
||||
const data = {
|
||||
project: form.value,
|
||||
designApprovalFiles: designApprovalFiles.value,
|
||||
contractFiles: contractFiles.value,
|
||||
acceptanceFiles: acceptanceFiles.value,
|
||||
completedFiles: completedFiles.value,
|
||||
otherFiles: otherFiles.value,
|
||||
}
|
||||
await formRef.value.validate().then(async () => {
|
||||
try {
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: '操作中',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
})
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/recovery/report',
|
||||
method: 'POST',
|
||||
data: data,
|
||||
})
|
||||
loading.close();
|
||||
if (res.code === '00000') {
|
||||
router.push({
|
||||
name: 'projectManagement',
|
||||
})
|
||||
} else {
|
||||
throw new Error(res.message || '操作失败')
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error('请处理表单中的错误项');
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.root {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.form-box {
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.button-box {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,473 @@
|
||||
<template>
|
||||
<div class="root">
|
||||
<div class="form-box">
|
||||
<el-form ref="formRef" :model="form" label-position="right" label-width="150px" style="padding-right: 50px"
|
||||
:rules="rules">
|
||||
<el-row>
|
||||
<el-col :span="20">
|
||||
<h4 style="margin:0 0 20px 50px;">基本信息</h4>
|
||||
</el-col>
|
||||
<el-col :span="4" style="display: flex; justify-content: center;">
|
||||
<el-tag :type="getApprovalStatusType(form.approvalStatus)">{{
|
||||
getApprovalStatusText(form.approvalStatus) }}</el-tag>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="区县名称" prop="区县名称">
|
||||
<el-input disabled v-model="form.districtName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="路线编码" prop="路线编码">
|
||||
<el-input disabled v-model="form.routeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="实施里程" prop="实施里程">
|
||||
<el-input-number disabled v-model="form.implementMileage" :controls="false">
|
||||
<template #suffix>
|
||||
<span>公里</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="塌方及损失" prop="塌方及损失">
|
||||
<el-input-number disabled v-model="form.earthworkLoss" :controls="false">
|
||||
<template #suffix>
|
||||
<span>方/万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="起点桩号" prop="起点桩号">
|
||||
<el-input disabled v-model="form.startStakeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="止点桩号" prop="止点桩号">
|
||||
<el-input disabled v-model="form.endStakeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="路况位置" prop="路况位置">
|
||||
<el-input disabled v-model="form.roadLocation"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="阻断点小地名" prop="阻断点小地名">
|
||||
<el-input disabled v-model="form.blockedPointName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="灾害类型" prop="灾害类型">
|
||||
<el-input disabled v-model="form.disasterType"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="预估费用" prop="预估费用">
|
||||
<el-input-number disabled v-model="form.estimatedCost" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="技术等级" prop="技术等级">
|
||||
<el-select disabled v-model="form.technicalGrade">
|
||||
<el-option
|
||||
v-for="item in [{ value: '三级', label: '三级' }, { value: '二级', label: '二级' }, { value: '一级', label: '一级' }]"
|
||||
:key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="资金来源" prop="资金来源">
|
||||
<el-input disabled v-model="form.fundingSource"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="处置灾毁处数" prop="处置灾毁处数">
|
||||
<el-input-number disabled v-model="form.disposalCount" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="已完工处数" prop="已完工处数">
|
||||
<el-input-number disabled v-model="form.completedCount" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="总投资" prop="总投资">
|
||||
<el-input-number disabled v-model="form.totalInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目费用类型" prop="项目费用类型">
|
||||
<el-radio-group disabled v-model="form.projectExpenseType">
|
||||
<el-radio value="自费重修">自费重修</el-radio>
|
||||
<el-radio value="申报重修">申报重修</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<h4 style="margin:0 0 20px 50px;">实施情况</h4>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="主要建设内容" prop="主要建设内容">
|
||||
<el-input disabled type="textarea" v-model="form.mainConstructionContent" clearable>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="开工或预计开工时间" prop="开工或预计开工时间">
|
||||
<el-date-picker disabled type="date" v-model="form.startTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="完工或预计完工时间" prop="完工或预计完工时间">
|
||||
<el-date-picker disabled type="date" v-model="form.endTime" clearable format="YYYY-MM-DD"
|
||||
value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否在部交通统计报表管理系统报送投资" prop="是否在部交通统计报表管理系统报送投资" label-width="300px">
|
||||
<el-radio-group disabled v-model="form.isReportedToMinistry">
|
||||
<el-radio :value="0">是</el-radio>
|
||||
<el-radio :value="1">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="已报送投资额" prop="已报送投资额">
|
||||
<el-input-number disabled v-model="form.reportedInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目实施进度" prop="项目实施进度">
|
||||
<el-select disabled v-model="form.projectProgress">
|
||||
<el-option v-for="item in [
|
||||
{ value: '立项', label: '立项' },
|
||||
{ value: '财政评审', label: '财政评审' },
|
||||
{ value: '开展施工图设计', label: '开展施工图设计' },
|
||||
{ value: '完成施设于批复', label: '完成施设于批复' },
|
||||
]" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位名称" prop="建设单位名称">
|
||||
<el-input disabled v-model="form.constructionUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位联系人" prop="建设单位联系人">
|
||||
<el-input disabled v-model="form.constructionUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设单位联系人电话" prop="建设单位联系人电话">
|
||||
<el-input disabled v-model="form.constructionUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工单位名称" prop="施工单位名称">
|
||||
<el-input disabled v-model="form.executionUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工单位联系人" prop="施工单位联系人">
|
||||
<el-input disabled v-model="form.executionUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工单位联系电话" prop="施工单位联系电话">
|
||||
<el-input disabled v-model="form.executionUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计单位名称" prop="设计单位名称">
|
||||
<el-input disabled v-model="form.designUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计单位联系人" prop="设计单位联系人">
|
||||
<el-input disabled v-model="form.designUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设计单位联系人电话" prop="设计单位联系人电话">
|
||||
<el-input disabled v-model="form.designUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监理单位名称" prop="监理单位名称">
|
||||
<el-input disabled v-model="form.supervisionUnit"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监理单位联系人" prop="监理单位联系人">
|
||||
<el-input disabled v-model="form.supervisionUnitContact"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="监理单位联系电话" prop="监理单位联系电话">
|
||||
<el-input disabled v-model="form.supervisionUnitPhone"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工图批复时间" prop="施工图批复时间">
|
||||
<el-date-picker disabled type="date" v-model="form.designApprovalTime" clearable
|
||||
format="YYYY-MM-DD" value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工图设计批复文件(附件)" prop="施工图设计批复文件" label-width="200px">
|
||||
<FileUpload readonly type="image" :limit="9" v-model="designApprovalFiles" :fileType=2 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工合同时间" prop="施工合同时间">
|
||||
<el-date-picker disabled type="date" v-model="form.contractTime" clearable
|
||||
format="YYYY-MM-DD" value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工合同金额" prop="施工合同金额">
|
||||
<el-input-number disabled v-model="form.contractAmount" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="施工合同(附件)" prop="施工合同">
|
||||
<FileUpload readonly type="image" :limit="9" v-model="contractFiles" :fileType=3 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="建设完成投资" prop="建设完成投资">
|
||||
<el-input-number disabled v-model="form.completedInvestment" :controls="false">
|
||||
<template #suffix>
|
||||
<span>万元</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="交竣工验收时间" prop="交竣工验收时间">
|
||||
<el-date-picker disabled type="date" v-model="form.acceptanceTime" clearable
|
||||
format="YYYY-MM-DD" value-format="YYYY-MM-DD">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="交竣工证书(附件)" prop="交竣工证书" label-width="200px">
|
||||
<FileUpload readonly type="image" :limit="9" v-model="acceptanceFiles" :fileType=4 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="其他佐证文件" prop="其他佐证文件">
|
||||
<FileUpload readonly type="image" :limit="9" v-model="otherFiles" :fileType=6 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="完工项目上传图片(附件)" prop="完工项目上传图片" label-width="200px">
|
||||
<FileUpload readonly type="image" :limit="9" v-model="completedFiles" :fileType=5 />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div v-if="form.rejectReason">
|
||||
<el-row>
|
||||
<h4 style="margin:0 0 20px 50px;">驳回原因</h4>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<span style="margin:0 0 20px 50px;"> {{form.rejectReason}} </span>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="button-box">
|
||||
<el-button type="primary" @click="goback" size="large">返回</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
import { ref, onMounted, watch, reactive, toRaw } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
||||
import { request } from '../../../../../shared/utils/request'
|
||||
import { ElLoading, ElMessage } from 'element-plus'
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const form = ref({})
|
||||
const formRef = ref(null)
|
||||
|
||||
// 附件分类: 1-现场图片/视频 2-施工图设计批复文件 3-施工合同 4-交竣工证书 5-完工项目上传图片 6-其他佐证文件
|
||||
const designApprovalFiles = ref([]) // 施工图设计批复文件
|
||||
const contractFiles = ref([]) // 施工合同
|
||||
const acceptanceFiles = ref([]) // 交竣工证书
|
||||
const completedFiles = ref([]) // 完工项目上传图片
|
||||
const otherFiles = ref([]) // 其他佐证文件
|
||||
|
||||
// 获取审批状态文本
|
||||
const getApprovalStatusText = (status) => {
|
||||
const statusMap = {
|
||||
0: '待区县审批',
|
||||
1: '区县审批通过(待业务部门审批)',
|
||||
2: '区县审批驳回',
|
||||
3: '业务部门审批通过',
|
||||
4: '业务部门审批驳回'
|
||||
}
|
||||
return statusMap[status] || '未知状态'
|
||||
}
|
||||
|
||||
// 获取审批状态标签类型
|
||||
const getApprovalStatusType = (status) => {
|
||||
const typeMap = {
|
||||
0: 'warning', // 待区县审批 - 警告色
|
||||
1: 'primary', // 区县审批通过 - 主要色
|
||||
2: 'danger', // 区县审批驳回 - 危险色
|
||||
3: 'success', // 业务部门审批通过 - 成功色
|
||||
4: 'danger' // 业务部门审批驳回 - 危险色
|
||||
}
|
||||
return typeMap[status] || 'info'
|
||||
}
|
||||
|
||||
|
||||
|
||||
// watch(() => designApprovalFiles.value, (data) => {
|
||||
// console.log('@@@@@', data);
|
||||
// })
|
||||
|
||||
// watch(() => form.value, (data) => {
|
||||
// console.log('@@@@@form', data);
|
||||
// }, { deep: true })
|
||||
|
||||
// 获取详情信息
|
||||
const getDetail = async (id) => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/recovery/getById',
|
||||
method: 'GET',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
if (res.code === '00000') {
|
||||
form.value = res.data
|
||||
designApprovalFiles.value = res.data.designApprovalFiles
|
||||
contractFiles.value = res.data.contractFiles
|
||||
acceptanceFiles.value = res.data.acceptanceFiles
|
||||
completedFiles.value = res.data.completedFiles
|
||||
otherFiles.value = res.data.otherFiles
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message)
|
||||
console.log('error', error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onMounted(async() => {
|
||||
if (route.params.data) {
|
||||
const data = JSON.parse(decodeURIComponent(route.params.data));
|
||||
await getDetail(data)
|
||||
}
|
||||
})
|
||||
|
||||
const goback = () => {
|
||||
router.push({
|
||||
name: 'projectManagement',
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.root {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.form-box {
|
||||
width: 100%;
|
||||
height: 90%;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.button-box {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div class="detail-container">
|
||||
<el-form ref="formRef" :model="form" label-position="right" label-width="auto"
|
||||
style="max-height: 60vh; overflow-y: auto;" :rules="rules">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="" prop="驳回原因">
|
||||
<el-input v-model="form.rejectReason"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, computed } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
const formRef = ref(null);
|
||||
defineExpose({ formRef });
|
||||
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
驳回原因: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.rejectReason) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请输入驳回原因"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@ -1,289 +0,0 @@
|
||||
<template>
|
||||
<div class="detail-container">
|
||||
<el-form ref="formRef" :model="form" label-position="right" label-width="150px"
|
||||
style="max-height: 60vh; overflow-y: auto; padding-right: 50px" :rules="rules" :disabled="disabled">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="区县名称" prop="区县名称">
|
||||
<el-input v-model="form.project.districtName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="路线编码" prop="路线编码">
|
||||
<el-input v-model="form.project.routeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="实施里程(公里)" prop="实施里程">
|
||||
<el-input-number v-model="form.project.implementMileage" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="塌方及损失" prop="塌方及损失">
|
||||
<el-input-number v-model="form.project.earthworkLoss" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="起点桩号" prop="起点桩号">
|
||||
<el-input v-model="form.project.startStakeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="止点桩号" prop="止点桩号">
|
||||
<el-input v-model="form.project.endStakeNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="路况位置" prop="路况位置">
|
||||
<el-input v-model="form.project.roadLocation"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="阻断点小地名" prop="阻断点小地名">
|
||||
<el-input v-model="form.project.blockedPointName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="灾害类型" prop="灾害类型">
|
||||
<el-input v-model="form.project.disasterType"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="预估费用" prop="预估费用">
|
||||
<el-input-number v-model="form.project.estimatedCost" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="技术等级" prop="技术等级">
|
||||
<el-select v-model="form.project.technicalGrade">
|
||||
<el-option
|
||||
v-for="item in [{ value: '三级', label: '三级' }, { value: '二级', label: '二级' }, { value: '一级', label: '一级' }]"
|
||||
:key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="资金来源" prop="资金来源">
|
||||
<el-input v-model="form.project.fundingSource"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="处置灾毁处数" prop="处置灾毁处数">
|
||||
<el-input-number v-model="form.project.disposalCount" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="已完工处数" prop="已完工处数">
|
||||
<el-input-number v-model="form.project.completedCount" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="总投资" prop="总投资">
|
||||
<el-input-number v-model="form.project.totalInvestment" :controls="false"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目费用类型" prop="项目费用类型">
|
||||
<el-radio-group v-model="form.project.projectExpenseType">
|
||||
<el-radio value="自费重修">自费重修</el-radio>
|
||||
<el-radio value="申报重修">申报重修</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, computed } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
const formRef = ref(null);
|
||||
defineExpose({ formRef });
|
||||
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
});
|
||||
const sfjwd = ref("是");
|
||||
const qx = ref("");
|
||||
const loading = ref(false);
|
||||
const selectOptions = ref([]);
|
||||
const qxList = ref([]);
|
||||
|
||||
// 根据用户信息 查询角色列表
|
||||
const getUserList = async (key) => {
|
||||
try {
|
||||
const keyword = key;
|
||||
let url = "";
|
||||
if (keyword) {
|
||||
url = `/snow-ops-platform/yhzry/getUserByKey?key=${keyword}`;
|
||||
} else {
|
||||
url = `/snow-ops-platform/yhzry/getUserByKey?key=`;
|
||||
}
|
||||
const res = await request({
|
||||
url: url,
|
||||
method: "GET",
|
||||
});
|
||||
if (res.code === "00000") {
|
||||
return res.data;
|
||||
} else {
|
||||
throw new Error(res.message);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message);
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
// 选择人员筛选
|
||||
const remoteMethod = async (query) => {
|
||||
if (query === "") {
|
||||
selectOptions.value = [];
|
||||
return [];
|
||||
}
|
||||
loading.value = true;
|
||||
const res = await getUserList(query);
|
||||
if (res) {
|
||||
selectOptions.value = res;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
// 根据区县名称 查询区县列表
|
||||
const getQxList = async (key) => {
|
||||
try {
|
||||
const keyword = key;
|
||||
let url = "";
|
||||
if (keyword) {
|
||||
url = `/snow-ops-platform/district/listDistricts?qxmc=${keyword}`;
|
||||
} else {
|
||||
url = `/snow-ops-platform/district/listDistricts?qxmc=`;
|
||||
}
|
||||
const res = await request({
|
||||
url: url,
|
||||
method: "GET",
|
||||
});
|
||||
if (res.code === "00000") {
|
||||
return res.data;
|
||||
} else {
|
||||
throw new Error(res.message);
|
||||
}
|
||||
} catch (error) { }
|
||||
};
|
||||
|
||||
// 选择区县筛选
|
||||
const remoteMethod_qx = async (query) => {
|
||||
loading.value = true;
|
||||
const res = await getQxList(query);
|
||||
if (res) {
|
||||
qxList.value = res;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
// 选择区县
|
||||
const handleSelect_qx = (value) => {
|
||||
props.form.qxmc = value;
|
||||
};
|
||||
|
||||
// 选择人员
|
||||
const handleSelect = (value) => {
|
||||
console.log("value", value);
|
||||
props.form.fzrXm = value.realName;
|
||||
props.form.fzrSjhm = value.phone;
|
||||
props.form.fzrUserId = value.userId;
|
||||
};
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
mc: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.mc) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请输入服务站名称"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
qxmc: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.qxmc) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请选择所属区县"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
fzr: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.fzrUserId && props.form.fzrXm && props.form.fzrSjhm) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请选择负责人"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
jd: [
|
||||
{
|
||||
required: sfjwd.value === "否",
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.jd) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请输入站点经度"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
wd: [
|
||||
{
|
||||
required: sfjwd.value === "否",
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.wd) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请输入站点纬度"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@ -1,235 +0,0 @@
|
||||
import { h, ref, onMounted, reactive, watch, toRaw, nextTick } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import ExamineDialog from "./examineDialog.vue";
|
||||
|
||||
const tableData = ref([]); // 表格数据
|
||||
const modelVisible = ref(false); // 弹窗状态
|
||||
const drawerVisible = ref(false); // 抽屉状态
|
||||
// 弹窗内容
|
||||
const model = reactive({
|
||||
title: '',
|
||||
content: null,
|
||||
props: {},
|
||||
onCancel: null,
|
||||
onConfirm: null,
|
||||
width: '',
|
||||
footerPosition: null,
|
||||
onCancelType: null,
|
||||
onConfirmName: null,
|
||||
onCancelName: null,
|
||||
tagContent: null,
|
||||
tagType: null,
|
||||
});
|
||||
const form = reactive({
|
||||
});
|
||||
const INIT_FORM = {
|
||||
project: {},
|
||||
fileList: []
|
||||
};
|
||||
// 抽屉内容
|
||||
const drawer = reactive({
|
||||
title: '',
|
||||
content: null,
|
||||
props: {},
|
||||
onCancel: null,
|
||||
onConfirm: null,
|
||||
direction: 'rtl',
|
||||
size: '50%'
|
||||
});
|
||||
const dialogRef = ref(null); // 弹窗实例
|
||||
const drawerRef = ref(null); // 抽屉实例
|
||||
|
||||
const columns = [
|
||||
{
|
||||
prop: "districtName",
|
||||
label: "区县",
|
||||
},
|
||||
{
|
||||
prop: "routeNo",
|
||||
label: "路线编码",
|
||||
},
|
||||
{
|
||||
prop: "disasterType",
|
||||
label: "灾害类型",
|
||||
},
|
||||
{
|
||||
prop: "startStakeNo",
|
||||
label: "起点桩号",
|
||||
},
|
||||
{
|
||||
prop: "endStakeNo",
|
||||
label: "止点桩号",
|
||||
},
|
||||
{
|
||||
prop: "implementMileage",
|
||||
label: "实施里程(公里)",
|
||||
},
|
||||
{
|
||||
prop: "technicalGrade",
|
||||
label: "技术等级",
|
||||
},
|
||||
{
|
||||
prop: "totalInvestment",
|
||||
label: "总投资金额(万元)",
|
||||
},
|
||||
{
|
||||
prop: "estimatedCost",
|
||||
label: "投资估算(万元)",
|
||||
},
|
||||
{
|
||||
prop: "startTime",
|
||||
label: "开工或预计开工时间",
|
||||
},
|
||||
{
|
||||
prop: "endTime",
|
||||
label: "完工或预计完工时间",
|
||||
},
|
||||
{
|
||||
prop: "approvalStatus",
|
||||
label: "审批状态",
|
||||
formatter: (row) => {
|
||||
const statusMap = {
|
||||
0: '待审批',
|
||||
1: '审批通过',
|
||||
2: '审批驳回'
|
||||
};
|
||||
return statusMap[row.approvalStatus] || '未知状态';
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: "updateTime",
|
||||
label: "更新日期",
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 150,
|
||||
render: (row) => () =>
|
||||
h("div", { class: "action-btns" }, [
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
type: "primary",
|
||||
link: true,
|
||||
onClick: async () => {
|
||||
},
|
||||
},
|
||||
() => "审批"
|
||||
),
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
type: "primary",
|
||||
link: true,
|
||||
style: "margin-left: 10px;",
|
||||
onClick: async () => {
|
||||
},
|
||||
},
|
||||
() => "详情"
|
||||
),
|
||||
]),
|
||||
},
|
||||
]
|
||||
|
||||
// 过滤条件
|
||||
const filterData = reactive({
|
||||
submitTimeStart: "",
|
||||
routeNo: "",
|
||||
})
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
pageSizes: [10, 20, 50],
|
||||
layout: "prev, pager, next, jumper",
|
||||
onChange: (page, pageSize) => {
|
||||
pagination.current = page;
|
||||
pagination.pageSize = pageSize;
|
||||
getTableData(filterData);
|
||||
},
|
||||
});
|
||||
|
||||
// 获取项目列表
|
||||
const getTableData = async (filterData) => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/recovery/list',
|
||||
method: "GET",
|
||||
params: {
|
||||
...filterData,
|
||||
submitTimeStart: filterData.submitTimeStart ? filterData.submitTimeStart+`-01-01 00:00:00` : null,
|
||||
pageNum: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('获取项目列表失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 打开审批弹窗
|
||||
const openExamineDialog = async () => {
|
||||
model.title = '项目审批';
|
||||
Object.assign(form, INIT_FORM);
|
||||
model.props = {
|
||||
form: form,
|
||||
};
|
||||
model.content = ExamineDialog;
|
||||
model.onCancel = () => {
|
||||
modelVisible.value = false;
|
||||
};
|
||||
model.onConfirm = async () => {
|
||||
dialogType.value = '';
|
||||
await dialogRef?.value?.dynamicComponentRef?.formRef.validate().then(() => {
|
||||
console.log('@@@@@填报项目', form);
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error('请处理表单中的错误项');
|
||||
});
|
||||
};
|
||||
model.width = "50%"
|
||||
model.footerPosition = 'flex-end'
|
||||
model.onCancelType = 'danger'
|
||||
model.onConfirmName = '审批通过'
|
||||
model.onCancelName = '审批驳回'
|
||||
// model.tagType = 'warning'
|
||||
// model.tagContent = '测试'
|
||||
modelVisible.value = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export default () => {
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
onMounted(() => {
|
||||
getTableData();
|
||||
})
|
||||
|
||||
|
||||
watch(filterData, (val) => {
|
||||
getTableData(filterData);
|
||||
}, { deep: true })
|
||||
|
||||
|
||||
return {
|
||||
tableData,
|
||||
filterData,
|
||||
pagination,
|
||||
columns,
|
||||
|
||||
modelVisible,
|
||||
model,
|
||||
drawerVisible,
|
||||
drawer,
|
||||
dialogRef,
|
||||
drawerRef,
|
||||
openExamineDialog,
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
<template>
|
||||
<div class="root">
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.root {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<div class="detail-container">
|
||||
<el-card class="basic-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>基本信息</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-descriptions column="3">
|
||||
<el-descriptions-item label="预警标题">{{ detailData.headline }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预警类型">{{ '大雾预警' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="发送时间">{{ detailData.createTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="生效时间">{{ detailData.onset }}</el-descriptions-item>
|
||||
<el-descriptions-item label="接收时间">{{ detailData.receiveTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预警转发时间">{{ detailData.forwardTime }}</el-descriptions-item>
|
||||
<el-descriptions-item span="3" label="预警结束时间">{{ detailData.expires }}</el-descriptions-item>
|
||||
<el-descriptions-item span="3" label="预警描述">{{ detailData.description }}</el-descriptions-item>
|
||||
<el-descriptions-item span="3" label="响应措施">{{ }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
<el-card class="sites-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>影响情况</span>
|
||||
</div>
|
||||
</template>
|
||||
<DynamicTable :dataSource="sitesList" :columns="columns" :autoHeight="true"></DynamicTable>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, computed, h } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
import DynamicTable from "../../../component/DynamicTable/index.js";
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
const detailData = ref({})
|
||||
const sitesList = ref([])
|
||||
|
||||
// 根据预警ID获取预警详情
|
||||
const getDetailData = async (id) => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/weatherWarning/getById',
|
||||
method: 'GET',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
if (res.code === '00000') {
|
||||
detailData.value = res.data
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message)
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 根据预警ID查询受影响的驻地列表
|
||||
const getAffectedSites = async (id) => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/weatherWarning/affected-sites',
|
||||
method: 'GET',
|
||||
params: {
|
||||
warningId: id
|
||||
}
|
||||
})
|
||||
if (res.code === '00000') {
|
||||
sitesList.value = res.data
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message)
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{
|
||||
prop: "county",
|
||||
label: "所属区县",
|
||||
},
|
||||
{
|
||||
prop: "siteName",
|
||||
label: "驻地名称",
|
||||
},
|
||||
{
|
||||
prop: "siteAddress",
|
||||
label: "驻地地址",
|
||||
},
|
||||
{
|
||||
prop: "sitePopulation",
|
||||
label: "驻地人数",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "首次响应时间",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "最新响应时间",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "最近催告时间",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "响应情况",
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 80,
|
||||
render: (row) => () =>
|
||||
h("div", { class: "action-btns" }, [
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
type: "primary",
|
||||
link: true,
|
||||
onClick: async () => {
|
||||
|
||||
},
|
||||
},
|
||||
() => "巡查记录"
|
||||
),
|
||||
]),
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
onMounted(async () => {
|
||||
await getDetailData(props.id);
|
||||
await getAffectedSites(props.id)
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
@ -2,6 +2,7 @@ import { h, ref, onMounted, reactive, watch, toRaw, nextTick } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import AddDialog from "./addDialog.vue";
|
||||
import DetailDrawer from "./detailDrawer.vue";
|
||||
|
||||
const tableData = ref([]); // 表格数据
|
||||
const modelVisible = ref(false); // 弹窗状态
|
||||
@ -18,7 +19,7 @@ const model = reactive({
|
||||
const form = reactive({
|
||||
});
|
||||
const INIT_FORM = {
|
||||
|
||||
|
||||
};
|
||||
// 抽屉内容
|
||||
const drawer = reactive({
|
||||
@ -35,39 +36,42 @@ const drawerRef = ref(null); // 抽屉实例
|
||||
|
||||
const columns = [
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "headline",
|
||||
label: "预警标题",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
// prop: "xxx",
|
||||
label: "预警类型",
|
||||
formatter: (row) => {
|
||||
return h(ElText, { style: {} }, '大雾预警');
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "createTime",
|
||||
label: "发送时间",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "onset",
|
||||
label: "生效时间",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "receiveTime",
|
||||
label: "接收时间",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "forwardTime",
|
||||
label: "预警转发时间",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "expires",
|
||||
label: "预警结束时间",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "affectedSiteCount",
|
||||
label: "影响数量",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
prop: "responseStatus",
|
||||
label: "响应情况",
|
||||
},
|
||||
{
|
||||
@ -82,31 +86,17 @@ const columns = [
|
||||
type: "primary",
|
||||
link: true,
|
||||
onClick: async () => {
|
||||
openDetailDrawer(row);
|
||||
},
|
||||
},
|
||||
() => "详情"
|
||||
),
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
type: "primary",
|
||||
link: true,
|
||||
style: "margin-left: 10px;",
|
||||
onClick: async () => {
|
||||
},
|
||||
},
|
||||
() => "结束预警"
|
||||
),
|
||||
]),
|
||||
},
|
||||
]
|
||||
|
||||
// 过滤条件
|
||||
const filterData = reactive({
|
||||
title: "",
|
||||
type: "",
|
||||
warningLevel: "",
|
||||
})
|
||||
const filterData = reactive({})
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
@ -122,22 +112,38 @@ const pagination = reactive({
|
||||
});
|
||||
|
||||
// 获取预警列表
|
||||
const getTableData = async (filterData) => {
|
||||
const getTableData = async (filterData = {}) => {
|
||||
try {
|
||||
// 过滤空字符串属性
|
||||
const filteredParams = {};
|
||||
Object.keys(filterData).forEach(key => {
|
||||
if (filterData[key] !== '' && filterData[key] != null) {
|
||||
filteredParams[key] = filterData[key];
|
||||
}
|
||||
});
|
||||
const res = await request({
|
||||
url: '',
|
||||
url: '/snow-ops-platform/weatherWarning/response-list',
|
||||
method: "GET",
|
||||
params: {
|
||||
|
||||
...filteredParams,
|
||||
pageNum: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
}
|
||||
})
|
||||
if (res.code === '00000') {
|
||||
tableData.value = res.data.records
|
||||
pagination.total = res.data.total
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
ElMessage.error('获取预警列表失败');
|
||||
console.error('获取预警列表失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 预警类型选项
|
||||
const typeOptions = [
|
||||
const eventTypeOptions = [
|
||||
{ label: "全部", value: "" },
|
||||
{ label: "台风预警", value: "台风预警" },
|
||||
{ label: "暴雨预警", value: "暴雨预警" },
|
||||
@ -150,7 +156,7 @@ const typeOptions = [
|
||||
];
|
||||
|
||||
// 预警级别选项
|
||||
const warningLevelOptions = [
|
||||
const severityOptions = [
|
||||
{ label: "全部", value: "" },
|
||||
{ label: "红色预警", value: "红色预警" },
|
||||
{ label: "橙色预警", value: "橙色预警" },
|
||||
@ -158,6 +164,14 @@ const warningLevelOptions = [
|
||||
{ label: "蓝色预警", value: "蓝色预警" },
|
||||
]
|
||||
|
||||
// 响应情况选项
|
||||
const responseOptions = [
|
||||
{ label: "全部", value: "" },
|
||||
{ label: "未响应", value: "未响应" },
|
||||
{ label: "部分响应", value: "部分响应" },
|
||||
{ label: "全部响应", value: "全部响应" },
|
||||
]
|
||||
|
||||
// 打开填报项目弹窗
|
||||
const openAddDialog = () => {
|
||||
model.title = '填报项目';
|
||||
@ -182,6 +196,16 @@ const openAddDialog = () => {
|
||||
modelVisible.value = true;
|
||||
}
|
||||
|
||||
// 打开详情弹窗
|
||||
const openDetailDrawer = (row) => {
|
||||
drawer.title = '预警详情';
|
||||
drawer.props = {
|
||||
id: row.id,
|
||||
};
|
||||
drawer.content = DetailDrawer;
|
||||
drawerVisible.value = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default () => {
|
||||
@ -193,13 +217,25 @@ export default () => {
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getTableData();
|
||||
})
|
||||
|
||||
|
||||
watch(filterData, (val) => {
|
||||
getTableData(filterData);
|
||||
}, { deep: true })
|
||||
|
||||
|
||||
|
||||
return {
|
||||
tableData,
|
||||
filterData,
|
||||
typeOptions,
|
||||
warningLevelOptions,
|
||||
|
||||
eventTypeOptions,
|
||||
severityOptions,
|
||||
responseOptions,
|
||||
|
||||
pagination,
|
||||
columns,
|
||||
gotoLedgerPage,
|
||||
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div class="root">
|
||||
<div class="search-box">
|
||||
<el-input v-model="script.filterData.headline" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="预警标题" :suffix-icon="Search" />
|
||||
<el-select v-model="script.filterData.eventType" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="预警类型" :suffix-icon="Search" :options="script.eventTypeOptions" clearable />
|
||||
<el-select v-model="script.filterData.severity" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="预警级别" :suffix-icon="Search" :options="script.severityOptions" clearable />
|
||||
<el-select v-model="script.filterData.responseStatus" style="width: 240px; margin-right: 10px" size="large"
|
||||
placeholder="响应情况" :suffix-icon="Search" :options="script.responseOptions" clearable />
|
||||
</div>
|
||||
<div class="event-box">
|
||||
<el-button type="primary" @click="script.gotoLedgerPage">驻地台账</el-button>
|
||||
<el-button type="primary" @click="script.openAddDialog">填报项目</el-button>
|
||||
<el-button type="primary" @click="">导入停工项目</el-button>
|
||||
<el-button type="primary" @click="">导入在建项目台账</el-button>
|
||||
<el-button type="primary" color="#952DE6" @click="">导出</el-button>
|
||||
</div>
|
||||
<DynamicTable :dataSource="script.tableData.value" :columns="script.columns" :autoHeight="true"
|
||||
:pagination="script.pagination">
|
||||
|
||||
</DynamicTable>
|
||||
<div class="model-box">
|
||||
<MyDialog v-model="script.modelVisible.value" :title="script.model?.title"
|
||||
:dynamicComponent="script.model?.content" :component-props="script.model?.props"
|
||||
:onConfirm="script.model?.onConfirm" :onCancel="script.model?.onCancel" ref="dialogRef"
|
||||
:width="script.model?.width">
|
||||
</MyDialog>
|
||||
<MyDrawer v-model="script.drawerVisible.value" :title="script.drawer?.title"
|
||||
:dynamicComponent="script.drawer?.content" :component-props="script.drawer?.props"
|
||||
:onConfirm="script.drawer?.onConfirm" :onCancel="script.drawer?.onCancel" ref="drawerRef"
|
||||
:direction="script.drawer?.direction" :size="script.drawer?.size">
|
||||
</MyDrawer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import DynamicTable from "../../../component/DynamicTable/index.js";
|
||||
import { Search } from "@element-plus/icons-vue";
|
||||
import MyDialog from "../../../component/MyDialog/index.js";
|
||||
import MyDrawer from "../../../component/MyDrawer/index.js";
|
||||
import scriptFn from "./index.js";
|
||||
const script = scriptFn();
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.root {
|
||||
height: 100%;
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.event-box {
|
||||
margin: 20px 0;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,392 @@
|
||||
<template>
|
||||
<div class="detail-container">
|
||||
<el-form ref="formRef" :model="form" label-position="right" label-width="auto"
|
||||
style="max-height: 60vh; overflow-y: auto; padding-right: 50px" :rules="rules">
|
||||
<div class="form-part">
|
||||
<el-row>
|
||||
<h4 style="margin: 20px 0;">项目信息</h4>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="工程状态" prop="工程状态">
|
||||
<el-radio-group v-model="form.zt">
|
||||
<el-radio value="1">在建</el-radio>
|
||||
<el-radio value="2">停工</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="所属区县" prop="所属区县">
|
||||
<el-select v-model="qx" filterable remote reserve-keyword clearable placeholder="输入区县名称查询"
|
||||
:remote-method="remoteMethod_qx" :loading="loading" @change="handleSelect_qx" value-key="index">
|
||||
<el-option v-for="(item, index) in qxList" :key="index" :label="item.qxmc" :value="item.qxmc" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="项目名称" prop="项目名称">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="驻地名称" prop="驻地名称">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="驻地类型" prop="驻地类型">
|
||||
<el-select>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="坐标点位" prop="坐标点位">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="12">
|
||||
<el-input aria-label="经度" placeholder="经度" />
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-input aria-label="纬度" placeholder="纬度" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="所属项目名称:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="项目类型:">
|
||||
<el-select>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="建设单位:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="施工单位:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="行政区域:">
|
||||
<el-select></el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="驻地人数:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="驻地风险等级:">
|
||||
<el-select></el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="房建类型:">
|
||||
<el-select></el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="搬迁状态:">
|
||||
<el-select></el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="form-part">
|
||||
<el-row>
|
||||
<h4 style="margin: 20px 0;">项目联系人信息</h4>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="吹哨人姓名:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="吹哨人电话:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="建设单位包保责任人姓名:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="建设单位包保责任人电话:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="施工单位包保责任人姓名:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="施工单位包保责任人电话:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="驻地包保责任人姓名:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="驻地包保责任人电话:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="区县级包保责任人姓名:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="区县级包保责任人电话:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="市级包保责任人姓名:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="市级包保责任人电话:">
|
||||
<el-input />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="form-part">
|
||||
<el-row>
|
||||
<h4 style="margin: 20px 0;">驻地情况</h4>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<FileUpload type="image" :limit="9" :fileType=6 />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="form-part">
|
||||
<el-row>
|
||||
<h4 style="margin: 20px 0;">现场情况</h4>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-input></el-input>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, computed } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
||||
const formRef = ref(null);
|
||||
defineExpose({ formRef });
|
||||
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
const sfjwd = ref("是");
|
||||
const qx = ref("");
|
||||
const loading = ref(false);
|
||||
const selectOptions = ref([]);
|
||||
const qxList = ref([]);
|
||||
|
||||
// 根据用户信息 查询角色列表
|
||||
const getUserList = async (key) => {
|
||||
try {
|
||||
const keyword = key;
|
||||
let url = "";
|
||||
if (keyword) {
|
||||
url = `/snow-ops-platform/yhzry/getUserByKey?key=${keyword}`;
|
||||
} else {
|
||||
url = `/snow-ops-platform/yhzry/getUserByKey?key=`;
|
||||
}
|
||||
const res = await request({
|
||||
url: url,
|
||||
method: "GET",
|
||||
});
|
||||
if (res.code === "00000") {
|
||||
return res.data;
|
||||
} else {
|
||||
throw new Error(res.message);
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message);
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
// 选择人员筛选
|
||||
const remoteMethod = async (query) => {
|
||||
if (query === "") {
|
||||
selectOptions.value = [];
|
||||
return [];
|
||||
}
|
||||
loading.value = true;
|
||||
const res = await getUserList(query);
|
||||
if (res) {
|
||||
selectOptions.value = res;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
// 根据区县名称 查询区县列表
|
||||
const getQxList = async (key) => {
|
||||
try {
|
||||
const keyword = key;
|
||||
let url = "";
|
||||
if (keyword) {
|
||||
url = `/snow-ops-platform/district/listDistricts?qxmc=${keyword}`;
|
||||
} else {
|
||||
url = `/snow-ops-platform/district/listDistricts?qxmc=`;
|
||||
}
|
||||
const res = await request({
|
||||
url: url,
|
||||
method: "GET",
|
||||
});
|
||||
if (res.code === "00000") {
|
||||
return res.data;
|
||||
} else {
|
||||
throw new Error(res.message);
|
||||
}
|
||||
} catch (error) { }
|
||||
};
|
||||
|
||||
// 选择区县筛选
|
||||
const remoteMethod_qx = async (query) => {
|
||||
loading.value = true;
|
||||
const res = await getQxList(query);
|
||||
if (res) {
|
||||
qxList.value = res;
|
||||
}
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
// 选择区县
|
||||
const handleSelect_qx = (value) => {
|
||||
props.form.qxmc = value;
|
||||
};
|
||||
|
||||
// 选择人员
|
||||
const handleSelect = (value) => {
|
||||
console.log("value", value);
|
||||
props.form.fzrXm = value.realName;
|
||||
props.form.fzrSjhm = value.phone;
|
||||
props.form.fzrUserId = value.userId;
|
||||
};
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
mc: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.mc) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请输入服务站名称"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
qxmc: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.qxmc) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请选择所属区县"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
fzr: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.fzrUserId && props.form.fzrXm && props.form.fzrSjhm) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请选择负责人"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
jd: [
|
||||
{
|
||||
required: sfjwd.value === "否",
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.jd) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请输入站点经度"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
wd: [
|
||||
{
|
||||
required: sfjwd.value === "否",
|
||||
validator: (rule, value, callback) => {
|
||||
if (props.form.wd) {
|
||||
callback();
|
||||
} else {
|
||||
callback(new Error("请输入站点纬度"));
|
||||
}
|
||||
},
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.form-part{
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<div class="detail-container">
|
||||
<el-card class="basic-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>基本信息</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-descriptions column="3">
|
||||
<el-descriptions-item label="预警标题">{{ detailData.headline }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预警类型">{{ '大雾预警' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="发送时间">{{ detailData.createTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="生效时间">{{ detailData.onset }}</el-descriptions-item>
|
||||
<el-descriptions-item label="接收时间">{{ detailData.receiveTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预警转发时间">{{ detailData.forwardTime }}</el-descriptions-item>
|
||||
<el-descriptions-item span="3" label="预警结束时间">{{ detailData.expires }}</el-descriptions-item>
|
||||
<el-descriptions-item span="3" label="预警描述">{{ detailData.description }}</el-descriptions-item>
|
||||
<el-descriptions-item span="3" label="响应措施">{{ }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
<el-card class="sites-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>影响情况</span>
|
||||
</div>
|
||||
</template>
|
||||
<DynamicTable :dataSource="sitesList" :columns="columns" :autoHeight="true"></DynamicTable>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, computed, h } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
import DynamicTable from "../../../component/DynamicTable/index.js";
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
const detailData = ref({})
|
||||
const sitesList = ref([])
|
||||
|
||||
// 根据预警ID获取预警详情
|
||||
const getDetailData = async (id) => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/weatherWarning/getById',
|
||||
method: 'GET',
|
||||
params: {
|
||||
id: id
|
||||
}
|
||||
})
|
||||
if (res.code === '00000') {
|
||||
detailData.value = res.data
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message)
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 根据预警ID查询受影响的驻地列表
|
||||
const getAffectedSites = async (id) => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/weatherWarning/affected-sites',
|
||||
method: 'GET',
|
||||
params: {
|
||||
warningId: id
|
||||
}
|
||||
})
|
||||
if (res.code === '00000') {
|
||||
sitesList.value = res.data
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message)
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{
|
||||
prop: "county",
|
||||
label: "所属区县",
|
||||
},
|
||||
{
|
||||
prop: "siteName",
|
||||
label: "驻地名称",
|
||||
},
|
||||
{
|
||||
prop: "siteAddress",
|
||||
label: "驻地地址",
|
||||
},
|
||||
{
|
||||
prop: "sitePopulation",
|
||||
label: "驻地人数",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "首次响应时间",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "最新响应时间",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "最近催告时间",
|
||||
},
|
||||
{
|
||||
prop: "xxx",
|
||||
label: "响应情况",
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 80,
|
||||
render: (row) => () =>
|
||||
h("div", { class: "action-btns" }, [
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
type: "primary",
|
||||
link: true,
|
||||
onClick: async () => {
|
||||
|
||||
},
|
||||
},
|
||||
() => "巡查记录"
|
||||
),
|
||||
]),
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
onMounted(async () => {
|
||||
await getDetailData(props.id);
|
||||
await getAffectedSites(props.id)
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
251
packages/screen/src/views/WarningManagement/district/index.js
Normal file
251
packages/screen/src/views/WarningManagement/district/index.js
Normal file
@ -0,0 +1,251 @@
|
||||
import { h, ref, onMounted, reactive, watch, toRaw, nextTick } from "vue";
|
||||
import { request } from "@/utils/request";
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import AddDialog from "./addDialog.vue";
|
||||
import DetailDrawer from "./detailDrawer.vue";
|
||||
|
||||
const tableData = ref([]); // 表格数据
|
||||
const modelVisible = ref(false); // 弹窗状态
|
||||
const drawerVisible = ref(false); // 抽屉状态
|
||||
// 弹窗内容
|
||||
const model = reactive({
|
||||
title: '',
|
||||
content: null,
|
||||
props: {},
|
||||
onCancel: null,
|
||||
onConfirm: null,
|
||||
width: '',
|
||||
});
|
||||
const form = reactive({
|
||||
});
|
||||
const INIT_FORM = {
|
||||
|
||||
};
|
||||
// 抽屉内容
|
||||
const drawer = reactive({
|
||||
title: '',
|
||||
content: null,
|
||||
props: {},
|
||||
onCancel: null,
|
||||
onConfirm: null,
|
||||
direction: 'rtl',
|
||||
size: '50%'
|
||||
});
|
||||
const dialogRef = ref(null); // 弹窗实例
|
||||
const drawerRef = ref(null); // 抽屉实例
|
||||
|
||||
const columns = [
|
||||
{
|
||||
prop: "headline",
|
||||
label: "预警标题",
|
||||
},
|
||||
{
|
||||
// prop: "xxx",
|
||||
label: "预警类型",
|
||||
formatter: (row) => {
|
||||
return h(ElText, { style: {} }, '大雾预警');
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: "createTime",
|
||||
label: "发送时间",
|
||||
},
|
||||
{
|
||||
prop: "onset",
|
||||
label: "生效时间",
|
||||
},
|
||||
{
|
||||
prop: "receiveTime",
|
||||
label: "接收时间",
|
||||
},
|
||||
{
|
||||
prop: "forwardTime",
|
||||
label: "预警转发时间",
|
||||
},
|
||||
{
|
||||
prop: "expires",
|
||||
label: "预警结束时间",
|
||||
},
|
||||
{
|
||||
prop: "affectedSiteCount",
|
||||
label: "影响数量",
|
||||
},
|
||||
{
|
||||
prop: "responseStatus",
|
||||
label: "响应情况",
|
||||
},
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 150,
|
||||
render: (row) => () =>
|
||||
h("div", { class: "action-btns" }, [
|
||||
h(
|
||||
ElButton,
|
||||
{
|
||||
type: "primary",
|
||||
link: true,
|
||||
onClick: async () => {
|
||||
openDetailDrawer(row);
|
||||
},
|
||||
},
|
||||
() => "详情"
|
||||
),
|
||||
]),
|
||||
},
|
||||
]
|
||||
|
||||
// 过滤条件
|
||||
const filterData = reactive({})
|
||||
// 分页
|
||||
const pagination = reactive({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
pageSizes: [10, 20, 50],
|
||||
layout: "prev, pager, next, jumper",
|
||||
onChange: (page, pageSize) => {
|
||||
pagination.current = page;
|
||||
pagination.pageSize = pageSize;
|
||||
getTableData(filterData);
|
||||
},
|
||||
});
|
||||
|
||||
// 获取预警列表
|
||||
const getTableData = async (filterData = {}) => {
|
||||
try {
|
||||
// 过滤空字符串属性
|
||||
const filteredParams = {};
|
||||
Object.keys(filterData).forEach(key => {
|
||||
if (filterData[key] !== '' && filterData[key] != null) {
|
||||
filteredParams[key] = filterData[key];
|
||||
}
|
||||
});
|
||||
const res = await request({
|
||||
url: '/snow-ops-platform/weatherWarning/response-list',
|
||||
method: "GET",
|
||||
params: {
|
||||
...filteredParams,
|
||||
pageNum: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
}
|
||||
})
|
||||
if (res.code === '00000') {
|
||||
tableData.value = res.data.records
|
||||
pagination.total = res.data.total
|
||||
} else {
|
||||
throw new Error(res.message)
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('获取预警列表失败');
|
||||
console.error('获取预警列表失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 预警类型选项
|
||||
const eventTypeOptions = [
|
||||
{ label: "全部", value: "" },
|
||||
{ label: "台风预警", value: "台风预警" },
|
||||
{ label: "暴雨预警", value: "暴雨预警" },
|
||||
{ label: "寒潮预警", value: "寒潮预警" },
|
||||
{ label: "大雾预警", value: "大雾预警" },
|
||||
{ label: "暴雪预警", value: "暴雪预警" },
|
||||
{ label: "道路结冰预警", value: "道路结冰预警" },
|
||||
{ label: "雷电预警", value: "雷电预警" },
|
||||
{ label: "强对流预警", value: "强对流预警" },
|
||||
];
|
||||
|
||||
// 预警级别选项
|
||||
const severityOptions = [
|
||||
{ label: "全部", value: "" },
|
||||
{ label: "红色预警", value: "红色预警" },
|
||||
{ label: "橙色预警", value: "橙色预警" },
|
||||
{ label: "黄色预警", value: "黄色预警" },
|
||||
{ label: "蓝色预警", value: "蓝色预警" },
|
||||
]
|
||||
|
||||
// 响应情况选项
|
||||
const responseOptions = [
|
||||
{ label: "全部", value: "" },
|
||||
{ label: "未响应", value: "未响应" },
|
||||
{ label: "部分响应", value: "部分响应" },
|
||||
{ label: "全部响应", value: "全部响应" },
|
||||
]
|
||||
|
||||
// 打开填报项目弹窗
|
||||
const openAddDialog = () => {
|
||||
model.title = '填报项目';
|
||||
Object.assign(form, INIT_FORM);
|
||||
model.props = {
|
||||
form: form,
|
||||
};
|
||||
model.content = AddDialog;
|
||||
model.onCancel = () => {
|
||||
modelVisible.value = false;
|
||||
};
|
||||
model.onConfirm = async () => {
|
||||
dialogType.value = '';
|
||||
await dialogRef?.value?.dynamicComponentRef?.formRef.validate().then(() => {
|
||||
console.log('@@@@@填报项目', form);
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error('请处理表单中的错误项');
|
||||
});
|
||||
};
|
||||
model.width = "70%"
|
||||
modelVisible.value = true;
|
||||
}
|
||||
|
||||
// 打开详情弹窗
|
||||
const openDetailDrawer = (row) => {
|
||||
drawer.title = '预警详情';
|
||||
drawer.props = {
|
||||
id: row.id,
|
||||
};
|
||||
drawer.content = DetailDrawer;
|
||||
drawerVisible.value = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default () => {
|
||||
|
||||
const router = useRouter();
|
||||
const gotoLedgerPage = () => {
|
||||
router.push({
|
||||
path: '/ledgerManagement2'
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getTableData();
|
||||
})
|
||||
|
||||
|
||||
watch(filterData, (val) => {
|
||||
getTableData(filterData);
|
||||
}, { deep: true })
|
||||
|
||||
|
||||
|
||||
return {
|
||||
tableData,
|
||||
filterData,
|
||||
|
||||
eventTypeOptions,
|
||||
severityOptions,
|
||||
responseOptions,
|
||||
|
||||
pagination,
|
||||
columns,
|
||||
gotoLedgerPage,
|
||||
|
||||
modelVisible,
|
||||
model,
|
||||
drawerVisible,
|
||||
drawer,
|
||||
dialogRef,
|
||||
drawerRef,
|
||||
openAddDialog,
|
||||
}
|
||||
}
|
||||
@ -10,10 +10,7 @@
|
||||
</div>
|
||||
<div class="event-box">
|
||||
<el-button type="primary" @click="script.gotoLedgerPage">驻地台账</el-button>
|
||||
<el-button type="primary" @click="script.openAddDialog">填报项目</el-button>
|
||||
<el-button type="primary" @click="">导入停工项目</el-button>
|
||||
<el-button type="primary" @click="">导入在建项目台账</el-button>
|
||||
<el-button type="primary" color="#952DE6" @click="">导出</el-button>
|
||||
<el-button type="primary" @click="script.openAddDialog">上报项目</el-button>
|
||||
</div>
|
||||
<DynamicTable :dataSource="script.tableData.value" :columns="script.columns" :autoHeight="true"
|
||||
:pagination="script.pagination">
|
||||
@ -35,10 +32,10 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import DynamicTable from "../../component/DynamicTable";
|
||||
import DynamicTable from "../../../component/DynamicTable/index.js";
|
||||
import { Search } from "@element-plus/icons-vue";
|
||||
import MyDialog from "../../component/MyDialog";
|
||||
import MyDrawer from "../../component/MyDrawer";
|
||||
import MyDialog from "../../../component/MyDialog/index.js";
|
||||
import MyDrawer from "../../../component/MyDrawer/index.js";
|
||||
import scriptFn from "./index.js";
|
||||
const script = scriptFn();
|
||||
</script>
|
||||
Loading…
x
Reference in New Issue
Block a user