From 92610ba4eedbc06062240c2f2967b7e1f691797e Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期二, 02 九月 2025 12:24:55 +0800
Subject: [PATCH] 补全设备匹配功能

---
 src/views/fysp/config/device/CompDeviceMatchEdit.vue |  163 +++++++++++++++++++++++++-
 src/views/fysp/config/DeviceMatch.vue                |   71 ++++++++++-
 src/components/list-item/ItemDevice.vue              |   38 ++++++
 src/main.js                                          |    5 
 src/components.d.ts                                  |    1 
 src/components/core/SiderMenu.vue                    |    2 
 src/api/fysp/userMapApi.js                           |   17 ++
 src/api/fysp/userApi.js                              |   12 +
 8 files changed, 288 insertions(+), 21 deletions(-)

diff --git a/src/api/fysp/userApi.js b/src/api/fysp/userApi.js
index bb6f58c..c3ae743 100644
--- a/src/api/fysp/userApi.js
+++ b/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);
   },
   /**
    * 鑾峰彇鍦烘櫙瀵瑰簲鐨勯缇界幆澧冪郴缁熺敤鎴穒d
@@ -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);
   }
 };
diff --git a/src/api/fysp/userMapApi.js b/src/api/fysp/userMapApi.js
index 57d107a..ac63ae8 100644
--- a/src/api/fysp/userMapApi.js
+++ b/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);
   }
 };
diff --git a/src/components.d.ts b/src/components.d.ts
index 19bc486..15e5c5a 100644
--- a/src/components.d.ts
+++ b/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']
diff --git a/src/components/core/SiderMenu.vue b/src/components/core/SiderMenu.vue
index 162fc70..6419154 100644
--- a/src/components/core/SiderMenu.vue
+++ b/src/components/core/SiderMenu.vue
@@ -84,7 +84,7 @@
       sysNames: [
         { name: '椋炵窘鐩戠', des: '' },
         { name: '椋炵窘鐜', des: '' },
-        { name: '鎺掓薄鎶借繍', des: '' }
+        // { name: '鎺掓薄鎶借繍', des: '' }
       ]
     };
   },
diff --git a/src/components/list-item/ItemDevice.vue b/src/components/list-item/ItemDevice.vue
new file mode 100644
index 0000000..e1b77e7
--- /dev/null
+++ b/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>
diff --git a/src/main.js b/src/main.js
index 6f7f655..ceb52d6 100644
--- a/src/main.js
+++ b/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);
diff --git a/src/views/fysp/config/DeviceMatch.vue b/src/views/fysp/config/DeviceMatch.vue
index 2bf5f74..31ce579 100644
--- a/src/views/fysp/config/DeviceMatch.vue
+++ b/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;
 }
+
+/**
+ * 鍚戠敤鎴锋坊鍔犳柊璁惧
+ * 涓嶄紶閫掍富閿甶d鍜岃澶囦俊鎭紝浠ユ琛ㄧず闇�瑕佹坊鍔犳柊鐨勮澶�
+ * @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>
diff --git a/src/views/fysp/config/device/CompDeviceMatchEdit.vue b/src/views/fysp/config/device/CompDeviceMatchEdit.vue
index ee429b8..a981b43 100644
--- a/src/views/fysp/config/device/CompDeviceMatchEdit.vue
+++ b/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;
+        });
     }
   }
 };

--
Gitblit v1.9.3