| 
@@ -6,20 +6,14 @@ | 
 | 
@@ -6,20 +6,14 @@ | 
| 
6
 | 
         @select="handleSelect"
 | 
6
 | 
         @select="handleSelect"
 | 
| 
7
 | 
         ref="organizationIdTreeRef"
 | 
7
 | 
         ref="organizationIdTreeRef"
 | 
| 
8
 | 
       />
 | 
8
 | 
       />
 | 
| 
9
 | 
-      <BasicTable
 | 
 | 
   | 
| 
10
 | 
-        @selection-change="useSelectionChange"
 | 
 | 
   | 
| 
11
 | 
-        :rowSelection="{ type: 'checkbox' }"
 | 
 | 
   | 
| 
12
 | 
-        @register="registerTable"
 | 
 | 
   | 
| 
13
 | 
-        class="w-5/6 xl:w-4/5"
 | 
 | 
   | 
| 
14
 | 
-        :clickToRowSelect="false"
 | 
 | 
   | 
| 
15
 | 
-      >
 | 
9
 | 
+      <BasicTable @register="registerTable" class="w-5/6 xl:w-4/5">
 | 
| 
16
 | 
         <template #toolbar>
 | 
10
 | 
         <template #toolbar>
 | 
| 
17
 | 
           <a-button type="primary" @click="handleCreate" v-if="authBtn(role)"> 新增设备 </a-button>
 | 
11
 | 
           <a-button type="primary" @click="handleCreate" v-if="authBtn(role)"> 新增设备 </a-button>
 | 
| 
18
 | 
           <a-button
 | 
12
 | 
           <a-button
 | 
| 
19
 | 
             color="error"
 | 
13
 | 
             color="error"
 | 
| 
20
 | 
             v-if="authBtn(role)"
 | 
14
 | 
             v-if="authBtn(role)"
 | 
| 
21
 | 
             @click="handleDeleteOrBatchDelete(null)"
 | 
15
 | 
             @click="handleDeleteOrBatchDelete(null)"
 | 
| 
22
 | 
-            :disabled="disabled"
 | 
16
 | 
+            :disabled="hasBatchDelete"
 | 
| 
23
 | 
           >
 | 
17
 | 
           >
 | 
| 
24
 | 
             批量删除
 | 
18
 | 
             批量删除
 | 
| 
25
 | 
           </a-button>
 | 
19
 | 
           </a-button>
 | 
 | 
@@ -38,6 +32,31 @@ | 
 | 
@@ -38,6 +32,31 @@ | 
| 
38
 | 
             "
 | 
32
 | 
             "
 | 
| 
39
 | 
           />
 | 
33
 | 
           />
 | 
| 
40
 | 
         </template>
 | 
34
 | 
         </template>
 | 
| 
 | 
   | 
35
 | 
+        <template #deviceTitle>
 | 
| 
 | 
   | 
36
 | 
+          <div>
 | 
| 
 | 
   | 
37
 | 
+            <span> 设备名称/设备SN</span>
 | 
| 
 | 
   | 
38
 | 
+            <Popover title="帮助" placement="right">
 | 
| 
 | 
   | 
39
 | 
+              <QuestionCircleOutlined class="ml-2" />
 | 
| 
 | 
   | 
40
 | 
+              <template #content>
 | 
| 
 | 
   | 
41
 | 
+                <ul>
 | 
| 
 | 
   | 
42
 | 
+                  <li>1.设备的SN码,为平台的唯一编码,对通过Modbus协议上报数据的设备,</li>
 | 
| 
 | 
   | 
43
 | 
+                  <li>   平台将通过设备SN进行鉴定.</li>
 | 
| 
 | 
   | 
44
 | 
+                  <li>2.为了方便使用,设备SN可以点击复制.</li>
 | 
| 
 | 
   | 
45
 | 
+                </ul>
 | 
| 
 | 
   | 
46
 | 
+              </template>
 | 
| 
 | 
   | 
47
 | 
+            </Popover>
 | 
| 
 | 
   | 
48
 | 
+          </div>
 | 
| 
 | 
   | 
49
 | 
+        </template>
 | 
| 
 | 
   | 
50
 | 
+        <template #name="{ record }">
 | 
| 
 | 
   | 
51
 | 
+          <div>
 | 
