index.vue 8.81 KB
<template>
  <div>
    <BasicTable @register="registerTable">
      <template #toolbar>
        <Authority>
          <a-button type="primary" @click="handleAdd"> {{ t('rule.chain.index.add') }} </a-button>
        </Authority>
        <Upload :show-upload-list="false" accept=".json," :customRequest="handleImport">
          <Button type="primary" :loading="importLoading">
            {{ t('rule.chain.index.import') }}
          </Button>
        </Upload>
        <Authority>
          <Popconfirm
            :title="t('rule.chain.index.sureBatchDelete')"
            :ok-text="t('common.okText')"
            :cancel-text="t('common.cancelText')"
            @confirm="handleDeleteOrBatchDelete(null)"
          >
            <a-button color="error" :disabled="hasBatchDelete">
              {{ t('rule.chain.index.batchDelete') }}
            </a-button>
          </Popconfirm>
        </Authority>
      </template>
      <template #root="{ record }">
        <Tag :color="record.root ? 'green' : 'red'">
          {{ record.root ? t('rule.chain.index.yes') : t('rule.chain.index.no') }}</Tag
        >
      </template>
      <template #action="{ record }">
        <TableAction
          :actions="[
            {
              label: t('rule.chain.index.open'),
              icon: 'ant-design:eye-outlined',
              onClick: handleView.bind(null, record),
            },
            {
              label: t('rule.chain.index.edit'),
              icon: 'clarity:note-edit-line',
              onClick: handleBussinessModal.bind(null, record),
            },
          ]"
          :dropDownActions="[
            {
              label: t('rule.chain.index.setRootChain'),
              icon: 'ant-design:gateway-outlined',
              color: 'error',
              ifShow: !record.root,
              popConfirm: {
                title: t('rule.chain.index.sureSetRootChain'),
                confirm: handleSettingRoot.bind(null, record),
              },
            },
            {
              label: t('rule.chain.index.export'),
              icon: 'ant-design:vertical-align-bottom-outlined',
              onClick: handleExport.bind(null, record),
            },
            {
              label: t('rule.chain.index.singleDelete'),
              icon: 'ant-design:delete-outlined',
              color: 'error',
              ifShow: !record.root,
              popConfirm: {
                title: t('rule.chain.index.sureDelete'),
                confirm: handleDeleteOrBatchDelete.bind(null, record.id.id),
              },
            },
          ]"
        />
      </template>
    </BasicTable>
    <RuleChainModal @register="registerModal" @success="handleSuccess" />

    <!-- <ChainDetailDrawer @register="registerDrawer" /> -->
  </div>
