riku
2025-09-02 92610ba4eedbc06062240c2f2967b7e1f691797e
补全设备匹配功能
已修改7个文件
已添加1个文件
309 ■■■■■ 文件已修改
src/api/fysp/userApi.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fysp/userMapApi.js 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/core/SiderMenu.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/list-item/ItemDevice.vue 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/config/DeviceMatch.vue 71 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/config/device/CompDeviceMatchEdit.vue 163 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fysp/userApi.js
@@ -28,7 +28,9 @@
   * è‡ªåŠ¨åˆ›å»ºè´¦æˆ·
   */
  autoCreateAccount(sId) {
    return $fysp.post(`userinfo/create?sceneId=${sId}`, {}).then((res) => res.data);
    return $fysp
      .post(`userinfo/create?sceneId=${sId}`, {})
      .then((res) => res.data);
  },
  /**
   * èŽ·å–åœºæ™¯å¯¹åº”çš„é£žç¾½çŽ¯å¢ƒç³»ç»Ÿç”¨æˆ·id
@@ -44,5 +46,13 @@
    return $fysp
      .get(`userinfo/type/get`, { params: { typeId, enable } })
      .then((res) => res.data);
  },
  searchUser(areaVo, keyword, page, perPage) {
    return $fysp
      .post(`userinfo/search`, areaVo, {
        params: { keyword, userType: 3, page, perPage }
      })
      .then((res) => res.data);
  }
};
src/api/fysp/userMapApi.js
@@ -6,5 +6,22 @@
   */
  fetchDeviceMap(param) {
    return $fysp.post(`usermap/device`, param).then((res) => res.data);
  },
  /**
   * æœç´¢ç¬¬ä¸‰æ–¹è®¾å¤‡
   */
  searchThirdPartyDevice(areaVo, keyword, page, perPage) {
    return $fysp
      .post(`usermap/searchThirdPartyDevice`, areaVo, {
        params: { keyword, page, perPage }
      })
      .then((res) => res.data);
  },
  insertOrUpdate(areaVo, deviceMap) {
    return $fysp
      .post(`usermap/insertOrUpdate`, { first: areaVo, second: deviceMap })
      .then((res) => res.data);
  }
};
src/components.d.ts
@@ -103,6 +103,7 @@
    FYSearchBar: typeof import('./components/search-option/FYSearchBar.vue')['default']
    FYTable: typeof import('./components/table/FYTable.vue')['default']
    Header: typeof import('./components/core/Header.vue')['default']
    ItemDevice: typeof import('./components/list-item/ItemDevice.vue')['default']
    ItemMonitorObj: typeof import('./components/list-item/ItemMonitorObj.vue')['default']
    ItemScene: typeof import('./components/list-item/ItemScene.vue')['default']
    ItemSubTask: typeof import('./components/list-item/ItemSubTask.vue')['default']
src/components/core/SiderMenu.vue
@@ -84,7 +84,7 @@
      sysNames: [
        { name: '飞羽监管', des: '' },
        { name: '飞羽环境', des: '' },
        { name: '排污抽运', des: '' }
        // { name: '排污抽运', des: '' }
      ]
    };
  },
src/components/list-item/ItemDevice.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,38 @@
<template>
  <div class="wrapper">
    <div>
      <el-text>{{ item.deviceName }}</el-text>
      <el-divider direction="vertical" />
      <el-text>设备编码:{{ item.deviceCode }}</el-text>
    </div>
    <el-row justify="space-between" style="margin-top: 4px">
      <el-space>
        <el-tag type="primary" effect="plain" size="small">
          {{ item.district }}
        </el-tag>
      </el-space>
      <el-button size="small" type="success" @click="add">添加</el-button>
    </el-row>
  </div>
</template>
<script setup>
const props = defineProps({
  item: {
    type: Object,
    default: () => {}
  }
});
const emit = defineEmits(['add']);
function add() {
  emit('add', props.item);
}
</script>
<style scoped>
.wrapper {
  border: 1px solid var(--el-border-color);
  border-radius: var(--el-border-radius-base);
  padding: 4px 8px;
}
</style>
src/main.js
@@ -9,6 +9,7 @@
// import 'element-plus/dist/index.css';
import './assets/main.css';
import { ElMessageBox, ElNotification, ElMessage } from 'element-plus';
import 'element-plus/theme-chalk/src/overlay.scss';
import 'element-plus/theme-chalk/src/message.scss';
import 'element-plus/theme-chalk/src/message-box.scss';
@@ -22,6 +23,7 @@
// echarts
import * as echarts from 'echarts'
dayjs.extend(isSameOrAfter);
dayjs.extend(isSameOrBefore);
@@ -29,6 +31,9 @@
app.config.globalProperties.$fm = timeUtil;
app.config.globalProperties.$echarts = echarts
app.config.globalProperties.$message = ElMessage
app.config.globalProperties.$notification = ElNotification
app.config.globalProperties.$messageBox = ElMessageBox
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component);
src/views/fysp/config/DeviceMatch.vue
@@ -14,7 +14,11 @@
        :type="2"
        v-model:value="formSearch.scenetype"
      ></FYOptionScene>
      <FYOptionTime :initValue="false" type="month" v-model:value="formSearch.time"></FYOptionTime>
      <FYOptionTime
        :initValue="false"
        type="month"
        v-model:value="formSearch.time"
      ></FYOptionTime>
    </template>
    <template #buttons> </template>