| 
 | 
   | 
52
 | 
+            {{ record.name }}
 | 
| 
 | 
   | 
53
 | 
+          </div>
 | 
| 
 | 
   | 
54
 | 
+          <Tooltip title="设备SN码" placement="topRight">
 | 
| 
 | 
   | 
55
 | 
+            <a-button type="link" @click="copySN(record.sn)" style="padding: 0">
 | 
| 
 | 
   | 
56
 | 
+              {{ record.sn }}
 | 
| 
 | 
   | 
57
 | 
+            </a-button>
 | 
| 
 | 
   | 
58
 | 
+          </Tooltip>
 | 
| 
 | 
   | 
59
 | 
+        </template>
 | 
| 
41
 | 
         <template #deviceProfile="{ record }">
 | 
60
 | 
         <template #deviceProfile="{ record }">
 | 
| 
42
 | 
           <a-button type="link" class="ml-2" @click="goDeviceProfile(record.deviceProfile.name)">
 | 
61
 | 
           <a-button type="link" class="ml-2" @click="goDeviceProfile(record.deviceProfile.name)">
 | 
| 
43
 | 
             {{ record.deviceProfile.name }}
 | 
62
 | 
             {{ record.deviceProfile.name }}
 | 
 | 
@@ -122,16 +141,16 @@ | 
 | 
@@ -122,16 +141,16 @@ | 
| 
122
 | 
       </BasicTable>
 | 
141
 | 
       </BasicTable>
 | 
| 
123
 | 
       <DeviceDetailDrawer @register="registerDetailDrawer" />
 | 
142
 | 
       <DeviceDetailDrawer @register="registerDetailDrawer" />
 | 
| 
124
 | 
       <DeviceModal @register="registerModal" @success="handleSuccess" @reload="handleSuccess" />
 | 
143
 | 
       <DeviceModal @register="registerModal" @success="handleSuccess" @reload="handleSuccess" />
 | 
| 
125
 | 
-      <CustomerModal @register="registerCustomerModal" @reload="handleSuccess" />
 | 
144
 | 
+      <CustomerModal @register="registerCustomerModal" @reload="handleReload" />
 | 
| 
126
 | 
     </PageWrapper>
 | 
145
 | 
     </PageWrapper>
 | 
| 
127
 | 
   </div>
 | 
146
 | 
   </div>
 | 
| 
128
 | 
 </template>
 | 
147
 | 
 </template>
 | 
| 
129
 | 
 <script lang="ts">
 | 
148
 | 
 <script lang="ts">
 | 
| 
130
 | 
-  import { defineComponent, reactive, ref } from 'vue';
 | 
149
 | 
+  import { defineComponent, reactive, unref } from 'vue';
 | 
| 
131
 | 
   import { DeviceState, DeviceTypeEnum } from '/@/api/device/model/deviceModel';
 | 
150
 | 
   import { DeviceState, DeviceTypeEnum } from '/@/api/device/model/deviceModel';
 | 
| 
132
 | 
   import { BasicTable, useTable, TableAction, TableImg } from '/@/components/Table';
 | 
151
 | 
   import { BasicTable, useTable, TableAction, TableImg } from '/@/components/Table';
 | 
| 
133
 | 
   import { columns, searchFormSchema } from './config/device.data';
 | 
152
 | 
   import { columns, searchFormSchema } from './config/device.data';
 | 
| 
134
 | 
-  import { Tag } from 'ant-design-vue';
 | 
153
 | 
+  import { Tag, Tooltip, Popover } from 'ant-design-vue';
 | 
