2026-08-12 302e8457c8d34a35d7eabbd474d98ebc16120ed2
Merge remote-tracking branch 'origin/fix/hsy/20260812' into dev_pro2.0
已修改6个文件
已添加2个文件
298 ■■■■■ 文件已修改
src/api/system/dept/index.ts 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/post/index.ts 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dept/data.ts 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dept/index.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dept/modules/import-form.vue 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/post/data.ts 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/post/index.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/post/modules/import-form.vue 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/dept/index.ts
@@ -50,3 +50,16 @@
export async function deleteDeptList(ids: number[]) {
  return requestClient.delete(`/system/dept/delete-list?ids=${ids.join(',')}`);
}
/** ä¸‹è½½éƒ¨é—¨å¯¼å…¥æ¨¡æ¿ */
export function importDeptTemplate() {
  return requestClient.download('/system/dept/get-import-template');
}
/** å¯¼å…¥éƒ¨é—¨ */
export function importDept(file: File, updateSupport: boolean) {
  return requestClient.upload('/system/dept/import', {
    file,
    updateSupport,
  });
}
src/api/system/post/index.ts
@@ -61,3 +61,16 @@
    params,
  });
}
/** ä¸‹è½½å²—位导入模板 */
export function importPostTemplate() {
  return requestClient.download('/system/post/get-import-template');
}
/** å¯¼å…¥å²—位 */
export function importPost(file: File, updateSupport: boolean) {
  return requestClient.upload('/system/post/import', {
    file,
    updateSupport,
  });
}
src/views/system/dept/data.ts
@@ -114,6 +114,30 @@
  ];
}
/** éƒ¨é—¨å¯¼å…¥çš„表单 */
export function useImportFormSchema(): VbenFormSchema[] {
  return [
    {
      fieldName: 'file',
      label: '部门数据',
      component: 'Upload',
      rules: 'required',
      help: '仅允许导入 xls、xlsx æ ¼å¼æ–‡ä»¶',
    },
    {
      fieldName: 'updateSupport',
      label: '是否覆盖',
      component: 'Switch',
      componentProps: {
        checkedChildren: '是',
        unCheckedChildren: '否',
      },
      rules: z.boolean().default(false),
      help: '是否更新已经存在的部门数据',
    },
  ];
}
/** åˆ—表的字段 */
export function useGridColumns(): VxeTableGridOptions<SystemDeptApi.Dept>['columns'] {
  return [
src/views/system/dept/index.vue
@@ -15,9 +15,15 @@
import { useGridColumns } from './data';
import Form from './modules/form.vue';
import ImportForm from './modules/import-form.vue';
const [FormModal, formModalApi] = useVbenModal({
  connectedComponent: Form,
  destroyOnClose: true,
});
const [ImportModal, importModalApi] = useVbenModal({
  connectedComponent: ImportForm,
  destroyOnClose: true,
});
@@ -36,6 +42,11 @@
/** åˆ›å»ºéƒ¨é—¨ */
function handleCreate() {
  formModalApi.setData(null).open();
}
/** å¯¼å…¥éƒ¨é—¨ */
function handleImport() {
  importModalApi.open();
}
/** æ·»åŠ ä¸‹çº§éƒ¨é—¨ */
@@ -129,6 +140,7 @@
<template>
  <Page auto-content-height>
    <FormModal @success="handleRefresh" />
    <ImportModal @success="handleRefresh" />
    <Grid table-title="部门列表">
      <template #toolbar-tools>
        <TableAction
@@ -141,6 +153,13 @@
              onClick: handleCreate,
            },
            {
              label: $t('ui.actionTitle.import', ['部门']),
              type: 'primary',
              icon: ACTION_ICON.UPLOAD,
              auth: ['system:dept:import'],
              onClick: handleImport,
            },
            {
              label: isExpanded ? '收缩' : '展开',
              type: 'primary',
              onClick: handleExpand,
src/views/system/dept/modules/import-form.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,104 @@
<script lang="ts" setup>
import type { FileType } from 'ant-design-vue/es/upload/interface';
import { h } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { downloadFileFromBlobPart } from '@vben/utils';
import { Button, message, notification, Upload } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { importDept, importDeptTemplate } from '#/api/system/dept';
import { $t } from '#/locales';
import { useImportFormSchema } from '../data';
const emit = defineEmits(['success']);
const [Form, formApi] = useVbenForm({
  commonConfig: {
    formItemClass: 'col-span-2',
    labelWidth: 120,
  },
  layout: 'horizontal',
  schema: useImportFormSchema(),
  showDefaultActions: false,
});
const [Modal, modalApi] = useVbenModal({
  async onConfirm() {
    const { valid } = await formApi.validate();
    if (!valid) {
      return;
    }
    modalApi.lock();
    // æäº¤è¡¨å•
    const data = await formApi.getValues();
    try {
      const response = (await importDept(data.file, data.updateSupport)) as any;
      // å…³é—­å¹¶æç¤º
      await modalApi.close();
      emit('success');
      const resultData = response?.data || response || {};
      const failureNames = resultData.failureDeptNames || {};
      if (Object.keys(failureNames).length > 0) {
        const errorNodes = Object.entries(failureNames).map(([name, reason]) => {
          return h('div', `${name}: ${reason}`);
        });
        notification.warning({
          message: '导入完成,部分部门导入失败',
          description: () => h('div', errorNodes),
          duration: null,
        });
      } else {
        message.success($t('ui.actionMessage.operationSuccess'));
      }
    } finally {
      modalApi.unlock();
    }
  },
});
/** ä¸Šä¼ å‰ */
function beforeUpload(file: FileType) {
  formApi.setFieldValue('file', file);
  return false;
}
/** ä¸‹è½½æ¨¡ç‰ˆ */
async function handleDownload() {
  const data = await importDeptTemplate();
  downloadFileFromBlobPart({ fileName: '部门导入模板.xls', source: data });
}
</script>
<template>
  <Modal title="导入部门" class="w-1/3">
    <Form class="mx-4">
      <template #file>
        <div class="w-full">
          <Upload
            :max-count="1"
            accept=".xls,.xlsx"
            :before-upload="beforeUpload"
          >
            <Button type="primary"> é€‰æ‹© Excel æ–‡ä»¶ </Button>
          </Upload>
        </div>
      </template>
    </Form>
    <div class="mx-4 mt-2 mb-4 text-gray-500 text-xs">
      æç¤ºï¼šæ¨¡æ¿é‡Œçš„“上级部门”请填写全路径(如:总公司/北京分公司)
      <div>上级部门空着即为顶级部门。</div>
    </div>
    <template #prepend-footer>
      <div class="flex flex-auto items-center">
        <Button @click="handleDownload"> ä¸‹è½½å¯¼å…¥æ¨¡æ¿ </Button>
      </div>
    </template>
  </Modal>
</template>
src/views/system/post/data.ts
@@ -68,6 +68,30 @@
  ];
}
/** å²—位导入的表单 */
export function useImportFormSchema(): VbenFormSchema[] {
  return [
    {
      fieldName: 'file',
      label: '岗位数据',
      component: 'Upload',
      rules: 'required',
      help: '仅允许导入 xls、xlsx æ ¼å¼æ–‡ä»¶',
    },
    {
      fieldName: 'updateSupport',
      label: '是否覆盖',
      component: 'Switch',
      componentProps: {
        checkedChildren: '是',
        unCheckedChildren: '否',
      },
      rules: z.boolean().default(false),
      help: '是否更新已经存在的岗位数据',
    },
  ];
}
/** åˆ—表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {
  return [
src/views/system/post/index.vue
@@ -20,9 +20,15 @@
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
import ImportForm from './modules/import-form.vue';
const [FormModal, formModalApi] = useVbenModal({
  connectedComponent: Form,
  destroyOnClose: true,
});
const [ImportModal, importModalApi] = useVbenModal({
  connectedComponent: ImportForm,
  destroyOnClose: true,
});
@@ -40,6 +46,11 @@
/** åˆ›å»ºå²—位 */
function handleCreate() {
  formModalApi.setData(null).open();
}
/** å¯¼å…¥å²—位 */
function handleImport() {
  importModalApi.open();
}
/** ç¼–辑岗位 */
@@ -126,6 +137,7 @@
<template>
  <Page auto-content-height>
    <FormModal @success="handleRefresh" />
    <ImportModal @success="handleRefresh" />
    <Grid table-title="岗位列表">
      <template #toolbar-tools>
        <TableAction
