fuliqi
2025-01-20 f1bc584fb51ea39cbda9590275c92e3246737561
Merge remote-tracking branch 'origin/master'
12个文件已修改
2135 ■■■■■ 已修改文件
src/api/projectEngineering/projectInfo.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Process/style/flow-viewer.scss 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/auth.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/user.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/components/Map/index.vue 982 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/components/noticeTable.vue 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/flowable/expression/index.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/flowable/task/myProcess/detail/index.vue 82 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/flowable/task/myProcess/send/index.vue 251 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/index.vue 627 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/projectProcess/detail/index.vue 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/projectProcess/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/projectEngineering/projectInfo.js
@@ -73,3 +73,10 @@
    data: data
  })
}
export function searchByKey(data) {
  return request({
    url: '/project/info/searchByKey',
    method: 'get',
    params: data
  })
}
src/components/Process/style/flow-viewer.scss
@@ -7,7 +7,9 @@
.flowMsgPopover {
  display: none;
}
.bjs-powered-by {
  display: none;
}
.tipBox {
  width: 180px;
  background: #fff;
src/plugins/auth.js
@@ -15,6 +15,7 @@
function authRole(role) {
  const super_admin = "admin";
  const roles = store.getters && store.getters.roles
  console.log("当前用户角色", roles)
  if (role && role.length > 0) {
    return roles.some(v => {
      return super_admin === v || v === role
src/store/modules/user.js
@@ -9,6 +9,7 @@
    avatar: '',
    deptId: null,
    roles: [],
    roleIds: [],
    permissions: []
  },
@@ -27,6 +28,9 @@
    },
    SET_ROLES: (state, roles) => {
      state.roles = roles
    },
    SET_ROLE_IDS: (state, roleIds) => {
      state.roleIds = roleIds
    },
    SET_DEPT: (state, deptId) => {
      state.deptId = deptId
@@ -67,6 +71,7 @@
            commit('SET_ROLES', ['ROLE_DEFAULT'])
          }
          commit('SET_ID', user.userId)
          commit('SET_ROLE_IDS', user.roles.map(role => role.roleId))
          commit('SET_NAME', user.userName)
          commit('SET_DEPT', user.deptId)
          commit('SET_AVATAR', avatar)
src/views/components/Map/index.vue
@@ -1,33 +1,33 @@
<template>
    <div :id="id" ref="contentRef" style="height: 100%; width: 100%">
        <div
            v-if="isShowControl"
            :class="controlPosition"
            class="control-container bottom-right"
        >
            <div
                v-for="item in controlMapping"
                :key="item.id"
                class="control-content"
            >
                <template v-if="item.children">
                    <div
                        v-for="child in item.children"
                        :key="child.id"
                        class="control-item"
                        @click="child.event"
                    >
                        <img :src="child.img" />
                    </div>
                </template>
                <template v-else>
                    <div class="control-item" @click="item.event">
                        <img :src="item.img" />
                    </div>
                </template>
            </div>
        </div>
  <div :id="id" ref="contentRef" style="height: 100%; width: 100%">
    <div
      v-if="isShowControl"
      :class="controlPosition"
      class="control-container bottom-right"
    >
      <div
        v-for="item in controlMapping"
        :key="item.id"
        class="control-content"
      >
        <template v-if="item.children">
          <div
            v-for="child in item.children"
            :key="child.id"
            class="control-item"
            @click="child.event"
          >
            <img :src="child.img" />
          </div>
        </template>
        <template v-else>
          <div class="control-item" @click="item.event">
            <img :src="item.img" />
          </div>
        </template>
      </div>
    </div>
  </div>
</template>
<script>
import Location from "@/assets/images/location.png";
@@ -36,426 +36,470 @@
import PlusImg from "@/assets/images/plus.png";
import FullScreenImg from "@/assets/images/fullScreen.png";
import PositionImg from "@/assets/images/position.png";
var infoWin;
export default {
    data() {
        return {
            zoom: 15,
            map: null,
            contentRef: {},
            infoWin: {},
            defaultMaskInfo: {},
            mapKey: "ffb871cd7ca48883db3b04cfd00d469f",
            controlMapping: [
                {
                    id: "定位",
                    img: PositionImg,
                    event: this.getCurrentPosition,
                },
                {
                    id: "缩放",
                    children: [
                        {
                            id: "放大",
                            img: PlusImg,
                            event: this.zoomIn,
                        },
                        {
                            id: "缩小",
                            img: MinusImg,
                            event: this.zoomOut,
                        },
                    ],
                },
                {
                    id: "全屏",
                    img: FullScreenImg,
                    event: this.fullScreen,
                },
            ],
  data() {
    return {
      zoom: 15,
      map: null,
      contentRef: {},
      infoWin: {},
      defaultMaskInfo: {},
      mapKey: "ffb871cd7ca48883db3b04cfd00d469f",
      controlMapping: [
        {
          id: "定位",
          img: PositionImg,
          event: this.getCurrentPosition,
        },
        {
          id: "缩放",
          children: [
            {
              id: "放大",
              img: PlusImg,
              event: this.zoomIn,
            },
            {
              id: "缩小",
              img: MinusImg,
              event: this.zoomOut,
            },
          ],
        },
        {
          id: "全屏",
          img: FullScreenImg,
          event: this.fullScreen,
        },
      ],
    };
  },
  props: {
    id: String,
    mapList: Array,
    listType: Boolean,
    isShowControl: Boolean,
    controlPosition: Object,
    isImmediateLoad: { type: Boolean, default: true },
    mapType: Boolean,
  },
  created() {
    this.defaultMaskInfo = {
      lon: this.$props.mapList[0]?.lon
        ? this.$props.mapList[0].lon
        : "105.37281",
      lat: this.$props.mapList[0]?.lat
        ? this.$props.mapList[0].lat
        : "30.87145",
      name: this.$props.mapList[0]?.name ? this.$props.mapList[0].name : "创建",
    };
    if (this.$props.isImmediateLoad) this.onLoad();
  },
  methods: {
    async onLoad() {
      const scripts = document.body.querySelectorAll("script");
      if (!this.mapKey) {
        // const res = await getDicts('map_key')
        // mapKey = res[0].dictLabel
        this.mapKey = "ffb871cd7ca48883db3b04cfd00d469f";
      }
      const scriptSrc = `http://api.tianditu.gov.cn/api?v=4.0&tk=${this.mapKey}`;
      const mapScript = Array.from(scripts).find((item) => {
        return item.getAttribute("src") === scriptSrc;
      });
      if (!mapScript) {
        // 创建script标签
        const script = document.createElement("script");
        // 设置API的URL
        script.src = scriptSrc;
        script.type = "text/javascript";
        // 将script标签添加到HTML中
        document.body.appendChild(script);
        script.onload = () => {
          this.initTianMap();
        };
    },
    props: {
        id: String,
        mapList: Array,
        listType: Boolean,
        isShowControl: Boolean,
        controlPosition: Object,
        isImmediateLoad: { type: Boolean, default: true },
        mapType: Boolean,
      } else {
        this.initTianMap();
      }
    },
    created() {
        this.defaultMaskInfo = {
            lon: this.$props.mapList[0]?.lon
                ? this.$props.mapList[0].lon
                : "105.37281",
            lat: this.$props.mapList[0]?.lat
                ? this.$props.mapList[0].lat
                : "30.87145",
            name: this.$props.mapList[0]?.name ? this.$props.mapList[0].name : "创建",
        };
        if (this.$props.isImmediateLoad) this.onLoad();
    initTianMap() {
      var T = window.T;
      setTimeout(async () => {
        // this.map = new T.Map(this.id, {
        //     projection: "EPSG:4326",
        // });
        this.map = new T.Map(this.id);
        this.map.centerAndZoom(
          new T.LngLat(this.defaultMaskInfo.lon, this.defaultMaskInfo.lat),
          this.zoom
        );
        if (!this.$props.listType) {
          // 清除之前的标记
          // map && map.clearOverLays()
          //form表单中是否有坐标,有则定位到对应位置,没有则使用默认的
          // 104.65417 28.75572 测试数据
          // 四川省宜宾市翠屏区大观楼街道外南街71
          if (this.$props.mapList[0].addr) {
            const { lng: lon, lat } = await this.getGeocode(
              this.$props.mapList[0].addr
            );
            this.defaultMaskInfo.lon = String(lon);
            this.defaultMaskInfo.lat = String(lat);
          }
          this.map && this.makeDefaultMask(this.defaultMaskInfo);
          this.addEvent(this.map, "click", (e) => this.mapClick(e));
        } else {
          this.$props.mapList.length && this.makeAllMask(this.$props.mapList);
        }
      }, 1500);
    },
    methods: {
        async onLoad() {
            const scripts = document.body.querySelectorAll("script");
            if (!this.mapKey) {
                // const res = await getDicts('map_key')
                // mapKey = res[0].dictLabel
                this.mapKey = "ffb871cd7ca48883db3b04cfd00d469f";
            }
            const scriptSrc = `http://api.tianditu.gov.cn/api?v=4.0&tk=${this.mapKey}`;
            const mapScript = Array.from(scripts).find((item) => {
                return item.getAttribute("src") === scriptSrc;
            });
    zoomIn() {
      this.map && this.map.zoomIn();
    },
            if (!mapScript) {
                // 创建script标签
                const script = document.createElement("script");
                // 设置API的URL
                script.src = scriptSrc;
                script.type = "text/javascript";
                // 将script标签添加到HTML中
                document.body.appendChild(script);
                script.onload = () => {
                    this.initTianMap();
                };
            } else {
                this.initTianMap();
            }
        },
    zoomOut() {
      this.map && this.map.zoomOut();
    },
        initTianMap() {
            var T = window.T;
            setTimeout(async () => {
                // this.map = new T.Map(this.id, {
                //     projection: "EPSG:4326",
                // });
                this.map = new T.Map(this.id);
                this.map.centerAndZoom(
                    new T.LngLat(this.defaultMaskInfo.lon, this.defaultMaskInfo.lat),
                    this.zoom
                );
                if (!this.$props.listType) {
                    // 清除之前的标记
                    // map && map.clearOverLays()
                    //form表单中是否有坐标,有则定位到对应位置,没有则使用默认的
                    // 104.65417 28.75572 测试数据
                    // 四川省宜宾市翠屏区大观楼街道外南街71
                    if (this.$props.mapList[0].addr) {
                        const { lng: lon, lat } = await this.getGeocode(
                            this.$props.mapList[0].addr
                        );
                        this.defaultMaskInfo.lon = String(lon);
                        this.defaultMaskInfo.lat = String(lat);
                    }
    fullScreen() {
      this.map && this.contentRef?.requestFullscreen();
    },
                    this.map && this.makeDefaultMask(this.defaultMaskInfo);
                    this.addEvent(this.map, "click", (e) => this.mapClick(e));
                } else {
                    this.$props.mapList.length && this.makeAllMask(this.$props.mapList);
                }
            }, 1500);
        },
    getCurrentPosition() {
      //   if (navigator.geolocation) {
      //     ElMessage.warning("该功能暂未开发");
      //     // TODO 地图定位
      //     // navigator.geolocation.getCurrentPosition(function (position) {
      //     //   var latitude = position.coords.latitude
      //     //   var longitude = position.coords.longitude
      //     //
      //     //   moveTo(String(longitude), String(latitude))
      //     // })
      //   } else {
      //     ElMessage.warning("当前浏览器不支持定位功能");
      //   }
    },
        zoomIn() {
            this.map && this.map.zoomIn();
        },
    moveTo(lon, lat) {
      this.map && this.map.panTo(new T.LngLat(lon, lat));
    },
    // 默认的点标记
    makeDefaultMask(mapInfo) {
      const { name, lon, lat } = mapInfo;
      const option = {
        text: name,
        offset: [-35, -45],
        labelBg: "#3369FF",
        labelColor: "#fff",
        labelClick: this.labelClick,
      };
      // 清除之前的标记
      this.map && this.map.clearOverLays();
      this.map.panTo(new T.LngLat(lon, lat));
      this.makeMask(lon, lat, { labelOptions: option });
    },
        zoomOut() {
            this.map && this.map.zoomOut();
        },
    // 地图点击事件
    mapClick(e) {
      e.originalEvent.stopPropagation();
        fullScreen() {
            this.map && this.contentRef?.requestFullscreen();
        },
      const { lat, lng: lon } = e.lnglat;
        getCurrentPosition() {
            if (navigator.geolocation) {
                ElMessage.warning("该功能暂未开发");
                // TODO 地图定位
                // navigator.geolocation.getCurrentPosition(function (position) {
                //   var latitude = position.coords.latitude
                //   var longitude = position.coords.longitude
                //
                //   moveTo(String(longitude), String(latitude))
                // })
            } else {
                ElMessage.warning("当前浏览器不支持定位功能");
            }
        },
      this.makeDefaultMask({
        ...this.defaultMaskInfo,
        lon: String(lon),
        lat: String(lat),
      });
      this.getReverseGeocode(e).then((addr) => {
        this.$emit("mapClick", {
          e,
          addr,
        });
      });
      console.log("点击事件", e);
    },
        moveTo(lon, lat) {
            this.map && this.map.panTo(new T.LngLat(lon, lat));
        },
    // 逆地理编码 获取地址
    getReverseGeocode(e) {
      return new Promise((resolve) => {
        const geocode = new T.Geocoder();
        geocode.getLocation(e.lnglat, (result) => {
          if (result.status === "0") {
            resolve(result.getAddress());
          }
        });
      });
    },
        // 默认的点标记
        makeDefaultMask(mapInfo) {
            const { name, lon, lat } = mapInfo
            const option = {
                text: name,
                offset: [-35, -45],
                labelBg: "#3369FF",
                labelColor: "#fff",
                labelClick: this.labelClick,
            };
            // 清除之前的标记
            this.map && this.map.clearOverLays();
            this.map.panTo(new T.LngLat(lon, lat));
            this.makeMask(lon, lat, { labelOptions: option });
        },
    // 地理编码
    getGeocode(addr) {
      return new Promise((resolve) => {
        const geocoder = new T.Geocoder();
        geocoder.getPoint(addr, (result) => {
          if (result.status === "0") {
            resolve(result.getLocationPoint());
          }
        });
      });
    },
        // 地图点击事件
        mapClick(e) {
            e.originalEvent.stopPropagation();
            const { lat, lng: lon } = e.lnglat;
            this.makeDefaultMask({
                ...this.defaultMaskInfo,
                lon: String(lon),
                lat: String(lat),
            });
          this.getReverseGeocode(e).then((addr) => {
            this.$emit("mapClick", {
              e,
              addr,
            });
          });
            console.log("点击事件", e);
        },
        // 逆地理编码 获取地址
        getReverseGeocode(e) {
            return new Promise((resolve) => {
                const geocode = new T.Geocoder();
                geocode.getLocation(e.lnglat, (result) => {
                    if (result.status === "0") {
                        resolve(result.getAddress());
                    }
                });
            });
        },
        // 地理编码
        getGeocode(addr) {
            return new Promise((resolve) => {
                const geocoder = new T.Geocoder();
                geocoder.getPoint(addr, (result) => {
                    if (result.status === "0") {
                        resolve(result.getLocationPoint());
                    }
                });
            });
        },
        // 生成点位内容
        // 生成点位内容
        generateContent(row, random) {
            if (row) {
                return `
    // 生成点位内容
    // 生成点位内容
    generateContent(row, random) {
      if (row) {
        return `
    <div class="map-window-info">
      <div class='title-block'>
        <div class="title truncate-content">
          ${row.projectName ?? "暂无数据"}
        </div>
        <div class='close-btn close-btn-${random}'>
          ×
        </div>
      </div>
      <div class="detail-info">
        <span class="truncate-content">总投资:${row.totalMoney ?? "暂无数据"
                    }</span>
        <span class="truncate-content">总投资:${row.totalMoney || ""}</span>
        <span class="truncate-content">
          项目状态:
          项目状态:${this.showProjectStatusStr(row.projectStatus)}
        </span>
         <span class="truncate-content">
          项目地址:${row.projectAddr ?? "暂无数据"}
        </span>
      </div>
    </div>`;
            } else {
                return `<div style="display: flex; justify-content:center; align-items:center; opacity: 0;">
      } else {
        return `<div style="display: flex; justify-content:center; align-items:center; opacity: 0;">
    </div>`;
            }
        },
        // 唯一标识
        getUniqueId() {
            return Math.random().toString(36).substr(2) + Date.now();
        },
        markerMouseover(_e, infoWin, info, random) {
            // 点位标记移入显示不同内容
            if (this.$props.isShowControl) {
                infoWin.setContent(this.generateContent(info, random));
                const contentWrapper = document.querySelector(
                    ".tdt-infowindow-content-wrapper"
                );
                if (contentWrapper) {
                    contentWrapper.style.opacity = "1";
                }
                // 查找到那个info 界面
                // const allCloseBtn = document.querySelectorAll(`.close-btn-${random}`);
                // allCloseBtn[allCloseBtn.length - 1].onclick = (_e) => {
                //   infoWin.setContent(generateContent());
                // };
            }
        },
        markerMouseout(_e, infoWin) {
            infoWin.setContent(this.generateContent());
            const contentWrapper = document.querySelector(
                ".tdt-infowindow-content-wrapper"
            );
            if (contentWrapper) {
                contentWrapper.style.opacity = "0";
            }
        },
        // 打标记
        makeMask(lon, lat, options) {
            const { markerOptions, labelOptions } = options;
            console.log("options", markerOptions, labelOptions);
            const icon = new T.Icon({
                iconUrl: Location,
                iconSize: new T.Point(19, 27),
                iconAnchor: new T.Point(10, 25),
            });
            var marker = new T.Marker(new T.LngLat(lon, lat), {
                icon,
                id: markerOptions?.id,
            });
            this.map && this.map.addOverLay(marker);
            const label = new T.Label({
                text: labelOptions.text,
                position: new T.LngLat(lon, lat),
                offset: new T.Point(...labelOptions.offset),
                id: labelOptions?.id,
            });
            labelOptions.labelBg && label.setBackgroundColor(labelOptions.labelBg);
            labelOptions.labelColor && label.setFontColor(labelOptions.labelColor);
            //创建地图文本对象
            if (!this.$props.mapType) {
                this.map && this.map.addOverLay(label);
            }
            markerOptions?.markerClick &&
                this.addEvent(marker, "click", (e) => markerOptions.markerClick(label, e));
            labelOptions?.labelClick &&
                this.addEvent(label, "click", (e) => labelOptions.labelClick(label, e));
            const lnglat = new T.LngLat(lon, lat);
            const infoWin = new T.InfoWindow(this.generateContent(), {
                id: markerOptions?.id,
                offset: new T.Point(0, -15),
                closeButton: false,
            });
            infoWin.setLngLat(lnglat);
            // 向地图上添加信息窗口
            if (this.$props.mapType) {
                this.map && this.map.addOverLay(infoWin);
            }
            this.addEvent(marker, "mouseover", (e) =>
                this.markerMouseover(e, infoWin, labelOptions, this.getUniqueId())
            );
            this.addEvent(marker, "mouseout", (e) => this.markerMouseout(e, infoWin));
        },
        // 标记所有点
        makeAllMask(mapList) {
            var _this = this;
            this.mapList.map((item) => {
                const config = {
                    markerOptions: {
                        id: item.id,
                        markerClick: _this.markerClick,
                    },
                    labelOptions: {
                        text: item.name,
                        offset: [-45, -45],
                        id: item.id,
                        markerClick: _this.labelClick,
                    },
                };
                _this.makeMask(item.lon, item.lat, config);
            });
        },
        // 通用添加事件的方法
        addEvent(component, name, func) {
            // 移出事件
            this.removeEvent(component, name, func);
            // 添加事件
            component.addEventListener(name, func);
        },
        // 通用移出事件的方法
        removeEvent(component, name, func) {
            component.removeEventListener(name, func);
        },
        //标记点击事件
        markerClick(currentLabel, e) {
            const id = e.target.options.id;
            this.currentLabelStyleChange(currentLabel);
            console.log("点击事件", e, currentLabel);
            this.getReverseGeocode(e).then((addr) => {
                this.$emit(
                    "markClick",
                    id
                        ? this.$props.mapList?.find((item) => item.id === id)
                        : { e, addr: addr }
                );
            });
        },
        // label点击事件
        labelClick(currentLabel, e) {
            console.log("触发点击事件")
            const id = e.target.options.id;
            this.currentLabelStyleChange(currentLabel);
            this.getReverseGeocode(e).then((addr) => {
                this.$emit(
                    "labelClick",
                    id
                        ? this.$props.mapList?.find((item) => {
                            return String(item.id) === String(id);
                        })
                        : { e, addr: addr }
                );
            });
        },
        currentLabelStyleChange(currentLabel) {
            this.$emit("currentLabelStyleChange", currentLabel);
        },
        resizeMap() {
            this.map.checkResize();
        },
      }
    },
    watch: {
        listType: {
            handler(val) {
                if (val) {
                    this.map && this.map.clearOverLays();
                    if (this.$props.mapList.length && T) {
                        this.makeAllMask(this.$props.mapList);
                    }
                }
            },
        },
    showProjectStatusStr(status) {
      switch (status) {
        case "1":
          return "储备项目";
        case "2":
          return "前期项目";
        case "3":
          return "实施项目";
        case "4":
          return "竣工项目";
        case "5":
          return "异常项目";
        default:
          return "异常项目";
      }
    },
    // 唯一标识
    getUniqueId() {
      return Math.random().toString(36).substr(2) + Date.now();
    },
    markerMouseover(_e, info, random, markerOptions) {
      if (infoWin) this.map.removeOverLay(infoWin);
      // 点位标记移入显示不同内容
      if (this.$props.isShowControl) {
        infoWin = new T.InfoWindow();
        infoWin.setContent(this.generateContent(info, random));
        infoWin.setLngLat(_e.lnglat);
        // 向地图上添加信息窗口
        // if (this.$props.mapType) {
        this.map && this.map.addOverLay(infoWin);
        // }
        // const contentWrapper = document.querySelector(
        //   ".tdt-infowindow-content-wrapper"
        // );
        // if (contentWrapper) {
        //   contentWrapper.style.opacity = "1";
        // }
        // 查找到那个info 界面
        // const allCloseBtn = document.querySelectorAll(`.close-btn-${random}`);
        // allCloseBtn[allCloseBtn.length - 1].onclick = (_e) => {
        //   infoWin.setContent(generateContent());
        // };
      }
    },
    markerMouseout(_e) {
      // infoWin.setContent(this.generateContent());
      // const contentWrapper = document.querySelector(
      //   ".tdt-infowindow-content-wrapper"
      // );
      // if (contentWrapper) {
      //   contentWrapper.style.opacity = "0";
      // }
      // this.map.removeOverLay(infoWin);
    },
    // 打标记
    makeMask(lon, lat, options) {
      if (lon && lat) {
        const { markerOptions, labelOptions } = options;
        const icon = new T.Icon({
          iconUrl: Location,
          iconSize: new T.Point(19, 27),
          iconAnchor: new T.Point(10, 25),
        });
        var marker = new T.Marker(new T.LngLat(lon, lat), {
          icon,
          id: markerOptions?.id,
        });
        this.map && this.map.addOverLay(marker);
        const label = new T.Label({
          text: labelOptions.text,
          position: new T.LngLat(lon, lat),
          offset: new T.Point(...labelOptions.offset),
          id: labelOptions?.id,
        });
        labelOptions.labelBg && label.setBackgroundColor(labelOptions.labelBg);
        labelOptions.labelColor && label.setFontColor(labelOptions.labelColor);
        //创建地图文本对象
        if (!this.$props.mapType) {
          this.map && this.map.addOverLay(label);
        }
        markerOptions?.markerClick &&
          this.addEvent(marker, "click", (e) =>
            markerOptions.markerClick(label, e)
          );
        labelOptions?.labelClick &&
          this.addEvent(label, "click", (e) =>
            labelOptions.labelClick(label, e)
          );
        this.addEvent(marker, "mouseover", (e) =>
          this.markerMouseover(e, options, this.getUniqueId(), markerOptions)
        );
        this.addEvent(marker, "mouseout", (e) => this.markerMouseout(e));
      }
    },
    // 标记所有点
    makeAllMask(mapList) {
      // 清除之前的标记
      this.map && this.map.clearOverLays();
      var minX = mapList[0].longitude;
      var maxX = mapList[0].longitude;
      var minY = mapList[0].latitude;
      var maxY = mapList[0].latitude;
      var _this = this;
      mapList.map((item) => {
        const config = {
          markerOptions: {
            id: item.id,
            //  markerClick: _this.markerClick,
          },
          labelOptions: {
            text: item.projectName,
            offset: [-45, -45],
            id: item.id,
            //   markerClick: _this.labelClick,
          },
          projectName: item.projectName,
          totalMoney: item.yearInvestAmount
            ? item.yearInvestAmount + "元"
            : "暂无数据",
          projectAddr: item.projectAddress,
          projectStatus: item.usedStatus,
        };
        _this.makeMask(item.longitude, item.latitude, config);
        if (item.longitude && item.longitude > maxX) {
          maxX = item.longitude;
        }
        if (item.longitude && item.longitude < minX) {
          minX = item.longitude;
        }
        if (item.latitude && item.latitude > maxY) {
          maxY = item.latitude;
        }
        if (item.latitude && item.latitude < minY) {
          minY = item.latitude;
        }
      });
      this.moveTo(
        (parseFloat(maxX) + parseFloat(minX)) / 2,
        (parseFloat(maxY) + parseFloat(minY)) / 2
      );
    },
    // 通用添加事件的方法
    addEvent(component, name, func) {
      // 移出事件
      this.removeEvent(component, name, func);
      // 添加事件
      component.addEventListener(name, func);
    },
    // 通用移出事件的方法
    removeEvent(component, name, func) {
      component.removeEventListener(name, func);
    },
    //标记点击事件
    markerClick(currentLabel, e) {
      const id = e.target.options.id;
      this.currentLabelStyleChange(currentLabel);
      console.log("点击事件", e, currentLabel);
      this.getReverseGeocode(e).then((addr) => {
        this.$emit(
          "markClick",
          id
            ? this.$props.mapList?.find((item) => item.id === id)
            : { e, addr: addr }
        );
      });
    },
    // label点击事件
    labelClick(currentLabel, e) {
      console.log("触发点击事件");
      const id = e.target.options.id;
      this.currentLabelStyleChange(currentLabel);
      this.getReverseGeocode(e).then((addr) => {
        this.$emit(
          "labelClick",
          id
            ? this.$props.mapList?.find((item) => {
                return String(item.id) === String(id);
              })
            : { e, addr: addr }
        );
      });
    },
    currentLabelStyleChange(currentLabel) {
      this.$emit("currentLabelStyleChange", currentLabel);
    },
    resizeMap() {
      this.map.checkResize();
    },
  },
  watch: {
    listType: {
      handler(val) {
        if (val) {
          this.map && this.map.clearOverLays();
          if (this.$props.mapList.length && T) {
            this.makeAllMask(this.$props.mapList);
          }
        }
      },
    },
  },
  beforeDestroy() {
    this.map = null;
  }
  },
};
// const emits = defineEmits<{
@@ -467,112 +511,112 @@
</script>
<style lang="scss" scoped>
:deep(.tdt-label) {
    border-radius: 15px;
    color: var(--el-color-primary);
    cursor: pointer;
  border-radius: 15px;
  color: var(--el-color-primary);
  cursor: pointer;
}
// #53547f
:deep(.tdt-bar a, .tdt-bar a:hover) {
    border-bottom: 0;
    color: #53547f;
  border-bottom: 0;
  color: #53547f;
}
:deep(.tdt-touch .tdt-control-zoom-in) {
    font-size: 18px;
  font-size: 18px;
}
:deep(.tdt-bar) {
    border-radius: 3px;
    box-shadow: 5px 0px 12px 0px rgb(0 0 0 / 0.03);
  border-radius: 3px;
  box-shadow: 5px 0px 12px 0px rgb(0 0 0 / 0.03);
}
.tdt-bar a.tdt-disabled,
.tdt-bar a:hover {
    background-color: #f4f4f4;
  background-color: #f4f4f4;
}
.control-container {
    position: absolute;
    display: flex;
    flex-direction: column;
    gap: 10px;
    z-index: 999;
  position: absolute;
  display: flex;
  flex-direction: column;
  gap: 10px;
  z-index: 999;
}
.top-left {
    top: 10px;
    left: 10px;
  top: 10px;
  left: 10px;
}
.top-right {
    top: 10px;
    right: 10px;
  top: 10px;
  right: 10px;
}
.bottom-left {
    bottom: 10px;
    left: 10px;
  bottom: 10px;
  left: 10px;
}
.bottom-right {
    bottom: 10px;
    right: 10px;
  bottom: 10px;
  right: 10px;
}
.control-content {
    border-radius: 3px;
    box-shadow: 5px 0px 12px 0px rgb(0 0 0 / 0.03);
    background-color: #fff;
  border-radius: 3px;
  box-shadow: 5px 0px 12px 0px rgb(0 0 0 / 0.03);
  background-color: #fff;
}
.control-item {
    box-sizing: border-box;
    width: 30px;
    height: 30px;
    line-height: 28px;
    padding: 0 9px;
  box-sizing: border-box;
  width: 30px;
  height: 30px;
  line-height: 28px;
  padding: 0 9px;
    img {
        display: inline-block;
    }
  img {
    display: inline-block;
  }
}
.control-item:hover {
    background-color: #f4f4f4;
  background-color: #f4f4f4;
}
</style>
<style lang="scss">
.map-window-info {
    padding: 0 20px;
    width: 300px;
    cursor: default;
  padding: 0 20px;
  width: 300px;
  cursor: default;
    .title {
        color: #3369ff;
        font-size: 18px;
        margin-bottom: 13px;
    }
  .title {
    color: #3369ff;
    font-size: 18px;
    margin-bottom: 13px;
  }
    .detail-info {
        display: flex;
        flex-direction: column;
        color: #7e809c;
        font-size: 12px;
        gap: 8px;
    }
  .detail-info {
    display: flex;
    flex-direction: column;
    color: #7e809c;
    font-size: 12px;
    gap: 8px;
  }
}
.title-block {
    display: flex;
    justify-content: space-between;
  display: flex;
  justify-content: space-between;
    .close-btn {
        font-size: 18px;
        color: #d8dde6;
        cursor: pointer;
        z-index: 999999;
    }
  .close-btn {
    font-size: 18px;
    color: #d8dde6;
    cursor: pointer;
    z-index: 999999;
  }
}
//.tdt-control-copyright {
@@ -580,10 +624,10 @@
//}
.tdt-infowindow-tip-container {
    opacity: 0;
  opacity: 1;
}
.tdt-infowindow-content-wrapper {
    opacity: 0;
  opacity: 1;
}
</style>
src/views/components/noticeTable.vue
@@ -20,6 +20,7 @@
            </div>
        </div>
        <el-table
          v-loading="tableLoading"
            :data="tableData"
            :header-cell-style="{
                background: '#F5F7FC',
@@ -69,12 +70,12 @@
        <div style="width: 100%;display: flex;flex-direction: row-reverse;align-items: center">
          <pagination
            style="width: 100%"
            v-show="total >= 0"
            v-show="total > 0"
            :page-sizes="[4]"
            :limit="queryParams.pageSize"
            :page="queryParams.pageNum"
            :page="queryParams.currentPage"
            :total="total"
            @pagination="getList"
            @pagination="pageChange"
          />
        </div>
      </div>
@@ -86,10 +87,11 @@
export default {
    data() {
        return {
            tableLoading: false,
            currentTab: "process",
            total: 0,
            queryParams: {
                pageNum: 1,
                currentPage: 1,
                pageSize: 4,
            },
            tableData: [],
@@ -164,21 +166,26 @@
        this.getList();
    },
    methods: {
        pageChange(data) {
          this.queryParams.currentPage = data.page
          this.getList()
        },
        async getList() {
            var resp;
            this.total = 0;
            this.tableData = [];
            this.tableLoading = true
            if (this.currentTab == "process") {
                resp = await getProjectProcessTodo(this.queryParams);
                if (resp.code === 200) {
                    this.total = resp.total;
                    this.tableData = resp.taskList;
                    this.tableLoading = false
                }
            } else {
                resp = await getProjectPlanToDoList(this.queryParams);
                if (resp.code === 200) {
                    this.total = resp.total;
                    this.tableData = resp.data;
                    this.tableLoading = false
                }
            }
        },
@@ -187,11 +194,13 @@
                const resp = await getDetailByProcessInsId({ processDefId: row.processDefId, processInsId: row.processInsId });
                if (resp.code === 200 && resp.data.length > 0) {
                    const projectProcess = resp.data[0]
                  sessionStorage.removeItem("projectProDetail")
                    this.$router.push({
                        path: '/projectFlow/detail',
                        query: {
                            projectId: projectProcess.projectId,
                            processDefId: row.processDefId
                            processDefId: row.processDefId,
                            processName: row.processName
                        }
                    })
                }
@@ -210,11 +219,13 @@
                const resp = await getDetailByProcessInsId({ processDefId: row.processDefId, processInsId: row.processInsId });
                if (resp.code === 200 && resp.data.length > 0) {
                    const projectProcess = resp.data[0]
                  sessionStorage.removeItem("projectProDetail")
                    this.$router.push({
                        path: '/projectFlow/detail',
                        query: {
                            projectId: projectProcess.projectId,
                            processDefId: row.processDefId
                            processDefId: row.processDefId,
                          processName: row.processName
                        }
                    })
                }
src/views/flowable/expression/index.vue
@@ -73,7 +73,6 @@
    <el-table v-loading="loading" :data="expressionList" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column label="主键" align="center" prop="id" />
      <el-table-column label="名称" align="center" prop="name" />
      <el-table-column label="表达式内容" align="center" prop="expression" />
      <el-table-column label="指定类型" align="center" prop="dataType" >
@@ -81,6 +80,7 @@
          <dict-tag :options="dict.type.exp_data_type" :value="scope.row.dataType"/>
        </template>
      </el-table-column>
      <el-table-column label="创建时间" align="center" prop="createTime" />
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template slot-scope="scope">
          <el-button
@@ -110,7 +110,7 @@
    />
    <!-- 添加或修改流程达式对话框 -->
    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
    <el-dialog :title="title" :visible.sync="open" width="500px" :close-on-click-modal="false" :destroy-on-close="true" append-to-body>
      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
        <el-form-item label="名称" prop="name">
          <el-input v-model="form.name" placeholder="请输入表达式名称" />
@@ -244,7 +244,7 @@
    handleAdd() {
      this.reset();
      this.open = true;
      this.title = "添加流程达式";
      this.title = "添加流程表达式";
    },
    /** 修改按钮操作 */
    handleUpdate(row) {
src/views/flowable/task/myProcess/detail/index.vue
@@ -10,39 +10,30 @@
        <!--表单信息-->
        <el-tab-pane label="表单信息" name="1">
          <!--初始化流程加载表单信息-->
          <el-col :span="16" :offset="4">
          <el-col :span="16" :offset="4" v-loading="formLoading" class="tab-min-height">
            <div v-if="formDataList && formDataList.length > 0">
              <div v-for="(formDataObj, index) in formDataList" :key="index" class="form-warp" style="position: relative">
                <div v-if="formDataObj.current">
                  <!--     当前节点可协同、转办等操作         -->
                  <div style="position: absolute; top: 4px; right: 4px; display: flex;justify-content: center; align-items: center;">
                    <el-button size="small" type="primary" @click="submitForm">确认并提交</el-button>
                    <el-button size="small" type="primary" disabled @click="submitForm">协同办理(功能开发中)</el-button>
                    <el-button size="small" type="primary" @click="openDelegation(formDataList[0].beforeNodeName)">转办</el-button>
                  </div>
                  <div style="margin-bottom: 15px;color: #E6A23C">当前阶段:<span style="color: #409EFF">{{formDataObj.beforeNodeName}}</span></div>
                  <div class="current">当前阶段:<span>{{formDataObj.beforeNodeName}}</span></div>
                </div>
                <div v-else-if="formDataList.length > 1">
                  <!--     前置节点可驳回         -->
                  <div style="position: absolute; top: 4px; right: 4px">
                    <el-button type="danger" size="small" @click="openRejectTask(formDataObj.beforeNodeDefId)">驳 回</el-button>
                  </div>
                  <div style="margin-bottom: 15px;color: #E6A23C">前置阶段:<span style="color: #F56C6C">{{formDataObj.beforeNodeName}}</span></div>
                  <div class="before">前置阶段:<span>{{formDataObj.beforeNodeName}}</span></div>
                </div>
                <div v-if="formDataObj.formJson !== null && formDataObj.formJson !== ''">
                  <v-form-render  :form-data="formDataObj.formJson" :ref="'form' + index"/>
                <div v-if="formDataObj != null && formDataObj.formJsonObj != null">
                  <v-form-render  :form-data="formDataObj.formJsonObj.formJson" :ref="'form' + index"/>
                </div>
                <div v-else>
                  <el-alert
                    title="节点未绑定表单"
                    title="未绑定表单"
                    type="warning"
                    :closable="false"
                  >
                  </el-alert>
                </div>
                <div v-if="formDataList.length <= 1">
                  <div class="before_none">前置阶段:<span>不存在前置阶段</span></div>
                  <el-alert
                    title="不存在前置节点"
                    title="不存在前置阶段"
                    type="warning"
                    :closable="false"
                  >
@@ -104,7 +95,9 @@
        </el-tab-pane>
        <!--流程图-->
        <el-tab-pane label="流程图" name="3">
          <bpmn-viewer :flowData="flowData" :procInsId="taskForm.procInsId"/>
          <div class="tab-min-height" v-loading="imgLoading">
            <bpmn-viewer :flowData="flowData" :procInsId="taskForm.procInsId"/>
          </div>
        </el-tab-pane>
    </el-tabs>
    </el-card>
@@ -126,6 +119,8 @@
  props: {},
  data() {
    return {
      formLoading: false, // 加载表单
      imgLoading: false, // 加载流程图
      projectName: '',
      flowName: '',
      // 模型xml数据
@@ -158,12 +153,14 @@
    this.flowName = this.$route.query && this.$route.query.flowName;
    // 流程任务重获取变量表单
    this.processVariables( this.taskForm.taskId)
    this.getFlowRecordList(this.taskForm.procInsId, this.taskForm.deployId);
    this.getFlowRecordList(this.taskForm.procInsId);
  },
  methods: {
    handleClick(tab, event) {
      if (tab.name === '3'){
        flowXmlAndNode({procInsId:this.taskForm.procInsId,deployId:this.taskForm.deployId}).then(res => {
        this.imgLoading = true
        flowXmlAndNode({processInsId:this.taskForm.procInsId,deployId:this.taskForm.deployId}).then(res => {
          this.imgLoading = false
          this.flowData = res.data;
        })
      }
@@ -183,9 +180,9 @@
      }
    },
    /** 流程流转记录 */
    getFlowRecordList(procInsId, deployId) {
    getFlowRecordList(procInsId) {
      const that = this
      const params = {procInsId: procInsId, deployId: deployId}
      const params = {procInsId: procInsId}
      flowRecord(params).then(res => {
        that.flowRecordList = res.data.flowList;
      }).catch(res => {
@@ -195,6 +192,7 @@
    /** 获取流程变量内容 */
    processVariables(taskId) {
      if (taskId) {
        this.formLoading = true
        // 提交流程申请时填写的表单存入了流程变量中后续任务处理时需要展示
        flowTaskFormDetail(taskId).then(res => {
          this.formDataList = res.data
@@ -203,7 +201,6 @@
              this.formDataList.forEach((formDataObj, index) => {
                console.log("表单数据列表", formDataObj.formJson)
                let that = this
                console.log(eval("that.$refs.form" + index)[0])
                if (formDataObj.formJsonObj) {
                  eval("that.$refs.form" + index)[0].setFormJson(formDataObj.formJsonObj.formJson);
@@ -216,6 +213,7 @@
              // this.formJson = this.formDataList[0].formJsonObj.formJson
            })
          }
          this.formLoading = false
          // this.$nextTick(() => {
          //   // 回显表单
          //   this.$refs.vFormRef.setFormJson(res.data.formJson);
@@ -283,4 +281,42 @@
  margin-bottom: 20px;
  box-shadow: rgba(67, 71, 85, 0.27) 0px 0px 0.25em, rgba(90, 125, 188, 0.05) 0px 0.25em 1em;
}
.before {
  span {
    color: #F56C6C
  }
  margin-bottom: 15px;
  color: #E6A23C
}
.before_none {
  span {
    color: #F56C6C
  }
  margin-bottom: 15px;
  margin-top: 15px;
  color: #E6A23C
}
.reject-but {
  position: absolute;
  top: 4px;
  right: 4px
}
.current {
  span {
    color: #409EFF
  }
  margin-bottom: 15px;
  color: #E6A23C
}
.op-list {
  position: absolute;
  top: 4px;
  right: 4px;
  display: flex;
  justify-content: center;
  align-items: center;
}
.tab-min-height {
  min-height: 500px;
}
</style>
src/views/flowable/task/myProcess/send/index.vue
@@ -10,39 +10,40 @@
        <!--表单信息-->
        <el-tab-pane label="表单信息" name="1">
          <!--初始化流程加载表单信息-->
          <el-col :span="16" :offset="4">
          <el-col :span="16" :offset="4" v-loading="formLoading"  class="tab-min-height">
            <div v-if="formDataList && formDataList.length > 0">
              <div v-for="(formDataObj, index) in formDataList" :key="index" class="form-warp" style="position: relative">
                <div v-if="formDataObj.current">
                  <!--     当前节点可协同、转办等操作         -->
                  <div style="position: absolute; top: 4px; right: 4px; display: flex;justify-content: center; align-items: center;">
                    <el-button size="small" type="primary" @click="submitForm">确认并提交</el-button>
                  <div class="op-list">
                    <el-button size="small" type="primary" :disabled="submitLoading" v-loading="submitLoading" @click="submitForm">确认并提交</el-button>
                    <el-button size="small" type="primary" disabled @click="submitForm">协同办理(功能开发中)</el-button>
                    <el-button size="small" type="primary" @click="openDelegation(formDataList[0].beforeNodeName)">转办</el-button>
                  </div>
                  <div style="margin-bottom: 15px;color: #E6A23C">当前阶段:<span style="color: #409EFF">{{formDataObj.beforeNodeName}}</span></div>
                  <div class="current">当前阶段:<span>{{formDataObj.beforeNodeName}}</span></div>
                </div>
                <div v-else-if="formDataList.length > 1">
                  <!--     前置节点可驳回         -->
                  <div style="position: absolute; top: 4px; right: 4px">
                    <el-button type="danger" size="small" @click="openRejectTask(formDataObj.beforeNodeDefId)">驳 回</el-button>
                  <div class="reject-but">
                    <el-button type="danger" size="small" @click="openRejectTask(formDataObj.beforeNodeName)">驳 回</el-button>
                  </div>
                  <div style="margin-bottom: 15px;color: #E6A23C">前置阶段:<span style="color: #F56C6C">{{formDataObj.beforeNodeName}}</span></div>
                  <div class="before">前置阶段:<span>{{formDataObj.beforeNodeName}}</span></div>
                </div>
                <div v-if="formDataObj.formJson !== null && formDataObj.formJson !== ''">
                  <v-form-render  :form-data="formDataObj.formJson" :ref="'form' + index"/>
                <div v-if="formDataObj != null && formDataObj.formJsonObj != null">
                  <v-form-render  :form-data="formDataObj.formJsonObj.formJson" :ref="'form' + index"/>
                </div>
                <div v-else>
                  <el-alert
                    title="节点未绑定表单"
                    title="未绑定表单"
                    type="warning"
                    :closable="false"
                  >
                  </el-alert>
                </div>
                <div v-if="formDataList.length <= 1">
                  <div class="before_none">前置阶段:<span>不存在前置阶段</span></div>
                  <el-alert
                    title="不存在前置节点"
                    title="不存在前置阶段"
                    type="warning"
                    :closable="false"
                  >
@@ -54,7 +55,9 @@
        </el-tab-pane>
        <!--流程图-->
        <el-tab-pane label="流程图" name="2">
          <bpmn-viewer :flowData="flowData" :procInsId="procInsId"/>
          <div v-loading="imgLoading" class="tab-min-height">
            <bpmn-viewer :flowData="flowData" :procInsId="procInsId"/>
          </div>
        </el-tab-pane>
      </el-tabs>
      <!--选择流程接收人-->
@@ -70,7 +73,7 @@
    <el-dialog
      :title="`驳回:` + rejectForm.projectName"
      :title="`驳回:` + rejectForm.taskName"
      :visible.sync="rejectShow"
      width="950px"
      :destroy-on-close="true"
@@ -85,7 +88,7 @@
        </el-input>
      </div>
      <div class="opBut">
        <el-button type="danger" size="small" @click="rejectTask">驳回</el-button>
        <el-button type="danger" size="small" :disabled="rejectLoading" v-loading="rejectLoading" @click="rejectTask">驳回</el-button>
      </div>
    </el-dialog>
@@ -152,7 +155,7 @@
        </el-form>
      </div>
      <div class="opBut">
        <el-button type="danger" size="small" @click="delegation">转 办</el-button>
        <el-button type="danger" size="small" :disabled="delegationButLoading" v-loading="delegationButLoading" @click="delegation">转 办</el-button>
      </div>
    </el-dialog>
@@ -184,6 +187,11 @@
  props: {},
  data() {
    return {
      rejectLoading: false, // 驳回按钮加载
      submitLoading: false, // 提交按钮加载
      delegationButLoading: false, // 转办按钮加载
      formLoading: false,  // 加载当前喝前置节点数据
      imgLoading: false,  // 加载流程图
      roleKey: 'role',
      deptKey: 'dept',
      multUserKey: 0,
@@ -209,7 +217,9 @@
        taskId: '',
        peopleType: '',
        targetId: '',
        taskName: ''
        taskName: '',
        processInsId: '',
        projectId: '',
      },
      delegationShow: false, // 转办显示
      rejectShow: false, // 驳回显示
@@ -244,7 +254,7 @@
      rejectForm: {
        comment: '', // 审核意见
        taskId: '',
        // rejectedTaskDefKey: ''  // 被驳回的任务key
        taskName: ''  // 被驳回的任务k
      }
    };
  },
@@ -305,8 +315,13 @@
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            this.delegationForm.projectId = this.goBackParams.projectId
            this.delegationForm.processInsId = this.procInsId
            this.delegationButLoading = true
            taskDelegation(this.delegationForm).then(res => {
              this.$message.success("已发起转办申请")
              this.delegationButLoading = false
              this.delegationShow = false
              this.goBack()
            })
          }).catch(() => {
@@ -434,19 +449,36 @@
      this.delegationShow = true
    },
    rejectTask() {
      rejectTask(this.rejectForm).then(res => {
        this.rejectShow = false
        this.$message.success("驳回成功")
      })
      this.$confirm(`确定要驳回任务【${this.rejectForm.taskName}】吗?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.rejectLoading = true
        rejectTask(this.rejectForm).then(res => {
          this.rejectShow = false
          this.$message.success("驳回成功")
          this.goBack()
        })
      }).catch((err) => {
        console.log(err)
        this.$message({
          type: 'info',
          message: '已取驳回交操作'
        });
      });
    },
    openRejectTask(rejectedTaskDefKey) {
      // this.rejectForm.rejectedTaskDefKey = rejectedTaskDefKey;
    openRejectTask(taskName) {
      this.rejectForm.taskName = taskName;
      this.rejectForm.taskId = this.taskId;
      this.rejectShow = true
    },
    handleClick(tab, event) {
      if (tab.name === '2'){
        this.imgLoading = true
        flowXmlAndNode({procInsId:this.procInsId,deployId:this.deployId}).then(res => {
          this.imgLoading = false
          this.flowData = res.data;
        })
      }
@@ -454,13 +486,13 @@
    /** 流程表单数据 */
    getFlowFormData(taskId) {
      const params = {taskId: taskId}
      this.formLoading = true
      flowTaskForm(params).then(res => {
        this.formDataList = res.data
        if (this.formDataList && this.formDataList.length > 0) {
          this.$nextTick(() => {
            this.formDataList.forEach((formDataObj, index) => {
              let that = this
              console.log(eval("that.$refs.form" +index))
              if (eval("that.$refs.form" +index) && formDataObj.formJsonObj) {
                eval("that.$refs.form" +index)[0].setFormJson(formDataObj.formJsonObj.formJson);
                eval("that.$refs.form" +index)[0].setFormData(formDataObj.formJsonObj);
@@ -470,8 +502,8 @@
              this.formJson = this.formDataList[0].formJsonObj.formJson
            }
          })
        }
        this.formLoading = false
        // if (res.data.formJson) {
        //   // 回显表单
        //   this.$refs.vFormRef.setFormJson(res.data.formJson);
@@ -511,54 +543,86 @@
    },
    /** 申请流程表单数据提交 */
    submitForm() {
      let that = this
      eval("that.$refs.form" +0)[0].getFormData().then(formData => {
        // 根据当前任务或者流程设计配置的下一步节点 todo 暂时未涉及到考虑网关、表达式和多节点情况
        getNextFlowNodeByStart({deploymentId: this.deployId, variables: formData}).then(res => {
          const data = res.data;
          if (data) {
            this.formData = formData;
            if (data.dataType === 'dynamic') {
              if (data.type === 'assignee') { // 指定人员
                this.checkSendUser = true;
                this.checkType = "single";
              } else if (data.type === 'candidateUsers') {  // 候选人员(多个)
                this.checkSendUser = true;
                this.checkType = "multiple";
              } else if (data.type === 'candidateGroups') { // 指定组(所属角色接收任务)
                this.checkSendRole = true;
              } else { // 会签
                // 流程设计指定的 elementVariable 作为会签人员列表
                this.multiInstanceVars = data.vars;
                this.checkSendUser = true;
                this.checkType = "multiple";
              }
              this.taskOpen = true;
              this.taskTitle = "选择任务接收";
            } else {
              if (this.procDefId) {
                const param = {
                  formJson:  this.formJson,
                }
                // 复制对象的属性值给新的对象
                Object.assign(param, formData);
                // 完成任务
                completeSubmitFormTask(this.taskId, param).then(res => {
                  this.$modal.msgSuccess(res.msg);
                  this.goBack();
                })
                // // 启动流程并将表单数据加入流程变量
                // definitionStart(this.procDefId, param).then(res => {
                //   this.$modal.msgSuccess(res.msg);
                //   this.goBack();
                // })
              }
      this.$confirm(`确定要提交任务【${this.processName}】吗?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.submitLoading = true
        let that = this
        if (eval("that.$refs.form" +0)) {
          eval("that.$refs.form" +0)[0].getFormData().then(formData => {
            this.formData = formData
            const param = {
              formJson:  this.formJson,
            }
          }
        })
      }).catch(error => {
        // this.$modal.msgError(error)
      })
            // 复制对象的属性值给新的对象
            Object.assign(param, formData);
            // 完成任务
            completeSubmitFormTask(this.taskId, param).then(res => {
              this.$modal.msgSuccess(res.msg);
              this.submitLoading = false
              this.goBack();
            })
          })
        } else {
          // 没关联表单直接传空
          completeSubmitFormTask(this.taskId, {}).then(res => {
            this.$modal.msgSuccess(res.msg);
            this.submitLoading = false
            this.goBack();
          })
        }
        // let that = this
        // eval("that.$refs.form" +0)[0].getFormData().then(formData => {
        //   // 根据当前任务或者流程设计配置的下一步节点 todo 暂时未涉及到考虑网关、表达式和多节点情况
        //   getNextFlowNodeByStart({deploymentId: this.deployId, variables: formData}).then(res => {
        //     const data = res.data;
        //     if (data) {
        //       this.formData = formData;
        //       if (data.dataType === 'dynamic') {
        //         if (data.type === 'assignee') { // 指定人员
        //           this.checkSendUser = true;
        //           this.checkType = "single";
        //         } else if (data.type === 'candidateUsers') {  // 候选人员(多个)
        //           this.checkSendUser = true;
        //           this.checkType = "multiple";
        //         } else if (data.type === 'candidateGroups') { // 指定组(所属角色接收任务)
        //           this.checkSendRole = true;
        //         } else { // 会签
        //           // 流程设计指定的 elementVariable 作为会签人员列表
        //           this.multiInstanceVars = data.vars;
        //           this.checkSendUser = true;
        //           this.checkType = "multiple";
        //         }
        //         this.taskOpen = true;
        //         this.taskTitle = "选择任务接收";
        //       } else {
        //         if (this.procDefId) {
        //           const param = {
        //             formJson:  this.formJson,
        //           }
        //           // 复制对象的属性值给新的对象
        //           Object.assign(param, formData);
        //           // 完成任务
        //           completeSubmitFormTask(this.taskId, param).then(res => {
        //             this.$modal.msgSuccess(res.msg);
        //             this.goBack();
        //           })
        //         }
        //       }
        //     }
        //   })
        // })
      }).catch((err) => {
        console.log(err)
        this.$message({
          type: 'info',
          message: '已取消提交操作'
        });
      });
    },
    /** 重置表单 */
    resetForm() {
@@ -635,7 +699,6 @@
  width: 800px;
  padding: 15px;
}
.clearfix:before,
.clearfix:after {
  display: table;
@@ -644,20 +707,16 @@
.clearfix:after {
  clear: both
}
.box-card {
  width: 100%;
  margin-bottom: 20px;
}
.el-tag + .el-tag {
  margin-left: 10px;
}
.my-label {
  background: #E1F3D8;
}
.form-warp {
  min-width: 700px;
  padding: 20px;
@@ -665,4 +724,42 @@
  margin-bottom: 20px;
  box-shadow: rgba(67, 71, 85, 0.27) 0px 0px 0.25em, rgba(90, 125, 188, 0.05) 0px 0.25em 1em;
}
.before {
  span {
    color: #F56C6C
  }
  margin-bottom: 15px;
  color: #E6A23C
}
.before_none {
  span {
    color: #F56C6C
  }
  margin-bottom: 15px;
  margin-top: 15px;
  color: #E6A23C
}
.reject-but {
  position: absolute;
  top: 4px;
  right: 4px
}
.current {
  span {
    color: #409EFF
  }
  margin-bottom: 15px;
  color: #E6A23C
}
.op-list {
  position: absolute;
  top: 4px;
  right: 4px;
  display: flex;
  justify-content: center;
  align-items: center;
}
.tab-min-height {
  min-height: 500px;
}
</style>
src/views/index.vue
@@ -1,145 +1,135 @@
<template>
    <div class="home">
        <div class="overview">
            <div class="overview-top">
                <div class="title">项目总览</div>
                <div class="qurey">
                    <el-form ref="queryFormRef" :model="queryParams">
                        <div class="search_from">
                            <el-form-item label="日期">
                                <el-date-picker
                                    style="width: 300px"
                                    v-model="timeMerge"
                                    clearable
                                    end-placeholder="结束时间"
                                    format="YYYY-MM-DD"
                                    placeholder="请选择日期"
                                    size="default"
                                    start-placeholder="开始时间"
                                    type="daterange"
                                    value-format="YYYY-MM-DD"
                                    @change="dataPickerChange"
                                />
                            </el-form-item>
                            <el-form-item label="行政区划">
                                <el-select
                                    v-model="queryParams.area"
                                    clearable
                                    placeholder="请选择区划"
                                    style="width: 180px"
                                >
                                    <el-option
                                        v-for="item in sys_administrative_divisions"
                                        :key="item.value"
                                        :label="item.label"
                                        :value="item.value"
                                    />
                                </el-select>
                            </el-form-item>
                            <el-form-item
                                label="投资金额"
                                style="margin-right: 50px"
                            >
                                <div class="from_input">
                                    <el-input
                                        v-model="queryParams.start"
                                        clearable
                                        placeholder="请输入"
                                        style="width: 100px"
                                        type="number"
                                    />
                                    至
                                    <el-input
                                        v-model="queryParams.end"
                                        clearable
                                        placeholder="请输入"
                                        style="width: 100px"
                                        type="number"
                                    />
                                </div>
                            </el-form-item>
                            <el-form-item style="margin-right: 20px">
                                <el-button
                                    icon="Search"
                                    type="primary"
                                    @click="handleQuery"
                                    >搜索</el-button
                                >
                                <el-button icon="Refresh" @click="resetQuery"
                                    >重置</el-button
                                >
                            </el-form-item>
                        </div>
                    </el-form>
  <div class="home">
    <div class="overview">
      <div class="overview-top">
        <div class="title">项目总览</div>
        <div class="qurey">
          <el-form ref="queryFormRef" :model="queryParams">
            <div class="search_from">
              <el-form-item label="日期">
                <el-date-picker
                  style="width: 300px"
                  v-model="timeMerge"
                  clearable
                  end-placeholder="结束时间"
                  format="YYYY-MM-DD"
                  placeholder="请选择日期"
                  size="default"
                  start-placeholder="开始时间"
                  type="daterange"
                  value-format="YYYY-MM-DD"
                  @change="dataPickerChange"
                />
              </el-form-item>
              <el-form-item label="行政区划">
                <el-select
                  v-model="queryParams.area"
                  clearable
                  placeholder="请选择区划"
                  style="width: 180px"
                >
                  <el-option
                    v-for="item in sys_administrative_divisions"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                  />
                </el-select>
              </el-form-item>
              <el-form-item label="投资金额" style="margin-right: 50px">
                <div class="from_input">
                  <el-input
                    v-model="queryParams.start"
                    clearable
                    placeholder="请输入"
                    style="width: 100px"
                    type="number"
                  />
                  至
                  <el-input
                    v-model="queryParams.end"
                    clearable
                    placeholder="请输入"
                    style="width: 100px"
                    type="number"
                  />
                </div>
              </el-form-item>
              <el-form-item style="margin-right: 20px">
                <el-button icon="Search" type="primary" @click="handleQuery"
                  >搜索</el-button
                >
                <el-button icon="Refresh" @click="resetQuery">重置</el-button>
              </el-form-item>
            </div>
            <!-- 统计情况 -->
            <ProjectOverview
                :calculation="calculation"
                :countExceptionProjectData="countExceptionProjectData"
            />
          </el-form>
        </div>
        <!-- 代办事项 -->
        <div class="flex">
            <div class="flex_card">
                <el-card>
                    <NoticeTable style="height: 340px" />
                </el-card>
            </div>
            <!-- 消息通知 -->
            <div class="flex_card">
                <el-card>
                    <TidingsTable style="height: 340px" />
                </el-card>
            </div>
            <!-- 地图 -->
        </div>
        <div style="margin-top: 10px">
            <el-card>
                <div>
                    <div class="search-form">
                        <el-form :model="searchForm" inline size="small">
                            <el-form-item label=" ">
                                <el-input
                                    v-model="searchForm.name"
                                    clearable
                                    placeholder="请输入项目名称或项目代码"
                                    style="width: 180px"
                                />
                            </el-form-item>
                            <el-form-item style="margin-right: 0px">
                                <el-button
                                    clearable
                                    @clear="searchList"
                                    icon="Search"
                                    type="primary"
                                    @click="searchList"
                                    >搜索</el-button
                                >
                                <el-button icon="Refresh" @click="mapQuery"
                                    >重置</el-button
                                >
                            </el-form-item>
                        </el-form>
                    </div>
                    <div class="map_div">
                        <Map
                            id="DangerSourceId"
                            ref="mapRef"
                            :is-show-control="true"
                            :list-type="true"
                            :map-list="tableDatas"
                            :map-type="true"
                            class="w-full h-full border-r border-[#DBDEEA]"
                            @label-click="showDetails"
                            @mark-click="showDetails"
                            @current-label-style-change="labelStyleChange"
                        />
                    </div>
                </div>
            </el-card>
        </div>
      </div>
      <!-- 统计情况 -->
      <ProjectOverview
        :calculation="calculation"
        :countExceptionProjectData="countExceptionProjectData"
      />
    </div>
    <!-- 待办事项 -->
    <div class="flex">
      <div class="flex_card">
        <el-card>
          <NoticeTable style="height: 340px" />
        </el-card>
      </div>
      <!-- 消息通知 -->
      <div class="flex_card">
        <el-card>
          <TidingsTable style="height: 340px" />
        </el-card>
      </div>
      <!-- 地图 -->
    </div>
    <div style="margin-top: 10px">
      <el-card>
        <div>
          <div class="search-form">
            <el-form :model="searchForm" inline size="small">
              <el-form-item label="">
                <el-input
                  v-model="searchForm.name"
                  clearable
                  placeholder="请输入项目名称或项目代码"
                  style="width: 240px"
                />
              </el-form-item>
              <el-form-item style="margin-right: 0px">
                <el-button
                  clearable
                  @clear="searchList"
                  icon="Search"
                  type="primary"
                  @click="searchList"
                  >搜索</el-button
                >
                <el-button icon="Refresh" @click="mapQuery">重置</el-button>
              </el-form-item>
            </el-form>
          </div>
          <div class="map_div">
            <Map
              id="DangerSourceId"
              ref="mapRef"
              :is-show-control="true"
              :list-type="false"
              :map-list="tableDatas"
              :map-type="true"
              class="w-full h-full border-r border-[#DBDEEA]"
              @label-click="showDetails"
              @mark-click="showDetails"
              @current-label-style-change="labelStyleChange"
            />
          </div>
        </div>
      </el-card>
    </div>
  </div>
</template>
<script>
@@ -148,235 +138,236 @@
import NoticeTable from "./components/noticeTable.vue";
import TidingsTable from "./components/tidingsTable.vue";
import Map from "./components/Map/index.vue";
import { getCalculatioln, getAbnormalData } from '@/api/login';
import { getCalculatioln, getAbnormalData } from "@/api/login";
import { searchByKey } from "@/api/projectEngineering/projectInfo";
export default {
    name: "Index",
    data() {
        return {
            queryParams: {},
            timeMerge: [],
            sys_administrative_divisions: [],
            countExceptionProjectData: {},
            searchForm: {},
            tableDatas: [
                {
                    name: "射洪市",
                    value: 105.37281,
                    lat: 30.87145,
                    lon: 105.37281,
                    id: "222222222",
                },
                {
                    name: "xxxx",
                    value: 105.22332,
                    lat: 31.52421,
                    lon: 106.22332,
                    id: "11112",
                },
            ],
            calculation: [
                { text: '储', mun: 0, statistics: '', statisticsMun: '0' },
                { text: '建', mun: 0, statistics: '', statisticsMun: '0' },
                { text: '省', mun: 0, statistics: '', statisticsMun: '0' },
                { text: '市', mun: 0, statistics: '', statisticsMun: '0' },
                { text: '新', mun: 0, statistics: '', statisticsMun: '0' },
                { text: '竣', mun: 0, statistics: '', statisticsMun: '0' },
                { text: '县', mun: 0, statistics: '', statisticsMun: '0' },
                { text: '普', mun: 0, statistics: '', statisticsMun: '0' }
            ]
        };
  name: "Index",
  data() {
    return {
      queryParams: {},
      timeMerge: [],
      sys_administrative_divisions: [],
      countExceptionProjectData: {},
      searchForm: {},
      tableDatas: [],
      calculation: [
        { text: "储", mun: 0, statistics: "", statisticsMun: "0" },
        { text: "建", mun: 0, statistics: "", statisticsMun: "0" },
        { text: "省", mun: 0, statistics: "", statisticsMun: "0" },
        { text: "市", mun: 0, statistics: "", statisticsMun: "0" },
        { text: "新", mun: 0, statistics: "", statisticsMun: "0" },
        { text: "竣", mun: 0, statistics: "", statisticsMun: "0" },
        { text: "县", mun: 0, statistics: "", statisticsMun: "0" },
        { text: "普", mun: 0, statistics: "", statisticsMun: "0" },
      ],
    };
  },
  components: {
    SvgIcon,
    ProjectOverview,
    NoticeTable,
    TidingsTable,
    Map,
  },
  created() {
    this.handleQuery();
    this.searchList();
  },
  methods: {
    dataPickerChange(val) {
      if (!val) {
        this.queryParams.startTime = "";
        this.queryParams.endTime = "";
        return;
      }
      this.queryParams.startTime = this.timeMerge[0];
      this.queryParams.endTime = this.timeMerge[1];
    },
    components: {
        SvgIcon,
        ProjectOverview,
        NoticeTable,
        TidingsTable,
        Map,
    handleQuery() {
      const obj = {
        startDate: this.queryParams.startTime,
        endDate: this.queryParams.endTime,
        areaCode: this.queryParams.area,
        minInvestment: this.queryParams.start,
        maxInvestment: this.queryParams.end,
      };
      getCalculatioln(obj).then((res) => {
        const arr = res.data.proPhaseCountVO?.concat(res.data.impTypeCountVO);
        const newArr = arr.map((item) => ({
          text: item.text,
          mun: item.count,
          statistics: item.type,
          statisticsMun: item.amount,
        }));
        // 创建一个对象,以便根据 text 属性快速查找 newArr 中的对象
        const newArrLookup = newArr.reduce((lookup, item) => {
          lookup[item.text] = item;
          return lookup;
        }, {});
        // 更新 calculation 数组,保持其原始顺序
        this.calculation = this.calculation.map((item) => {
          const newItem = newArrLookup[item.text];
          return newItem ? newItem : item; // 如果 newItem 存在,则返回 newItem,否则返回原始 item
        });
      });
      this.abnormalData(obj);
    },
    created() {
        this.handleQuery()
    // 地图搜索
    searchList() {
      var _this = this;
      searchByKey({ wordKey: this.searchForm.name }).then((res) => {
        if (res.code == 200) {
          if (res.data.length > 0) {
            // this.$refs["mapRef"].showProjectInfo(res.data);
            // _this.tableDatas = res.data;
            setTimeout(() => {
              _this.$refs["mapRef"].makeAllMask(res.data);
            }, 2000);
          } else {
            _this.$message.error("未查询到对应项目");
          }
        } else {
          _this.$message.error(res.msg);
        }
      });
    },
    methods: {
        dataPickerChange(val) {
            if (!val) {
                this.queryParams.startTime = "";
                this.queryParams.endTime = "";
                return;
            }
            this.queryParams.startTime = this.timeMerge[0];
            this.queryParams.endTime = this.timeMerge[1];
        },
        handleQuery() {
            const obj = {
                startDate: this.queryParams.startTime,
                endDate: this.queryParams.endTime,
                areaCode: this.queryParams.area,
                minInvestment: this.queryParams.start,
                maxInvestment: this.queryParams.end,
            };
            getCalculatioln(obj).then((res) => {
                const arr = res.data.proPhaseCountVO?.concat(res.data.impTypeCountVO);
                const newArr = arr.map((item) => ({
                    text: item.text,
                    mun: item.count,
                    statistics: item.type,
                    statisticsMun: item.amount,
                }));
                // 创建一个对象,以便根据 text 属性快速查找 newArr 中的对象
                const newArrLookup = newArr.reduce((lookup, item) => {
                    lookup[item.text] = item;
                    return lookup;
                }, {});
                // 更新 calculation 数组,保持其原始顺序
                this.calculation = this.calculation.map((item) => {
                    const newItem = newArrLookup[item.text];
                    return newItem ? newItem : item; // 如果 newItem 存在,则返回 newItem,否则返回原始 item
                });
            });
            this.abnormalData(obj);
        },
        // 获取异常数据
        async abnormalData(obj) {
            const res = await getAbnormalData(obj);
            this.countExceptionProjectData = res.data;
        },
        //地图详情
        showDetails(row) {
            console.log(row);
        },
        labelStyleChange(currentLabel) {
            if (lastLabel) {
                lastLabel.setBackgroundColor("#fff");
                lastLabel.setFontColor("var(--el-color-primary)");
            }
            currentLabel.setBackgroundColor("var(--el-color-primary)");
            currentLabel.setFontColor("#fff");
            lastLabel = currentLabel;
        },
        resetQuery() {
            this.queryParams = {
                area: "",
                start: "",
                end: "",
                startTime: "",
                endTime: "",
            };
            this.timeMerge = [];
            this.handleQuery();
        },
        // 地图搜索
        async searchList() {
            // await search()
            this.mapRef.moveTo(105.37281, 30.87145);
        },
        mapQuery() { },
    // 获取异常数据
    async abnormalData(obj) {
      const res = await getAbnormalData(obj);
      this.countExceptionProjectData = res.data;
    },
    //地图详情
    showDetails(row) {
      console.log(row);
    },
    labelStyleChange(currentLabel) {
      if (lastLabel) {
        lastLabel.setBackgroundColor("#fff");
        lastLabel.setFontColor("var(--el-color-primary)");
      }
      currentLabel.setBackgroundColor("var(--el-color-primary)");
      currentLabel.setFontColor("#fff");
      lastLabel = currentLabel;
    },
    resetQuery() {
      this.queryParams = {
        area: "",
        start: "",
        end: "",
        startTime: "",
        endTime: "",
      };
      this.timeMerge = [];
      this.handleQuery();
    },
    mapQuery() {},
  },
};
</script>
<style scoped lang="scss">
.home {
    padding: 10px;
    background-color: #f3f7fc;
    min-height: calc(100vh - 85px);
    overflow-x: auto;
  padding: 10px;
  background-color: #f3f7fc;
  min-height: calc(100vh - 85px);
  overflow-x: auto;
    .overview {
        padding: 10px 0 0 10px;
        height: 280px;
        min-width: 1600px;
        background-color: #fff;
        border-radius: 6px;
  .overview {
    padding: 10px 0 0 10px;
    height: 280px;
    min-width: 1600px;
    background-color: #fff;
    border-radius: 6px;
        .overview-top {
            display: flex;
            justify-content: space-between;
    .overview-top {
      display: flex;
      justify-content: space-between;
            .title {
                font-size: 16px;
            }
      .title {
        font-size: 16px;
      }
            .qurey {
                font-size: 12px;
                font-weight: 100;
            }
        }
      .qurey {
        font-size: 12px;
        font-weight: 100;
      }
    }
  }
    .search-form {
        display: flex;
        justify-content: flex-end;
    }
  .search-form {
    padding: 5px;
    position: absolute;
    z-index: 999;
    display: flex;
    justify-content: flex-end;
  }
}
// ::v-deep .el-form-item {
//     display: inline-block !important;
//     margin-right: 10px;
// }
::v-deep .el-form-item--medium .el-form-item__content {
    display: inline-block !important;
  display: inline-block !important;
}
::v-deep .el-form-item__label {
    font-size: 12px;
    font-weight: 400;
  font-size: 12px;
  font-weight: 400;
}
::v-deep .el-button {
    font-size: 12px;
  font-size: 12px;
}
::v-deep.el-input__inner {
    font-size: 12px;
    height: 32px;
  font-size: 12px;
  height: 32px;
}
::v-deep.el-range-input {
    font-size: 12px;
  font-size: 12px;
}
::v-deep.el-select__placeholder {
    font-size: 12px;
  font-size: 12px;
}
::v-deep input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
::v-deep input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
input[type='number'] {
    -moz-appearance: textfield;
input[type="number"] {
  -moz-appearance: textfield;
}
.search_from {
    display: flex;
    justify-self: justify-end;
    gap: 10px;
  display: flex;
  justify-self: justify-end;
  gap: 10px;
}
.flex {
    display: flex;
    gap: 2%;
  display: flex;
  gap: 2%;
}
.flex_card {
    width: 49%;
    margin: 10px 0px;
  width: 49%;
  margin: 10px 0px;
}
.from_input {
    display: flex;
    gap: 10px;
    font-size: 12px;
  display: flex;
  gap: 10px;
  font-size: 12px;
}
.map_div {
    display: flex;
    width: 100%;
    height: 500px;
    border: #dbdeea;
  display: flex;
  width: 100%;
  height: 500px;
  border: #dbdeea;
}
</style>
src/views/projectProcess/detail/index.vue
@@ -18,7 +18,7 @@
      </div>
      <div class="search-warp">
        <div @click="changeTab(1, 'all')" :class="{'item-warm': true, 'all-color': true, 'active': 1 === selectTabId}">全部事项<span v-if="detailData && detailData.statistics">({{detailData.statistics.totalTaskNum}})</span></div>
        <div @click="changeTab(2, 'todo')" :class="{'item-warm': true, 'all-color': true, 'active': 2 === selectTabId}">代办事项<span v-if="detailData && detailData.statistics">({{detailData.statistics.todoTaskNum}})</span></div>
        <div @click="changeTab(2, 'todo')" :class="{'item-warm': true, 'all-color': true, 'active': 2 === selectTabId}">待办事项<span v-if="detailData && detailData.statistics">({{detailData.statistics.todoTaskNum}})</span></div>
        <div @click="changeTab(3, 'todo')" :class="{'item-warm': true, 'current-color': true, 'active': 3 === selectTabId}">当前环节</div>
        <div @click="changeTab(4, 'remaining')" :class="{'item-warm': true, 'remaining-color': true, 'active': 4 === selectTabId}">剩余事项<span v-if="detailData && detailData.statistics">({{detailData.statistics.remainingTaskNum}})</span></div>
        <div @click="changeTab(5, 'timely')" :class="{'item-warm': true, 'timely-color': true, 'active': 5 === selectTabId}">按时完成(0)</div>
@@ -26,7 +26,7 @@
        <div @click="changeTab(7, 'willOvertime')" :class="{'item-warm': true, 'willOvertime-color': true, 'active': 7 === selectTabId}">临期事项(0)</div>
        <div @click="changeTab(8, 'urge')" :class="{'item-warm': true, 'urge-color': true, 'active': 8 === selectTabId}">督办事项(0)</div>
      </div>
      <div style="display: flex;justify-content: center;align-items: center;margin-top: 20px">
      <div style="display: flex;justify-content: center;align-items: center;margin-top: 20px; position: relative">
        <el-form :inline="true" :model="queryParams" class="demo-form-inline">
          <el-form-item label="任务名称">
            <el-input v-model="queryParams.taskName" placeholder="任务名称"></el-input>
@@ -35,6 +35,10 @@
            <el-button type="primary" @click="search">查询</el-button>
          </el-form-item>
        </el-form>
        <div style="position: absolute; right: 0; top: 0">
          <el-button @click="openProcessImg" v-loading="imgLoading" type="primary">流程图</el-button>
          <el-button @click="openRecord" type="info" v-loading="recordLoading">流转记录</el-button>
        </div>
      </div>
      <div class="table">
        <el-table
@@ -115,6 +119,75 @@
        </el-pagination>
      </div>
    </div>
    <el-dialog
      :title="`${this.queryParams.processName}:流程图`"
      :visible.sync="processImgShow"
      :fullscreen="true"
      :close-on-click-modal="false"
      :destroy-on-close="true"
    >
      <div>
        <bpmn-viewer :flowData="flowData" :procInsId="queryParams.processInsId"/>
      </div>
    </el-dialog>
    <el-dialog
      :title="`${this.queryParams.processName}:流转记录`"
      :visible.sync="processRecordShow"
      :fullscreen="true"
      :close-on-click-modal="false"
      :destroy-on-close="true"
    >
      <div>
        <div class="block">
          <el-timeline>
            <el-timeline-item
              v-for="(item,index ) in flowRecordList"
              :key="index"
              :icon="setIcon(item.finishTime)"
              :color="setColor(item.finishTime)"
            >
              <p style="font-weight: 700">{{item.taskName}}
                <span v-if="item.comment && item.comment.type === '3'" style="color: red">(执行了驳回)</span>
                <span v-if="item.overtime && item.overtime==='red'" style="color: red">(已超时)</span>
                <span v-if="item.overtime && item.overtime==='yellow'" style="color: orange">(即将超时)</span>
              </p>
              <el-card :body-style="{ padding: '10px' }">
                <el-descriptions class="margin-top" :column="1" size="small" border>
                  <el-descriptions-item v-if="item.assigneeName" label-class-name="my-label">
                    <template slot="label"><i class="el-icon-user"></i>办理人</template>
                    {{item.assigneeName}}
                    <el-tag type="info" size="mini">{{item.deptName}}</el-tag>
                  </el-descriptions-item>
                  <el-descriptions-item v-if="item.candidate" label-class-name="my-label">
                    <template slot="label"><i class="el-icon-user"></i>候选办理</template>
                    {{item.candidate}}
                  </el-descriptions-item>
                  <el-descriptions-item label-class-name="my-label">
                    <template slot="label"><i class="el-icon-date"></i>接收时间</template>
                    {{item.createTime}}
                  </el-descriptions-item>
                  <el-descriptions-item v-if="item.finishTime" label-class-name="my-label">
                    <template slot="label"><i class="el-icon-date"></i>处理时间</template>
                    {{item.finishTime}}
                  </el-descriptions-item>
                  <el-descriptions-item v-if="item.duration"  label-class-name="my-label">
                    <template slot="label"><i class="el-icon-time"></i>耗时</template>
                    {{item.duration}}
                  </el-descriptions-item>
                  <el-descriptions-item v-if="item.comment" label-class-name="my-label">
                    <template slot="label"><i class="el-icon-tickets"></i>处理意见</template>
                    {{item.comment.comment}}
                  </el-descriptions-item>
                </el-descriptions>
              </el-card>
            </el-timeline-item>
          </el-timeline>
        </div>
      </div>
    </el-dialog>
  </div>
</template>
@@ -124,11 +197,24 @@
  getProjectProcessDetailTaskList,
  getTaskIsAuditing
} from "@/api/projectProcess/projectProcess";
import {flowXmlAndNode} from "@/api/flowable/definition";
import BpmnViewer from '@/components/Process/viewer';
import {flowRecord} from "@/api/flowable/finished";
export default {
  name: "Detail",
  components: {
    BpmnViewer
  },
  data() {
    return {
      processRecordShow: false, // 流转记录显示
      flowRecordList: [], // 流程流转数据
      recordLoading: false, // 流转记录加载
      // 模型xml数据
      flowData: {},
      processImgShow: false, // 流程图显示
      imgLoading: false, // 流程图加载
      loading: false,
      tableLoading: false,
      detailData: {},
@@ -142,18 +228,21 @@
        currentPage: 1,
        projectId: null,
        processDefId: null,
        processInsId: null,
        deployId: null,
        processName: '' // 流程名称
      }
    }
  },
  mounted() {
    console.log(this.$route.query, "参数")
    let params = JSON.parse(sessionStorage.getItem("projectProDetail"))
    console.log(params, "参数")
    if (!params || ! params.projectId) {
      this.queryParams.projectId = this.$route.query.projectId
      this.queryParams.processDefId = this.$route.query.processDefId
      this.queryParams.processInsId = this.$route.query.processInsId
      this.queryParams.deployId = this.$route.query.deployId
      this.queryParams.processName = this.$route.query.processName
      sessionStorage.setItem("projectProDetail", JSON.stringify(this.queryParams))
    } else {
@@ -163,6 +252,43 @@
    this.getProjectProcessInfo()
  },
  methods: {
    setIcon(val) {
      if (val) {
        return "el-icon-check";
      } else {
        return "el-icon-time";
      }
    },
    setColor(val) {
      if (val) {
        return "#2bc418";
      } else {
        return "#b3bdbb";
      }
    },
    openRecord() {
      this.getFlowRecordList(this.queryParams.processInsId);
    },
    openProcessImg() {
      this.imgLoading = true
      flowXmlAndNode({processInsId:this.queryParams.processInsId,deployId:this.queryParams.deployId}).then(res => {
        this.imgLoading = false
        this.processImgShow = true
        this.$nextTick(() => {
          this.flowData = res.data;
        })
      })
    },
    /** 流程流转记录 */
    getFlowRecordList(procInsId) {
      const params = {procInsId: procInsId}
      this.recordLoading = true
      flowRecord(params).then(res => {
        this.flowRecordList = res.data.flowList;
        this.recordLoading = false
        this.processRecordShow = true
      })
    },
    unitFormatter(row) {
      if (row.handlerType === 'USER') {
        return null;
@@ -186,7 +312,7 @@
      if (row.taskStatus !== '已完成') {
        return null
      } else {
        return row.handlerName
        return row.actualHandlerUserName
      }
    },
    showHandle(row) {
@@ -199,7 +325,7 @@
          return row.handlerUnitId.indexOf(this.$store.state.user.deptId) !== -1
          // return this.$store.state.user.name === '市发展改革委' || this.$store.state.user.name === '市住建局'
        } else if (row.handlerType === "ROLE") {
          return this.$auth.hasRole(row.handlerUnitName)
          return row.handlerUnitId.some(roleId => this.$store.state.user.roleIds.indexOf(roleId) !== -1)
        }
      } else {
        return false
@@ -256,11 +382,12 @@
      this.getList()
    },
    getList() {
      this.tableLoading = true
      // 获取任务列表
      getProjectProcessDetailTaskList(this.queryParams).then(res => {
        this.tableLoading =false
        this.taskList = res.data
        this.total = res.total
        this.tableLoading =false
      })
    },
    // 查询详情
@@ -273,14 +400,12 @@
      })
    },
    changeTab(id, event) {
      this.tableLoading = true
      let beforeId = this.selectTabId
      this.selectTabId = id
      this.queryParams.taskType = event
      if (beforeId !== id) {
        this.getList()
      }
    }
  }
}
src/views/projectProcess/index.vue
@@ -399,6 +399,8 @@
        query: {
          projectId: row.id,
          processDefId: row.processDefId,
          processInsId: row.processInsId,
          deployId: row.deployId,
          processName: row.flowableProcessName
        }
      })