@@ -29,7 +33,13 @@
    </template> -->
    <template #table-column>
      <el-table-column fixed="left" type="index" label="#" width="40" index="1"></el-table-column>
      <el-table-column
        fixed="left"
        type="index"
        label="#"
        width="40"
        index="1"
      ></el-table-column>
      <el-table-column
        prop="deviceCode"
        :show-overflow-tooltip="true"
@@ -37,11 +47,23 @@
        width="160"
      >
      </el-table-column>
      <el-table-column prop="deviceName" :show-overflow-tooltip="true" label="监测设备名称">
      <el-table-column
        prop="deviceName"
        :show-overflow-tooltip="true"
        label="监测设备名称"
      >
      </el-table-column>
      <el-table-column prop="svUserName" :show-overflow-tooltip="true" label="监管用户名称">
      <el-table-column
        prop="svUserName"
        :show-overflow-tooltip="true"
        label="监管用户名称"
      >
      </el-table-column>
      <el-table-column prop="tzUserName" :show-overflow-tooltip="true" label="守法自助用户名称">
      <el-table-column
        prop="tzUserName"
        :show-overflow-tooltip="true"
        label="守法自助用户名称"
      >
      </el-table-column>
      <el-table-column
        prop="createTime"
@@ -50,9 +72,18 @@
        :formatter="timeFormat"
      >
      </el-table-column>
      <el-table-column fixed="right" label="操作" width="100">
      <el-table-column fixed="right" label="操作" width="150">
        <template #default="{ row }">
          <el-button type="primary" size="small" @click="itemEdit(row)">编辑</el-button>
          <el-button
            v-show="row.deviceCode"
            type="primary"
            size="small"
            @click="itemEdit(row)"
            >编辑</el-button
          >
          <el-button type="success" size="small" @click="itemAdd(row)"
            >添加设备</el-button
          >
        </template>
      </el-table-column>
    </template>
@@ -64,7 +95,11 @@
    size="80%"
    destroy-on-close
  >
    <CompDeviceMatchEdit :data="selectedItem" :area="area"></CompDeviceMatchEdit>
    <CompDeviceMatchEdit
      :data="selectedItem"
      :area="area"
      @save="onSave"
    ></CompDeviceMatchEdit>
  </el-drawer>
</template>
<script setup>
@@ -135,4 +170,24 @@
  selectedItem.value = row;
  drawerShow.value = true;
}
/**
 * å‘用户添加新设备
 * ä¸ä¼ é€’主键id和设备信息,以此表示需要添加新的设备
 * @param row é€‰ä¸­çš„行数据
 */
function itemAdd(row) {
  selectedItem.value = {
    svUserName: row.svUserName,
    tzUserName: row.tzUserName,
    svUserId: row.svUserId,
    tzUserId: row.tzUserId
  };
  drawerShow.value = true;
}
function onSave() {
  tableRef.value.onSearch();
  drawerShow.value = false;
}
</script>
src/views/fysp/config/device/CompDeviceMatchEdit.vue
@@ -1,4 +1,9 @@
<template>
  <el-row justify="end">
    <el-button icon="check" type="success" @click="save" :loading="saveLoading"
      >保存</el-button
    >
  </el-row>
  <el-row :gutter="20">
    <el-col :span="8">
      <CompInfoSearch
@@ -11,12 +16,20 @@
          <div>
            <el-text>编号:{{ row.deviceCode }}</el-text>
          </div>
          <div>
          <el-space>
            <el-text>名称:{{ row.deviceName }}</el-text>
          </div>
            <el-button
              v-show="row.deviceName"
              type="primary"
              icon="DocumentCopy"
              text
              circle
              @click="copyDeviceName(row.deviceName)"
            />
          </el-space>
        </template>
        <template #default="{ row, click }">
          <el-text>deviceInfo</el-text>
          <ItemDevice :item="row" @add="selectDevice(row, click)" />
        </template>
      </CompInfoSearch>
    </el-col>
@@ -31,9 +44,17 @@
          <div>
            <el-text>编号:{{ row.svUserId }}</el-text>
          </div>
          <div>
          <el-space>
            <el-text>名称:{{ row.svUserName }}</el-text>
          </div>
            <el-button
              v-show="row.svUserName"
              type="primary"
              icon="DocumentCopy"
              text
              circle
              @click="copySVUser(row.svUserName)"
            />
          </el-space>
        </template>
        <template #default="{ row, click }">
          <ItemUser :item="row" @add="selectSVUser(row, click)" />
