PhysicalModelManagementStep.vue 9.35 KB
<template>
  <div class="p-style">
    <BasicTable
      :rowSelection="{ type: 'checkbox' }"
      class="bg-gray-100 dark:bg-dark-900"
      :clickToRowSelect="false"
      @register="registerTable"
    >
      <template #toolbar>
        <div class="flex-auto">
          <div class="mb-2">
            <Alert type="info" show-icon>
              <template #message>
                <span v-if="!isShowBtn">
                  当前展示的是已发布到线上的功能定义,如需修改,请点击
                  <span
                    @click="handleEditPhysicalModel"
                    class="cursor-pointer text-blue-400"
                    size="small"
                  >
                    "编辑物模型"
                  </span>
                </span>
                <span v-if="isShowBtn"> 您正在编辑的是草稿,需点击发布后,物模型才会正式生效. </span>
              </template>
            </Alert>
          </div>
          <div class="flex justify-between items-end">
            <div class="flex gap-2">
              <Authority :value="ModelOfMatterPermission.CREATE">
                <Button v-if="isShowBtn" type="primary" @click="handleCreateOrEdit()">
                  新增物模型
                </Button>
              </Authority>
              <Button type="primary" @click="handleOpenTsl"> 物模型TSL </Button>
              <Authority value="api:yt:things_model:import">
                <Upload
                  v-if="isShowBtn"
                  accept=".json,"
                  :show-upload-list="false"
                  :customRequest="handleImportModel"
                >
                  <Button type="primary" :loading="importLoading"> 导入物模型 </Button>
                </Upload>
              </Authority>
            </div>
            <div class="flex gap-2">
              <Authority :value="ModelOfMatterPermission.RELEASE">
                <Popconfirm
                  title="是否需要发布上线?"
                  ok-text="确定"
                  cancel-text="取消"
                  @confirm="handleEmit"
                >
                  <Button v-if="isShowBtn" type="primary" :loading="releaseLoading">
                    发布上线
                  </Button>
                </Popconfirm>
              </Authority>

              <Button v-if="isShowBtn" class="!bg-gray-200" type="text" @click="handleReturn">
                返回
              </Button>
              <Authority :value="ModelOfMatterPermission.DELETE">
                <Popconfirm
                  title="您确定要批量删除数据"
                  ok-text="确定"
                  cancel-text="取消"
                  @confirm="handleDeleteOrBatchDelete(null)"
                >
                  <Button
                    style="display: none"
                    type="primary"
                    color="error"
                    :disabled="hasBatchDelete"
                  >
                    批量删除
                  </Button>
                </Popconfirm>
              </Authority>
            </div>
          </div>
        </div>
      </template>
      <template #action="{ record }">
        <TableAction
          :actions="[
            {
              label: '查看',
              icon: 'ant-design:eye-outlined',
              onClick: handleViewDetail.bind(null, record),
              ifShow: isShowBtn ? false : true,
            },
            {
              label: '编辑',
              icon: 'clarity:note-edit-line',
              auth: ModelOfMatterPermission.UPDATE,
              onClick: handleCreateOrEdit.bind(null, record),
              ifShow: !isShowBtn ? false : true,
            },
            {
              label: '删除',
              icon: 'ant-design:delete-outlined',
              auth: ModelOfMatterPermission.DELETE,
              color: 'error',
              ifShow: !isShowBtn ? false : true,
              popConfirm: {
                title: '是否确认删除',
                confirm: handleDeleteOrBatchDelete.bind(null, record),
              },
            },
          ]"
        />
      </template>
    </BasicTable>
    <PhysicalModelModal
      :record="$props.record"
      @register="registerModal"
      @success="handleSuccess"
    />
    <PhysicalModelTsl :record="$props.record" @register="registerModalTsl" />
  </div>
