PhysicalModelManagementStep.vue 11.2 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, ModelCategoryPermission.CREATE]">
                <Button v-if="isShowBtn" type="primary" @click="handleCreateOrEdit()">
                  新增物模型
                </Button>
              </Authority>
              <Button v-if="!record.ifShowClass" type="primary" @click="handleOpenTsl">
                物模型TSL</Button
              >
              <Authority v-else :value="['api:yt:things_model:category:export']">
                <Button type="primary" @click="handleExport" :loading="loading">导出物模型</Button>
              </Authority>
              <Authority
                :value="[
                  'api:yt:things_model:import',
                  'api:yt:things_model:category:import',
                  'api:yt:things_model:excel_import',
                ]"
              >
                <Button type="primary" @click="handleSelectImport">导入物模型</Button>
              </Authority>
              <Button type="primary" v-if="!isShowBtn" @click="handleEditPhysicalModel"
                >编辑物模型</Button
              >
            </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
                v-if="isShowBtn"
                :value="[ModelOfMatterPermission.DELETE, ModelCategoryPermission.DELETE]"
              >
                <Popconfirm
                  title="您确定要批量删除数据"
                  ok-text="确定"
                  cancel-text="取消"
                  @confirm="handleDeleteOrBatchDelete()"
                  :disabled="getHasBatchDelete"
                >
                  <Button type="primary" danger :disabled="getHasBatchDelete"> 批量删除 </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, ModelCategoryPermission.UPDATE],
              onClick: handleCreateOrEdit.bind(null, record),
              ifShow: !isShowBtn ? false : true,
            },
            {
              label: '删除',
              icon: 'ant-design:delete-outlined',
              auth: [ModelOfMatterPermission.DELETE, ModelCategoryPermission.DELETE],
              color: 'error',
              ifShow: !isShowBtn ? false : true,
              popConfirm: {
                title: '是否确认删除',
                confirm: handleDeleteOrBatchDelete.bind(null, record),
              },
            },
          ]"
        />
      </template>
    </BasicTable>
    <PhysicalModelModal :record="$props.record" @register="registerModal" @success="reload" />
    <PhysicalModelTsl :record="$props.record" @register="registerModalTsl" />
    <SelectImport
      :record="$props.record"
      @register="registerModalSelect"
      @handleReload="handleReload"
    />
  </div>
