index.vue 12.2 KB
<template>
  <div>
    <PageWrapper dense contentFullHeight contentClass="flex">
      <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" />
      <BasicTable style="flex: auto" @register="registerTable" class="w-5/6 xl:w-4/5">
        <template #toolbar>
          <Authority value="api:yt:device:post">
            <a-button type="primary" @click="handleCreate" v-if="authBtn(role)">
              新增设备
            </a-button>
          </Authority>
          <Authority value="api:yt:device:delete">
            <Popconfirm
              title="您确定要批量删除数据"
              ok-text="确定"
              cancel-text="取消"
              @confirm="handleDeleteOrBatchDelete(null)"
            >
              <a-button color="error" v-if="authBtn(role)" :disabled="hasBatchDelete">
                批量删除
              </a-button>
            </Popconfirm>
          </Authority>
        </template>
        <template #img="{ record }">
          <TableImg
            :size="30"
            :showBadge="false"
            :simpleShow="true"
            :imgList="
              typeof record?.deviceInfo?.avatar !== 'undefined' &&
              record?.deviceInfo?.avatar !== '' &&
              record?.deviceInfo?.avatar != null
                ? [record.deviceInfo.avatar]
                : null
            "
          />
        </template>
        <template #deviceTitle>
          <div>
            <span> 设备名称/设备SN</span>
            <Popover title="帮助" placement="right">
              <QuestionCircleOutlined class="ml-2" />
              <template #content>
                <ul>
                  <li>1.设备的SN码,为平台的唯一编码,对通过Modbus协议上报数据的设备,</li>
                  <li>&nbsp;&nbsp;&nbsp;平台将通过设备SN进行鉴定.</li>
                  <li>2.为了方便使用,设备SN可以点击复制.</li>
                </ul>
              </template>
            </Popover>
          </div>
        </template>
        <template #name="{ record }">
          <div>
            <Tooltip :title="record.name" placement="topRight">
              {{ record.name.slice(0, 13) }}
            </Tooltip>
          </div>
          <Tooltip title="设备SN码" placement="topRight">
            <a-button type="link" @click="copySN(record.sn)" style="padding: 0">
              {{ record.sn }}
            </a-button>
          </Tooltip>
        </template>
        <template #deviceProfile="{ record }">
          <a-button type="link" class="ml-2" @click="goDeviceProfile(record.deviceProfile.name)">
            {{ record.deviceProfile.name }}
          </a-button>
        </template>

        <template #deviceType="{ record }">
          <Tag color="success" class="ml-2">
            {{
              record.deviceType === DeviceTypeEnum.GATEWAY
                ? '网关设备'
                : record.deviceType === DeviceTypeEnum.DIRECT_CONNECTION
                ? '直连设备'
                : '网关子设备'
            }}
          </Tag>
        </template>
        <template #deviceState="{ record }">
          <Tag
            :color="
              record.deviceState == DeviceState.INACTIVE
                ? 'warning'
                : record.deviceState == DeviceState.ONLINE
                ? 'success'
                : 'error'
            "
            class="ml-2"
          >
            {{
              record.deviceState == DeviceState.INACTIVE
                ? '待激活'
                : record.deviceState == DeviceState.ONLINE
                ? '在线'
                : '离线'
            }}
          </Tag>
        </template>
        <template #action="{ record }">
          <TableAction
            :actions="[
              record.customerId
                ? {
                    label: '取消分配',
                    icon: 'mdi:account-arrow-left',
                    ifShow: authBtn(role),
                    popConfirm: {
                      title: '是否取消分配客户',
                      confirm: handleCancelDispatchCustomer.bind(null, record),
                    },
                  }
                : {
                    label: '分配客户',
                    icon: 'mdi:account-arrow-right',
                    ifShow: authBtn(role),
                    onClick: handleDispatchCustomer.bind(null, record),
                  },

              {
                label: '详情',
                icon: 'ant-design:eye-outlined',
                auth: 'api:yt:device:get',
                onClick: handleDetail.bind(null, record),
              },
              {
                label: '编辑',
                auth: 'api:yt:device:update',
                icon: 'clarity:note-edit-line',
                ifShow: authBtn(role) && record.customerId === undefined,
                onClick: handleEdit.bind(null, record),
              },
              {
                label: '删除',
                auth: 'api:yt:device:delete',
                icon: 'ant-design:delete-outlined',
                ifShow: authBtn(role) && record.customerId === undefined,
                color: 'error',
                popConfirm: {
                  title: '是否确认删除',
                  confirm: handleDeleteOrBatchDelete.bind(null, record),
                },
              },
            ]"
          />
        </template>
      </BasicTable>
      <DeviceDetailDrawer
        @register="registerDetailDrawer"
        @open-tb-device-detail="handleOpenTbDeviceDetail"
      />
      <DeviceDetailDrawer @register="registerTbDetailDrawer" />

      <DeviceModal @register="registerModal" @success="handleSuccess" @reload="handleSuccess" />
      <CustomerModal @register="registerCustomerModal" @reload="handleReload" />
    </PageWrapper>
  </div>