@@ -145,6 +157,13 @@
              onClick: handleExport,
            },
            {
              label: $t('ui.actionTitle.import'),
              type: 'primary',
              icon: ACTION_ICON.UPLOAD,
              auth: ['system:post:import'],
              onClick: handleImport,
            },
            {
              label: $t('ui.actionTitle.deleteBatch'),
              type: 'primary',
              danger: true,
src/views/system/post/modules/import-form.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
<script lang="ts" setup>
import type { FileType } from 'ant-design-vue/es/upload/interface';
import { useVbenModal } from '@vben/common-ui';
import { downloadFileFromBlobPart } from '@vben/utils';
import { Button, message, Upload } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { importPost, importPostTemplate } from '#/api/system/post';
import { $t } from '#/locales';
import { useImportFormSchema } from '../data';
const emit = defineEmits(['success']);
const [Form, formApi] = useVbenForm({
  commonConfig: {
    formItemClass: 'col-span-2',
    labelWidth: 120,
  },
  layout: 'horizontal',
  schema: useImportFormSchema(),
  showDefaultActions: false,
});
const [Modal, modalApi] = useVbenModal({
  async onConfirm() {
    const { valid } = await formApi.validate();
    if (!valid) {
      return;
    }
    modalApi.lock();
    // æäº¤è¡¨å•
    const data = await formApi.getValues();
    try {
      await importPost(data.file, data.updateSupport);
      // å…³é—­å¹¶æç¤º
      await modalApi.close();
      emit('success');
      message.success($t('ui.actionMessage.operationSuccess'));
    } finally {
      modalApi.unlock();
    }
  },
});
/** ä¸Šä¼ å‰ */
function beforeUpload(file: FileType) {
  formApi.setFieldValue('file', file);
  return false;
}
/** ä¸‹è½½æ¨¡ç‰ˆ */
async function handleDownload() {
  const data = await importPostTemplate();
  downloadFileFromBlobPart({ fileName: '岗位导入模板.xls', source: data });
}
</script>
<template>
  <Modal title="导入岗位" class="w-1/3">
    <Form class="mx-4">
      <template #file>
        <div class="w-full">
          <Upload
            :max-count="1"
            accept=".xls,.xlsx"
            :before-upload="beforeUpload"
          >
            <Button type="primary"> é€‰æ‹© Excel æ–‡ä»¶ </Button>
          </Upload>
        </div>
      </template>
    </Form>
    <template #prepend-footer>
      <div class="flex flex-auto items-center">
        <Button @click="handleDownload"> ä¸‹è½½å¯¼å…¥æ¨¡æ¿ </Button>
      </div>
    </template>
  </Modal>
</template>