Bladeren bron

feat(系统模块): 添加license管理页面

shizhongming 2 jaren geleden
bovenliggende
commit
95e01e1125

+ 1 - 0
src/components/Form/index.ts

@@ -15,5 +15,6 @@ export { default as ApiCascader } from './src/components/ApiCascader.vue';
 export { default as ApiTransfer } from './src/components/ApiTransfer.vue';
 export { default as SmartTableSelect } from './src/smart-boot/components/base/SmartTableSelect';
 export { default as SmartUserSelectModal } from './src/smart-boot/components/SmartUserSelectModal.vue';
+export { default as SmartApiSelectTable } from './src/smart-boot/components/SmartApiSelectTable.vue';
 
 export { BasicForm };

+ 2 - 0
src/components/Form/src/componentMap.ts

@@ -36,6 +36,7 @@ import { BasicTitle } from '@/components/Basic';
 import { CropperAvatar } from '@/components/Cropper';
 import SmartApiSelectDict from './smart-boot/components/SmartApiSelectDict.vue';
 import SmartUserTableSelect from './smart-boot/components/user/SmartUserTableSelect.vue';
+import SmartApiSelectTable from './smart-boot/components/SmartApiSelectTable.vue';
 
 const componentMap = new Map<ComponentType | string, Component>();
 
@@ -83,6 +84,7 @@ componentMap.set('BasicTitle', BasicTitle);
 
 componentMap.set('SmartApiSelectDict', SmartApiSelectDict);
 componentMap.set('SmartUserTableSelect', SmartUserTableSelect);