@@ -51,9 +72,17 @@
          <div>
            <el-text>编号:{{ row.tzUserId }}</el-text>
          </div>
          <div>
          <el-space>
            <el-text>名称:{{ row.tzUserName }}</el-text>
          </div>
            <el-button
              v-show="row.tzUserName"
              type="primary"
              icon="DocumentCopy"
              text
              circle
              @click="copyTZUser(row.tzUserName)"
            />
          </el-space>
        </template>
        <template #default="{ row, click }">
          <ItemUser :item="row" @add="selectTZUser(row, click)" />
@@ -68,7 +97,9 @@
import CompInfoSearch from './CompInfoSearch.vue';
import tzUserApi from '@/api/fytz/userApi';
import svUserApi from '@/api/fysp/userApi';
import userMapApi from '@/api/fysp/userMapApi';
import { svToTz } from '@/enum/scene';
import { saveAs } from 'file-saver';
export default {
  components: { CompInfoSearch },
@@ -78,6 +109,7 @@
    // æ£€ç´¢èŒƒå›´ï¼ˆåŒ…含行政区划、场景类型)
    area: Object
  },
  emits: ['save'],
  data() {
    return {
      // ç›‘测设备
@@ -85,7 +117,9 @@
      // ç›‘管用户
      svUser: {},
      // çŽ¯å¢ƒç”¨æˆ·
      tzUser: {}
      tzUser: {},
      // ä¿å­˜loading
      saveLoading: false
    };
  },
  watch: {
@@ -111,7 +145,27 @@
  },
  methods: {
    // æŸ¥è¯¢ç›‘测设备
    searchDevice() {},
    searchDevice(param, callback) {
      const { text, page, pageSize } = param;
      const { cloned: area } = useCloned(this.area);
      return userMapApi
        .searchThirdPartyDevice(area.value, text, page, pageSize)
        .then((res) => {
          if (res.success) {
            const l = res.data.map((value) => {
              return {
                deviceCode: value.mnCode,
                deviceName: value.name,
                district: area.value.districtname
              };
            });
            callback({
              data: l,
              total: res.head.totalCount
            });
          }
        });
    },
    // æŸ¥è¯¢ç›‘管用户
    searchSVUser(param, callback) {
      const { text, page, pageSize } = param;
@@ -153,7 +207,7 @@
      area.townCode = this.area.towncode;
      area.townName = this.area.townname;
      // åœºæ™¯ç±»åž‹
      const tzSceneType = svToTz(this.area.scensetypeid)
      const tzSceneType = svToTz(this.area.scensetypeid);
      area.sceneTypes = [tzSceneType.value];
      // ä¸Šä¸‹çº¿çŠ¶æ€
      area.online = this.area.online;
@@ -182,7 +236,13 @@
          callback();
        });
    },
    selectDevice() {},
    selectDevice(row, click) {
      const p = {
        deviceCode: row.deviceCode,
        deviceName: row.deviceName
      };
      click(p);
    },
    selectSVUser(row, click) {
      const p = {
        svUserId: row.guid,
@@ -196,6 +256,87 @@
        tzUserName: row.realname
      };
      click(p);
    },
    // å¤åˆ¶ç›‘管用户
    copySVUser(svUserName) {
      // ä½¿ç”¨Clipboard API将用户名称复制到剪贴板
      navigator.clipboard
        .writeText(svUserName)
        .then(() => {
          this.$message({
            message: '监管用户名称已复制到剪贴板',
            type: 'success'
          });
        })
        .catch((err) => {
          this.$message({
            message: '复制失败,请手动复制',
            type: 'error'
          });
          console.error('复制失败:', err);
        });
    },
    // å¤åˆ¶çŽ¯å¢ƒç”¨æˆ·
    copyTZUser(tzUserName) {
      // ä½¿ç”¨Clipboard API将用户名称复制到剪贴板
      navigator.clipboard
        .writeText(tzUserName)
        .then(() => {
          this.$message({
            message: '环境用户名称已复制到剪贴板',
            type: 'success'
          });
        })
        .catch((err) => {
          this.$message({
            message: '复制失败,请手动复制',
            type: 'error'
          });
          console.error('复制失败:', err);
        });
    },
    // å¤åˆ¶ç›‘测设备名称
    copyDeviceName(deviceName) {
      // ä½¿ç”¨Clipboard API将用户名称复制到剪贴板
      navigator.clipboard
        .writeText(deviceName)
        .then(() => {
          this.$message({
            message: '监测设备名称已复制到剪贴板',
            type: 'success'
          });
        })
        .catch((err) => {
          this.$message({
            message: '复制失败,请手动复制',
            type: 'error'
          });
          console.error('复制失败:', err);
        });
    },
    // ä¿å­˜
    save() {
      const deviceMap = {
        id: this.data.id,
        ...this.device,
        ...this.svUser,
        ...this.tzUser
      };
      this.saveLoading = true;
      userMapApi
        .insertOrUpdate(this.area, deviceMap)
        .then((res) => {
          if (res.success) {
            this.$message({
              message: '保存成功',
              type: 'success'
            });
            this.$emit('save', deviceMap);
          }
        })
        .finally(() => {
          this.saveLoading = false;
        });
    }
  }
};