| 
135
 | 
   import {
 | 
154
 | 
   import {
 | 
| 
136
 | 
     deleteDevice,
 | 
155
 | 
     deleteDevice,
 | 
| 
137
 | 
     devicePage,
 | 
156
 | 
     devicePage,
 | 
 | 
@@ -151,7 +170,9 @@ | 
 | 
@@ -151,7 +170,9 @@ | 
| 
151
 | 
   import { USER_INFO_KEY } from '/@/enums/cacheEnum';
 | 
170
 | 
   import { USER_INFO_KEY } from '/@/enums/cacheEnum';
 | 
| 
152
 | 
   import { getAuthCache } from '/@/utils/auth';
 | 
171
 | 
   import { getAuthCache } from '/@/utils/auth';
 | 
| 
153
 | 
   import { authBtn } from '/@/enums/roleEnum';
 | 
172
 | 
   import { authBtn } from '/@/enums/roleEnum';
 | 
| 
154
 | 
-
 | 
173
 | 
+  import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
 | 
| 
 | 
   | 
174
 | 
+  import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
 | 
| 
 | 
   | 
175
 | 
+  import { QuestionCircleOutlined } from '@ant-design/icons-vue';
 | 
| 
155
 | 
   export default defineComponent({
 | 
176
 | 
   export default defineComponent({
 | 
| 
156
 | 
     name: 'DeviceManagement',
 | 
177
 | 
     name: 'DeviceManagement',
 | 
| 
157
 | 
     components: {
 | 
178
 | 
     components: {
 | 
 | 
@@ -164,18 +185,30 @@ | 
 | 
@@ -164,18 +185,30 @@ | 
| 
164
 | 
       DeviceDetailDrawer,
 | 
185
 | 
       DeviceDetailDrawer,
 | 
| 
165
 | 
       CustomerModal,
 | 
186
 | 
       CustomerModal,
 | 
| 
166
 | 
       TableImg,
 | 
187
 | 
       TableImg,
 | 
| 
 | 
   | 
188
 | 
+      Tooltip,
 | 
| 
 | 
   | 
189
 | 
+      QuestionCircleOutlined,
 | 
| 
 | 
   | 
190
 | 
+      Popover,
 | 
| 
167
 | 
     },
 | 
191
 | 
     },
 | 
| 
168
 | 
     setup(_) {
 | 
192
 | 
     setup(_) {
 | 
| 
 | 
   | 
193
 | 
+      const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =
 | 
| 
 | 
   | 
194
 | 
+        useBatchDelete(deleteDevice, handleSuccess);
 | 
| 
 | 
   | 
195
 | 
+      selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
 | 
| 
 | 
   | 
196
 | 
+        // Demo:status为1的选择框禁用
 | 
| 
 | 
   | 
197
 | 
+        if (record.customerId) {
 | 
| 
 | 
   | 
198
 | 
+          return { disabled: true };
 | 
| 
 | 
   | 
199
 | 
+        } else {
 | 
| 
 | 
   | 
200
 | 
+          return { disabled: false };
 | 
| 
 | 
   | 
201
 | 
+        }
 | 
| 
 | 
   | 
202
 | 
+      };
 | 
| 
 | 
   | 
203
 | 
+
 | 
| 
169
 | 
       const { createMessage } = useMessage();
 | 
204
 | 
       const { createMessage } = useMessage();
 | 
| 
170
 | 
-      let selectedRowKeys: any = [];
 | 
 | 
   | 
| 
171
 | 
-      const disabled = ref(true);
 | 
 | 
   | 
| 
172
 | 
       const go = useGo();
 | 
205
 | 
       const go = useGo();
 | 
| 
173
 | 
       const searchInfo = reactive<Recordable>({});
 | 
206
 | 
       const searchInfo = reactive<Recordable>({});
 | 
| 
174
 | 
       const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
 | 
207
 | 
       const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
 | 
| 
175
 | 
       const [registerModal, { openModal }] = useModal();
 | 
208
 | 
       const [registerModal, { openModal }] = useModal();
 | 
| 
176
 | 
       const [registerCustomerModal, { openModal: openCustomerModal }] = useModal();
 | 
209
 | 
       const [registerCustomerModal, { openModal: openCustomerModal }] = useModal();
 | 
| 
177
 | 
       const [registerDetailDrawer, { openDrawer }] = useDrawer();
 | 
210
 | 
       const [registerDetailDrawer, { openDrawer }] = useDrawer();
 | 
| 
178
 | 
-      const [registerTable, { reload, getSelectRows, getSelectRowKeys }] = useTable({
 | 
211
 | 
+      const [registerTable, { reload, setSelectedRowKeys }] = useTable({
 | 
| 
179
 | 
         title: '设备列表',
 | 
212
 | 
         title: '设备列表',
 | 
| 
180
 | 
         api: devicePage,
 | 
213
 | 
         api: devicePage,
 | 
| 
181
 | 
         columns,
 | 
214
 | 
         columns,
 | 
 | 
@@ -190,12 +223,14 @@ | 
 | 
@@ -190,12 +223,14 @@ | 
| 
190
 | 
         showIndexColumn: false,
 | 
223
 | 
         showIndexColumn: false,
 | 
| 
191
 | 
         rowKey: 'id',
 | 
224
 | 
         rowKey: 'id',
 | 
| 
192
 | 
         searchInfo: searchInfo,
 | 
225
 | 
         searchInfo: searchInfo,
 | 
| 
 | 
   | 
226
 | 
+        clickToRowSelect: false,
 | 
| 
193
 | 
         actionColumn: {
 | 
227
 | 
         actionColumn: {
 | 
| 
194
 | 
           width: 300,
 | 
228
 | 
           width: 300,
 | 
| 
195
 | 
           title: '操作',
 | 
229
 | 
           title: '操作',
 | 
| 
196
 | 
           slots: { customRender: 'action' },
 | 
230
 | 
           slots: { customRender: 'action' },
 | 
| 
197
 | 
           fixed: 'right',
 | 
231
 | 
           fixed: 'right',
 | 
| 
198
 | 
         },
 | 
232
 | 
         },
 | 
| 
 | 
   | 
233
 | 
+        ...selectionOptions,
 | 
| 
199
 | 
       });
 | 
234
 | 
       });
 | 
| 
200
 | 
 
 | 
235
 | 
 
 | 
| 
201
 | 
       const userInfo: any = getAuthCache(USER_INFO_KEY);
 | 
236
 | 
       const userInfo: any = getAuthCache(USER_INFO_KEY);
 | 
 | 
@@ -210,10 +245,15 @@ | 
 | 
@@ -210,10 +245,15 @@ | 
| 
210
 | 
       function handleDispatchCustomer(record: Recordable) {
 | 
245
 | 
       function handleDispatchCustomer(record: Recordable) {
 | 
| 
211
 | 
         openCustomerModal(true, record);
 | 
246
 | 
         openCustomerModal(true, record);
 | 
| 
212
 | 
       }
 | 
247
 | 
       }
 | 
| 
 | 
   | 
248
 | 
+      function handleReload() {
 | 
| 
 | 
   | 
249
 | 
+        setSelectedRowKeys([]);
 | 
| 
 | 
   | 
250
 | 
+        resetSelectedRowKeys();
 | 
| 
 | 
   | 
251
 | 
+        handleSuccess();
 | 
| 
 | 
   | 
252
 | 
+      }
 | 
| 
213
 | 
       // 取消分配客户
 | 
253
 | 
       // 取消分配客户
 | 
| 
214
 | 
       async function handleCancelDispatchCustomer(record: Recordable) {
 | 
254
 | 
       async function handleCancelDispatchCustomer(record: Recordable) {
 | 
| 
215
 | 
         await cancelDispatchCustomer(record);
 | 
255
 | 
         await cancelDispatchCustomer(record);
 | 
| 
216
 | 
-        handleSuccess();
 | 
256
 | 
+        handleReload();
 | 
| 
217
 | 
       }
 | 
257
 | 
       }
 | 
| 
218
 | 
 
 | 
258
 | 
 
 | 
| 
219
 | 
       function handleDetail(record: Recordable) {
 | 
259
 | 
       function handleDetail(record: Recordable) {
 | 
 | 
@@ -244,42 +284,11 @@ | 
 | 
@@ -244,42 +284,11 @@ | 
| 
244
 | 
       function goDeviceProfile(e) {
 | 
284
 | 
       function goDeviceProfile(e) {
 | 
| 
245
 | 
         go(PageEnum.DEVICE_PROFILE + '?name=' + String(e));
 | 
285
 | 
         go(PageEnum.DEVICE_PROFILE + '?name=' + String(e));
 | 
| 
246
 | 
       }
 | 
286
 | 
       }
 | 
| 
247
 | 
-      const useSelectionChange = () => {
 | 
 | 
   | 
| 
248
 | 
-        selectedRowKeys = getSelectRowKeys();
 | 
 | 
   | 
| 
249
 | 
-        if (selectedRowKeys.length > 0) {
 | 
 | 
   | 
| 
250
 | 
-          disabled.value = false;
 | 
 | 
   | 
| 
251
 | 
-        }
 | 
 | 
   | 
| 
252
 | 
-        const isJudge = getSelectRows().map((m) => {
 | 
 | 
   | 
| 
253
 | 
-          return {
 | 
 | 
   | 
| 
254
 | 
-            status: m.customerId,
 | 
 | 
   | 
| 
255
 | 
-            id: m.id,
 | 
 | 
   | 
| 
256
 | 
-          };
 | 
 | 
   | 
| 
257
 | 
-        });
 | 
 | 
   | 
| 
258
 | 
-        isJudge.some((s) => {
 | 
 | 
   | 
| 
259
 | 
-          if (s.status != undefined) {
 | 
 | 
   | 
| 
260
 | 
-            disabled.value = true;
 | 
 | 
   | 
| 
261
 | 
-          }
 | 
 | 
   | 
| 
262
 | 
-        });
 | 
 | 
   | 
| 
263
 | 
-      };
 | 
 | 
   | 
| 
264
 | 
-      // 删除或批量删除
 | 
 | 
   | 
| 
265
 | 
-      const handleDeleteOrBatchDelete = async (record: Recordable | null) => {
 | 
 | 
   | 
| 
266
 | 
-        if (record) {
 | 
 | 
   | 
| 
267
 | 
-          try {
 | 
 | 
   | 
| 
268
 | 
-            await deleteDevice([record.id]);
 | 
 | 
   | 
| 
269
 | 
-            createMessage.success('删除成功');
 | 
 | 
   | 
| 
270
 | 
-            handleSuccess();
 | 
 | 
   | 
| 
271
 | 
-          } catch (e: any) {}
 | 
 | 
   | 
| 
272
 | 
-        } else {
 | 
 | 
   | 
| 
273
 | 
-          try {
 | 
 | 
   | 
| 
274
 | 
-            await deleteDevice(selectedRowKeys);
 | 
 | 
   | 
| 
275
 | 
-            createMessage.success('批量删除成功');
 | 
 | 
   | 
| 
276
 | 
-            handleSuccess();
 | 
 | 
   | 
| 
277
 | 
-            selectedRowKeys.length = 0;
 | 
 | 
   | 
| 
278
 | 
-          } catch (e: any) {
 | 
 | 
   | 
| 
279
 | 
-            selectedRowKeys.length = 0;
 | 
 | 
   | 
| 
280
 | 
-          } finally {
 | 
 | 
   | 
| 
281
 | 
-            selectedRowKeys.length = 0;
 | 
 | 
   | 
| 
282
 | 
-          }
 | 
287
 | 
+      const { clipboardRef } = useCopyToClipboard();
 | 
| 
 | 
   | 
288
 | 
+      const copySN = (snCode: string) => {
 | 
| 
 | 
   | 
289
 | 
+        clipboardRef.value = snCode;
 | 
| 
 | 
   | 
290
 | 
+        if (unref(clipboardRef)) {
 | 
| 
 | 
   | 
291
 | 
+          createMessage.success('复制成功~');
 | 
| 
283
 | 
         }
 | 
292
 | 
         }
 | 
| 
284
 | 
       };
 | 
293
 | 
       };
 | 
| 
285
 | 
 
 | 
294
 | 
 
 | 
 | 
@@ -302,9 +311,10 @@ | 
 | 
@@ -302,9 +311,10 @@ | 
| 
302
 | 
         registerCustomerModal,
 | 
311
 | 
         registerCustomerModal,
 | 
| 
303
 | 
         authBtn,
 | 
312
 | 
         authBtn,
 | 
| 
304
 | 
         role,
 | 
313
 | 
         role,
 | 
| 
 | 
   | 
314
 | 
+        copySN,
 | 
| 
 | 
   | 
315
 | 
+        hasBatchDelete,
 | 
| 
305
 | 
         handleDeleteOrBatchDelete,
 | 
316
 | 
         handleDeleteOrBatchDelete,
 | 
| 
306
 | 
-        disabled,
 | 
 | 
   | 
| 
307
 | 
-        useSelectionChange,
 | 
317
 | 
+        handleReload,
 | 
| 
308
 | 
       };
 | 
318
 | 
       };
 | 
| 
309
 | 
     },
 | 
319
 | 
     },
 | 
| 
310
 | 
   });
 | 
320
 | 
   });
 |