+componentMap.set('SmartApiSelectTable', SmartApiSelectTable);
 
 export function add<T extends string, R extends Component>(
   compName: ComponentType | T,

+ 4 - 0
src/components/Form/src/types/index.ts

@@ -130,6 +130,9 @@ interface _CustomComponents {
   SmartUserTableSelect: ExtractPropTypes<
     (typeof import('@/components/Form/src/smart-boot/components/user/SmartUserTableSelect.vue'))['default']
   >;
+  SmartApiSelectTable: ExtractPropTypes<
+    (typeof import('@/components/Form/src/smart-boot/components/SmartApiSelectTable.vue'))['default']
+  >;
 }
 
 type CustomComponents<T = _CustomComponents> = {
@@ -181,4 +184,5 @@ export interface ComponentProps {
   BasicTitle: CustomComponents['BasicTitle'];
   SmartApiSelectDict: CustomComponents['SmartApiSelectDict'] & ComponentProps['ApiSelect'];
   SmartUserTableSelect: CustomComponents['SmartUserTableSelect'];
+  SmartApiSelectTable: CustomComponents['SmartApiSelectTable'] & ComponentProps['ApiSelect'];
 }

+ 100 - 0
src/modules/system/components/system/SystemSimpleList.vue

@@ -0,0 +1,100 @@
+<template>
+  <SmartTable
+    class="system-table"
+    v-bind="$attrs"
+    @register="registerTable"
+    @cell-click="handleCellClick"
+    @proxy-query="handleAfterLoad"
+  />
+</template>
+
+<script lang="ts" setup>
+  import { ref, unref, watch } from 'vue';
+  import { propTypes } from '@/utils/propTypes';
+
+  import { listSystemApi } from '@/api/sys/SystemApi';
+
+  import { SmartTable, useSmartTable } from '@/components/SmartTable';
+
+  const props = defineProps({
+    // 是否自动选中第一行
+    autoSelected: propTypes.bool.def(true),
+    // 是否支持点击取消
+    clickCancel: propTypes.bool,
+  });
+
+  const emit = defineEmits(['current-change']);
+
+  const currentRef = ref<any>({});
+
+  /**
+   * 数据加载完成时间
+   */
+  const handleAfterLoad = () => {
+    if (props.autoSelected) {
+      const dataList = getData();
+      if (dataList.length > 0) {
+        currentRef.value = dataList[0];
+      }
+    }
+  };
+
+  watch(currentRef, (value) => {
+    if (value.id) {
+      getTableInstance().setCurrentRow(value);
+    } else {
+      getTableInstance().clearCurrentRow();
+    }
+    emit('current-change', value);
+  });
+
+  const handleCellClick = ({ row }) => {
+    if (unref(currentRef).id === row.id && props.clickCancel) {
+      currentRef.value = {};
+    } else {
+      currentRef.value = row;
+    }
+  };
+
+  const [registerTable, { getTableInstance, getData }] = useSmartTable({
+    rowConfig: {
+      isHover: true,
+      isCurrent: true,
+      keyField: 'id',
+    },
+    toolbarConfig: {
+      refresh: true,
+    },
+    proxyConfig: {
+      ajax: {
+        query: (params) => {
+          return listSystemApi(
+            {
+              ...params.ajaxParameter,
+              sortName: 'seq',
+            },
+            true,
+          );
+        },
+      },
+    },
+    columns: [
+      {
+        field: 'name',
+        title: '{system.views.system.title.name}',
+        minWidth: 160,
+        formatter: ({ row }) => {
+          return `${row.name}(${row.code})`;
+        },
+      },
+    ],
+  });
+</script>
+
+<style lang="less" scoped>
+  .system-table {
+    :deep(.vxe-body--row) {
+      cursor: pointer;
+    }
+  }
+</style>

+ 58 - 0
src/modules/system/views/license/LicenseListView.api.ts

@@ -0,0 +1,58 @@
+import { ApiServiceEnum, defHttp } from '@/utils/http/axios';
+
+enum Api {
+  list = 'smart/license/listBySystem',
+  getById = 'smart/license/getById',
+  saveUpdateBatch = 'smart/license/saveUpdateBatch',
+  delete = 'smart/license/batchDeleteById',
+  generator = 'smart/license/generator',
+  download = 'smart/license/download',
+}
+
+export const listApi = (params) => {
+  return defHttp.post({
+    service: ApiServiceEnum.SMART_SYSTEM,
+    url: Api.list,
+    data: params,
+  });
+};
+
+export const getByIdApi = (data) => {
+  return defHttp.post({
+    service: ApiServiceEnum.SMART_SYSTEM,
+    url: Api.getById,
+    data: data.id,
+  });
+};
+
+export const saveUpdateBatchApi = (dataList: any[]) => {
+  return defHttp.post({
+    service: ApiServiceEnum.SMART_SYSTEM,
+    url: Api.saveUpdateBatch,
+    data: dataList,
+  });
+};
+
+export const deleteApi = (deleteDataList: any[]) => {
+  return defHttp.post({
+    service: ApiServiceEnum.SMART_SYSTEM,
+    url: Api.delete,
+    data: deleteDataList.map((item) => item.id),
+  });
+};
+
+export const generatorApi = (id: number) => {
+  return defHttp.post({
+    service: ApiServiceEnum.SMART_SYSTEM,
+    url: Api.generator,
+    data: id,
+  });
+};
+
+export const downloadApi = (id) => {
+  return defHttp.download({
+    service: ApiServiceEnum.SMART_SYSTEM,
+    url: Api.download,
+    data: { id },
+  });
+};

+ 318 - 0
src/modules/system/views/license/LicenseListView.config.ts

@@ -0,0 +1,318 @@
+import type { SmartColumn, SmartSearchFormSchema } from '@/components/SmartTable';
+import type { FormSchema } from '@/components/Form';
+
+export const getTableColumns = (): SmartColumn[] => {
+  return [
+    {
+      type: 'checkbox',
+      width: 60,
+      align: 'center',
+      fixed: 'left',
+    },
+    {
+      field: 'licenseCode',
+      title: '{smart.license.title.licenseCode}',
+      width: 120,
+      fixed: 'left',
+    },
+    {
+      field: 'licenseName',
+      title: '{smart.license.title.licenseName}',
+      width: 120,
+      fixed: 'left',
+    },
+    {
+      field: 'macAddress',
+      title: '{smart.license.title.macAddress}',
+      width: 200,
+    },
+    {
+      field: 'ipAddress',
+      title: '{smart.license.title.ipAddress}',
+      width: 200,
+    },
+    {
+      field: 'cpuSerial',
+      title: '{smart.license.title.cpuSerial}',
+      width: 200,
+    },
+    {
+      field: 'mainBoardSerial',
+      title: '{smart.license.title.mainBoardSerial}',
+      width: 200,
+    },
+    {
+      field: 'enterprise',
+      title: '{smart.license.title.enterprise}',
+      width: 160,
+    },
+    {
+      field: 'version',
+      title: '{smart.license.title.version}',
+      width: 160,
+      sortable: true,
+    },
+    {
+      field: 'contractNo',
+      title: '{smart.license.title.contractNo}',
+      width: 160,
+    },
+    {
+      field: 'effectiveTime',
+      title: '{smart.license.title.effectiveTime}',
+      width: 160,
+      sortable: true,
+    },
+    {
+      field: 'expirationTime',
+      title: '{smart.license.title.expirationTime}',
+      width: 160,
+      sortable: true,
+    },
+    {
+      field: 'status',
+      title: '{smart.license.title.status}',
+      width: 120,
+      sortable: true,
+    },
+    {
+      field: 'remark',
+      title: '{common.table.remark}',
+      width: 160,
+    },
+    {
+      field: 'seq',
+      title: '{common.table.seq}',
+      width: 100,
+      sortable: true,
+    },
+    {
+      field: 'createTime',
+      title: '{common.table.createTime}',
+      width: 160,
+    },
+    {
+      field: 'createBy',
+      title: '{common.table.createUser}',
+      width: 120,
+    },
+    {
+      field: 'updateTime',
+      title: '{common.table.updateTime}',
+      width: 160,
+    },
+    {
+      field: 'updateBy',
+      title: '{common.table.updateUser}',
+      width: 120,
+    },
+    {
+      title: '{common.table.operation}',
+      field: 'operation',
+      width: 145,
+      fixed: 'right',
+      slots: {
+        default: 'table-operation',
+      },
+    },
+  ];
+};
+
+export const getSearchFormSchemas = (t: Function): SmartSearchFormSchema[] => {
+  return [
+    {
+      label: t('smart.license.title.licenseCode'),
+      field: 'licenseCode',
+      component: 'Input',
+      searchSymbol: 'like',
+    },
+    {
+      label: t('smart.license.title.licenseName'),
+      field: 'licenseName',
+      component: 'Input',
+      searchSymbol: 'like',
+    },
+    {
+      label: t('smart.license.title.version'),
+      field: 'version',
+      component: 'Input',
+      searchSymbol: 'like',
+    },
+    {
+      label: t('smart.license.title.status'),
+      field: 'status',
+      component: 'Input',
+      searchSymbol: '=',
+    },
+  ];
+};
+
+export const getAddEditFormSchemas = (t: Function): FormSchema[] => {
+  return [
+    {
+      label: '',
+      field: 'id',
+      component: 'Input',
+      show: false,
+    },
+    {
+      label: t('smart.license.title.basic'),
+      field: 'id',
+      component: 'Divider',
+      colProps: {
+        span: 24,
+      },
+      componentProps: {
+        class: ['form-divider'],
+      },
+    },
+    {
+      label: t('smart.license.title.licenseCode'),
+      field: 'licenseCode',
+      componentProps: {
+        disabled: true,
+      },
+      component: 'Input',
+    },
+    {
+      label: t('smart.license.title.licenseName'),
+      field: 'licenseName',
+      component: 'Input',
+      required: true,
+    },
+    {
+      label: t('smart.license.title.times'),
+      field: 'times',
+      component: 'RangePicker',
+      required: true,
+      componentProps: {
+        style: {
+          width: '100%',
+        },
+      },
+    },
+    {
+      label: t('common.table.seq'),
+      field: 'seq',
+      required: true,
+      defaultValue: 1,
+      component: 'InputNumber',
+    },
+    {
+      label: t('smart.license.title.subject'),
+      field: 'subject',
+      component: 'Input',
+      required: true,
+    },
+    {
+      label: '',
+      field: 'status',
+      component: 'Input',
+      show: false,
+    },
+    {
+      label: t('smart.license.title.secretKey'),
+      field: 'secretKeyId',
+      required: true,
+      slot: 'form-secretKey',
+    },
+    {
+      label: t('smart.license.title.fileStorage'),
+      field: 'fileStorageId',
+      component: 'SmartApiSelectTable',
+      required: true,
+      componentProps: {
+        modelClassName: 'com.smart.file.manager.model.SmartFileStoragePO',
+        valueFieldName: 'id',
+        labelFieldName: 'storageName',
+        params: {
+          sortName: 'seq',
+          parameter: {
+            'deleteYn@<>': true,
+            'useYn@=': true,
+          },
+        },
+      },
+    },
+    {
+      label: t('smart.license.title.serverInfo'),
+      field: 'id',
+      component: 'Divider',
+      colProps: {
+        span: 24,
+      },
+      componentProps: {
+        class: ['form-divider'],
+      },
+    },
+    {
+      label: t('smart.license.title.macAddress'),
+      field: 'macAddress',
+      component: 'Input',
+    },
+    {
+      label: t('smart.license.title.ipAddress'),
+      field: 'ipAddress',
+      component: 'Input',
+    },
+    {
+      label: t('smart.license.title.cpuSerial'),
+      field: 'cpuSerial',
+      component: 'Input',
+    },
+    {
+      label: t('smart.license.title.mainBoardSerial'),
+      field: 'mainBoardSerial',
+      component: 'Input',
+    },
+    {
+      label: t('smart.license.title.projectInfo'),
+      field: 'id',
+      component: 'Divider',
+      colProps: {
+        span: 24,
+      },
+      componentProps: {
+        class: ['form-divider'],
+      },
+    },
+    {
+      label: t('smart.license.title.enterprise'),
+      field: 'enterprise',
+      component: 'Input',
+    },
+    {
+      label: t('smart.license.title.project'),
+      field: 'systemName',
+      component: 'Input',
+      componentProps: {
+        disabled: true,
+      },
+    },
+    {
+      label: '',
+      field: 'systemId',
+      component: 'Input',
+      show: false,
+    },
+    {
+      label: t('smart.license.title.version'),
+      field: 'version',
+      component: 'Input',
+    },
+    {
+      label: t('smart.license.title.contractNo'),
+      field: 'contractNo',
+      component: 'Input',
+    },
+  ];
+};
+
+export enum Permissions {
+  save = 'sys:license:save',
+  update = 'sys:license:update',
+  query = 'sys:license:query',
+  delete = 'sys:license:delete',
+  generator = 'sys:license:generator',
+  download = 'sys:license:download',
+}

+ 273 - 0
src/modules/system/views/license/LicenseListView.vue

@@ -0,0 +1,273 @@
+<!--
+license管理页面
+-->
+<template>
+  <div class="full-height page-container">
+    <LayoutSeparate first-size="240px" :show-line="false" class="full-height">
+      <template #first>
+        <div class="full-height system-container">
+          <SystemSimpleList
+            @current-change="handleSelectSystemChange"
+            :row-config="{ isHover: true, isCurrent: true }"
+            height="auto"
+          />
+        </div>
+      </template>
+      <template #second>
+        <SmartTable class="license-view" @register="registerTable" :size="getTableSize">
+          <template #table-operation="{ row }">
+            <SmartVxeTableAction
+              :drop-down-actions="getTableDropDownActions(row)"
+              :actions="getTableActions(row)"
+            />
+          </template>
+          <template #form-secretKey="{ model, size }">
+            <SmartApiSelectTable
+              v-model:value="model.secretKeyId"
+              :size="size"
+              model-class-name="com.smart.system.model.auth.SmartAuthSecretKeyPO"
+              label-field-name="keyName"
+              value-field-name="id"
+              :params="getSecretSelectTableParams"
+            />
+          </template>
+        </SmartTable>
+      </template>
+    </LayoutSeparate>
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import type { ActionItem } from '@/components/SmartTable';
+
+  import { computed, ref, unref } from 'vue';
+  import { LayoutSeparate } from '@/components/LayoutSeparate';
+  import SystemSimpleList from '@/modules/system/components/system/SystemSimpleList.vue';
+  import { useSmartTable, SmartTable, SmartVxeTableAction } from '@/components/SmartTable';
+  import { useI18n } from '@/hooks/web/useI18n';
+  import { useSizeSetting } from '@/hooks/setting/UseSizeSetting';
+  import { useAppStore } from '@/store/modules/app';
+  import { useMessage } from '@/hooks/web/useMessage';
+
+  import {
+    getAddEditFormSchemas,
+    getSearchFormSchemas,
+    getTableColumns,
+    Permissions,
+  } from './LicenseListView.config';
+  import {
+    listApi,
+    deleteApi,
+    saveUpdateBatchApi,
+    getByIdApi,
+    generatorApi,
+    downloadApi,
+  } from './LicenseListView.api';
+  import { buildUUID } from '@/utils/uuid';
+  import dayjs from 'dayjs';
+  import { SmartApiSelectTable } from '@/components/Form';
+
+  const { t } = useI18n();
+  const { getTableSize } = useSizeSetting();
+  const appStore = useAppStore();
+  const { createConfirm, successMessage } = useMessage();
+
+  /**
+   * 系统变更时触发:更新数据
+   */
+  const currentSystemRef = ref<Recordable>({});
+  const handleSelectSystemChange = (system) => {
+    currentSystemRef.value = system;
+    query();
+  };
+
+  const getSecretSelectTableParams = computed(() => {
+    return {
+      sortName: 'seq',
+      parameter: {
+        'useYn@=': true,
+        'deleteYn@=': false,
+        'systemId@=': unref(currentSystemRef)?.id,
+      },
+    };
+  });
+
+  const getTableActions = (row): ActionItem[] => {
+    return [
+      {
+        label: t('common.button.edit'),
+        auth: Permissions.update,
+        onClick: () => editByRowModal(row),
+      },
+    ];
+  };
+
+  const getTableDropDownActions = (row): ActionItem[] => {
+    return [
+      {
+        label: t('smart.license.button.generator'),
+        preIcon: 'ant-design:check-outlined',
+        auth: Permissions.generator,
+        onClick: () => {
+          const message =
+            row.status == 'GENERATOR'
+              ? t('smart.license.message.rebuildGeneratorConfirm')
+              : t('smart.license.message.generatorConfirm');
+          createConfirm({
+            iconType: 'warning',
+            type: 'confirm',
+            content: message,
+            onOk: async () => {
+              try {
+                appStore.setPageLoading(true);
+                await generatorApi(row.id);
+                successMessage(t('smart.license.message.generatorSuccess'));
+              } finally {
+                appStore.setPageLoading(false);
+              }
+              query();
+            },
+          });
+        },
+      },
+      {
+        label: t('common.button.download'),
+        preIcon: 'ant-design:download-outlined',
+        auth: Permissions.download,
+        disabled: row.status !== 'GENERATOR',
+        onClick: async () => {
+          try {
+            appStore.setPageLoading(true);
+            await downloadApi(row.id);
+          } finally {
+            appStore.setPageLoading(false);
+          }
+        },
+      },
+    ];
+  };
+
+  const [registerTable, { query, editByRowModal, showAddModal }] = useSmartTable({
+    columns: getTableColumns(),
+    border: true,
+    height: 'auto',
+    stripe: true,
+    showOverflow: 'tooltip',
+    highlightHoverRow: true,
+    columnConfig: {
+      resizable: true,
+    },
+    pagerConfig: true,
+    sortConfig: {
+      remote: true,
+      defaultSort: {
+        field: 'seq',
+        order: 'asc',
+      },
+    },
+    useSearchForm: true,
+    searchFormConfig: {
+      colon: true,
+      compact: true,
+      layout: 'inline',
+      searchWithSymbol: true,
+      // layout: 'inline',
+      actionColOptions: {
+        span: undefined,
+      },
+      schemas: getSearchFormSchemas(t),
+    },
+    proxyConfig: {
+      ajax: {
+        query: (params) => {
+          const parameter = {
+            ...params.ajaxParameter,
+            systemId: unref(currentSystemRef)?.id,
+          };
+          return listApi(parameter);
+        },
+        save: ({ body: { insertRecords, updateRecords } }) => {
+          const dataList = [...insertRecords, ...updateRecords];
+          dataList.forEach((item) => {
+            const times = item.times;
+            Object.assign(item, {
+              effectiveTime: times[0],
+              expirationTime: times[1],
+            });
+            delete item.times;
+          });
+          return saveUpdateBatchApi(dataList);
+        },
+        delete: ({ body: { removeRecords } }) => deleteApi(removeRecords),
+        getById: async (params) => {
+          const result = await getByIdApi(params);
+          const system = result.system;
+          return {
+            ...result,
+            times: [dayjs(result.effectiveTime), dayjs(result.expirationTime)],
+            systemName: `${system.name}(${system.code})`,
+          };
+        },
+      },
+    },
+    printConfig: {},
+    exportConfig: {},
+    toolbarConfig: {
+      refresh: true,
+      zoom: true,
+      column: {
+        columnOrder: true,
+      },
+      buttons: [
+        {
+          code: 'ModalAdd',
+          auth: Permissions.save,
+          props: {
+            onClick: () => {
+              const currentSystem = unref(currentSystemRef);
+              showAddModal({
+                licenseCode: buildUUID(),
+                systemId: currentSystem.id,
+                systemName: `${currentSystem.name}(${currentSystem.code})`,
+              });
+            },
+          },
+        },
+        {
+          code: 'delete',
+          auth: Permissions.delete,
+        },
+      ],
+    },
+    addEditConfig: {
+      modalConfig: {
+        width: '1000px',
+        defaultFullscreen: true,
+      },
+      formConfig: {
+        colon: true,
+        labelCol: {
+          span: 6,
+        },
+        wrapperCol: {
+          span: 17,
+        },
+        schemas: getAddEditFormSchemas(t),
+        baseColProps: { span: 12 },
+      },
+    },
+  });
+</script>
+
+<style lang="less" scoped>
+  .license-view {
+    :deep(.smart-table-container) {
+      height: calc(100% - 122px) !important;
+    }
+  }
+
+  .system-container {
+    margin-right: 5px;
+    background: white;
+  }
+</style>

+ 75 - 0
src/modules/system/views/license/lang/en_US.ts

@@ -0,0 +1,75 @@
+/**
+ * 许可证管理 国际化信息
+ */
+export default {
+  trans: true,
+  key: 'smart.license',
+  data: {
+    title: {
+      licenseCode: 'License code',
+      projectId: 'Project',
+      macAddress: 'Mac address',
+      ipAddress: 'IP address',
+      cpuSerial: 'CPU serial',
+      mainBoardSerial: 'Main board serial',
+      effectiveTime: 'Effective',
+      expirationTime: 'Expiration',
+      status: 'status',
+      times: 'Validity',
+      storePath: 'Store path',
+      licensePath: 'License path',
+      storePassword: 'Store password',
+      keyPassword: 'Key password',
+      alias: 'Alias',
+      subject: 'Subject',
+      enterprise: 'Enterprise',
+      project: 'project&system',
+      version: 'System version',
+      contractNo: 'Contract no',
+      serverInfo: 'Server info',
+      projectInfo: 'Project&system info',
+      secretKey: 'Secret key',
+      licenseName: 'License name',
+      basic: 'Basic',
+      fileStorage: 'License storage',
+    },
+    validate: {
+      licenseCode: 'Please enter license code',
+      macAddress: 'Please enter mac address',
+      ipAddress: 'Please enter IP address',
+      cpuSerial: 'Please enter CPU serial',
+      mainBoardSerial: 'Please enter main board serial',
+      effectiveTime: 'Please enter effective',
+      expirationTime: 'Please enter expiration',
+      status: 'Please enter status',
+      times: 'Please enter validity',
+      timeValidate: 'Expiration time cannot be earlier than current date',
+      storePath: 'Please enter the store path',
+      licensePath: 'Please enter the license path',
+      storePassword: 'Please enter the store password',
+      keyPassword: 'Please enter the key password',
+      alias: 'Please enter the key alias',
+      subject: 'Please enter the key subject',
+      enterprise: 'Please enter the enterprise',
+      project: 'Please enter the project&system',
+      version: 'Please enter the system version',
+      contractNo: 'Please enter the contract no',
+      licenseName: 'Please enter the license name',
+    },
+    rules: {},
+    search: {
+      licenseCode: 'Please enter license code',
+      version: 'Please enter license version',
+    },
+    button: {
+      generator: 'Generator',
+    },
+    message: {
+      generatorConfirm: 'Are you sure you want to generate a license?',
+      rebuildGeneratorConfirm:
+        'The license has been generated. Are you sure you want to regenerate it?',
+      generatorSuccess: 'Generator success',
+      reGeneratorConfirm: 'The license has been generated. Are you sure you want to regenerate it?',
+    },
+  },
+};

+ 74 - 0
src/modules/system/views/license/lang/zh_CN.ts

@@ -0,0 +1,74 @@
+/**
+ * 许可证管理 国际化信息
+ */
+export default {
+  trans: true,
+  key: 'smart.license',
+  data: {
+    title: {
+      licenseCode: 'license编码',
+      projectId: '所属项目',
+      macAddress: 'mac地址',
+      ipAddress: 'IP地址',
+      cpuSerial: 'cpu序列号',
+      mainBoardSerial: '主板序列号',
+      effectiveTime: '生效时间',
+      expirationTime: '过期时间',
+      status: '状态',
+      times: '有效期',
+      storePath: '密钥路径',
+      licensePath: 'license存储路径',
+      storePassword: '密钥库密码',
+      keyPassword: '私钥密码',
+      alias: '别称',
+      subject: '主题',
+      enterprise: '企业',
+      project: '项目&系统',
+      version: '系统版本',
+      contractNo: '合同编号',
+      serverInfo: '服务器信息',
+      projectInfo: '项目&系统信息',
+      secretKey: '密钥',
+      licenseName: 'license名称',
+      basic: 'Basic',
+      fileStorage: 'license存储库',
+    },
+    validate: {
+      licenseCode: '请输入license编码',
+      macAddress: '请输入mac地址,多个mac地址以逗号分隔',
+      ipAddress: '请输入IP地址,多个IP以逗号分隔',
+      cpuSerial: '请输入cpu序列号',
+      mainBoardSerial: '请输入主板序列号',
+      effectiveTime: '请输入生效时间',
+      expirationTime: '请输入过期时间',
+      status: '请输入状态',
+      times: '请输入有效期',
+      timeValidate: '过期时间不能早于当前日期',
+      storePath: '请输入密钥路径',
+      licensePath: '请输入license存储路径',
+      storePassword: '请输入密钥库密码',
+      keyPassword: '请输入私钥密码',
+      alias: '请输入别称',
+      subject: '请输入主题',
+      enterprise: '请输入企业',
+      project: '请输入项目&系统',
+      version: '请输入系统版本',
+      contractNo: '请输入合同编号',
+      licenseName: '请输入license名称',
+    },
+    rules: {},
+    search: {
+      licenseCode: '请输入license编码',
+      version: '请输入license版本',
+    },
+    button: {
+      generator: '生成license',
+    },
+    message: {
+      generatorConfirm: '确定要生成license吗?',
+      rebuildGeneratorConfirm: 'license已生成,确定要重新生成吗?',
+      generatorSuccess: '生成成功',
+      reGeneratorConfirm: 'license已生成,确定要重新生成吗?',
+    },
+  },
+};

+ 25 - 0
src/utils/http/axios/Axios.ts

@@ -8,6 +8,7 @@ import { isFunction } from '@/utils/is';
 import { cloneDeep } from 'lodash-es';
 import { ContentTypeEnum, RequestEnum } from '@/enums/httpEnum';
 import { useGlobSetting } from '@/hooks/setting';
+import { downloadByData } from '@/utils/file/download';
 
 export * from './axiosTransform';
 
@@ -259,4 +260,28 @@ export class VAxios {
     headers['Content-Type'] = ContentTypeEnum.FORM_URLENCODED;
     return this.request({ ...config, method: 'POST', headers }, options);
   }
+
+  /**
+   * 下载文件请
+   * @param config
+   * @param filename
+   * @param options
+   */
+  async download(config: SmartAxiosRequestConfig, filename?: string, options?: RequestOptions) {
+    const response: AxiosResponse<Blob> = await this.request(
+      {
+        method: 'post',
+        responseType: 'blob',
+        ...config,
+      },
+      {
+        ...options,
+      },
+    );
+    const name =
+      filename ||
+      response.headers['content-disposition']?.split(';')[1].split('filename=')[1] ||
+      '';
+    downloadByData(response.data, name);
+  }
 }