riku
2024-10-18 c7bd6db3190ff5c4b55d004db0b9fa944604925f
Merge branch 'lsf-topTask'
已修改24个文件
已添加15个文件
2884 ■■■■ 文件已修改
.prettierrc.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
index.html 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fysp/domainApi.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fysp/sceneApi.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fysp/taskApi.js 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fysp/userApi.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fytz/userApi.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/SearchBar.vue 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/core/BaseContentLayout.vue 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/form/FYForm.vue 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/list-item/ItemSubTask.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/map/BaseMap.vue 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/map/SceneMap.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search-option/FYOptionLocation.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search-option/FYOptionTime.vue 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constants/menu.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/toolbox.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/index_old.js 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/marks.js 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/check/ProCheck.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/check/components/CompProRecent.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/check/components/CompProblemAddOrUpd.vue 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/task/MonitorObjEdit copy.vue 370 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/task/MonitorObjEdit.vue 370 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/task/MonitorTaskCreate.vue 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/task/TaskManage.vue 152 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/task/TaskProxy.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/task/components/CompDayTask.vue 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/task/components/CompMonitorObj.vue 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/task/components/CompMonitorObjEdit.vue 451 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/task/components/CompSubTaskList.vue 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/task/components/CompSubTaskSelect.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/task/components/CompTaskEdit.vue 342 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/task/components/CompTaskMap.vue 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.prettierrc.json
@@ -3,6 +3,6 @@
  "semi": true,
  "tabWidth": 2,
  "singleQuote": true,
  "printWidth": 100,
  "printWidth": 80,
  "trailingComma": "none"
}
index.html
@@ -1,13 +1,23 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>生态环境线上监管</title>
  </head>
  <body>
    <div id="app"></div>
  </body>
  <script type="text/javascript">
    window._AMapSecurityConfig = {
      serviceHost: 'http://47.100.191.150:8083/_AMapService'
      //例如 ï¼šserviceHost:'http://1.1.1.1:80/_AMapService',
    };
  </script>
  <script
    type="text/javascript"
    src="https://webapi.amap.com/maps?v=1.4.5&key=520c5e5cf44c7793104e500cbf0ed711&plugin=Map3D,ElasticMarker,AMap.ControlBar,AMap.Geocoder"
  ></script>
  <script type="module" src="/src/main.js"></script>
