Commit c660991e29a48ca2acc6a91a4f8a207e013e894a

Authored by ww
1 parent 4c866a48

feat: 设备列表新增批量分配按钮

... ... @@ -15,6 +15,7 @@
15 15 "SNMP",
16 16 "unref",
17 17 "vben",
18   - "VITE"
  18 + "VITE",
  19 + "windicss"
19 20 ]
20 21 }
... ...
... ... @@ -48,6 +48,8 @@ export interface DeviceModel {
48 48 label: string;
49 49 lastConnectTime: string;
50 50 deviceType: DeviceTypeEnum;
  51 + organizationId: string;
  52 + customerId?: string;
51 53 }
52 54
53 55 export interface DeviceProfileModel {
... ...
  1 +import { computed } from 'vue';
  2 +import { TableActionType } from '/@//components/Table';
  3 +
  4 +const useBatchOperation = (
  5 + getRowSelection: TableActionType['getRowSelection'],
  6 + setSelectedRowKeys: TableActionType['setSelectedRowKeys']
  7 +) => {
  8 + const isExistOption = computed(() => {
  9 + const rowSelection = getRowSelection();
  10 + return !!rowSelection.selectedRowKeys?.length;
  11 + });
  12 +
  13 + const resetSelectedOptions = () => {
  14 + setSelectedRowKeys([]);
  15 + };
  16 +
  17 + return {
  18 + isExistOption,
  19 + resetSelectedOptions,
  20 + };
  21 +};
  22 +
  23 +export { useBatchOperation };
... ...
... ... @@ -20,6 +20,8 @@
20 20 import { BasicForm, useForm } from '/@/components/Form';
21 21 import { customerForm } from '../../config/detail.config';
22 22 import { dispatchCustomer as dispatchCustomerApi } from '/@/api/device/deviceManager';
  23 + import { DeviceModel } from '/@/api/device/model/deviceModel';
  24 + import { isArray } from '/@/utils/is';
23 25 export default defineComponent({
24 26 name: 'AlarmDetailModal',
25 27 components: {
... ... @@ -28,9 +30,10 @@
28 30 },
29 31 emits: ['reload', 'register'],
30 32 setup(_, { emit }) {
31   - let record = {};
32   - const [registerModal, { closeModal }] = useModalInner((data: any) => {
33   - const { organizationId } = data;
  33 + let record: DeviceModel[] = [];
  34 + const [registerModal, { closeModal }] = useModalInner((data: DeviceModel | DeviceModel[]) => {
  35 + data = isArray(data) ? data : [data as DeviceModel];
  36 + const { organizationId } = data.at(0) || {};
34 37 record = data;
35 38 updateSchema([
36 39 {
... ... @@ -50,7 +53,11 @@
50 53 const dispatchCustomer = async () => {
51 54 await validate();
52 55 const { customerId } = getFieldsValue();
53   - await dispatchCustomerApi({ ...record, customerId });
  56 + const task: Promise<any>[] = [];
  57 + for await (const item of record) {
  58 + task.push(dispatchCustomerApi({ ...item, customerId }));
  59 + }
  60 + await Promise.all(task);
54 61 closeModal();
55 62 resetFields();
56 63 emit('reload');
... ...
... ... @@ -14,13 +14,21 @@
14 14 title="您确定要批量删除数据"
15 15 ok-text="确定"
16 16 cancel-text="取消"
17   - @confirm="handleDeleteOrBatchDelete(null)"
  17 + @confirm="handleDelete()"
18 18 >
19   - <a-button color="error" v-if="authBtn(role)" :disabled="hasBatchDelete">
  19 + <a-button color="error" v-if="authBtn(role)" :disabled="!isExistOption">
20 20 批量删除
21 21 </a-button>
22 22 </Popconfirm>
23 23 </Authority>
  24 + <a-button
  25 + v-if="authBtn(role)"
  26 + type="primary"
  27 + @click="handleBatchAssign"
  28 + :disabled="!isExistOption"
  29 + >
  30 + 批量分配
  31 + </a-button>
24 32 </template>
25 33 <template #img="{ record }">
26 34 <TableImg
... ... @@ -147,7 +155,7 @@
147 155 color: 'error',
148 156 popConfirm: {
149 157 title: '是否确认删除',
150   - confirm: handleDeleteOrBatchDelete.bind(null, record),
  158 + confirm: handleDelete.bind(null, record),
151 159 },
152 160 },
153 161 ]"
... ... @@ -170,7 +178,12 @@
170 178 </template>
171 179 <script lang="ts">
172 180 import { defineComponent, reactive, unref, nextTick, h, onUnmounted, ref } from 'vue';
173   - import { DeviceState, DeviceTypeEnum } from '/@/api/device/model/deviceModel';
  181 + import {
  182 + DeviceModel,
  183 + DeviceRecord,
  184 + DeviceState,
  185 + DeviceTypeEnum,
  186 + } from '/@/api/device/model/deviceModel';
174 187 import { BasicTable, useTable, TableAction, TableImg } from '/@/components/Table';
175 188 import { columns, searchFormSchema } from './config/device.data';
176 189 import { Tag, Tooltip, Popover, Popconfirm } from 'ant-design-vue';
... ... @@ -194,11 +207,11 @@
194 207 import { USER_INFO_KEY } from '/@/enums/cacheEnum';
195 208 import { getAuthCache } from '/@/utils/auth';
196 209 import { authBtn } from '/@/enums/roleEnum';
197   - import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
198 210 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
199 211 import { QuestionCircleOutlined } from '@ant-design/icons-vue';
200 212 import { Authority } from '/@/components/Authority';
201 213 import { useRouter } from 'vue-router';
  214 + import { useBatchOperation } from '/@/utils/useBatchOperation';
202 215
203 216 export default defineComponent({
204 217 name: 'DeviceManagement',
... ... @@ -233,7 +246,17 @@
233 246
234 247 const [
235 248 registerTable,
236   - { reload, setSelectedRowKeys, setProps, setTableData, getForm, setPagination },
  249 + {
  250 + reload,
  251 + setLoading,
  252 + setSelectedRowKeys,
  253 + setTableData,
  254 + getForm,
  255 + setPagination,
  256 + getSelectRowKeys,
  257 + getSelectRows,
  258 + getRowSelection,
  259 + },
237 260 ] = useTable({
238 261 title: '设备列表',
239 262 api: devicePage,
... ... @@ -241,7 +264,6 @@
241 264 columns,
242 265 beforeFetch: (params) => {
243 266 const { deviceProfileId } = params;
244   - console.log(deviceProfileId);
245 267 const obj = {
246 268 ...params,
247 269 ...{
... ... @@ -272,21 +294,16 @@
272 294 slots: { customRender: 'action' },
273 295 fixed: 'right',
274 296 },
275   - });
276   - const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =
277   - useBatchDelete(deleteDevice, handleSuccess, setProps);
278   - selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
279   - // Demo:status为1的选择框禁用
280   - if (record.customerId) {
281   - return { disabled: true };
282   - } else {
283   - return { disabled: false };
284   - }
285   - };
286   - nextTick(() => {
287   - setProps(selectionOptions);
  297 + rowSelection: {
  298 + type: 'checkbox',
  299 + getCheckboxProps: (record: DeviceModel) => {
  300 + return { disabled: !!record.customerId };
  301 + },
  302 + },
288 303 });
289 304
  305 + const { isExistOption } = useBatchOperation(getRowSelection, setSelectedRowKeys);
  306 +
290 307 function getParams(keyword) {
291 308 const reg = new RegExp('(^|&)' + keyword + '=([^&]*)(&|$)', 'i');
292 309 const r = window.location.search.substr(1).match(reg);
... ... @@ -349,7 +366,6 @@
349 366 }
350 367 function handleReload() {
351 368 setSelectedRowKeys([]);
352   - resetSelectedRowKeys();
353 369 handleSuccess();
354 370 }
355 371 // 取消分配客户
... ... @@ -419,6 +435,48 @@
419 435 });
420 436 };
421 437
  438 + const handleCheckHasDiffenterOrg = (options: DeviceModel[]) => {
  439 + let orgId: string | undefined;
  440 + let flag = false;
  441 + for (const item of options) {
  442 + const _orgId = item.organizationId;
  443 + if (!orgId) orgId = _orgId;
  444 + if (orgId !== _orgId) {
  445 + flag = true;
  446 + break;
  447 + }
  448 + }
  449 + return flag;
  450 + };
  451 +
  452 + const handleBatchAssign = () => {
  453 + const options = getSelectRows();
  454 + if (handleCheckHasDiffenterOrg(options)) {
  455 + createMessage.error('当前选中项中存在不同所属组织的设备!');
  456 + return;
  457 + }
  458 + openCustomerModal(true, options);
  459 + };
  460 +
  461 + const handleDelete = async (record?: DeviceRecord) => {
  462 + let ids: string[] = [];
  463 + if (record) {
  464 + ids.push(record.id);
  465 + } else {
  466 + ids = getSelectRowKeys();
  467 + }
  468 + try {
  469 + setLoading(true);
  470 + await deleteDevice(ids);
  471 + createMessage.success('删除成功');
  472 + handleReload();
  473 + } catch (error) {
  474 + createMessage.error('删除失败');
  475 + } finally {
  476 + setLoading(false);
  477 + }
  478 + };
  479 +
422 480 return {
423 481 registerTable,
424 482 handleCreate,
... ... @@ -439,14 +497,17 @@
439 497 authBtn,
440 498 role,
441 499 copySN,
442   - hasBatchDelete,
443   - handleDeleteOrBatchDelete,
  500 + isExistOption,
  501 + handleDelete,
  502 + // hasBatchDelete,
  503 + // handleDeleteOrBatchDelete,
444 504 handleReload,
445 505 registerTbDetailDrawer,
446 506 handleOpenTbDeviceDetail,
447 507 handleOpenGatewayDetail,
448 508 registerGatewayDetailDrawer,
449 509 handleUpAndDownRecord,
  510 + handleBatchAssign,
450 511 };
451 512 },
452 513 });
... ...
... ... @@ -260,6 +260,8 @@
260 260 }
261 261 };
262 262 const setClientProperties = (record: Recordable) => {
  263 + const type = Reflect.get(record, 'type');
  264 + if (type === 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode') return;
263 265 const configuration = Reflect.get(record, 'configuration');
264 266 const clientProperties = Reflect.get(configuration, 'clientProperties');
265 267 !clientProperties && record.configuration && (record.configuration.clientProperties = {});
... ...