src/api/index.js
@@ -13,8 +13,8 @@ let ip2_file = 'https://fyami.com.cn/'; if (debug) { ip1 = 'http://192.168.0.103:9001/'; // ip1 = 'http://localhost:9001/'; // ip1 = 'http://192.168.0.103:9001/'; ip1 = 'http://localhost:9001/'; // ip1_file = 'http://192.168.0.138:8080/'; // ip2 = 'http://192.168.0.138:8080/'; // ip2_file = 'https://fyami.com.cn/'; src/components/bg-task/FYBgTaskItem.vue
@@ -31,10 +31,10 @@ </el-col> <el-col :span="12"> <el-text type="default" size="default" tag="div" >开始:{{ $fm.formatYMDH(model.startTime) }}</el-text >开始:{{ $fm.formatYMDHMS(model.startTime) }}</el-text > <el-text type="default" size="default" tag="div" >结束:{{ $fm.formatYMDH(model.endTime) }}</el-text >结束:{{ $fm.formatYMDHMS(model.endTime) }}</el-text > </el-col> </el-row> src/components/list-item/ItemSubTask.vue
@@ -31,7 +31,7 @@ <el-icon class="m-r-4" size="16"><AlarmClock /></el-icon> <span>时间:</span> </div> {{ $fm.formatYMD(item.planstarttime) }} {{ $fm.formatYMDHM(item.executionstarttime) }}至{{ $fm.formatYMDHM(item.executionendtime) }} </div> <div class="text-info"> <div class="text-label"> src/components/map/BaseMap.vue
@@ -7,7 +7,9 @@ import { createMap, map } from '@/utils/map/index'; onMounted(() => { // 高德地图初始化 setTimeout(() => { createMap('container'); }, 1000); }); onUnmounted(() => { map?.destroy(); src/utils/time-util.js
@@ -29,7 +29,15 @@ } }, formatYMDH(date) { formatYMDHM(date) { if (date) { return this.format(date, 'YYYY-MM-DD HH:mm'); } else { return '----/--/-- --:--'; } }, formatYMDHMS(date) { if (date) { return this.format(date, 'YYYY-MM-DD HH:mm:ss'); } else { @@ -51,5 +59,47 @@ format + (date < 10 ? '0' + date : date) ); }, /** * 将秒数转换为中文描述格式 * @param {number} seconds - 秒数 * @returns {string} 中文时间描述 */ formatSecondsToChinese(seconds) { if (!seconds || seconds < 0 || isNaN(seconds)) { return '--'; } // 定义时间单位和对应的秒数 const units = [ { unit: '天', value: 24 * 60 * 60 }, { unit: '小时', value: 60 * 60 }, { unit: '分', value: 60 }, { unit: '秒', value: 1 } ]; let remainingSeconds = Math.floor(seconds); let result = ''; // 遍历时间单位,计算每个单位的数量 for (const { unit, value } of units) { if (remainingSeconds >= value) { const count = Math.floor(remainingSeconds / value); result += `${count}${unit}`; remainingSeconds %= value; // // 如果剩余秒数为0,且已经有结果,就可以结束了 // if (remainingSeconds === 0 && result) { // break; // } // 如果已经有结果,就可以结束了 if (result) { break; } } } return result; } }; src/views/fysp/check/components/CompProRecent.vue
@@ -145,11 +145,11 @@ return { startTime: this.activeName === '近三个月' ? this.$fm.formatYMDH(threeMonthsAgo) ? this.$fm.formatYMDHMS(threeMonthsAgo) : this.activeName === '近半年' ? this.$fm.formatYMDH(sixMonthsAgo) : this.$fm.formatYMDH(oneYearAgo), endTime: this.$fm.formatYMDH(today), ? this.$fm.formatYMDHMS(sixMonthsAgo) : this.$fm.formatYMDHMS(oneYearAgo), endTime: this.$fm.formatYMDHMS(today), sceneId: this.deepCopyPro.sguid }; }, src/views/fysp/config/DeviceMatch.vue
@@ -133,7 +133,7 @@ districtname: formSearch.locations.dName, towncode: formSearch.locations.tCode, townname: formSearch.locations.tName, starttime: $fm.formatYMDH(formSearch.time), starttime: $fm.formatYMDHMS(formSearch.time), scensetypeid: formSearch.scenetype.value, online: true, // 此处数据来源固定为飞羽监管系统 @@ -157,7 +157,7 @@ function timeFormat(row) { const time = row.createTime; if (time) { return $fm.formatYMDH(time); return $fm.formatYMDHMS(time); } else { return ''; } src/views/fysp/evaluation/components/precheck/CompPreCheck.vue
@@ -71,8 +71,8 @@ districtname: v._locations.dName, towncode: v._locations.tCode, townname: v._locations.tName, starttime: this.$fm.formatYMDH(v.time), endtime: this.$fm.formatYMDH(v.time), starttime: this.$fm.formatYMDHMS(v.time), endtime: this.$fm.formatYMDHMS(v.time), scensetypeid: v._scenetype.value, online: true, sourceType: v.sourceType src/views/fysp/evaluation/components/precheck/components/CompCheckConfirm.vue
@@ -90,7 +90,7 @@ districtname: v._locations.dName, towncode: v._locations.tCode, townname: v._locations.tName, starttime: this.$fm.formatYMDH(v.time), starttime: this.$fm.formatYMDHMS(v.time), scensetypeid: v._scenetype.value, online: true, sourceType: v.sourceType src/views/fysp/evaluation/components/precheck/components/CompCheckSource.vue
@@ -309,7 +309,7 @@ // districtname: v._locations.dName, // towncode: v._locations.tCode, // townname: v._locations.tName, // starttime: this.$fm.formatYMDH(v.time), // starttime: this.$fm.formatYMDHMS(v.time), // scensetypeid: v._scenetype.value, // online: true, // sourceType: v.sourceType src/views/fysp/task/TaskManage.vue
@@ -37,10 +37,11 @@ >计划调整</el-button > --> <el-tabs model-value="first"> <el-tab-pane label="监管计划" name="first"> <el-tab-pane label="巡查计划" name="first"> <el-row> <el-col :span="curSubTaskList ? 16 : 24"> <CompMonitorPlan :loading="daytaskLoading" ref="planRef" :task="curTask.data" :day-task-list="curDayTaskList" @@ -51,6 +52,7 @@ <CompSubTaskList create v-model="curSubTaskList" :date="curDay" :loading="subTaskLoading" :create-loading="daytaskCreateLoading" height="56vh" @@ -60,7 +62,7 @@ </el-col> </el-row> </el-tab-pane> <el-tab-pane label="监管地图" name="second"> <el-tab-pane label="场景地图" name="second"> <CompTaskMap :plans="curMonitorObjList"></CompTaskMap> </el-tab-pane> </el-tabs> @@ -283,12 +285,16 @@ fetchDayTasks() { // 获取日任务统计信息 this.dayTaskLoading = true; this.mainLoading = true; return taskApi .fetchDayTasks(this.curTask.data.tguid) .then((res) => { this.curDayTaskList = res; }) .finally(() => (this.dayTaskLoading = false)); .finally(() => { this.dayTaskLoading = false; this.mainLoading = false; }); }, editTask() { this.$router.push({ src/views/fysp/task/components/CompMonitorPlan.vue
@@ -5,39 +5,141 @@ @update:model-value="onDateChange" > <template #header="{ date }"> <span>{{ title }}</span> <div> <el-row justify="space-between"> <el-space> <el-tag>总计:{{ taskStatistic.total }}</el-tag> <el-tag>完成:{{ taskStatistic.complete }}</el-tag> <el-tag>整改:{{ taskStatistic.changed }}</el-tag> <el-tag type="default" >巡查量:{{ `${taskStatistic.complete}/${taskStatistic.total}` }}</el-tag > <el-tag type="default" >综合整改率:{{ formatPercent( taskStatistic.changedProblemNum / taskStatistic.totalProblemNum ) }}</el-tag > <el-tag type="default">整改:{{ taskStatistic.changed }}</el-tag> </el-space> <!-- <span>{{ date }}</span> --> <el-space> <el-text>聚焦用户:</el-text> <el-select v-model="selectedUsers" multiple clearable style="width: 150px" > <el-option v-for="user in taskStatistic.progressPerUser" :key="user.userId" :label="user.userName" :value="user.userName" /> </el-select> </el-space> </el-row> <el-row class="m-t-4"> <el-space wrap> <el-tag type="default" v-for="user in taskStatistic.progressPerUser" :key="user.userId" > {{ `${user.userName}:巡查量 ${ user.completeTaskNum },及时整改率 ${formatPercent( user.changedProblemNumOnTime / user.totalProblemNum )},平均耗时 ${ user.avgInspectionTime ? user.avgInspectionTime : '--' }` }} </el-tag> </el-space> </el-row> </div> </template> <template #date-cell="{ data }"> <div :class="calendarDayClz(data.day)"> <div style="background-color: #f8f4f4">{{ getDay(data.day) }}</div> <template v-if="computeDayTask(data.day)"> <!-- <el-divider></el-divider> --> <el-row justify="space-between" class="m-t-16"> <el-row v-if="computeDayTask(data.day).totalTaskNum > 0" justify="space-between" > <el-space direction="vertical"> <el-text size="small">总计</el-text> <el-text>{{ computeDayTask(data.day).totalTaskNum }}</el-text> <el-text size="small" tag="b">巡查量</el-text> <el-text size="small" >{{ computeDayTask(data.day).completeTaskNum }} / {{ computeDayTask(data.day).totalTaskNum }}</el-text > </el-space> <el-space direction="vertical"> <el-text size="small">完成</el-text> <el-text>{{ computeDayTask(data.day).completeTaskNum }}</el-text> <el-text size="small" tag="b">综合整改率</el-text> <el-text size="small">{{ formatPercent( computeDayTask(data.day).changedProblemNum / computeDayTask(data.day).totalProblemNum ) }}</el-text> </el-space> <el-space direction="vertical"> <el-text size="small">整改</el-text> <el-text>{{ computeDayTask(data.day).changedTaskNum }}</el-text> </el-space> <!-- <el-statistic title="总计" :value="computeDayTask(data.day).totalTaskNum" /> <el-statistic title="完成" :value="computeDayTask(data.day).completeTaskNum" /> <el-statistic title="整改" :value="computeDayTask(data.day).changedTaskNum" /> --> </el-row> <!-- <div>任务总计:{{ computeDayTask(data.day).totalTaskNum }}</div> <div>任务完成:{{ computeDayTask(data.day).completeTaskNum }}</div> <div>任务整改:{{ computeDayTask(data.day).changedTaskNum }}</div> --> <div style="border-top: 1px solid #0000002f" class="m-t-4"></div> <div v-for="item in computeDayTask(data.day).progressPerUser" :key="item.userId" class="m-t-4" > <el-row justify="space-between"> <el-text size="small" :type=" selectedUsers.includes(item.userName) ? 'primary' : 'info' " :tag="selectedUsers.includes(item.userName) ? 'b' : 'span'" >{{ item.userName }}</el-text > </el-row> <el-row justify="space-between"> <!-- <el-space> --> <el-text size="small" style="text-align: center; flex: 1" :type=" selectedUsers.includes(item.userName) ? 'primary' : 'info' " :tag="selectedUsers.includes(item.userName) ? 'b' : 'span'" >{{ item.completeTaskNum }}</el-text > <el-text size="small" style="text-align: center; flex: 1" :type=" selectedUsers.includes(item.userName) ? 'primary' : 'info' " :tag="selectedUsers.includes(item.userName) ? 'b' : 'span'" >{{ formatPercent( item.changedProblemNumOnTime / item.totalProblemNum ) }}</el-text > <el-text size="small" style="text-align: center; flex: 1" :type=" selectedUsers.includes(item.userName) ? 'primary' : 'info' " :tag="selectedUsers.includes(item.userName) ? 'b' : 'span'" >{{ timeUtil.formatSecondsToChinese(item.avgInspectionTime) }}</el-text > <!-- </el-space> --> </el-row> </div> </template> </div> </template> @@ -47,6 +149,7 @@ import { ref, computed, onMounted, watch } from 'vue'; import taskApi from '@/api/fysp/taskApi'; import dayjs from 'dayjs'; import timeUtil from '@/utils/time-util'; const props = defineProps({ task: { @@ -60,16 +163,9 @@ }); const emit = defineEmits(['dateChange']); // 选中日期 const selectedUsers = ref([]); // const dateValue = ref(new Date()); const dateValue = ref(); // 日历标题 const title = computed(() => { if (props.task) { // return `${props.task.name}计划`; return `巡查计划`; } else { return ''; } }); // 日历范围 const startDay = computed(() => dayjs(props.task.starttime)); const endDay = computed(() => dayjs(props.task.endtime)); @@ -77,7 +173,6 @@ startDay.value.toDate(), endDay.value.toDate() ]); // const dateRange = computed(() => [new Date(2024, 4, 27), new Date(2024, 5, 30)]); // 日期是否在任务范围内 function isDayEnable(day) { @@ -154,14 +249,52 @@ // 总任务统计 const taskStatistic = computed(() => { const res = { total: 0, complete: 0, changed: 0 }; const res = { total: 0, complete: 0, changed: 0, changedProblemNum: 0, totalProblemNum: 0 }; const userMap = new Map(); props.dayTaskList.forEach((e) => { res.total += e.totalTaskNum; res.complete += e.completeTaskNum; res.changed += e.changedTaskNum; res.changedProblemNum += e.changedProblemNum; res.totalProblemNum += e.totalProblemNum; e.progressPerUser.forEach((user) => { if (!userMap.has(user.userId)) { userMap.set(user.userId, { userName: user.userName, completeTaskNum: 0, changedProblemNumOnTime: 0, totalProblemNum: 0, totalInspectionTime: 0, dayTaskNum: 0 }); } const userItem = userMap.get(user.userId); userItem.completeTaskNum += user.completeTaskNum; userItem.changedProblemNumOnTime += user.changedProblemNumOnTime; userItem.totalProblemNum += user.totalProblemNum; userItem.totalInspectionTime += user.avgInspectionTime; userItem.dayTaskNum++; }); }); res.progressPerUser = Array.from(userMap.values()).map((user) => ({ ...user, completeTaskNum: Math.round(user.completeTaskNum * 100) / 100, avgInspectionTime: timeUtil.formatSecondsToChinese( user.totalInspectionTime / user.dayTaskNum ) })); return res; }); const formatPercent = (num) => { return isNaN(num) ? '0%' : parseInt(num * 100) + '%'; }; /********************** 初始化 *********************************/ // watch( src/views/fysp/task/components/CompSubTaskList.vue
@@ -1,6 +1,6 @@ <template> <el-row justify="space-between"> <el-text>单日计划</el-text> <el-text>{{dateStr}}计划</el-text> <div v-show="create && data && data.length > 0"> <el-button icon="IconPrinter" @@ -63,6 +63,7 @@ </div> </el-scrollbar> </div> <!-- 编辑巡查子任务 --> <el-dialog v-model="dialogVisible" width="600" @@ -78,6 +79,7 @@ @cancel="dialogVisible = false" ></CompSubTaskEdit> </el-dialog> <!-- 巡查单下载 --> <SceneInspectFile v-model="downloadDialog" :value="downloadSceneList" @@ -85,13 +87,14 @@ </template> <script setup> import { ref, computed, watch, onMounted, onUnmounted } from 'vue'; import { ElMessageBox, ElNotification, ElMessage } from 'element-plus'; import { ElMessageBox, ElNotification, ElMessage, dayjs } from 'element-plus'; import CompSubTaskEdit from './CompSubTaskEdit.vue'; import SceneInspectFile from '@/views/fysp/scene/SceneInspectFile.vue'; import subtaskApi from '@/api/fysp/subtaskApi'; const props = defineProps({ modelValue: Array, date: Date, height: { type: String, default: '70vh' @@ -110,6 +113,8 @@ const emit = defineEmits(['submit', 'add', 'remove', 'update:modelValue']); const dateStr = computed(()=> dayjs(props.date).format('MM月DD日')) function remove(item) { if (item.status == '未执行') { ElMessageBox.confirm('是否移除监管任务', `移除确认`, {