</template>
<script lang="ts" setup>
  import { BasicTable, useTable, TableAction } from '/@/components/Table';
  import {
    RuleChainPermisssion,
    columns,
    encode,
    exportJSONFile,
    searchFormSchema,
    paseJSON,
  } from './config/config.data';
  import {
    deleteRuleChine,
    getRuleChinsList,
    exportRuleChine,
    settingRootChine,
    importRuleChine,
    createRuleChine,
  } from '/@/api/ruleengine/ruleengineApi';
  import { useModal } from '/@/components/Modal';
  import { Authority } from '/@/components/Authority';
  import { Tag, Button, Upload, Popconfirm } from 'ant-design-vue';
  import { RuleChainModal } from './component/index';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { usePermission } from '/@/hooks/web/usePermission';
  import { useRouter } from 'vue-router';
  import { ref } from 'vue';
  import { isObject } from '/@/utils/is';
  import { useI18n } from '/@/hooks/web/useI18n';

  const { t } = useI18n(); // 加载国际化
  const [registerModal, { openModal }] = useModal();
  const { createMessage } = useMessage();
  const { hasPermission } = usePermission();
  const router = useRouter();

  const isEmptyObject = (value: any) => isObject(value) && !Object.keys(value).length;
  const importLoading = ref<boolean>(false);
  const hasBatchDelete = ref<boolean>(true);

  const beforeFetch = (params) => {
    Reflect.set(params, 'page', params.page - 1);
    Reflect.set(params, 'sortProperty', 'createdTime');
    Reflect.set(params, 'sortOrder', 'DESC');
    return params;
  };

  const rowSelection = () => {
    return {
      type: 'checkbox',
      getCheckboxProps: (record: Recordable) => {
        return { disabled: record.root };
      },
      onChange(rowKeys: string[]) {
        hasBatchDelete.value = rowKeys.length <= 0;
      },
    };
  };

  const [registerTable, { reload, setProps, getSelectRowKeys, clearSelectedRowKeys }] = useTable({
    title: t('rule.chain.index.title'),
    api: getRuleChinsList,
    rowKey: (record) => record.id.id,
    columns,
    pagination: true,
    useSearchForm: true,
    showTableSetting: true,
    bordered: true,
    showIndexColumn: false,
    formConfig: {
      labelWidth: 120,
      schemas: searchFormSchema,
    },
    resizeHeightOffset: 40,
    canResize: true,
    fetchSetting: {
      pageField: 'page',
      totalField: 'totalElements',
      listField: 'data',
    },
    beforeFetch: (params) => beforeFetch(params),
    rowSelection: rowSelection() as any,
    actionColumn: {
      width: 220,
      title: t('rule.chain.index.action'),
      dataIndex: 'action',
      slots: { customRender: 'action' },
      fixed: 'right',
    },
  });

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

  const handleAdd = () => {
    openModal(true, {
      text: t('rule.chain.index.add'),
    });
  };

  const handleBussinessModal = (record) => {
    openModal(true, {
      text: t('rule.chain.index.update'),
      record,
    });
  };

  const handleView = (record: Recordable) => {
    const hasDetailPermission = hasPermission(RuleChainPermisssion.DETAIL);
    if (hasDetailPermission) {
      const boardId = encode(record.id.id);
      router.push(`/rule/chain/${boardId}`);
    } else createMessage.warning('没有权限');
  };

  const handleImport = (data: { file: File }) => {
    const fileReader = new FileReader();

    fileReader.onload = async () => {
      const { flag, data } = paseJSON(fileReader.result as string);
      if (!flag) {
        createMessage.warning(t('rule.chain.index.importJSONFailed'));
        return;
      }
      try {
        importLoading.value = true;

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

        // 创建规则链
        const value = await createRuleChine(ruleChain);
        const { id } = value;

        const values = {
          ruleChainId: id,
          ...metadata,
        };
        // 导入规则链详情nodes的东西
        const rules = await importRuleChine(values);

        rules
          ? createMessage.success(t('common.importSuccessText'))
          : createMessage.error(t('rule.chain.index.importJSONFailed'));

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

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

  const handleExport = async (record: Recordable) => {
    if (!record) return;
    const { additionalInfo, name, type, firstRuleNodeId, root, debugMode, configuration } =
      record || {};
    const { firstNodeIndex, nodes, connections, ruleChainConnections } = await exportRuleChine(
      record.id.id
    );

    const node = nodes.map((item) => {
      return {
        ...item,
        id: undefined,
        ruleChainId: undefined,
      };
    });
    const value = {
      ruleChain: { additionalInfo, name, type, firstRuleNodeId, root, debugMode, configuration },
      metadata: { firstNodeIndex, nodes: node, connections, ruleChainConnections },
    };
    exportJSONFile(value, name);
  };

  const handleSettingRoot = async (record) => {
    setProps({
      loading: true,
    });
    try {
      await settingRootChine(record.id.id);
      createMessage.success(t('common.operationSuccessText'));
    } finally {
      setProps({
        loading: false,
      });
      reload();
    }
  };

  const handleDeleteOrBatchDelete = async (id: string | null) => {
    setProps({
      loading: true,
    });
    try {
      if (!id) {
        const ids = getSelectRowKeys();
        await Promise.all(ids.map((item) => deleteRuleChine(item)));
        createMessage.success(t('common.deleteSuccessText'));
        return;
      }
      const { code, msg } = await deleteRuleChine(id);

      if (code === 400000) {
        createMessage.error(msg);
        return;
      }
      createMessage.success(t('common.deleteSuccessText'));
    } finally {
      setProps({
        loading: false,
      });
      clearSelectedRowKeys();
      reload();
    }
  };
</script>