</html>
package-lock.json
@@ -8,6 +8,7 @@
      "name": "supervision-vue",
      "version": "0.0.0",
      "dependencies": {
        "@amap/amap-jsapi-loader": "^1.0.1",
        "@ctrl/tinycolor": "^4.0.2",
        "@element-plus/icons-vue": "^2.0.10",
        "@vueuse/core": "^9.7.0",
@@ -48,6 +49,11 @@
        "vite": "^3.2.5",
        "vitest": "^0.25.3"
      }
    },
    "node_modules/@amap/amap-jsapi-loader": {
      "version": "1.0.1",
      "resolved": "https://registry.npmmirror.com/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz",
      "integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw=="
    },
    "node_modules/@ampproject/remapping": {
      "version": "2.2.0",
@@ -7679,6 +7685,11 @@
    }
  },
  "dependencies": {
    "@amap/amap-jsapi-loader": {
      "version": "1.0.1",
      "resolved": "https://registry.npmmirror.com/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz",
      "integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw=="
    },
    "@ampproject/remapping": {
      "version": "2.2.0",
      "dev": true,
package.json
@@ -13,6 +13,7 @@
    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
  },
  "dependencies": {
    "@amap/amap-jsapi-loader": "^1.0.1",
    "@ctrl/tinycolor": "^4.0.2",
    "@element-plus/icons-vue": "^2.0.10",
    "@vueuse/core": "^9.7.0",
src/App.vue
@@ -21,9 +21,9 @@
              <Content></Content>
              <!-- <el-backtop
                target=".el-main .el-scrollbar__wrap"
                :right="40"
                :right="10"
                :bottom="100"
                style="width: 120px;z-index: 1000;"
                style="z-index: 1000;"
              >
                <div class="back-top">
                  <el-icon><ArrowUpBold /></el-icon>
src/api/fysp/domainApi.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
import { $fysp } from '../index';
export default {
  // èŽ·å–å·¡æŸ¥ä»»åŠ¡ç±»åž‹
  fetchTaskType() {
    return $fysp.get(`domainitem/taskType`).then((res) => res.data);
  },
  // èŽ·å–å·¡æŸ¥ä»»åŠ¡æœŸé™ç±»åž‹
  fetchDeadlineType() {
    return $fysp.get(`domainitem/deadlineType`).then((res) => res.data);
  },
  // èŽ·å–å·¡æŸ¥ä»»åŠ¡å±‚æ¬¡ç±»åž‹
  fetchLevelType() {
    return $fysp.get(`domainitem/level`).then((res) => res.data);
  }
};
src/api/fysp/sceneApi.js
@@ -67,6 +67,14 @@
  updateScene(scene) {
    return $fysp.post('scense', scene).then((res) => res.data);
  },
  /**
   * æ‰¹é‡æ›´æ–°åœºæ™¯
   */
  updateSceneList(sceneList) {
    return $fysp.post('scense/update/list', sceneList).then((res) => res.data);
  },
  /**
   * èŽ·å–æ‰€æœ‰åœºæ™¯ç±»åž‹
   */
src/api/fysp/taskApi.js
@@ -2,10 +2,28 @@
export default {
  /**
   * æ–°å»ºä»»åŠ¡
   * @param {Object} task
   */
  putTask(task){
    return $fysp.put(`task/create`, task).then((res) => res.data);
  },
  /**
   * æ ¹æ®ä¸»é”®èŽ·å–æ€»ä»»åŠ¡æˆ–æ—¥ä»»åŠ¡
   */
  fetchTaskById(id){
    return $fysp.get(`task/${id}`).then((res) => res.data);
  },
  /**
   * èŽ·å–é¡¶å±‚ä»»åŠ¡
   */
  getTopTask() {
    return $fysp.get('task/alltask/0').then((res) => res.data);
  },
  getLastTopTask(task){
    return $fysp.post(`task/lastTask`, task).then((res) => res.data);
  },
  /**
@@ -89,8 +107,8 @@
  /**
   * èŽ·å–å­ä»»åŠ¡é—®é¢˜è¯¦æƒ…
   */
  async getProBySubtask(id) {
    return await $fysp
  getProBySubtask(id) {
    return $fysp
      .get('problemlist/subtask', {
        params: {
          stGuid: id
src/api/fysp/userApi.js
@@ -19,7 +19,9 @@
   * èŽ·å–åœºæ™¯çš„ç”¨æˆ·è¯¦æƒ…
   */
  getUserByScene(sId) {
    return $fysp.get(`userinfo/scene/get?sceneId=${sId}`).then((res) => res.data);
    return $fysp
      .get(`userinfo/scene/get?sceneId=${sId}`)
      .then((res) => res.data);
  },
  /**
@@ -33,5 +35,14 @@
 */
   getTzId(sceneId) {
    return $fysp.get(`usermap?sceneId=${sceneId}`).then((res) => res.data);
  },
  /**
   * æŒ‰ç”¨æˆ·ç±»åž‹èŽ·å–ç”¨æˆ·ä¿¡æ¯
   */
  getUserByType(typeId, enable = true) {
    return $fysp
      .get(`userinfo/type/get`, { params: { typeId, enable } })
      .then((res) => res.data);
  }
};
src/api/fytz/userApi.js
@@ -45,7 +45,7 @@
   * é‡ç½®ç”¨æˆ·å¯†ç 
   */
  resetPassword(id) {
    return $fytz.post(`userInfo/resetPw?userId=${id}`).then((res) => res);
    return $fytz.post(`userInfo/resetPw?userId=${id}`).then((res) => res.data);
  },
src/components.d.ts
@@ -8,9 +8,11 @@
declare module '@vue/runtime-core' {
  export interface GlobalComponents {
    BaseContentLayout: typeof import('./components/core/BaseContentLayout.vue')['default']
    BaseMap: typeof import('./components/map/BaseMap.vue')['default']
    BasePanelLayout: typeof import('./components/core/BasePanelLayout.vue')['default']
    CompQuickSet: typeof import('./components/search-option/CompQuickSet.vue')['default']
    Content: typeof import('./components/core/Content.vue')['default']
    ElAffix: typeof import('element-plus/es')['ElAffix']
    ElAside: typeof import('element-plus/es')['ElAside']
    ElAvatar: typeof import('element-plus/es')['ElAvatar']
    ElBadge: typeof import('element-plus/es')['ElBadge']
@@ -20,6 +22,7 @@
    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']
    ElCol: typeof import('element-plus/es')['ElCol']
    ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
    ElContainer: typeof import('element-plus/es')['ElContainer']
@@ -68,6 +71,7 @@
    MenuItems: typeof import('./components/core/MenuItems.vue')['default']
    RouterLink: typeof import('vue-router')['RouterLink']
    RouterView: typeof import('vue-router')['RouterView']
    SceneMap: typeof import('./components/map/SceneMap.vue')['default']
    SearchBar: typeof import('./components/SearchBar.vue')['default']
    SideList: typeof import('./components/SideList.vue')['default']
    SiderMenu: typeof import('./components/core/SiderMenu.vue')['default']
src/components/SearchBar.vue
@@ -4,7 +4,11 @@
      <el-form :inline="true" :model="formSearch">
        <el-form-item label="总任务">
          <!-- <el-input v-model="formSearch.topTaskId" placeholder="总任务" /> -->
          <el-select v-model="formSearch.topTaskId" placeholder="总任务" style="width: 260px">
          <el-select
            v-model="formSearch.topTaskId"
            placeholder="总任务"
            style="width: 260px"
          >
            <el-option
              v-for="s in topTasks"
              :key="s.value"
@@ -14,7 +18,11 @@
          </el-select>
        </el-form-item>
        <el-form-item label="场景类型">
          <el-select v-model="formSearch.sceneTypeId" placeholder="场景类型" style="width: 150px">
          <el-select
            v-model="formSearch.sceneTypeId"
            placeholder="场景类型"
            style="width: 150px"
          >
            <el-option
              v-for="s in sceneTypes"
              :key="s.value"
@@ -38,7 +46,7 @@
<script>
import taskApi from '@/api/fysp/taskApi';
import { enumScene } from "@/enum/scene";
import { enumScene } from '@/enum/scene';
export default {
  emits: ['onSubmit'],
@@ -48,42 +56,44 @@
      sceneTypes: enumScene(2, false),
      formSearch: {
        topTaskId: '',
        sceneTypeId: '',
        obj: '',
      },
        sceneTypeId: ''
      }
    };
  },
  methods: {
    //获取查询条件
    getOptions() {
      taskApi.getTopTask().then((res) => {
        const list = [];
        res.forEach((r) => {
          list.push({
        const list = res.map((r) => {
          return {
            value: r.tguid,
            label: r.name,
            obj: r,
            towncode: r.towncode,
            districtCode: r.districtcode,
            month: r.starttime.slice(0, 7),
          });
            data: r
          };
        });
        this.topTasks = list;
        this.formSearch.topTaskId = list[0].value;
        this.formSearch.obj = list[0].obj;
        this.$emit('onSubmit', this.formSearch);
        this.onSubmit();
      });
    },
    //查询子任务统计信息
    onSubmit() {
      // console.log(this.formSearch.sceneTypeId)
      this.$emit('onSubmit', this.formSearch);
    },
      const task = this.topTasks.find(
        (t) => t.data.tguid == this.formSearch.topTaskId
      );
      const param = {
        topTask: task ? task.data : {},
        sceneTypeId: this.formSearch.sceneTypeId
      };
      console.log(param);
      this.$emit('onSubmit', param);
    }
  },
  mounted() {
    this.formSearch.sceneTypeId = this.sceneTypes[0].value;
    this.getOptions();
  },
  }
};
</script>
src/components/core/BaseContentLayout.vue
@@ -1,15 +1,15 @@
<template>
  <el-container>
    <el-header class="el-header">
    <el-header ref="headerRef" class="el-header">
      <slot name="header"></slot>
    </el-header>
    <el-container>
      <el-aside class="el-aside">
      <el-aside class="el-aside" :style="'height: ' + mainHeight">
        <el-scrollbar>
          <slot name="aside"></slot>
        </el-scrollbar>
      </el-aside>
      <el-main class="el-main">
      <el-main class="el-main" :style="'height: ' + mainHeight">
        <slot name="main"></slot>
      </el-main>
    </el-container>
@@ -19,6 +19,28 @@
<script>
export default {
  // å³ä¾§æ“ä½œç•Œé¢åŸºç¡€å¸ƒå±€
  data() {
    return {
      mainHeight: 'calc(100vh - 60px * 2 - var(--el-main-padding) * 2)'
    };
  },
  methods: {
    // å†…容高度
    calHeight() {
      if (this.$refs.headerRef) {
        const h1 = this.$refs.headerRef.$el.offsetHeight;
        const h = h1;
        return `calc(100vh - ${h}px - 60px - var(--el-main-padding) * 2 + 6px)`;
      } else {
        return `calc(100vh - 60px * 2 - var(--el-main-padding) * 2)`;
      }
    }
  },
  mounted() {
    setTimeout(() => {
      this.mainHeight = this.calHeight();
    }, 150);
  }
};
</script>
@@ -26,7 +48,7 @@
.el-aside {
  /* width: initial; */
  position: relative;
  height: calc(100vh - 60px * 2 - 20px * 2);
  /* height: calc(100vh - 60px * 2 - 20px * 2); */
  /* background-color: aqua; */
  /* overflow-y: auto; */
  border-right: 1px solid var(--el-color-info-light-7);
@@ -43,7 +65,7 @@
.el-main {
  position: relative;
  /* background-color: whitesmoke; */
  height: calc(100vh - 60px * 2 - 20px * 2);
  /* height: calc(100vh - 60px * 2 - 20px * 2); */
  padding: initial;
  padding-left: 20px;
  /* overflow: hidden; */
src/components/form/FYForm.vue
@@ -9,10 +9,16 @@
  >
    <slot name="form-item" :formObj="formObj"></slot>
    <el-form-item v-if="showButtons">
      <el-button :disabled="!edit" type="primary" @click="onSubmit" :loading="loading"
        >提交</el-button
      <el-button
        :disabled="!edit"
        type="primary"
        @click="onSubmit"
        :loading="loading"
        >{{ submitName }}</el-button
      >
      <el-button v-if="useReset" :disabled="!edit" @click="onReset">重置</el-button>
      <el-button v-if="useReset" :disabled="!edit" @click="onReset"
        >重置</el-button
      >
      <el-button v-if="useCancel" @click="onCancel">取消</el-button>
    </el-form-item>
  </el-form>
@@ -26,7 +32,15 @@
 * å¯ä¼ å…¥åˆå§‹è¡¨å•数据formInfo,表单校验规则rules
 * å®žçްsubmit和cancel触发函数
 */
import { defineProps, defineEmits, reactive, ref, watch, computed, defineExpose } from 'vue';
import {
  defineProps,
  defineEmits,
  reactive,
  ref,
  watch,
  computed,
  defineExpose
} from 'vue';
import { useFormConfirm } from '@/composables/formConfirm';
const props = defineProps({
@@ -42,6 +56,10 @@
  showButtons: {
    type: Boolean,
    default: true
  },
  submitName: {
    type: String,
    default: '提交'
  },
  //取消按钮是否可用
  useCancel: Boolean,
@@ -81,7 +99,8 @@
});
//表单操作函数
const { formObj, formRef, edit, onSubmit, onCancel, onReset, clear } = useFormConfirm({
const { formObj, formRef, edit, onSubmit, onCancel, onReset, clear } =
  useFormConfirm({
  submit: {
    do: submit
  },
@@ -106,7 +125,7 @@
      },
      (err) => {
        loading.value = false;
        reject(err);
        reject(err ? err : '');
      }
    );
  });
src/components/list-item/ItemSubTask.vue
@@ -1,16 +1,20 @@
<template>
  <div class="wrapper">
    <div>
      <el-text truncated>{{ item.name }}</el-text>
      <el-text truncated class="w-250px" size="large">{{ 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">{{
    </div>
    <div>
      <el-text truncated size="small">{{
          $fm.formatYMDH(item.planstarttime)
        }}</el-text>
        <el-text truncated class="w-250px" size="small">{{ item.executorrealtimes }}</el-text>
      </el-space>
    </div>
    <div>
      <el-text truncated class="w-250px" size="small">{{
        item.executorrealtimes
      }}</el-text>
    </div>
    <el-row justify="end" style="margin-top: 4px">
      <slot :item="item"></slot>
src/components/map/BaseMap.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
<template>
  <div id="container"></div>
</template>
<script setup>
import { onMounted } from 'vue';
import { createMap } from '@/utils/map/index_old';
onMounted(() => {
  // é«˜å¾·åœ°å›¾åˆå§‹åŒ–
  createMap('container');
});
</script>
<style>
#container {
  position: relative;
  width: 100%;
  height: 100vh;
  min-height: var(--screen-min-height);
  min-width: var(--screen-min-width);
  z-index: 0px;
}
/* åŽ»é™¤é«˜å¾·åœ°å›¾çš„å›ºå®šç‰ˆå·å›¾æ ‡ */
.amap-logo {
  display: none;
  opacity: 0 !important;
}
.amap-copyright {
  display: none;
  opacity: 0 !important;
}
.amap-marker-label {
  font-size: 13px;
  text-align: center;
  color: white;
  background-color: transparent;
  text-shadow: black 2px 2px 2px;
  border-radius: 2px;
  border: 0px;
  padding: 4px;
}
</style>
src/components/map/SceneMap.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
<template>
  <div style="width: 70vw; height: 500px; background-color: aliceblue">
    <BaseMap></BaseMap>
  </div>
</template>
<script setup>
const props = defineProps({
  // åœºæ™¯ç‚¹ä½ä¿¡æ¯
  data: Array
});
</script>
<style scoped></style>
src/components/search-option/FYOptionLocation.vue
@@ -43,7 +43,7 @@
      default: '_locations'
    }
  },
  emits: ['update:value'],
  emits: ['update:value', 'change'],
  data() {
    return {
      locations: enumLocation(this.allOption, this.level),
@@ -68,6 +68,7 @@
  methods: {
    handleChange(value) {
      this.$emit('update:value', this.optionFormat(value));
      this.$emit('change', this.optionFormat(value));
    },
    /**
     * åœ°åŒºé€‰é¡¹ç»“果格式化
src/components/search-option/FYOptionTime.vue
@@ -1,10 +1,12 @@
<template>
  <el-form-item label="时间" :prop="prop">
  <el-form-item :label="label" :prop="prop">
    <el-date-picker
      v-model="date"
      @change="handleChange"
      :type="type"
      placeholder="选择时间"
      start-placeholder="选择开始时间"
      end-placeholder="选择结束时间"
      style="width: 150px"
    />
  </el-form-item>
@@ -15,6 +17,7 @@
const MONTH = 'month';
const DATE = 'date';
const RANGE = 'datetimerange';
export default {
  props: {
@@ -23,30 +26,37 @@
      default: MONTH
    },
    // è¿”回结果
    value: Date,
    value: Date || Array,
    // æ˜¯å¦é»˜è®¤è¿”回初始选项
    initValue: {
      type: Boolean,
      default: true
    },
    prop: String
    label: {
      type: String,
      default: '时间'
  },
  emits: ['update:value'],
    prop: {
      type: String,
      default: 'time'
    }
  },
  emits: ['update:value', 'change'],
  data() {
    return {
      date: this.value
    };
  },
  computed:{
  },
  computed: {},
  methods: {
    handleChange(value) {
      this.$emit('update:value', value);
    },
      this.$emit('change', value);
    }
  },
  mounted() {
    if (this.initValue) {
      this.date = new Date()
      this.date = new Date();
      this.handleChange(this.date);
    }
  }
src/constants/menu.js
@@ -15,25 +15,31 @@
  //   ]
  // },
  {
    path: '/fysp/task/manage',
    icon: 'CircleCheck',
    name: '监管任务'
  },
  {
    path: '/fysp/procheck',
    icon: 'CircleCheck',
    name: '问题审核'
  },
  {
    icon: 'List',
    name: '任务管理',
    children: [
      {
        path: '/fysp/task/manage',
        icon: 'CircleCheck',
        name: '监管任务',
      },
      {
        path: '/fysp/sceneInfo',
        icon: 'Files',
        name: '场景信息',
      },
    ],
  },
  // {
  //   path: '/changecheck',
  //   icon: 'Search',
  //   name: '整改审核',
  // },
  {
    path: '/fysp/sceneInfo',
    icon: 'Files',
    name: '场景信息'
  },
  {
    icon: 'DocumentChecked',
    name: '自动评估',
src/router/index.js
@@ -86,6 +86,12 @@
    component: () => import('@/views/fysp/task/MonitorPlanEdit.vue')
  },
  {
    //监管任务计划编辑
    name: 'monitorTaskCreate',
    path: '/fysp/task/create',
    component: () => import('@/views/fysp/task/MonitorTaskCreate.vue')
  },
  {
    //问题审核
    name: 'procheck',
    path: '/fysp/procheck',
src/stores/toolbox.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
import { ref } from 'vue';
import { defineStore } from 'pinia';
export const useToolboxStore = defineStore('toolbox', () => {
  // å¼€å…³åœ°ç‰©æ ‡æ³¨
  const featuresStatus = ref(false);
  // å¼€å…³å«æ˜Ÿåœ°å›¾
  const satelliteStatus = ref(false);
  // å¼€å…³æŽ§åˆ¶ç½—盘
  const controlbarStatus = ref(false);
  // å¼€å…³åæ ‡æ‹¾å–
  const coorPickStatus = ref(false);
  // å¼€å…³æ•°æ®æ ‡è®°
  const dataMarkerStatus = ref(true);
  // å¼€å…³æ•°æ®å¼¹æ¡†
  const dataDialogStatus = ref(true);
  // å¼€å…³æº¯æºæ¸…单
  const sceneSearchStatus = ref(true);
  return {
    featuresStatus,
    satelliteStatus,
    controlbarStatus,
    coorPickStatus,
    dataMarkerStatus,
    dataDialogStatus,
    sceneSearchStatus
  };
});
src/utils/map/index_old.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,117 @@
/* eslint-disable no-undef */
// import '@/lib/AMap';
import { useToolboxStore } from '@/stores/toolbox';
const toolboxStore = useToolboxStore();
var mapInitDone = false;
var onMapMountedEvents = [];
// åœ°å›¾å¯¹è±¡
var map;
// å«æ˜Ÿå›¾å±‚
var satellite;
// åœ°å›¾æ‹–动控制
var controlbar;
// é¼ æ ‡ç»˜å›¾
var mouseTool;
// 3D图层
var object3Dlayer;
// åœ°å›¾æ‹–动状态
var isDragging = false;
// åœ°å›¾åŠ è½½å®Œæˆè§¦å‘
function onMapMounted(...events) {
  if (mapInitDone) {
    events.forEach((e) => {
      e();
    });
  } else {
    onMapMountedEvents = onMapMountedEvents.concat(events);
  }
}
function createMap(id) {
  _initMap(id);
  mapInitDone = true;
  onMapMountedEvents.forEach((e) => {
    e();
  });
  onMapMountedEvents = [];
}
function _initMap(elementId) {
  map = new AMap.Map(elementId, {
    rotateEnable: true,
    pitchEnable: true,
    alwaysRender: false,
    showLabel: true,
    showBuildingBlock: true,
    mapStyle: 'amap://styles/e1e78509de64ddcd2efb4cb34c6fae2a',
    features: ['bg', 'road'],
    pitch: 45, // åœ°å›¾ä¿¯ä»°è§’度,有效范围 0 åº¦- 83 åº¦
    viewMode: '3D', // åœ°å›¾æ¨¡å¼
    resizeEnable: true,
    center: [121.6039283, 31.25295567],
    zooms: [0, 18],
    zoom: 14
  });
  // æ·»åŠ å«æ˜Ÿåœ°å›¾
  satellite = new AMap.TileLayer.Satellite();
  satellite.show();
  map.add([satellite]);
  toolboxStore.featuresStatus = true;
  // _initControlbar();
  // _initMouseTool();
  _init3DLayer();
  _initDragEvent();
}
function _initControlbar() {
  controlbar = new AMap.ControlBar({
    position: {
      right: '300px',
      top: '260px'
    }
  });
  map.addControl(controlbar);
  toolboxStore.controlbarStatus = true;
}
// é¼ æ ‡ç»˜å›¾åˆå§‹åŒ–
// function _initMouseTool() {
//   mouseTool = new AMap.MouseTool(map);
// }
// 3D图层初始化
function _init3DLayer() {
  object3Dlayer = new AMap.Object3DLayer();
  map.add(object3Dlayer);
}
// è®¾ç½®åœ°å›¾æ‹–拽监听事件
function _initDragEvent() {
  let dragEndEvent;
  map.on('dragstart', () => {
    clearTimeout(dragEndEvent);
    isDragging = true;
  });
  map.on('dragend', function () {
    dragEndEvent = setTimeout(() => {
      isDragging = false;
    }, 8000);
  });
}
export {
  createMap,
  onMapMounted,
  map,
  controlbar,
  mouseTool,
  satellite,
  object3Dlayer,
  isDragging
};
src/utils/map/marks.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,149 @@
/**
 * é«˜å¾·åœ°å›¾ç‚¹æ ‡è®°ç»˜åˆ¶ç›¸å…³
 */
import { map } from './index_old';
import { useToolboxStore } from '@/stores/toolbox';
const toolboxStore = useToolboxStore();
var _massMarks = undefined;
export default {
  /**
   * ç»˜åˆ¶æµ·é‡ç‚¹æ ‡è®°
   * @param fDatas å®Œæ•´ç›‘测数据
   * @param _factor å½“前展示的监测因子对象
   */
  drawMassMarks(fDatas, _factor, onClick) {
    if (!toolboxStore.dataMarkerStatus) {
      return;
    }
    this.clearMassMarks();
    const lnglats = fDatas.lnglats_GD;
    var data = [];
    for (let i = 0; i < lnglats.length; i++) {
      data.push({
        lnglat: lnglats[i], //点标记位置
        name: `${fDatas.times[i]}<br/>${_factor.factorName}: ${_factor.datas[i].factorData} mg/m³`,
        id: i
      });
    }
    // åˆ›å»ºæ ·å¼å¯¹è±¡
    var styleObject = {
      url: 'https://a.amap.com/jsapi_demos/static/images/mass1.png',
      // url: './asset/mipmap/ic_up_white.png', // å›¾æ ‡åœ°å€
      // eslint-disable-next-line no-undef
      size: new AMap.Size(11, 11), // å›¾æ ‡å¤§å°
      // eslint-disable-next-line no-undef
      anchor: new AMap.Pixel(5, 5) // å›¾æ ‡æ˜¾ç¤ºä½ç½®åç§»é‡ï¼ŒåŸºå‡†ç‚¹ä¸ºå›¾æ ‡å·¦ä¸Šè§’
    };
    // eslint-disable-next-line no-undef
    var massMarks = new AMap.MassMarks(data, {
      zIndex: 5, // æµ·é‡ç‚¹å›¾å±‚叠加的顺序
      zooms: [15, 18], // åœ¨æŒ‡å®šåœ°å›¾ç¼©æ”¾çº§åˆ«èŒƒå›´å†…展示海量点图层
      style: styleObject // è®¾ç½®æ ·å¼å¯¹è±¡
    });
    massMarks.on('click', (event) => {
      const i = event.data.id;
      // 3. è‡ªå®šä¹‰ç‚¹å‡»äº‹ä»¶
      onClick(i);
    });
    // eslint-disable-next-line no-undef
    var marker = new AMap.Marker({
      content: ' ',
      map: map,
      // eslint-disable-next-line no-undef
      offset: new AMap.Pixel(13, 12)
    });
    var timeout;
    massMarks.on('mouseover', (e) => {
      if (timeout) {
        clearTimeout(timeout);
      }
      marker.setPosition(e.data.lnglat);
      marker.setLabel({ content: e.data.name });
      map.add(marker);
      timeout = setTimeout(() => {
        map.remove(marker);
      }, 2000);
    });
    _massMarks = massMarks;
    map.add(massMarks);
  },
  clearMassMarks() {
    if (_massMarks) {
      map.remove(_massMarks);
      _massMarks = undefined;
    }
  },
  /**
   * åˆ›å»ºæ ‡è®°ç‚¹
   * @param {string | Array} img å›¾æ ‡æˆ–图标数组
   * @param {Array} dataList ç›‘测数据
   * @param {boolean} collision æ ‡æ³¨é¿è®©
   * @returns
   */
  createLabelMarks(img, dataList, collision = true) {
    // eslint-disable-next-line no-undef
    const layer = new AMap.LabelsLayer({
      zooms: [3, 20],
      zIndex: 1000,
      // å¼€å¯æ ‡æ³¨é¿è®©ï¼Œé»˜è®¤ä¸ºå¼€å¯ï¼Œv1.4.15 æ–°å¢žå±žæ€§
      collision: collision,
      // å¼€å¯æ ‡æ³¨æ·¡å…¥åŠ¨ç”»ï¼Œé»˜è®¤ä¸ºå¼€å¯ï¼Œv1.4.15 æ–°å¢žå±žæ€§
      animation: true
    });
    map.add(layer);
    // var markers = [];
    for (var i = 0; i < dataList.length; i++) {
      const data = dataList[i];
      var curData = {
        name: data.name,
        position: [data.longitude, data.latitude],
        zooms: [10, 20],
        opacity: 1,
        zIndex: 10,
        icon: {
          type: 'image',
          image: typeof img === 'string' ? img : img[i],
          // clipOrigin: [14, 92],
          // clipSize: [50, 68],
          size: [30, 30],
          anchor: 'bottom-center',
          angel: 0,
          retina: true
        },
        text: {
          content: data.name,
          direction: 'top',
          offset: [0, -5],
          style: {
            fontSize: 16,
            fontWeight: 'normal',
            fillColor: '#fff',
            strokeColor: '#333',
            strokeWidth: 0,
            backgroundColor: '#122b54a9'
          }
        }
      };
      curData.extData = {
        index: i
      };
      // eslint-disable-next-line no-undef
      var labelMarker = new AMap.LabelMarker(curData);
      // markers.push(labelMarker);
      layer.add(labelMarker);
    }
    return layer;
  }
};
src/views/fysp/check/ProCheck.vue
@@ -237,8 +237,9 @@
      });
    },
    // å…³é—­è®¾å¤‡å›¾å¼¹çª—
    beforeDeviceShowDialogclose() {
      this.deviceShowDialog = false;
    beforeDeviceShowDialogclose(done) {
      // this.deviceShowDialog = false;
      done()
    },
    // å…³é—­ä»»æ„å›¾ç‰‡å¼¹çª—
    beforeAnyPhotoDialogclose() {
@@ -252,12 +253,16 @@
    },
    //查询子任务统计信息
    search(formSearch) {
      this.topTask = formSearch.obj;
      this.topTask = formSearch.topTask;
      this.sideLoading = true;
      this.mainLoading = true;
      this.curProList = [];
      this.curSubtask = {};
      taskApi.getSubtaskSummary(formSearch).then((res) => {
      const param = {
        topTaskId: formSearch.topTask.tguid,
        sceneTypeId :formSearch.sceneTypeId
      }
      taskApi.getSubtaskSummary(param).then((res) => {
        const list = [];
        res.forEach((s) => {
          const t = this.getSubtaskType(s);
src/views/fysp/check/components/CompProRecent.vue
@@ -155,11 +155,11 @@
    /**
     * èŽ·å–è¿‘æœŸæƒ…å†µ
     * */
    async getRecentPros() {
    getRecentPros() {
      this.loading = true;
      this.subtaskCount = 0
      // èŽ·å–å­ä»»åŠ¡åˆ—è¡¨
      await taskApi.getSubtaskByScene(this.generateQueryParam()).then((subtasks) => {
      taskApi.getSubtaskByScene(this.generateQueryParam()).then((subtasks) => {
        this.curProList = [];
        if (subtasks) {
          subtasks.forEach((subtask) => {
@@ -175,7 +175,7 @@
      this.loading = false;
    },
    // æ ¹æ®å­ä»»åŠ¡èŽ·å–é‡Œé¢çš„é—®é¢˜åˆ—è¡¨
    async getProBySubtask(subtask) {
    getProBySubtask(subtask) {
      taskApi.getProBySubtask(subtask.stGuid).then((pros) => {
        if (pros) {
          pros.forEach((pro) => {
src/views/fysp/check/components/CompProblemAddOrUpd.vue
@@ -311,11 +311,12 @@
        return new Date(x.dlCreateTime) - new Date(y.dlCreateTime); //    é™åºï¼Œå‡åºåˆ™åä¹‹
      });
    },
    async getDeviceImgList() {
    getDeviceImgList() {
      this.deviceImgObjList = [];
      for (const deviceTopTypeElement of this.deviceTopTypes) {
        const topTypeId = deviceTopTypeElement.id;
        await deviceApi.fetchDevices(this.subtask.sceneId, topTypeId).then((result) => {
      this.deviceTopTypes.forEach(e => {
        const topTypeId = e.id;
        deviceApi.fetchDevices(this.subtask.sceneId, topTypeId).then((result) => {
          // æ ‡å‡†åŒ–属性名
          for (let i = 0; i < result.data.length; i++) {
            var element = this.convertKeys(result.data[i]);
@@ -355,7 +356,7 @@
              .catch((err) => {});
          }
        });
      }
      });
    },
    initOptions() {
      if (this.problem == undefined || this.problem == null) {
src/views/fysp/task/MonitorObjEdit copy.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,370 @@
<template>
  <el-affix :offset="60" target=".el-main">
    <div class="page-header">
      <el-page-header @back="goBack">
        <template #content>
          <span> {{title}} </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">
      <div>
        <el-text>已选场景</el-text>
      </div>
      <el-divider />
      <CompMonitorObj
        :data="curMonitorObjList"
        show-btn
        v-model:tabName="curSceneType"
        v-model:showData="showMonitorObjList"
        :tabOptions="sceneTypeOptions"
        @item-click="deleteMov"
      >
      </CompMonitorObj>
    </el-col>
    <el-col :span="8">
      <el-affix :offset="140">
        <div>
          <el-text>可选场景</el-text>
        </div>
        <el-divider />
        <div>
          <el-segmented v-model="curSceneType" :options="sceneTypeOptions" />
        </div>
        <FYInfoSearch
          placeholder="请输入场景名称关键字"
          :data="showSceneList"
          :on-search="searchScene"
          :total="total"
          scroll-height="65vh"
          :page-show="false"
        >
          <template #default="{ row }">
            <ItemScene :item="row">
              <el-button-group>
                <el-button size="small" type="primary" @click="openInsertDialog(row)"
                  >插入</el-button
                >
                <el-button size="small" type="primary" @click="openAddDialog(row)">新增</el-button>
              </el-button-group>
            </ItemScene>
          </template>
        </FYInfoSearch>
      </el-affix>
    </el-col>
  </el-row>
  <el-dialog v-model="insertDialog" title="插入场景至空余编号" width="500">
    <div v-if="valibleIndex.length > 0">以下为可选的空余编号</div>
    <div v-else>无可选的空余编号</div>
    <el-radio-group v-model="selectedIndex" size="default">
      <el-radio-button v-for="item in valibleIndex" :key="item" :label="item" :value="item" />
    </el-radio-group>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="insertDialog = false">取消</el-button>
        <el-button :disabled="!selectedIndex" type="primary" @click="insertMov"> ç¡®è®¤ </el-button>
      </div>
    </template>
  </el-dialog>
  <el-dialog v-model="addDialog" title="新增场景编号顺延" width="500">
    <div>顺延编号为:{{ lastIndex }}</div>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="addDialog = false">取消</el-button>
        <el-button type="primary" @click="addMov"> ç¡®è®¤ </el-button>
      </div>
    </template>
  </el-dialog>
</template>
<script>
import CompMonitorObj from './components/CompMonitorObj.vue';
import svUserApi from '@/api/fysp/userApi';
import taskApi from '@/api/fysp/taskApi';
import sceneApi from '@/api/fysp/sceneApi';
import { ElMessage, ElNotification, ElMessageBox } from 'element-plus';
export default {
  async beforeRouteLeave(to, from) {
    // åœ¨å¯¼èˆªç¦»å¼€æ¸²æŸ“该组件的对应路由时调用
    // ä¸Ž `beforeRouteUpdate` ä¸€æ ·ï¼Œå®ƒå¯ä»¥è®¿é—®ç»„件实例 `this`
    // return this.routerChangeCheck();
  },
  components: { CompMonitorObj },
  props: {
    title:{
      type:String,
      default: '总任务编辑'
    },
  },
  data() {
    return {
      // ç›‘管场景
      curMonitorObjList: [],
      // å½“前筛选的场景类型
      curSceneType: undefined,
      showMonitorObjList: [],
      // è¡Œæ”¿åŒºåˆ’
      area: {},
      // æ‰€æœ‰åœºæ™¯
      sceneList: [],
      total: 0,
      // æ’入弹出框
      insertDialog: false,
      // æ’入或新增的编号
      selectedIndex: undefined,
      // æ’入或新增的场景
      selectedScene: undefined,
      // ç›‘管次数
      monitorTimes: 1,
      // æ–°å¢žå¼¹å‡ºæ¡†
      addDialog: false,
      // æ–°å¢žçš„监管场景
      insertObj: [],
      // æ›´æ–°çš„监管场景
      updateObj: [],
      // åˆ é™¤çš„监管场景
      deleteObj: []
    };
  },
  computed: {
    // å½“前场景类型下的展示场景
    showSceneList() {
      return this.sceneList.filter((v) => {
        const index = this.curMonitorObjList.findIndex((o) => {
          return o.sguid == v.guid;
        });
        return index == -1 && v.type == this.curSceneType;
      });
    },
    sceneTypeOptions() {
      const list = [];
      this.sceneList.forEach((d) => {
        if (list.indexOf(d.type) == -1) list.push(d.type);
      });
      return list;
    },
    // å½“前场景类型下的可插入编号
    valibleIndex() {
      // åŽŸåˆ—è¡¨å·²ç»æŒ‰ç…§ç¼–å·é¡ºåºæŽ’åˆ—
      let index = 1;
      const indexList = [];
      this.showMonitorObjList.forEach((l) => {
        while (l.displayid > index) {
          indexList.push(index);
          index++;
        }
        index++;
      });
      if (this.showMonitorObjList.length == 0 && indexList.length == 0) {
        indexList.push(1);
      }
      return indexList;
    },
    lastIndex() {
      const len = this.showMonitorObjList.length;
      if (len > 0) {
        return this.showMonitorObjList[len - 1].displayid + 1;
      } else {
        return 1;
      }
    },
    isEdit() {
      return this.insertObj.length > 0 || this.deleteObj.length > 0 || this.updateObj.length > 0;
    }
  },
  methods: {
    // æŸ¥è¯¢
    searchScene({ text, page, pageSize }) {
      this.area.sceneName = text;
      return sceneApi.searchScene(this.area, 1, 10000).then((res) => {
        if (res.success) {
          // æŸ¥è¯¢ç»“æžœ
          this.sceneList = res.data;
          // æ€»æ•°æ®é‡
          this.total = res.head.totalCount;
        }
      });
    },
    deleteMov(item) {
      if (item.extension1) {
        ElMessage({
          message: '已监管场景无法移除',
          type: 'error'
        });
        return;
      }
      const i = this.curMonitorObjList.indexOf(item);
      this.curMonitorObjList.splice(i, 1);
      const i1 = this.insertObj.indexOf(item);
      this.insertObj.splice(i1, 1);
      const i2 = this.updateObj.indexOf(item);
      this.updateObj.splice(i2, 1);
      this.deleteObj.push(item);
    },
    openInsertDialog(item) {
      this.insertDialog = true;
      this.selectedScene = item;
      this.monitorTimes = 1;
    },
    openAddDialog(item) {
      this.addDialog = true;
      this.selectedScene = item;
      this.monitorTimes = 1;
    },
    insertMov() {
      // 1. åˆ›å»ºæ–°åœºæ™¯
      let mov = this.createMov(this.selectedIndex, this.selectedScene);
      // 2. æŸ¥æ‰¾ç¬¬ä¸€ä¸ªç¼–号大于插入编号的值,将新监管对象插入其之前
      const insertAtIndex = this.curMonitorObjList.findIndex((v) => {
        return v.displayid > this.selectedIndex;
      });
      this.curMonitorObjList.splice(insertAtIndex, 0, mov);
      this.selectedIndex = undefined;
      this.insertDialog = false;
    },
    addMov() {
      // 1. åˆ›å»ºæ–°åœºæ™¯
      let mov = this.createMov(this.lastIndex, this.selectedScene);
      // 2. æ·»åŠ è‡³æœ«å°¾
      this.curMonitorObjList.push(mov);
      this.addDialog = false;
    },
    // åˆ›å»ºä¸€ä¸ªæ–°çš„监管对象
    createMov(displayid, scene) {
      // 1. æŸ¥æ‰¾è¯¥åœºæ™¯æ˜¯å¦ä¹‹å‰å·²è¢«åˆ é™¤
      const index = this.deleteObj.findIndex((v) => {
        return v.sguid == scene.guid;
      });
      let mov;
      // 2. è‹¥æ˜¯å…¨æ–°çš„场景,则新生成一个监管对象,否则只更新编号
      if (index == -1) {
        mov = {
          tid: this.task.tguid,
          sguid: scene.guid,
          sensename: scene.name,
          tasktypeid: 1,
          tasktype: '巡查',
          monitornum: this.monitorTimes,
          displayid: displayid,
          sceneTypeId: scene.typeid,
          sceneType: scene.type
        };
        this.insertObj.push(mov);
      } else {
        mov = this.deleteObj[index];
        mov.displayid = displayid;
        this.updateObj.push(mov);
        this.deleteObj.splice(index, 1);
      }
      return mov;
    },
    // ä¿å­˜ä¿®æ”¹
    saveEdit() {
      // this.saveLoading = true;
      if (this.insertObj.length > 0) {
        const p1 = taskApi.addMonitorObject(this.insertObj).then((res) => {
          ElNotification({
            title: `巡查任务新增完成`,
            message: `新增场景${res}个`,
            type: 'success',
            position: 'bottom-left'
          });
          this.insertObj = [];
        });
      }
      if (this.updateObj.length > 0) {
        const p2 = taskApi.updateMonitorObject(this.updateObj).then((res) => {
          ElNotification({
            title: `巡查任务更新完成`,
            message: `更新场景${res}个`,
            type: 'success',
            position: 'bottom-left'
          });
          this.updateObj = [];
        });
      }
      if (this.deleteObj.length > 0) {
        const p3 = taskApi.deleteMonitorObject(this.deleteObj).then((res) => {
          ElNotification({
            title: `巡查任务删除完成`,
            message: `删除场景${res}个`,
            type: 'success',
            position: 'bottom-left'
          });
          this.deleteObj = [];
        });
      }
      // 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() {
    // ç›‘管场景信息
    this.curMonitorObjList = JSON.parse(decodeURIComponent(this.$route.query.data));
    // æ ¹æ®æ€»ä»»åŠ¡èŽ·å–è¡Œæ”¿åŒºåˆ’ä¿¡æ¯
    const task = JSON.parse(decodeURIComponent(this.$route.query.task));
    this.task = task;
    this.area = {
      provincecode: task.provincecode,
      provincename: task.provincename,
      citycode: task.citycode,
      cityname: task.cityname,
      districtcode: task.districtcode,
      districtname: task.districtname,
      towncode: task.towncode,
      townname: task.townname,
      online: true
    };
    this.searchScene({ text: '' });
  }
};
</script>
<style scoped>
.page-header {
  background-color: white;
  padding: 10px 0;
  border-bottom: 1px solid var(--el-color-info-light-7);
}
</style>
src/views/fysp/task/MonitorObjEdit.vue
@@ -1,5 +1,5 @@
<template>
  <el-affix :offset="60">
  <el-affix :offset="60" target=".el-main">
    <div class="page-header">
      <el-page-header @back="goBack">
        <template #content>
@@ -7,7 +7,11 @@
        </template>
        <template #extra>
          <div>
            <el-button type="primary" :disabled="!isEdit" :loading="saveLoading" @click="saveEdit"
            <el-button
              type="primary"
              :disabled="!isEdit"
              :loading="saveLoading"
              @click="handleSaveClick"
              >保存修改</el-button
            >
          </div>
@@ -16,346 +20,54 @@
      <el-divider />
    </div>
  </el-affix>
  <el-row gutter="20">
    <el-col :span="16">
      <div>
        <el-text>已选场景</el-text>
      </div>
      <el-divider />
      <CompMonitorObj
        :data="curMonitorObjList"
        show-btn
        v-model:tabName="curSceneType"
        v-model:showData="showMonitorObjList"
        :tabOptions="sceneTypeOptions"
        @item-click="deleteMov"
      >
      </CompMonitorObj>
    </el-col>
    <el-col :span="8">
      <el-affix :offset="140">
        <div>
          <el-text>可选场景</el-text>
        </div>
        <el-divider />
        <div>
          <el-segmented v-model="curSceneType" :options="sceneTypeOptions" />
        </div>
        <FYInfoSearch
          placeholder="请输入场景名称关键字"
          :data="showSceneList"
          :on-search="searchScene"
          :total="total"
          scroll-height="70vh"
          :page-show="false"
        >
          <template #default="{ row }">
            <ItemScene :item="row">
              <el-button-group>
                <el-button size="small" type="primary" @click="openInsertDialog(row)"
                  >插入</el-button
                >
                <el-button size="small" type="primary" @click="openAddDialog(row)">新增</el-button>
              </el-button-group>
            </ItemScene>
          </template>
        </FYInfoSearch>
      </el-affix>
    </el-col>
  </el-row>
  <el-dialog v-model="insertDialog" title="插入场景至空余编号" width="500">
    <div>以下为可选的空余编号</div>
    <el-radio-group v-model="selectedIndex" size="default">
      <el-radio-button v-for="item in valibleIndex" :key="item" :label="item" :value="item" />
    </el-radio-group>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="insertDialog = false">取消</el-button>
        <el-button :disabled="!selectedIndex" type="primary" @click="insertMov"> ç¡®è®¤ </el-button>
      </div>
    </template>
  </el-dialog>
  <el-dialog v-model="addDialog" title="新增场景编号顺延" width="500">
    <div>顺延编号为:{{ lastIndex }}</div>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="addDialog = false">取消</el-button>
        <el-button type="primary" @click="addMov"> ç¡®è®¤ </el-button>
      </div>
    </template>
  </el-dialog>
  <CompMonitorObjEdit
    ref="objEditRef"
    :task="task"
    :objList="curMonitorObjList"
    @upload-success="goBack"
  ></CompMonitorObjEdit>
</template>
<script>
import CompMonitorObj from './components/CompMonitorObj.vue';
import svUserApi from '@/api/fysp/userApi';
import taskApi from '@/api/fysp/taskApi';
import sceneApi from '@/api/fysp/sceneApi';
import { ElMessage, ElNotification, ElMessageBox } from 'element-plus';
<script setup>
import { ref, computed, onMounted } from 'vue';
import CompMonitorObjEdit from './components/CompMonitorObjEdit.vue';
import { useRoute, useRouter } from 'vue-router';
export default {
  async beforeRouteLeave(to, from) {
    // åœ¨å¯¼èˆªç¦»å¼€æ¸²æŸ“该组件的对应路由时调用
    // ä¸Ž `beforeRouteUpdate` ä¸€æ ·ï¼Œå®ƒå¯ä»¥è®¿é—®ç»„件实例 `this`
    // return this.routerChangeCheck();
  },
  components: { CompMonitorObj },
  props: {},
  data() {
    return {
      // ç›‘管场景
      curMonitorObjList: [],
      // å½“前筛选的场景类型
      curSceneType: undefined,
      showMonitorObjList: [],
const route = useRoute();
const router = useRouter();
      // è¡Œæ”¿åŒºåˆ’
      area: {},
      // æ‰€æœ‰åœºæ™¯
      sceneList: [],
      total: 0,
const objEditRef = ref(null);
const curMonitorObjList = ref([]);
const task = ref({});
      // æ’入弹出框
      insertDialog: false,
      // æ’入或新增的编号
      selectedIndex: undefined,
      // æ’入或新增的场景
      selectedScene: undefined,
      // ç›‘管次数
      monitorTimes: 1,
      // æ–°å¢žå¼¹å‡ºæ¡†
      addDialog: false,
      // æ–°å¢žçš„监管场景
      insertObj: [],
      // æ›´æ–°çš„监管场景
      updateObj: [],
      // åˆ é™¤çš„监管场景
      deleteObj: []
    };
  },
  computed: {
    // å½“前场景类型下的展示场景
    showSceneList() {
      return this.sceneList.filter((v) => {
        const index = this.curMonitorObjList.findIndex((o) => {
          return o.sguid == v.guid;
const isEdit = computed(() => {
  return objEditRef.value ? objEditRef.value.isEdit : false;
        });
        return index == -1 && v.type == this.curSceneType;
      });
    },
    sceneTypeOptions() {
      const list = [];
      this.sceneList.forEach((d) => {
        if (list.indexOf(d.type) == -1) list.push(d.type);
      });
      return list;
    },
    // å½“前场景类型下的可插入编号
    valibleIndex() {
      // åŽŸåˆ—è¡¨å·²ç»æŒ‰ç…§ç¼–å·é¡ºåºæŽ’åˆ—
      let index = 1;
      const indexList = [];
      this.showMonitorObjList.forEach((l) => {
        while (l.displayid > index) {
          indexList.push(index);
          index++;
        }
        index++;
      });
      if (indexList.length == 0) {
        indexList.push(1);
      }
      return indexList;
    },
    lastIndex() {
      const len = this.showMonitorObjList.length;
      if (len > 0) {
        return this.showMonitorObjList[len - 1].displayid + 1;
      } else {
        return 1;
      }
    },
    isEdit() {
      return this.insertObj.length > 0 || this.deleteObj.length > 0 || this.updateObj.length > 0;
    }
  },
  methods: {
    // æŸ¥è¯¢
    searchScene({ text, page, pageSize }) {
      this.area.sceneName = text;
      return sceneApi.searchScene(this.area, 1, 10000).then((res) => {
        if (res.success) {
          // æŸ¥è¯¢ç»“æžœ
          this.sceneList = res.data;
          // æ€»æ•°æ®é‡
          this.total = res.head.totalCount;
        }
      });
    },
    deleteMov(item) {
      if (item.extension1) {
        ElMessage({
          message: '已监管场景无法移除',
          type: 'error'
        });
        return;
      }
      const i = this.curMonitorObjList.indexOf(item);
      this.curMonitorObjList.splice(i, 1);
      const i1 = this.insertObj.indexOf(item);
      this.insertObj.splice(i1, 1);
      const i2 = this.updateObj.indexOf(item);
      this.updateObj.splice(i2, 1);
      this.deleteObj.push(item);
    },
    openInsertDialog(item) {
      this.insertDialog = true;
      this.selectedScene = item;
      this.monitorTimes = 1;
    },
    openAddDialog(item) {
      this.addDialog = true;
      this.selectedScene = item;
      this.monitorTimes = 1;
    },
    insertMov() {
      // 1. åˆ›å»ºæ–°åœºæ™¯
      let mov = this.createMov(this.selectedIndex, this.selectedScene);
      // 2. æŸ¥æ‰¾ç¬¬ä¸€ä¸ªç¼–号大于插入编号的值,将新监管对象插入其之前
      const insertAtIndex = this.curMonitorObjList.findIndex((v) => {
        return v.displayid > this.selectedIndex;
      });
      this.curMonitorObjList.splice(insertAtIndex, 0, mov);
      this.selectedIndex = undefined;
      this.insertDialog = false;
    },
    addMov() {
      // 1. åˆ›å»ºæ–°åœºæ™¯
      let mov = this.createMov(this.lastIndex, this.selectedScene);
      // 2. æ·»åŠ è‡³æœ«å°¾
      this.curMonitorObjList.push(mov);
      this.addDialog = false;
    },
    // åˆ›å»ºä¸€ä¸ªæ–°çš„监管对象
    createMov(displayid, scene) {
      // 1. æŸ¥æ‰¾è¯¥åœºæ™¯æ˜¯å¦ä¹‹å‰å·²è¢«åˆ é™¤
      const index = this.deleteObj.findIndex((v) => {
        return v.sguid == scene.guid;
      });
      let mov;
      // 2. è‹¥æ˜¯å…¨æ–°çš„场景,则新生成一个监管对象,否则只更新编号
      if (index == -1) {
        mov = {
          tid: this.task.tguid,
          sguid: scene.guid,
          sensename: scene.name,
          tasktypeid: 1,
          tasktype: '巡查',
          monitornum: this.monitorTimes,
          displayid: displayid,
          sceneTypeId: scene.typeid,
          sceneType: scene.type
        };
        this.insertObj.push(mov);
      } else {
        mov = this.deleteObj[index];
        mov.displayid = displayid;
        this.updateObj.push(mov);
        this.deleteObj.splice(index, 1);
function handleSaveClick() {
  objEditRef.value.saveEdit();
      }
      return mov;
    },
    // ä¿å­˜ä¿®æ”¹
    saveEdit() {
      // this.saveLoading = true;
      if (this.insertObj.length > 0) {
        const p1 = taskApi.addMonitorObject(this.insertObj).then((res) => {
          ElNotification({
            title: `巡查任务修改成功`,
            message: `新增场景${res}个`,
            type: 'success',
            position: 'bottom-left'
          });
          this.insertObj = [];
        });
function goBack() {
  router.back();
      }
      if (this.updateObj.length > 0) {
        const p2 = taskApi.updateMonitorObject(this.updateObj).then((res) => {
          ElNotification({
            title: `巡查任务修改成功`,
            message: `更新场景${res}个`,
            type: 'success',
            position: 'bottom-left'
          });
          this.updateObj = [];
        });
      }
      if (this.deleteObj.length > 0) {
        const p3 = taskApi.deleteMonitorObject(this.deleteObj).then((res) => {
          ElNotification({
            title: `巡查任务修改成功`,
            message: `删除场景${res}个`,
            type: 'success',
            position: 'bottom-left'
          });
          this.deleteObj = [];
        });
      }
      // 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() {
onMounted(() => {
    // ç›‘管场景信息
    this.curMonitorObjList = JSON.parse(decodeURIComponent(this.$route.query.data));
    // æ ¹æ®æ€»ä»»åŠ¡èŽ·å–è¡Œæ”¿åŒºåˆ’ä¿¡æ¯
    const task = JSON.parse(decodeURIComponent(this.$route.query.task));
    this.task = task;
    this.area = {
      provincecode: task.provincecode,
      provincename: task.provincename,
      citycode: task.citycode,
      cityname: task.cityname,
      districtcode: task.districtcode,
      districtname: task.districtname,
      towncode: task.towncode,
      townname: task.townname,
      online: true
    };
    this.searchScene({ text: '' });
  }
};
  // curMonitorObjList.value = JSON.parse(decodeURIComponent(route.query.data));
  // æ€»ä»»åŠ¡
  task.value = JSON.parse(decodeURIComponent(route.query.task));
  // ç›‘管场景信息
  curMonitorObjList.value = JSON.parse(
    decodeURIComponent(route.query.data)
  );
});
</script>
<style scoped>
.page-header {
  background-color: #fff;
  background-color: white;
  padding: 10px 0;
  /* border-bottom: 1px solid var(--el-color-info-light-7); */
}
</style>
src/views/fysp/task/MonitorTaskCreate.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,93 @@
<template>
  <el-affix :offset="60" target=".el-main">
    <div class="page-header">
      <el-page-header @back="goBack">
        <template #content>
          <span> æ–°å»ºå·¡æŸ¥æ€»ä»»åŠ¡ </span>
          <el-text type="info">(任务模板:{{ lastTask.name }})</el-text>
        </template>
        <template #extra>
          <div>
            <el-button
              type="primary"
              :disabled="!isEdit"
              :loading="saveLoading"
              @click="handleSaveClick"
              >提交</el-button
            >
          </div>
        </template>
      </el-page-header>
      <el-divider />
    </div>
  </el-affix>
  <CompMonitorObjEdit
    ref="objEditRef"
    create
    :task="task"
    :objList="curMonitorObjList"
    @upload-success="goBack"
  ></CompMonitorObjEdit>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import CompMonitorObjEdit from './components/CompMonitorObjEdit.vue';
import taskApi from '../../../api/fysp/taskApi';
const route = useRoute();
const router = useRouter();
const objEditRef = ref(null);
const curMonitorObjList = ref([]);
const task = ref({});
const lastTask = ref({})
const isEdit = computed(()=>{
  return objEditRef.value ? objEditRef.value.isEdit : false
})
function handleSaveClick() {
  objEditRef.value.saveEdit()
}
function goBack() {
  router.back();
}
function getLastTopTask(task) {
  taskApi.getLastTopTask(task).then(t=>{
    lastTask.value = t
    if (t) {
      taskApi
        .fetchMonitorObjectVersion(t.tguid)
        .then((res) => {
          // ä»¥åŽ†å²ç›‘ç®¡åœºæ™¯ä¸ºåŸºç¡€ï¼ŒåŒæ—¶åˆå§‹åŒ–éƒ¨åˆ†å±žæ€§
          res.forEach(e => {
            e.movid = null
            e.tid = task.tguid
            e.extension1 = null
          });
          curMonitorObjList.value = res;
        })
        .finally(() => {
          // this.mainLoading = false;
        });
    }
  })
}
onMounted(() => {
  // ç›‘管场景信息
  // curMonitorObjList.value = JSON.parse(decodeURIComponent(route.query.data));
  // æ€»ä»»åŠ¡
  task.value = JSON.parse(decodeURIComponent(route.query.task));
  getLastTopTask(task.value)
});
</script>
<style scoped>
.page-header {
  background-color: white;
  padding-top: 20px;
}
</style>
src/views/fysp/task/TaskManage.vue
@@ -1,9 +1,8 @@
<template>
  <BaseContentLayout>
    <template #header>
      <FYSearchBar @search="search">
      <!-- <FYSearchBar @search="search">
        <template #options>
          <!-- åŒºåŽ¿ -->
          <FYOptionLocation
            :allOption="true"
            :level="3"
@@ -11,13 +10,14 @@
            v-model:value="formSearch.locations"
          ></FYOptionLocation>
        </template>
        <!-- <template #buttons>
          <slot name="buttons"></slot>
        </template> -->
      </FYSearchBar>
      </FYSearchBar> -->
    </template>
    <template #aside>
      <SideList :items="tasks" :loading="sideLoading" @item-click="chooseTask"></SideList>
      <SideList
        :items="tasks"
        :loading="sideLoading"
        @item-click="chooseTask"
      ></SideList>
    </template>
    <template #main>
      <ToolBar
@@ -32,36 +32,91 @@
        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>
          <!-- <div><el-text>监管计划</el-text></div>
          <el-button type="warning" size="small" @click="editPlan"
            >计划调整</el-button
          > -->
          <el-tabs model-value="first">
            <el-tab-pane label="监管计划" name="first">
              <el-row>
                <el-col :span="curSubTaskList.length > 0 ? 16 : 24">
                  <CompMonitorPlan
                    :task="curTask.data"
                    @date-change="onDateChange"
                  ></CompMonitorPlan>
                </el-col>
                <el-col v-if="curSubTaskList.length > 0" :span="8">
                  <CompSubTaskList
                    :data="curSubTaskList"
                    height="56vh"
                    @add="subTaskDrawer = true"
                  ></CompSubTaskList>
                </el-col>
              </el-row>
            </el-tab-pane>
            <el-tab-pane label="监管地图" name="second">
              <CompTaskMap></CompTaskMap>
            </el-tab-pane>
          </el-tabs>
        </el-row>
        <el-divider></el-divider>
        <el-row justify="space-between">
          <div><el-text>监管场景</el-text></div>
          <el-button type="warning" size="small" @click="editTask">场景调整</el-button>
          <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>
            <ItemMonitorObj
              v-for="item in curMonitorObjList"
              :key="item.movid"
              :item="item"
            ></ItemMonitorObj>
          </el-space>
        </div> -->
      </el-scrollbar>
      <el-empty v-else description="暂无记录" v-loading="mainLoading" />
      <div v-else>
        <el-empty description="暂无记录" v-loading="mainLoading" />
        <el-row v-if="!mainLoading" justify="center">
          <el-button
            type="primary"
            size="default"
            @click="navToTaskCreate(curTask.data)"
            >添加监管场景</el-button
          >
        </el-row>
      </div>
    </template>
  </BaseContentLayout>
  <el-drawer
    v-model="subTaskDrawer"
    title="日计划管理"
    direction="btt"
    size="96%"
    destroy-on-close
  >
    <CompDayTask
      :day-task="curDayTask"
      :mObjList="curMonitorObjList"
    ></CompDayTask>
  </el-drawer>
  <el-dialog
    v-model="topTaskAddVisible"
    width="600"
    title="一键创建总任务"
    destroy-on-close
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    :show-close="false"
  >
    <CompTaskEdit
      @submit="navToTaskCreate"
      @cancel="topTaskAddVisible = false"
    ></CompTaskEdit>
  </el-dialog>
</template>
<script>
import taskApi from '@/api/fysp/taskApi';
import CompMonitorObj from './components/CompMonitorObj.vue';
import CompMonitorPlan from './components/CompMonitorPlan.vue';
import CompDayTask from './components/CompDayTask.vue';
import CompTaskMap from './components/CompTaskMap.vue';
import CompTaskEdit from './components/CompTaskEdit.vue';
import CompSubTaskList from './components/CompSubTaskList.vue';
export default {
  beforeRouteEnter(to, from, next) {
    // åœ¨æ¸²æŸ“该组件的对应路由被验证前调用
@@ -70,10 +125,19 @@
    next((vm) => {
      if (from.name == 'monitorObjEdit' && vm.task) {
        vm.chooseTask(vm.task);
      } else if (from.name == 'monitorTaskCreate') {
        vm.search();
      }
    });
  },
  components: { CompMonitorObj, CompMonitorPlan },
  components: {
    CompMonitorObj,
    CompMonitorPlan,
    CompDayTask,
    CompTaskMap,
    CompTaskEdit,
    CompSubTaskList
  },
  data() {
    return {
      formSearch: {
@@ -96,15 +160,26 @@
      curTask: {},
      //操作按钮
      buttons: [
        // {
        //   name: '计划调整',
        //   color: 'success'
        // },
        {
          name: '一键创建总任务',
          color: 'success',
          click: () => {
            this.topTaskAddVisible = true;
          }
        }
        // {
        //   name: '场景调整',
        //   color: 'warning'
        // }
      ]
      ],
      // å­ä»»åŠ¡ç¼–è¾‘å¼¹å‡ºæ¡†
      subTaskDrawer: false,
      // å½“前选择的日任务
      curDayTask: {},
      // å½“前选择的日任务下的子任务
      curSubTaskList: [],
      // æ€»ä»»åŠ¡æ–°å¢žå¼¹å‡ºæ¡†
      topTaskAddVisible: false
    };
  },
  computed: {
@@ -163,6 +238,7 @@
      this.task = task;
      this.sideLoading = false;
      this.mainLoading = true;
      this.curSubTaskList = []
      taskApi
        .fetchMonitorObjectVersion(task.data.tguid)
        .then((res) => {
@@ -187,7 +263,23 @@
        name: 'monitorPlanEdit',
        query: {
          data: encodeURIComponent(JSON.stringify(this.curMonitorObjList)),
          task: encodeURIComponent(JSON.stringify(this.curTask.data)),
          task: encodeURIComponent(JSON.stringify(this.curTask.data))
        }
      });
    },
    onDateChange(dayTask) {
      // this.subTaskDrawer = true;
      this.curDayTask = dayTask;
      taskApi.fetchSubtaskByDayTask(dayTask.guid).then((res) => {
        this.curSubTaskList = res;
      });
    },
    navToTaskCreate(value) {
      this.topTaskAddVisible = false;
      this.$router.push({
        name: 'monitorTaskCreate',
        query: {
          task: encodeURIComponent(JSON.stringify(value))
        }
      });
    }
@@ -206,6 +298,6 @@
}
.el-scrollbar {
  height: calc((100vh - 60px * 2 - 20px * 2 - var(--height-toolbar)));
  height: calc((100vh - 60px - 20px * 2 - var(--height-toolbar)));
}
</style>
src/views/fysp/task/TaskProxy.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
export default {
  /**
   * ç”Ÿæˆå·¡æŸ¥å­ä»»åŠ¡å¯¹è±¡
   */
  ceateSubTask(){
  }
}
src/views/fysp/task/components/CompDayTask.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,141 @@
<template>
  <el-row gutter="20">
    <el-col :span="16">
      <div>
        <el-text>监管场景</el-text>
      </div>
      <el-divider />
      <CompSubTaskSelect
        :data="seletedSceneList"
        :dayTask="dayTask"
        @delete="deleteScene"
      ></CompSubTaskSelect>
      <div>
        <!-- <el-scrollbar height="50vh"> -->
          <CompMonitorObj :data="curMonitorObjList" height="50vh">
            <template #default="{ item }">
              <el-button
                v-if="item.select"
                size="small"
                type="info"
                plain
                disabled
                icon="select"
                >选择</el-button
              >
              <el-button
                v-else
                size="small"
                type="primary"
                plain
                @click="selectScene(item)"
                >选择</el-button
              >
            </template>
          </CompMonitorObj>
        <!-- </el-scrollbar> -->
      </div>
    </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 />
      <div>
        <el-scrollbar :height="height">
          <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>
        </el-scrollbar>
      </div>
    </el-col>
  </el-row>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue';
import { useCloned } from '@vueuse/core';
import { useRoute, useRouter } from 'vue-router';
import taskApi from '@/api/fysp/taskApi';
import TaskProxy from '../TaskProxy';
import CompMonitorObj from './CompMonitorObj.vue';
import CompSubTaskSelect from './CompSubTaskSelect.vue';
const route = useRoute();
const props = defineProps({
  // æ—¥ä»»åŠ¡
  dayTask: Object,
  mObjList: Array
});
/*************************** æ•°æ®åˆå§‹åŒ– ************************************/
// å·¡æŸ¥å­ä»»åŠ¡é›†åˆ
const curMonitorObjList = ref([]);
const curSubTaskList = ref([]);
const height = ref('70vh');
// ç›‘听日任务变化
watch(
  () => props.dayTask,
  (nV) => {
    onDayTaskChange(nV);
  },
  { immediate: true }
);
// ç›‘听监管场景变化
watch(
  () => props.mObjList,
  (nV, oV) => {
    if (nV != oV) {
      curMonitorObjList.value = useCloned(nV).cloned.value;
    }
  },
  { immediate: true }
);
// æ ¹æ®æ—¥ä»»åŠ¡èŽ·å–å¯¹åº”å­ä»»åŠ¡
function onDayTaskChange(dayTask) {
  if (dayTask) {
    fetchSubTask(dayTask.guid);
  } else {
    curSubTaskList.value = [];
  }
}
// èŽ·å–å·¡æŸ¥å­ä»»åŠ¡
function fetchSubTask(dayTaskId) {
  taskApi.fetchSubtaskByDayTask(dayTaskId).then((res) => {
    curSubTaskList.value = res;
  });
}
/*************************** æ·»åŠ å­ä»»åŠ¡ ************************************/
// æ‰€é€‰åœºæ™¯
const seletedSceneList = ref([]);
// é€‰æ‹©ä»»åŠ¡åœºæ™¯
function selectScene(item) {
  item.select = true;
  seletedSceneList.value.push(item);
}
// ç§»é™¤ä»»åŠ¡åœºæ™¯
function deleteScene(item) {
  item.select = false;
  const index = seletedSceneList.value.indexOf(item);
  seletedSceneList.value.splice(index, 1);
}
</script>
<style scoped></style>
src/views/fysp/task/components/CompMonitorObj.vue
@@ -1,17 +1,40 @@
<template>
  <div class="monitor-obj-wrapper">
    <el-affix v-if="affix" :offset="60" target=".monitor-obj-wrapper">
  <div>
    <el-segmented :model-value="activeName" :options="activeTabs" @change="tabChange" />
        <el-segmented
          :model-value="activeName"
          :options="activeTabs"
          @change="tabChange"
        />
  </div>
    </el-affix>
    <div v-else>
      <el-segmented
        :model-value="activeName"
        :options="activeTabs"
        @change="tabChange"
      />
    </div>
    <el-scrollbar :height="height">
  <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="showBtn" size="small" type="danger" @click="itemClick(item)">{{
          btnName
        }}</el-button>
            <slot :item="item">
              <el-button
                v-if="showBtn"
                size="small"
                plain
                :type="btnType"
                @click="itemClick(item)"
                >{{ btnName }}</el-button
              >
            </slot>
      </template>
    </ItemMonitorObj>
  </el-space>
    </el-scrollbar>
  </div>
</template>
<script>
@@ -34,7 +57,14 @@
    btnName: {
      type: String,
      default: '移除'
    }
    },
    btnType: {
      type: String,
      default: 'danger'
    },
    // å¤´éƒ¨é€‰é¡¹æ˜¯å¦å¸é¡¶
    affix: Boolean,
    height: String
  },
  emits: ['update:tabName', 'update:showData', 'itemClick'],
  data() {
@@ -46,7 +76,9 @@
  computed: {
    activeData() {
      const list = this.data.filter((v) => {
        return this.activeName == defaultTabName || v.sceneType == this.activeName;
        return (
          this.activeName == defaultTabName || v.sceneType == this.activeName
        );
        // return this.tabName == defaultTabName || v.sceneType == this.tabName;
      });
      this.$emit('update:showData', list);
src/views/fysp/task/components/CompMonitorObjEdit.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,451 @@
<template>
  <el-row gutter="20">
    <el-col
      :span="16"
      style="border-right: 1px solid var(--el-color-info-light-7)"
    >
      <div>
        <el-text>已选场景</el-text>
        <el-text type="info" size="small">{{ statisticText }}</el-text>
      </div>
      <el-divider />
      <CompMonitorObj
        height="68vh"
        :data="curMonitorObjList"
        show-btn
        v-model:tabName="curSceneType"
        v-model:showData="showMonitorObjList"
        :tabOptions="sceneTypeOptions"
        @item-click="deleteMov"
      >
      </CompMonitorObj>
    </el-col>
    <el-col :span="8">
      <el-affix :offset="140">
        <div>
          <el-text>可选场景</el-text>
        </div>
        <el-divider />
        <div>
          <el-segmented v-model="curSceneType" :options="sceneTypeOptions" />
        </div>
        <FYInfoSearch
          placeholder="请输入场景名称关键字"
          :data="showSceneList"
          :on-search="searchScene"
          :total="total"
          scroll-height="60vh"
          :page-show="false"
        >
          <template #default="{ row }">
            <ItemScene :item="row">
              <el-button-group>
                <el-button
                  size="small"
                  type="primary"
                  @click="openInsertDialog(row)"
                  >插入</el-button
                >
                <el-button
                  size="small"
                  type="primary"
                  @click="openAddDialog(row)"
                  >新增</el-button
                >
              </el-button-group>
            </ItemScene>
          </template>
        </FYInfoSearch>
      </el-affix>
    </el-col>
  </el-row>
  <el-dialog v-model="insertDialog" title="插入场景至空余编号" width="500">
    <div v-if="valibleIndex.length > 0">以下为可选的空余编号</div>
    <div v-else>无可选的空余编号</div>
    <el-radio-group v-model="selectedIndex" size="default">
      <el-radio-button
        v-for="item in valibleIndex"
        :key="item"
        :label="item"
        :value="item"
      />
    </el-radio-group>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="insertDialog = false">取消</el-button>
        <el-button :disabled="!selectedIndex" type="primary" @click="insertMov">
          ç¡®è®¤
        </el-button>
      </div>
    </template>
  </el-dialog>
  <el-dialog v-model="addDialog" title="新增场景编号顺延" width="500">
    <div>顺延编号为:{{ lastIndex }}</div>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="addDialog = false">取消</el-button>
        <el-button type="primary" @click="addMov"> ç¡®è®¤ </el-button>
      </div>
    </template>
  </el-dialog>
</template>
<script>
import { useCloned } from '@vueuse/core';
import CompMonitorObj from './CompMonitorObj.vue';
import taskApi from '@/api/fysp/taskApi';
import sceneApi from '@/api/fysp/sceneApi';
import { ElMessage, ElNotification, ElMessageBox } from 'element-plus';
const MODE_CREATE = 'create';
const MODE_UPDATE = 'update';
export default {
  components: { CompMonitorObj },
  props: {
    // ç¼–辑模式,新增create或更新update
    mode: {
      type: String,
      default: MODE_CREATE
    },
    create: Boolean,
    // å·¡æŸ¥æ€»ä»»åŠ¡
    task: {
      type: Object,
      default: () => {
        return {};
      }
    },
    // ç›‘管场景集合
    objList: Array
  },
  data() {
    return {
      // ç›‘管场景
      curMonitorObjList: [],
      // å½“前筛选的场景类型
      curSceneType: undefined,
      showMonitorObjList: [],
      // æ‰€æœ‰åœºæ™¯
      sceneList: [],
      total: 0,
      // æ’入弹出框
      insertDialog: false,
      // æ’入或新增的编号
      selectedIndex: undefined,
      // æ’入或新增的场景
      selectedScene: undefined,
      // ç›‘管次数
      monitorTimes: 1,
      // æ–°å¢žå¼¹å‡ºæ¡†
      addDialog: false,
      // æ–°å¢žçš„监管场景
      insertObj: [],
      // æ›´æ–°çš„监管场景
      updateObj: [],
      // åˆ é™¤çš„监管场景
      deleteObj: [],
      // æ›´æ–°çš„场景基本信息(更新场景的编号)
      updateScene: []
    };
  },
  emits: ['uploadSuccess', 'uploadFail'],
  watch: {
    objList: {
      handler(nV, oV) {
        if (nV != oV) {
          this.curMonitorObjList = useCloned(nV).cloned.value;
        }
      },
      immediate: true
    }
    // task: {
    //   handler(nV, oV) {
    //     if (nV != oV) {
    //       this.searchScene({ text: '' });
    //     }
    //   },
    //   immediate: true
    // }
  },
  computed: {
    // æŸ¥è¯¢åœºæ™¯èŒƒå›´æ¡ä»¶
    area() {
      return {
        provincecode: this.task.provincecode,
        provincename: this.task.provincename,
        citycode: this.task.citycode,
        cityname: this.task.cityname,
        districtcode: this.task.districtcode,
        districtname: this.task.districtname,
        towncode: this.task.towncode,
        townname: this.task.townname,
        online: true
      };
    },
    // å½“前场景类型下的展示场景
    showSceneList() {
      return this.sceneList.filter((v) => {
        const index = this.curMonitorObjList.findIndex((o) => {
          return o.sguid == v.guid;
        });
        return index == -1 && v.type == this.curSceneType;
      });
    },
    sceneTypeOptions() {
      const list = [];
      this.sceneList.forEach((d) => {
        if (list.indexOf(d.type) == -1) list.push(d.type);
      });
      return list;
    },
    // å½“前场景类型下的可插入编号
    valibleIndex() {
      // åŽŸåˆ—è¡¨å·²ç»æŒ‰ç…§ç¼–å·é¡ºåºæŽ’åˆ—
      let index = 1;
      const indexList = [];
      this.showMonitorObjList.forEach((l) => {
        while (l.displayid > index) {
          indexList.push(index);
          index++;
        }
        index++;
      });
      if (this.showMonitorObjList.length == 0 && indexList.length == 0) {
        indexList.push(1);
      }
      return indexList;
    },
    lastIndex() {
      const len = this.showMonitorObjList.length;
      if (len > 0) {
        return this.showMonitorObjList[len - 1].displayid + 1;
      } else {
        return 1;
      }
    },
    isEdit() {
      // æ–°å»ºç›‘管总任务模式
      if (this.create) {
        return this.curMonitorObjList.length > 0;
      }
      // æ›´æ–°ç›‘管总任务模式
      else {
        return (
          this.insertObj.length > 0 ||
          this.deleteObj.length > 0 ||
          this.updateObj.length > 0
        );
      }
    },
    statisticText() {
      const total = this.curMonitorObjList.length;
      const map = new Map();
      this.curMonitorObjList.forEach((e) => {
        const d = e.scene
        if (!map.has(d.type)) {
          map.set(d.type, { num: 1 });
        }
        map.get(d.type).num++;
      });
      let res = `(总计${total}个`;
      for (const [key, value] of map) {
        res += `,${key}${value.num}个`;
      }
      res += ')';
      return res;
    }
  },
  methods: {
    // æŸ¥è¯¢
    searchScene({ text, page, pageSize }) {
      this.area.sceneName = text;
      return sceneApi.searchScene(this.area, 1, 10000).then((res) => {
        if (res.success) {
          // æŸ¥è¯¢ç»“æžœ
          this.sceneList = res.data;
          // æ€»æ•°æ®é‡
          this.total = res.head.totalCount;
        }
      });
    },
    deleteMov(item) {
      if (item.extension1) {
        ElMessage({
          message: '已监管场景无法移除',
          type: 'error'
        });
        return;
      }
      const i = this.curMonitorObjList.indexOf(item);
      this.curMonitorObjList.splice(i, 1);
      const i1 = this.insertObj.indexOf(item);
      this.insertObj.splice(i1, 1);
      const i2 = this.updateObj.indexOf(item);
      this.updateObj.splice(i2, 1);
      const i3 = this.updateScene.findIndex((s) => {
        return s.guid == item.sguid;
      });
      this.updateScene.splice(i3, 1);
      this.deleteObj.push(item);
    },
    openInsertDialog(item) {
      this.insertDialog = true;
      this.selectedScene = item;
      this.monitorTimes = 1;
    },
    openAddDialog(item) {
      this.addDialog = true;
      this.selectedScene = item;
      this.monitorTimes = 1;
    },
    insertMov() {
      // 1. åˆ›å»ºæ–°åœºæ™¯
      let mov = this.createMov(this.selectedIndex, this.selectedScene);
      // 2. æŸ¥æ‰¾ç¬¬ä¸€ä¸ªç¼–号大于插入编号的值,将新监管对象插入其之前
      const insertAtIndex = this.curMonitorObjList.findIndex((v) => {
        return v.displayid > this.selectedIndex;
      });
      this.curMonitorObjList.splice(insertAtIndex, 0, mov);
      this.selectedIndex = undefined;
      this.insertDialog = false;
    },
    addMov() {
      // 1. åˆ›å»ºæ–°åœºæ™¯
      let mov = this.createMov(this.lastIndex, this.selectedScene);
      // 2. æ·»åŠ è‡³æœ«å°¾
      this.curMonitorObjList.push(mov);
      this.addDialog = false;
    },
    // åˆ›å»ºä¸€ä¸ªæ–°çš„监管对象
    createMov(displayid, scene) {
      // 1. æŸ¥æ‰¾è¯¥åœºæ™¯æ˜¯å¦ä¹‹å‰å·²è¢«åˆ é™¤
      const index = this.deleteObj.findIndex((v) => {
        return v.sguid == scene.guid;
      });
      let mov;
      // 2. è‹¥æ˜¯å…¨æ–°çš„场景,则新生成一个监管对象,否则只更新编号
      if (index == -1) {
        mov = {
          tid: this.task.tguid,
          sguid: scene.guid,
          sensename: scene.name,
          tasktypeid: 1,
          tasktype: '巡查',
          monitornum: this.monitorTimes,
          displayid: displayid,
          sceneTypeId: scene.typeid,
          sceneType: scene.type
        };
        this.insertObj.push(mov);
      } else {
        mov = this.deleteObj[index];
        mov.displayid = displayid;
        this.updateObj.push(mov);
        this.deleteObj.splice(index, 1);
      }
      // 3. åŒæ­¥æ›´æ–°åœºæ™¯åŸºæœ¬ä¿¡æ¯ä¸­çš„编号
      scene._index = displayid;
      this.updateScene.push(scene);
      return mov;
    },
    // ä¿å­˜ä¿®æ”¹
    saveEdit() {
      if (this.create) {
        this.createTask();
      } else {
        this.updateTask();
      }
    },
    createTask() {
      if (this.curMonitorObjList.length > 0) {
        taskApi
          .addMonitorObject(this.curMonitorObjList)
          .then((res) => {
            ElNotification({
              title: `巡查总任务创建完成`,
              message: `新增场景${res}个`,
              type: 'success',
              position: 'bottom-left'
            });
            this.$emit('uploadSuccess');
          })
          .catch((err) => this.$emit('uploadFail', err));
      }
      this.updateSceneList();
    },
    updateTask() {
      // new Promise((resolve, reject)=>{
      // })
      // this.saveLoading = true;
      if (this.insertObj.length > 0) {
        const p1 = taskApi.addMonitorObject(this.insertObj).then((res) => {
          ElNotification({
            title: `巡查任务新增完成`,
            message: `新增场景${res}个`,
            type: 'success',
            position: 'bottom-left'
          });
          this.insertObj = [];
        });
      }
      if (this.updateObj.length > 0) {
        const p2 = taskApi.updateMonitorObject(this.updateObj).then((res) => {
          ElNotification({
            title: `巡查任务更新完成`,
            message: `更新场景${res}个`,
            type: 'success',
            position: 'bottom-left'
          });
          this.updateObj = [];
        });
      }
      if (this.deleteObj.length > 0) {
        const p3 = taskApi.deleteMonitorObject(this.deleteObj).then((res) => {
          ElNotification({
            title: `巡查任务删除完成`,
            message: `删除场景${res}个`,
            type: 'success',
            position: 'bottom-left'
          });
          this.deleteObj = [];
        });
      }
      this.updateSceneList();
      // return Promise.all([p1, p2, p3]).finally(() => {
      //   this.saveLoading = false;
      // });
    },
    updateSceneList() {
      if (this.updateScene.length > 0) {
        this.updateScene.forEach((s) => {
          s.index = s._index;
        });
        sceneApi.updateSceneList(this.updateScene).then((res) => {
          ElNotification({
            title: `场景编号更新完成`,
            message: `更新场景${res}个`,
            type: 'success',
            position: 'bottom-left'
          });
          this.updateScene = [];
        });
      }
    }
  },
  mounted() {
    setTimeout(() => {
      this.searchScene({ text: '' });
    }, 1000);
  }
};
</script>
<style scoped></style>
src/views/fysp/task/components/CompSubTaskList.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
<template>
  <el-row justify="space-between">
    <el-text>单日计划</el-text>
    <el-button type="success" size="small" @click="add">新增</el-button>
  </el-row>
  <el-divider />
  <div>
    <el-scrollbar :height="height">
      <el-space fill direction="vertical">
        <ItemSubTask v-for="s in data" :key="s.guid" :item="s">
          <template #default="{ item }">
            <el-button type="danger" size="small" @click="remove(item)"
              >移除</el-button
            >
          </template>
        </ItemSubTask>
      </el-space>
    </el-scrollbar>
  </div>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue';
const props = defineProps({
  data: Array,
  height: {
    type: String,
    default: '70vh'
  }
});
const curSubTaskList = ref([]);
const emit = defineEmits(['add', 'remove']);
function remove(item) {
  emit('remove', item);
}
function add() {
  emit('add');
}
</script>
src/views/fysp/task/components/CompSubTaskSelect.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,190 @@
<template>
  <div class="wrapper">
    <el-row>
      <FYForm
        :inline="true"
        label-width=""
        :form-info="formInfo"
        :rules="rules"
        @submit="submit"
      >
        <template #form-item="{ formObj }">
          <el-form-item label="执行人" prop="executor">
            <el-select
              v-model="formObj.executor"
              multiple
              clearable
              collapse-tags
              placeholder="选择执行人"
              :max-collapse-tags="1"
              style="width: 240px"
            >
              <template #header>
                <el-checkbox
                  v-model="checkAll"
                  :indeterminate="indeterminate"
                  @change="handleCheckAll"
                >
                  å…¨é€‰
                </el-checkbox>
              </template>
              <el-option
                v-for="item in executors"
                :key="item.value"
                :label="item.label"
                :value="item.value"
              />
            </el-select>
          </el-form-item>
        </template>
      </FYForm>
    </el-row>
    <div>
      <el-scrollbar :height="scrollHeight" v-if="data.length > 0">
        <el-space wrap>
          <ItemMonitorObj v-for="obj in data" :key="obj.movid" :item="obj">
            <template #default="{ item }">
              <el-button
                size="small"
                type="danger"
                plain
                @click="deleteScene(item)"
                >移除</el-button
              >
            </template>
          </ItemMonitorObj>
        </el-space>
      </el-scrollbar>
      <el-empty v-else description=" ">
        <template #image>
          <el-row align="middle">
            <el-icon size="20"><WarningFilled /></el-icon>
            <el-text size="small" type="info">未选择场景</el-text>
          </el-row>
        </template>
      </el-empty>
    </div>
  </div>
</template>
<script setup>
/**
 * å·¡æŸ¥å­ä»»åŠ¡åˆ›å»º
 */
import { ref, reactive, watch, computed, onMounted } from 'vue';
import { ElMessageBox, ElNotification, ElMessage } from 'element-plus';
import taskApi from '@/api/fysp/taskApi';
onMounted(() => {
  // if (props.height) {
  //   scrollHeight.value =
  // }
});
const props = defineProps({
  // å­ä»»åŠ¡é›†åˆ
  data: {
    type: Array,
    default: () => []
  },
  height: String,
  // æ—¥ä»»åŠ¡
  dayTask: Object
});
const emit = defineEmits(['delete']);
const scrollHeight = ref('14vh');
// ç§»é™¤ä»»åŠ¡åœºæ™¯
function deleteScene(item) {
  emit('delete', item);
}
/************************* ä»»åŠ¡åˆ›å»ºè¡¨å• *******************************/
const formInfo = ref({});
const rules = reactive({
  name: [
    {
      required: true,
      message: '场景名称不能为空',
      trigger: 'blur'
    }
  ]
});
function submit(v, success, fail) {
  if (props.data.length == 0) {
    // ElMessage({
    //   message: '未选择监管场景',
    //   type: 'warning'
    // });
    fail('未选择监管场景');
  } else {
    success();
  }
}
/************************* ä»»åŠ¡æ‰§è¡Œäººä¸‹æ‹‰é€‰æ¡† *******************************/
const executors = ref([]);
// æ˜¯å¦å…¨é€‰
const checkAll = ref(false);
// å¤šé€‰æ¡†æ˜¯å¦ä¸­é—´çŠ¶æ€
const indeterminate = ref(false);
// å…¨é€‰äº‹ä»¶
function handleCheckAll(val) {
  indeterminate.value = false;
  if (val) {
    formInfo.value.executor = executors.value.map((_) => _.value);
  } else {
    formInfo.value.executor = [];
  }
}
watch(
  () => props.dayTask,
  (nV, oV) => {
    if (nV != oV) {
      taskApi.fetchTaskById(nV.guid).then((res) => {
        const ids = res.executorguids.split('#');
        const userNames = res.executorusernames.split('#');
        const realNames = res.executorrealnames.split('#');
        const list = [];
        ids.forEach((e, i) => {
          if (i < userNames.length && i < realNames.length) {
            list.push({
              label: realNames[i],
              value: e,
              data: {
                id: e,
                userName: userNames[i],
                realName: realNames[i]
              }
            });
          }
        });
        executors.value = list;
      });
    }
  },
  { immediate: true }
);
//
watch(
  () => formInfo.value.executor,
  (val) => {
    if (val.length === 0) {
      checkAll.value = false;
      indeterminate.value = false;
    } else if (val.length === executors.value.length) {
      checkAll.value = true;
      indeterminate.value = false;
    } else {
      indeterminate.value = true;
    }
  }
);
</script>
<style scoped>
.wrapper {
  border-bottom: 1px solid var(--el-color-info-light-7);
}
</style>
src/views/fysp/task/components/CompTaskEdit.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,342 @@
<template>
  <FYForm
    ref="formRef"
    :form-info="formInfo"
    :rules="rules"
    :useCancel="true"
    label-width="120px"
    submit-name="创建"
    @submit="submit"
    @cancel="cancel"
  >
    <template #form-item="{ formObj }">
      <!-- åŒºåŽ¿ -->
      <FYOptionLocation
        :allOption="false"
        :level="3"
        :initValue="false"
        :checkStrictly="false"
        v-model:value="formObj._locations"
        @change="handleLocationChange"
      ></FYOptionLocation>
      <el-form-item label="任务名称" prop="name">
        <el-input
          clearable
          show-word-limit
          v-model="formObj.name"
          placeholder="任务名称"
        />
      </el-form-item>
      <FYOptionTime
        label="起止日期"
        prop="_timeArr"
        :initValue="false"
        type="daterange"
        v-model:value="formObj._timeArr"
        @change="handleTimeChange"
      ></FYOptionTime>
      <el-form-item v-show="showMore" label="任务类型" prop="_type">
        <el-select v-model="formObj._type" style="width: 150px">
          <el-option
            v-for="s in taskTypeOptions"
            :key="s.label"
            :label="s.label"
            :value="s.value"
          />
        </el-select>
      </el-form-item>
      <el-form-item v-show="showMore" label="任务期限类别" prop="_deadlinetype">
        <el-select v-model="formObj._deadlinetype" style="width: 150px">
          <el-option
            v-for="s in deadlineTypeOptions"
            :key="s.label"
            :label="s.label"
            :value="s.value"
          />
        </el-select>
      </el-form-item>
      <el-form-item v-show="showMore" label="任务层次" prop="levelnum">
        <el-select v-model="formObj.levelnum" style="width: 150px">
          <el-option
            v-for="s in levelOptions"
            :key="s.label"
            :label="s.label"
            :value="s.value"
          />
        </el-select>
      </el-form-item>
      <el-form-item v-show="showMore" label="执行人" prop="_executors">
        <el-select
          v-model="formObj._executors"
          multiple
          clearable
          collapse-tags
          placeholder="选择执行人"
          :max-collapse-tags="3"
          style="width: 300px"
        >
          <el-option
            v-for="s in executorOptions"
            :key="s.value"
            :label="s.label"
            :value="s.value"
          />
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-row justify="center">
          <el-link type="primary" @click="showMore = !showMore">
            {{ showMore ? '收起' : '查看更多选项' }}
            <el-icon v-if="showMore"><ArrowUp /></el-icon>
            <el-icon v-else><ArrowDown /></el-icon>
          </el-link>
        </el-row>
      </el-form-item>
    </template>
  </FYForm>
</template>
<script setup>
import { ref, reactive, watch, onMounted } from 'vue';
import domainApi from '@/api/fysp/domainApi';
import userApi from '@/api/fysp/userApi';
import dayjs from 'dayjs';
import taskApi from '@/api/fysp/taskApi';
const props = defineProps({
  //数据
  model: {
    type: Object,
    default: () => {
      return {};
    }
  },
  //是创建或者更新场景,默认更新
  create: Boolean
});
const emit = defineEmits(['submit', 'cancel']);
const rules = reactive({
  name: [
    {
      required: true,
      message: '任务名称不能为空',
      trigger: 'change'
    }
  ],
  _type: [
    {
      required: true,
      message: '任务类型不能为空',
      trigger: 'change'
    }
  ],
  _deadlinetype: [
    {
      required: true,
      message: '任务期限类型不能为空',
      trigger: 'change'
    }
  ],
  levelnum: [
    {
      required: true,
      message: '任务层次不能为空',
      trigger: 'change'
    }
  ],
  // starttime: [
  //   {
  //     required: true,
  //     message: '开始日期不能为空',
  //     trigger: 'change'
  //   }
  // ],
  // endtime: [
  //   {
  //     required: true,
  //     message: '结束日期不能为空',
  //     trigger: 'change'
  //   }
  // ],
  _timeArr: [
    {
      required: true,
      message: '起止日期不能为空',
      trigger: 'change'
    }
  ],
  _executors: [
    {
      required: true,
      message: '任务执行人不能为空',
      trigger: 'change'
    }
  ]
});
const formRef = ref(null);
const formInfo = ref({
  starttime: dayjs().add(1, 'month').startOf('month').toDate(),
  endtime: dayjs().add(1, 'month').endOf('month').toDate(),
  _timeArr: [
    dayjs().add(1, 'month').startOf('month').toDate(),
    dayjs().add(1, 'month').endOf('month').set('millisecond', 0).toDate()
  ]
});
// ä»»åŠ¡ç±»åž‹é€‰é¡¹
const taskTypeOptions = ref([]);
// ä»»åŠ¡æœŸé™ç±»åˆ«é€‰é¡¹
const deadlineTypeOptions = ref([]);
// ä»»åŠ¡å±‚æ¬¡ç±»åˆ«é€‰é¡¹
const levelOptions = ref([]);
// ä»»åŠ¡æ‰§è¡Œäººé€‰é¡¹
const executorOptions = ref([]);
const showMore = ref(false);
function locationText(location) {
  if (location.pName == (undefined | null)) return '';
  let res = location.pName;
  if (location.cName && location.cName != location.pName) {
    res += location.cName;
  }
  if (location.dName && location.dName != location.cName) {
    res += location.dName;
  }
  return res;
}
function handleLocationChange(location) {
  genTaskName();
}
function handleTimeChange(timeArr) {
  genTaskName();
}
function genTaskName() {
  let name = dayjs(formRef.value.formObj._timeArr[0]).format('YYYYå¹´MM月');
  name += locationText(formRef.value.formObj._locations);
  name += formRef.value.formObj._type.text;
  name += '任务';
  formRef.value.formObj.name = name;
}
/*************************** æ•°æ®æ›´æ–° ************************************/
function getExecutors(data) {
  const ids = [];
  const uNames = [];
  const rNames = [];
  executorOptions.value.forEach((e) => {
    const index = data._executors.indexOf(e.value);
    if (index != -1) {
      ids.push(e.data.guid);
      uNames.push(e.data.acountname);
      rNames.push(e.data.realname);
    }
  });
  return {
    id: ids.join('#'),
    uName: uNames.join('#'),
    rName: rNames.join('#')
  };
}
function submit(data, success, fail) {
  const v = data.value;
  const executors = getExecutors(v);
  const task = {
    levelnum: v.levelnum,
    name: v.name,
    typeno: v._type.value,
    typename: v._type.text,
    deadlinetype: v._deadlinetype.text,
    provincecode: v._locations.pCode,
    provincename: v._locations.pName,
    citycode: v._locations.cCode,
    cityname: v._locations.cName,
    districtcode: v._locations.dCode,
    districtname: v._locations.dName,
    starttime: v._timeArr[0],
    endtime: v._timeArr[1],
    // fixme 2024.10.16, åŽç»­åŠ å…¥ç”¨æˆ·ç³»ç»ŸåŽï¼Œé‡‡ç”¨å½“å‰ç™»å½•ç”¨æˆ·ä¿¡æ¯
    plannerguid: 'rAR0A4gJdlOZEqZs',
    plannerusername: 'ccheck',
    plannerrealname: '整改审核',
    settime: new Date(),
    executorguids: executors.id,
    executorusernames: executors.uName,
    executorrealnames: executors.rName,
    t1stverifierguid: 'rAR0A4gJdlOZEqZs',
    t1stverifierusername: 'ccheck',
    t1stverifierrealname: '整改审核',
    t1stverifytime: new Date(),
    t1stisverify: true,
    runingstatus: '未执行',
    extension1: '3',
    extension2: '0'
  };
  // success();
  // emit('submit', task);
  taskApi
    .putTask(task)
    .then((res) => {
      success();
      emit('submit', res.data);
    })
    .catch((err) => fail(err));
}
function cancel() {
  emit('cancel');
}
/*************************** æ•°æ®åˆå§‹åŒ– ************************************/
// å„选项的初始化
function initOptions() {
  domainApi.fetchTaskType().then((res) => {
    taskTypeOptions.value = res.map((v) => {
      return {
        label: v.text,
        value: v
      };
    });
    formInfo.value._type = taskTypeOptions.value[0].value;
  });
  domainApi.fetchDeadlineType().then((res) => {
    deadlineTypeOptions.value = res.map((v) => {
      return {
        label: v.text,
        value: v
      };
    });
    formInfo.value._deadlinetype = deadlineTypeOptions.value[0].value;
  });
  domainApi.fetchLevelType().then((res) => {
    levelOptions.value = res.map((v) => {
      return {
        label: v.text,
        value: v.value
      };
    });
    formInfo.value.levelnum = levelOptions.value[1].value;
  });
  userApi.getUserByType(1).then((res) => {
    executorOptions.value = res.map((v) => {
      return {
        label: v.realname,
        value: v.guid,
        data: v
      };
    });
    formInfo.value._executors = executorOptions.value.map((v) => v.value);
  });
}
onMounted(() => {
  initOptions();
});
</script>
<style scoped></style>
src/views/fysp/task/components/CompTaskMap.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
<template>
  <SceneMap></SceneMap>
</template>
<script setup>
</script>