</template>
<script lang="ts" setup>
  import { BasicTable, useTable, TableAction } from '/@/components/Table';
  import { useModal } from '/@/components/Modal';
  import {
    modelOfMatterForm,
    ModelOfMatterPermission,
    ModelCategoryPermission,
    physicalColumn,
  } from '../device.profile.data';
  import { Authority } from '/@/components/Authority';
  import PhysicalModelModal from './cpns/physical/PhysicalModelModal.vue';
  import PhysicalModelTsl from './cpns/physical/PhysicalModelTsl.vue';
  import { Popconfirm, Button, Alert } from 'ant-design-vue';
  import { useMessage } from '/@/hooks/web/useMessage';
  import {
    deleteModel,
    deleteModelCategory,
    getModelList,
    releaseModel,
  } from '/@/api/device/modelOfMatter';
  import {
    ModelOfMatterItemRecordType,
    ModelOfMatterParams,
  } from '/@/api/device/model/modelOfMatterModel';
  import { computed, ref, unref } from 'vue';
  import { isObject } from '/@/utils/is';
  import { useRole } from '/@/hooks/business/useRole';
  import { ExportModelCategory } from '/@/api/device/modelOfMatter';
  import { FunctionTypeEnum } from '/@/enums/objectModelEnum';
  import SelectImport from '../components/SelectImport.vue';
  import { DataActionModeEnum } from '/@/enums/toolEnum';
  import { DeviceProfileDetail } from '/@/api/device/model/deviceConfigModel';

  const { isPlatformAdmin, isSysadmin } = useRole();
  defineEmits(['register']);

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

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

  const [registerTable, { reload, getSelectRowKeys, getRowSelection, clearSelectedRowKeys }] =
    useTable({
      api: async (params: Record<'page' | 'pageSize', number>) => {
        return await getModelList({
          ...params,
          id: props.record.id,
          selectType: props.record.ifShowClass ? 'category' : undefined,
        });
      },
      columns: props.record.ifShowClass
        ? physicalColumn.filter((item) => item.dataIndex !== 'status')
        : physicalColumn,
      showIndexColumn: false,
      clickToRowSelect: false,
      showTableSetting: true,
      bordered: true,
      useSearchForm: true,
      rowKey: 'id',
      formConfig: {
        schemas: modelOfMatterForm,
        labelWidth: 120,
      },
      actionColumn: {
        width: 200,
        title: '操作',
        dataIndex: 'action',
        slots: { customRender: 'action' },
        fixed: 'right',
      },
    });

  const getHasBatchDelete = computed(() => !getRowSelection().selectedRowKeys?.length);

  const handleViewDetail = (record: ModelOfMatterParams) => {
    if (record) {
      openModal(true, {
        record,
        mode: DataActionModeEnum.READ,
      } as ModalParamsType<ModelOfMatterParams>);
    }
  };

  // 新增或编辑
  const handleCreateOrEdit = (record?: ModelOfMatterParams) => {
    openModal(true, {
      record,
      mode: record ? DataActionModeEnum.UPDATE : DataActionModeEnum.CREATE,
    } as ModalParamsType<ModelOfMatterParams>);
  };

  const handleDeleteOrBatchDelete = async (record?: ModelOfMatterItemRecordType) => {
    const deleteFn =
      props.record.ifShowClass && (unref(isPlatformAdmin) || unref(isSysadmin))
        ? deleteModelCategory
        : deleteModel;

    const ids = record ? [record.id] : getSelectRowKeys();
    await deleteFn(ids);
    createMessage.success('删除成功');
    clearSelectedRowKeys();
    reload();
  };

  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 isEmptyObject = (value: any) => isObject(value) && !Object.keys(value).length;

  // 选择导入物模型的方式
  const handleSelectImport = () => {
    openModalSelect(true, {
      id: props.record.id,
      isCateGory: (unref(isPlatformAdmin) || unref(isSysadmin)) && props.record.ifShowClass,
    });
  };

  const handleReload = () => {
    reload();
  };

  // 导出物模型
  const loading = ref<boolean>(false);

  const getAllCategory = () => {
    const { id: deviceProfileId } = props.record;
    return Promise.all([
      ExportModelCategory({
        deviceProfileId,
        functionType: FunctionTypeEnum.EVENTS,
      }),
      ExportModelCategory({
        deviceProfileId,
        functionType: FunctionTypeEnum.PROPERTIES,
      }),
      ExportModelCategory({
        deviceProfileId,
        functionType: FunctionTypeEnum.SERVICE,
      }),
    ]);
  };
  const exportJSONFile = (value: Recordable) => {
    const blob = new Blob([JSON.stringify(value, null, 2)], { type: 'text/json' });
    const objectURL = URL.createObjectURL(blob);
    const element = document.createElement('a');
    element.href = objectURL;
    element.download = `${props.record.name}-model.json`;
    element.style.display = 'none';
    document.body.appendChild(element);
    element.click();
    element.remove();
    URL.revokeObjectURL(objectURL);
  };

  const isEmptyStr = (s: any) => {
    if (s == undefined || s == null || s == '') {
      return true;
    }
    return false;
  };

  //产品品类物模型导出
  const handleExport = async () => {
    loading.value = true;
    try {
      const [events, properties, services] = await getAllCategory();
      const value = {
        properties: isEmptyObject(properties) || isEmptyStr(properties) ? [] : properties,
        services: isEmptyObject(services) || isEmptyStr(services) ? [] : services,
        events: isEmptyObject(events) || isEmptyStr(events) ? [] : events,
      };
      exportJSONFile(value);
    } catch (error) {
      throw error;
    } finally {
      loading.value = false;
    }
  };

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

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