</template>
<script lang="ts">
  import { defineComponent, reactive, unref, nextTick, h } from 'vue';
  import { DeviceState, DeviceTypeEnum } from '/@/api/device/model/deviceModel';
  import { BasicTable, useTable, TableAction, TableImg } from '/@/components/Table';
  import { columns, searchFormSchema } from './config/device.data';
  import { Tag, Tooltip, Popover, Popconfirm } from 'ant-design-vue';
  import {
    deleteDevice,
    devicePage,
    checkDeviceOccupied,
    cancelDispatchCustomer,
    getGATEWAY,
  } from '/@/api/device/deviceManager';
  import { PageEnum } from '/@/enums/pageEnum';
  import { useGo } from '/@/hooks/web/usePage';
  import { PageWrapper } from '/@/components/Page';
  import { useModal } from '/@/components/Modal';
  import { OrganizationIdTree, useResetOrganizationTree } from '/@/views/common/organizationIdTree';
  import DeviceModal from './cpns/modal/DeviceModal.vue';
  import { useDrawer } from '/@/components/Drawer';
  import DeviceDetailDrawer from './cpns/modal/DeviceDetailDrawer.vue';
  import CustomerModal from './cpns/modal/CustomerModal.vue';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { USER_INFO_KEY } from '/@/enums/cacheEnum';
  import { getAuthCache } from '/@/utils/auth';
  import { authBtn } from '/@/enums/roleEnum';
  import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
  import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
  import { QuestionCircleOutlined } from '@ant-design/icons-vue';
  import { Authority } from '/@/components/Authority';

  export default defineComponent({
    name: 'DeviceManagement',
    components: {
      BasicTable,
      PageWrapper,
      TableAction,
      OrganizationIdTree,
      Tag,
      DeviceModal,
      DeviceDetailDrawer,
      CustomerModal,
      TableImg,
      Tooltip,
      QuestionCircleOutlined,
      Popover,
      Authority,
      Popconfirm,
    },
    setup(_) {
      const { createMessage } = useMessage();
      const go = useGo();
      const searchInfo = reactive<Recordable>({});
      const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
      const [registerModal, { openModal }] = useModal();
      const [registerCustomerModal, { openModal: openCustomerModal }] = useModal();
      const [registerDetailDrawer, { openDrawer }] = useDrawer();
      const [registerTbDetailDrawer, { openDrawer: openTbDeviceDrawer }] = useDrawer();

      const [registerTable, { reload, setSelectedRowKeys, setProps }] = useTable({
        title: '设备列表',
        api: devicePage,
        columns,
        formConfig: {
          labelWidth: 100,
          schemas: searchFormSchema,
          resetFunc: resetFn,
        },
        useSearchForm: true,
        showTableSetting: true,
        bordered: true,
        showIndexColumn: false,
        rowKey: 'id',
        searchInfo: searchInfo,
        clickToRowSelect: false,
        actionColumn: {
          width: 300,
          title: '操作',
          slots: { customRender: 'action' },
          fixed: 'right',
        },
      });
      const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions, resetSelectedRowKeys } =
        useBatchDelete(deleteDevice, handleSuccess, setProps);
      selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
        // Demo:status为1的选择框禁用
        if (record.customerId) {
          return { disabled: true };
        } else {
          return { disabled: false };
        }
      };
      nextTick(() => {
        setProps(selectionOptions);
      });

      const userInfo: any = getAuthCache(USER_INFO_KEY);
      const role: string = userInfo.roles[0];

      function handleCreate() {
        openModal(true, {
          isUpdate: false,
        });
      }
      // 分配客户
      function handleDispatchCustomer(record: Recordable) {
        openCustomerModal(true, record);
      }
      function handleReload() {
        setSelectedRowKeys([]);
        resetSelectedRowKeys();
        handleSuccess();
      }
      // 取消分配客户
      async function handleCancelDispatchCustomer(record: Recordable) {
        try {
          // 该设备是否正在被场景联动使用中?
          const isEnabled = await checkDeviceOccupied(record.id);
          if (!isEnabled.data) {
            const props = { style: { maxWidth: '600' + 'px' } };
            const small = h('small', '');
            createMessage.warn(h('h2', props, [`${isEnabled.message}`, small]));
          } else {
            await cancelDispatchCustomer(record);
            handleReload();
          }
        } catch {}
      }

      function handleDetail(record: Recordable) {
        const { id, tbDeviceId } = record;
        openDrawer(true, {
          id,
          tbDeviceId,
        });
      }

      async function handleEdit(record: Recordable) {
        if (record.deviceType === 'SENSOR') {
          const res = await getGATEWAY(record.tbDeviceId);
          Reflect.set(record, 'gatewayId', res.id);
        }
        openModal(true, {
          isUpdate: true,
          record,
        });
      }
      function handleSuccess() {
        reload();
      }
      function handleSelect(organization) {
        searchInfo.organizationId = organization;
        handleSuccess();
      }
      function goDeviceProfile(e) {
        go(PageEnum.DEVICE_PROFILE + '?name=' + String(e));
      }
      const { clipboardRef } = useCopyToClipboard();
      const copySN = (snCode: string) => {
        clipboardRef.value = snCode;
        if (unref(clipboardRef)) {
          createMessage.success('复制成功~');
        }
      };

      const handleOpenTbDeviceDetail = (data: { id: string; tbDeviceId: string }) => {
        openTbDeviceDrawer(true, data);
      };

      return {
        registerTable,
        handleCreate,
        handleDetail,
        handleEdit,
        handleSuccess,
        goDeviceProfile,
        handleSelect,
        registerModal,
        registerDetailDrawer,
        DeviceTypeEnum,
        DeviceState,
        searchInfo,
        organizationIdTreeRef,
        handleDispatchCustomer,
        handleCancelDispatchCustomer,
        registerCustomerModal,
        authBtn,
        role,
        copySN,
        hasBatchDelete,
        handleDeleteOrBatchDelete,
        handleReload,
        registerTbDetailDrawer,
        handleOpenTbDeviceDetail,
      };
    },
  });
</script>

<style scoped lang="css">
  /* /deep/.ant-message-notice-content {
    max-width: 600px !important;
  } */
</style>