</template>
<script lang="ts" setup>
  import { BasicTable, useTable, TableAction } from '/@/components/Table';
  import { useModal } from '/@/components/Modal';
  import {
    modelOfMatterForm,
    ModelOfMatterPermission,
    physicalColumn,
  } from '../device.profile.data';
  import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
  import { Authority } from '/@/components/Authority';
  import PhysicalModelModal from './cpns/physical/PhysicalModelModal.vue';
  import PhysicalModelTsl from './cpns/physical/PhysicalModelTsl.vue';
  import { Popconfirm, Button, Alert, Upload } from 'ant-design-vue';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { DeviceRecord } from '/@/api/device/model/deviceModel';
  import {
    deleteModel,
    getModelList,
    importModelOfMatter,
    releaseModel,
  } from '/@/api/device/modelOfMatter';
  import { OpenModelOfMatterModelParams, OpenModelMode } from './cpns/physical/types';
  import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  import { ref } from 'vue';
  import { isObject, isString } from '/@/utils/is';
  defineEmits(['register']);

  const props = defineProps<{
    record: DeviceRecord;
  }>();

  const { createMessage } = useMessage();
  const isShowBtn = ref(false);
  const [registerModal, { openModal }] = useModal();
  const [registerModalTsl, { openModal: openModalTsl }] = useModal();

  const [registerTable, { reload, setProps }] = useTable({
    api: async (params: Record<'page' | 'pageSize', number>) => {
      return await getModelList({ ...params, deviceProfileId: props.record.id });
    },
    columns: physicalColumn,
    showIndexColumn: false,
    clickToRowSelect: false,
    showTableSetting: true,
    bordered: true,
    useSearchForm: true,
    formConfig: {
      schemas: modelOfMatterForm,
      labelWidth: 120,
    },
    actionColumn: {
      width: 200,
      title: '操作',
      dataIndex: 'action',
      slots: { customRender: 'action' },
      fixed: 'right',
    },
  });

  // 刷新
  const handleSuccess = () => {
    reload();
  };

  const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete(
    deleteModel,
    handleSuccess,
    setProps
  );

  selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
    return { disabled: record.status === 1 };
  };

  const handleViewDetail = (record: ModelOfMatterParams) => {
    if (record) {
      openModal(true, {
        record,
        mode: OpenModelMode.VIEW,
      } as OpenModelOfMatterModelParams);
    }
  };

  // 新增或编辑
  const handleCreateOrEdit = (record?: ModelOfMatterParams) => {
    if (record) {
      openModal(true, {
        mode: OpenModelMode.UPDATE,
        record,
      } as OpenModelOfMatterModelParams);
    } else {
      openModal(true, {
        mode: OpenModelMode.CREATE,
      } as OpenModelOfMatterModelParams);
    }
  };

  const handleOpenTsl = () => {
    openModalTsl(true, {
      isUpdate: true,
    });
  };

  const handleEditPhysicalModel = () => (isShowBtn.value = true);

  const handleReturn = () => (isShowBtn.value = false);

  const releaseLoading = ref(false);
  const handleEmit = async () => {
    try {
      releaseLoading.value = true;
      await releaseModel(props.record.id);
      handleReturn();
      createMessage.success('发布成功');
      reload();
    } catch (error) {
    } finally {
      releaseLoading.value = false;
    }
  };

  const paseJSON = (string: string) => {
    let data = null;
    let flag = false;
    try {
      if (!isString(string)) return { flag: false, data };
      data = JSON.parse(string);
      flag = true;
      if (!isObject(data)) flag = false;
    } catch (error) {}
    return { flag, data };
  };

  const isEmptyObject = (value: any) => isObject(value) && !Object.keys(value).length;

  const importLoading = ref(false);
  const handleImportModel = async (data: { file: File }) => {
    const fileReader = new FileReader();

    fileReader.onload = async () => {
      const { flag, data } = paseJSON(fileReader.result as string);
      if (!flag) {
        createMessage.warning('JSON解析失败,请导入正确的JSON~');
        return;
      }
      try {
        importLoading.value = true;

        Object.keys(data || {}).forEach((key) => {
          const value = (data || {})[key];
          if (value && isEmptyObject(value)) {
            (data || {})[key] = [];
          }
        });

        const result = await importModelOfMatter({
          tkDeviceProfileId: props.record.id,
          data: data!,
          functionType: 'all',
        });

        result
          ? createMessage.success('导入成功~')
          : createMessage.error('JSON解析失败,请导入正确的JSON~');

        result && reload();
      } catch (error) {
        throw error;
      } finally {
        importLoading.value = false;
      }
    };

    fileReader.readAsText(data.file, 'utf-8');
  };

  defineExpose({});
</script>
<style lang="less" scoped>
  @import url('./common/PhysicalModelManagementStep.less');

  :deep(.ant-table-body) {
    height: auto !important;
  }
</style>