src/api/fysp/taskApi.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/components.d.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/components/list-item/ItemSubTask.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/router/index.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/fysp/task/MonitorObjEdit.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/fysp/task/MonitorPlanEdit.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/fysp/task/TaskManage.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/fysp/task/components/CompMonitorObj.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/fysp/task/components/CompMonitorPlan.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/fysp/taskApi.js
@@ -50,6 +50,18 @@ }, /** * è·åæ¯æ¥ä»»å¡ç»è®¡ä¿¡æ¯ * @param {String} topTaskId æ»ä»»å¡ä¸»é®id * @param {String} userId ç¨æ·idï¼å½ç¨æ·ç±»åuserType为1ï¼çç®¡ç¨æ·ï¼æ¶ï¼ä¼æ ¹æ®ç¨æ·idè·åå ¶æéå çç»è®¡ä¿¡æ¯ * @param {String} userType ç¨æ·ç±»åï¼0ï¼ç®¡çåï¼1ï¼çç®¡ç¨æ·ï¼2ï¼æ¿åºé¨é¨ï¼3ï¼ä¼ä¸ */ fetchDayTasks(topTaskId, userId = '', userType = '0') { return $fysp .get(`task/dayTask/${topTaskId}?userId=${userId}&userType=${userType}`) .then((res) => res.data); }, /** * è·ååä»»å¡ç»è®¡ä¿¡æ¯ */ getSubtaskSummary({ topTaskId = undefined, sceneTypeId = undefined }) { @@ -64,6 +76,17 @@ }, /** * è·åå ·ä½åä»»å¡ä¿¡æ¯ * @param {String} dayTaskId æ¥ä»»å¡ä¸»é®id * @param {String} userId ç¨æ·idï¼å½ç¨æ·ç±»åuserType为1ï¼çç®¡ç¨æ·ï¼æ¶ï¼ä¼æ ¹æ®ç¨æ·idè·åå ¶æéå çç»è®¡ä¿¡æ¯ * @param {String} userType ç¨æ·ç±»åï¼0ï¼ç®¡çåï¼1ï¼çç®¡ç¨æ·ï¼2ï¼æ¿åºé¨é¨ï¼3ï¼ä¼ä¸ */ fetchSubtaskByDayTask(dayTaskId, userId = '', userType = '0') { const params = `?dayTaskId=${dayTaskId}&userId=${userId}&userType=${userType}`; return $fysp.get(`subtask/byDayTaskId${params}`).then((res) => res.data); }, /** * è·ååä»»å¡é®é¢è¯¦æ */ getProBySubtask(id) { src/components.d.ts
@@ -22,6 +22,7 @@ ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] ElButton: typeof import('element-plus/es')['ElButton'] ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup'] ElCalendar: typeof import('element-plus/es')['ElCalendar'] ElCard: typeof import('element-plus/es')['ElCard'] ElCascader: typeof import('element-plus/es')['ElCascader'] ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] @@ -58,6 +59,7 @@ ElSegmented: typeof import('element-plus/es')['ElSegmented'] ElSelect: typeof import('element-plus/es')['ElSelect'] ElSpace: typeof import('element-plus/es')['ElSpace'] ElStatistic: typeof import('element-plus/es')['ElStatistic'] ElStep: typeof import('element-plus/es')['ElStep'] ElSteps: typeof import('element-plus/es')['ElSteps'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] @@ -92,6 +94,7 @@ Header: typeof import('./components/core/Header.vue')['default'] ItemMonitorObj: typeof import('./components/list-item/ItemMonitorObj.vue')['default'] ItemScene: typeof import('./components/list-item/ItemScene.vue')['default'] ItemSubTask: typeof import('./components/list-item/ItemSubTask.vue')['default'] ItemUser: typeof import('./components/list-item/ItemUser.vue')['default'] MenuItems: typeof import('./components/core/MenuItems.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] src/components/list-item/ItemSubTask.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,38 @@ <template> <div class="wrapper"> <div> <el-text truncated>{{ item.name }}</el-text> </div> <div> <el-space fill> <el-text truncated class="w-250px" size="small">{{ item.scenseaddress }}</el-text> <el-text truncated class="w-250px" size="small">{{ $fm.formatYMDH(item.planstarttime) }}</el-text> <el-text truncated class="w-250px" size="small">{{ item.executorrealtimes }}</el-text> </el-space> </div> <el-row justify="end" style="margin-top: 4px"> <slot :item="item"></slot> </el-row> </div> </template> <script setup> /** * ç管对象 */ const props = defineProps({ item: { type: Object, default: () => {} } }); </script> <style scoped> .wrapper { /* width: 300px; */ border: 1px solid var(--el-border-color); border-radius: var(--el-border-radius-base); padding: 4px 8px; } </style> src/router/index.js
@@ -73,6 +73,12 @@ component: () => import('@/views/fysp/task/MonitorObjEdit.vue') }, { //ç管任å¡è®¡åç¼è¾ name: 'monitorPlanEdit', path: '/fysp/task/plan/edit', component: () => import('@/views/fysp/task/MonitorPlanEdit.vue') }, { //é®é¢å®¡æ ¸ name: 'procheck', path: '/fysp/procheck', src/views/fysp/task/MonitorObjEdit.vue
@@ -1,7 +1,7 @@ <template> <el-affix :offset="60"> <div class="page-header"> <el-page-header @back="$router.back()"> <el-page-header @back="goBack"> <template #content> <span> æ»ä»»å¡ç¼è¾ </span> </template> @@ -24,10 +24,11 @@ <el-divider /> <CompMonitorObj :data="curMonitorObjList" show-delete show-btn v-model:tabName="curSceneType" v-model:showData="showMonitorObjList" @delete-item="deleteMov" :tabOptions="sceneTypeOptions" @item-click="deleteMov" > </CompMonitorObj> </el-col> @@ -41,7 +42,6 @@ <el-segmented v-model="curSceneType" :options="sceneTypeOptions" /> </div> <FYInfoSearch label="" placeholder="请è¾å ¥åºæ¯åç§°å ³é®å" :data="showSceneList" :on-search="searchScene" @@ -92,9 +92,14 @@ import svUserApi from '@/api/fysp/userApi'; import taskApi from '@/api/fysp/taskApi'; import sceneApi from '@/api/fysp/sceneApi'; import { ElMessage, ElNotification } from 'element-plus'; import { ElMessage, ElNotification, ElMessageBox } from 'element-plus'; export default { async beforeRouteLeave(to, from) { // å¨å¯¼èªç¦»å¼æ¸²æè¯¥ç»ä»¶ç对åºè·¯ç±æ¶è°ç¨ // ä¸ `beforeRouteUpdate` 䏿 ·ï¼å®å¯ä»¥è®¿é®ç»ä»¶å®ä¾ `this` // return this.routerChangeCheck(); }, components: { CompMonitorObj }, props: {}, data() { @@ -104,7 +109,6 @@ // å½åçéçåºæ¯ç±»å curSceneType: undefined, showMonitorObjList: [], // è¡æ¿åºå area: {}, @@ -302,6 +306,30 @@ // return Promise.all([p1, p2, p3]).finally(() => { // this.saveLoading = false; // }); }, async goBack() { // const answer = await this.routerChangeCheck() // if (answer) { // this.$router.back(); // } this.$router.back(); }, async routerChangeCheck() { if (this.isEdit) { const answer = await ElMessageBox.confirm('æ¯å¦æ¾å¼å·²ä¿®æ¹çæ»ä»»å¡ï¼', 'åæ¶æ»ä»»å¡ä¿®æ¹', { confirmButtonText: '确认', cancelButtonText: 'åæ¶', type: 'warning' }) .then(() => { return true; }) .catch(() => { return false; }); return answer; } return true; } }, mounted() { src/views/fysp/task/MonitorPlanEdit.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,99 @@ <template> <el-affix :offset="60"> <div class="page-header"> <el-page-header @back="goBack"> <template #content> <span> 计åè°æ´ </span> </template> <template #extra> <div> <el-button type="primary" :disabled="!isEdit" :loading="saveLoading" @click="saveEdit" >ä¿åä¿®æ¹</el-button > </div> </template> </el-page-header> <el-divider /> </div> </el-affix> <el-row gutter="20"> <el-col :span="16"> <el-affix :offset="140"> <div> <el-text>ç管计å</el-text> </div> <el-divider /> <CompMonitorPlan :task="task" @date-change="onDateChange"></CompMonitorPlan> </el-affix> </el-col> <el-col :span="8"> <el-row justify="space-between"> <el-text>åæ¥è®¡å</el-text> <el-button type="success" size="small" @click="editTask">æ°å¢</el-button> </el-row> <el-divider /> <ItemSubTask v-for="stask in curSubTaskList" :key="stask.guid" :item="stask"> <template #default="{ item }"> <el-button type="danger" size="small" @click="editTask">ç§»é¤</el-button> </template> </ItemSubTask> <!-- <CompMonitorObj :data="curMonitorObjList" show-btn v-model:tabName="curSceneType" v-model:showData="showMonitorObjList" btn-name="æ·»å " @item-click="deleteMov" > </CompMonitorObj> --> </el-col> </el-row> </template> <script setup> import { ref, onMounted } from 'vue'; import { useRoute, useRouter } from 'vue-router'; import CompMonitorPlan from './components/CompMonitorPlan.vue'; import CompMonitorObj from './components/CompMonitorObj.vue'; import taskApi from '@/api/fysp/taskApi'; const route = useRoute(); const router = useRouter(); const curMonitorObjList = ref([]); const task = ref({}); const curSceneType = ref({}); const showMonitorObjList = ref({}); const curSubTaskList = ref([]); function onDateChange(dayTask) { if (dayTask) { fetchSubTask(dayTask.guid); } else { curSubTaskList.value = []; } } function fetchSubTask(dayTaskId) { taskApi.fetchSubtaskByDayTask(dayTaskId).then((res) => { curSubTaskList.value = res; }); } onMounted(() => { // çç®¡åºæ¯ä¿¡æ¯ curMonitorObjList.value = JSON.parse(decodeURIComponent(route.query.data)); // æ ¹æ®æ»ä»»å¡è·åè¡æ¿åºåä¿¡æ¯ task.value = JSON.parse(decodeURIComponent(route.query.task)); }); function goBack() { router.back(); } </script> <style scoped> .page-header { background-color: white; } </style> src/views/fysp/task/TaskManage.vue
@@ -31,11 +31,17 @@ class="el-scrollbar" v-loading="mainLoading" > <el-row justify="space-between"> <div><el-text>ç管计å</el-text></div> <el-button type="warning" size="small" @click="editPlan">计åè°æ´</el-button> <CompMonitorPlan :task="curTask.data"></CompMonitorPlan> </el-row> <el-divider></el-divider> <el-button type="primary" size="small" @click="editTask">åºæ¯è°æ´</el-button> <el-row justify="space-between"> <div><el-text>çç®¡åºæ¯</el-text></div> <CompMonitorObj :data="curMonitorObjList" v-model:showData="showMonitorObjList"></CompMonitorObj> <el-button type="warning" size="small" @click="editTask">åºæ¯è°æ´</el-button> </el-row> <CompMonitorObj :data="curMonitorObjList"></CompMonitorObj> <!-- <div><el-text>çç®¡åºæ¯</el-text></div> <div> <el-space wrap> @@ -55,8 +61,19 @@ <script> import taskApi from '@/api/fysp/taskApi'; import CompMonitorObj from './components/CompMonitorObj.vue'; import CompMonitorPlan from './components/CompMonitorPlan.vue'; export default { components: { CompMonitorObj }, beforeRouteEnter(to, from, next) { // 卿¸²æè¯¥ç»ä»¶ç对åºè·¯ç±è¢«éªè¯åè°ç¨ // ä¸è½è·åç»ä»¶å®ä¾ `this` ï¼ // å 为å½å®å«æ§è¡æ¶ï¼ç»ä»¶å®ä¾è¿æ²¡è¢«åå»ºï¼ next((vm) => { if (from.name == 'monitorObjEdit' && vm.task) { vm.chooseTask(vm.task); } }); }, components: { CompMonitorObj, CompMonitorPlan }, data() { return { formSearch: { @@ -79,14 +96,14 @@ curTask: {}, //æä½æé® buttons: [ { name: '计åè°æ´', color: 'success' }, { name: 'åºæ¯è°æ´', color: 'warning' } // { // name: '计åè°æ´', // color: 'success' // }, // { // name: 'åºæ¯è°æ´', // color: 'warning' // } ] }; }, @@ -143,6 +160,7 @@ return type; }, chooseTask(task) { this.task = task; this.sideLoading = false; this.mainLoading = true; taskApi @@ -163,6 +181,15 @@ task: encodeURIComponent(JSON.stringify(this.curTask.data)) } }); }, editPlan(){ this.$router.push({ name: 'monitorPlanEdit', query: { data: encodeURIComponent(JSON.stringify(this.curMonitorObjList)), task: encodeURIComponent(JSON.stringify(this.curTask.data)), } }); } }, mounted() { src/views/fysp/task/components/CompMonitorObj.vue
@@ -1,14 +1,14 @@ <template> <div> <el-segmented :model-value="tabName" :options="tabs" @change="tabChange" /> <el-segmented :model-value="activeName" :options="activeTabs" @change="tabChange" /> </div> <el-space wrap> <ItemMonitorObj v-for="obj in activeData" :key="obj.movid" :item="obj"> <template #default="{ item }"> <!-- <slot :item="item"></slot> --> <el-button v-if="showDelete" size="small" type="danger" @click="deleteMov(item)" >ç§»é¤</el-button > <el-button v-if="showBtn" size="small" type="danger" @click="itemClick(item)">{{ btnName }}</el-button> </template> </ItemMonitorObj> </el-space> @@ -26,12 +26,17 @@ type: String, default: defaultTabName }, tabOptions: Array, showData: Array, // æ¯å¦æ·»å é»è®¤çå ¨é¨é项 allOption: Boolean, showDelete: Boolean showBtn: Boolean, btnName: { type: String, default: 'ç§»é¤' } }, emits: ['update:tabName', 'update:showData', 'deleteItem'], emits: ['update:tabName', 'update:showData', 'itemClick'], data() { return { activeName: defaultTabName, @@ -41,11 +46,18 @@ computed: { activeData() { const list = this.data.filter((v) => { // return this.activeName == defaultTabName || v.sceneType == this.activeName; return this.tabName == defaultTabName || v.sceneType == this.tabName; return this.activeName == defaultTabName || v.sceneType == this.activeName; // return this.tabName == defaultTabName || v.sceneType == this.tabName; }); this.$emit('update:showData', list); return list; }, activeTabs() { if (this.tabOptions) { return this.tabOptions; } else { return this.tabs; } } }, watch: { @@ -60,11 +72,16 @@ tabs: { handler(nV, oV) { if (nV != oV && nV.length > 0) { // this.activeName = nV[0]; this.tabChange(nV); this.activeName = nV[0]; this.tabChange(nV[0]); } }, immediate: true }, tabName(nV, oV) { if (nV != oV) { this.activeName = nV; } } }, methods: { @@ -73,13 +90,14 @@ dataList.forEach((d) => { if (list.indexOf(d.sceneType) == -1) list.push(d.sceneType); }); this.tabs = list; this.tabs = list.sort(); }, tabChange(tabName) { this.activeName = tabName; this.$emit('update:tabName', tabName); }, deleteMov(item) { this.$emit('deleteItem', item); itemClick(item) { this.$emit('itemClick', item); } } }; src/views/fysp/task/components/CompMonitorPlan.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,225 @@ <template> <el-calendar v-loading="dayTaskLoading" v-model="dateValue" :range="dateRange" @update:model-value="onDateChange" > <template #header="{ date }"> <span>{{ title }}</span> <el-space> <el-tag>æ»è®¡ï¼{{ taskStatistic.total }}</el-tag> <el-tag>宿ï¼{{ taskStatistic.complete }}</el-tag> <el-tag>æ´æ¹ï¼{{ taskStatistic.changed }}</el-tag> </el-space> <!-- <span>{{ date }}</span> --> </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-space direction="vertical"> <el-text size="small">æ»è®¡</el-text> <el-text>{{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-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> --> </template> </div> </template> </el-calendar> </template> <script setup> import { ref, computed, onMounted, watch } from 'vue'; import taskApi from '@/api/fysp/taskApi'; import dayjs from 'dayjs'; const props = defineProps({ task: { type: Object, default: () => {} } }); const emit = defineEmits(['dateChange']) // é䏿¥æ const dateValue = ref(new Date()); // æ¥åæ é¢ 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)); const dateRange = computed(() => [startDay.value.toDate(), endDay.value.toDate()]); // const dateRange = computed(() => [new Date(2024, 4, 27), new Date(2024, 5, 30)]); // æ¥ææ¯å¦å¨ä»»å¡èå´å function isDayEnable(day) { const _day = dayjs(day); return _day.isSameOrAfter(startDay.value, 'day') && _day.isSameOrBefore(endDay.value, 'day'); } /********************** æ¥ææ ·å¼ *********************************/ function calendarDayClz(day) { return 'calendar-day ' + (isDayEnable(day) ? 'calendar-day-enable' : 'calendar-day-disable'); } function getDay(day) { return day.split('-').splice(1, 2).join('-'); } /********************** 任塿°æ® *********************************/ // è·åæ¥ä»»å¡ç»è®¡ä¿¡æ¯ const dayTaskLoading = ref(false); const dayTaskList = ref([]); function fetchDayTasks(topTaskId) { dayTaskLoading.value = true; taskApi .fetchDayTasks(topTaskId) .then((res) => { dayTaskList.value = res; }) .finally(() => (dayTaskLoading.value = false)); } // æ¥ä»»å¡æ°æ®å±ç¤º const compMap = new Map(); function computeDayTask(day) { const key = props.task.tguid + day; if (compMap.has(key)) { return compMap.get(key).value; } const result = computed(() => { return dayTaskList.value.find((v) => { return dayjs(v.date).isSame(dayjs(day)); }); }); compMap.set(key, result); return result.value; } function onDateChange(e) { const day = dayjs(e).format('YYYY-MM-DD') const t = computeDayTask(day) console.log(t); emit('dateChange', t) } // æ»ä»»å¡ç»è®¡ const taskStatistic = computed(() => { const res = { total: 0, complete: 0, changed: 0 }; dayTaskList.value.forEach((e) => { res.total += e.totalTaskNum; res.complete += e.completeTaskNum; res.changed += e.changedTaskNum; }); return res; }); /********************** åå§å *********************************/ watch( () => props.task, (nV) => { if (nV.tguid) { fetchDayTasks(nV.tguid); } }, { immediate: true } ); </script> <style scoped> .li-01 { width: 31px !important; height: 31px; background: #fff !important; color: #001529 !important; border: 1.5px solid #25de9d; border-radius: 50%; margin-left: 50%; transform: translate(-15px); line-height: 30px; text-align: center; font-size: 16px; top: 5px; } ::v-deep .el-calendar-table .el-calendar-day { height: initial; padding: initial; } ::v-deep .el-calendar-table .el-calendar-day:hover { background-color: transparent; } /* ::v-deep .el-calendar-table td.is-selected { background-color: initial; } */ .calendar-day { /* text-align: center; line-height: 30px; width: 30px; height: 30px; border: 1px solid rgb(172, 165, 165); border-radius: 50%; */ padding: 8px; height: var(--el-calendar-cell-width); } .calendar-day-enable { } .calendar-day-enable:hover { background-color: var(--el-calendar-selected-bg-color); } .calendar-day-disable { color: var(--el-text-color-disabled); cursor: not-allowed; } /* ::v-deep .el-calendar-table tr td:first-child { border-left: none !important; } */ /* ::v-deep .el-calendar-table tr:first-child td { border-top: none; } */ /* ::v-deep .el-calendar-table td { border-bottom: none; border-right: none; vertical-align: top; -webkit-transition: background-color 0.2s ease; transition: background-color 0.2s ease; } */ ::v-deep .el-calendar-table thead th { padding: 12px 0; color: #606266; font-weight: normal; background-color: #faeaea; } </style>