feat: 用户导入
This commit is contained in:
parent
eb61c9ee9d
commit
b05fb6d56f
@ -48,14 +48,16 @@ export function userExport(data: any) {
|
|||||||
* @returns void
|
* @returns void
|
||||||
*/
|
*/
|
||||||
export function userImportData(data: UserImportParam) {
|
export function userImportData(data: UserImportParam) {
|
||||||
return requestClient.post<void>(Api.userImport, data, {
|
return requestClient.post<{ code: number; msg: string }>(
|
||||||
// 返回的msg包含<br> 用modal显示
|
Api.userImport,
|
||||||
errorMessageMode: 'modal',
|
data,
|
||||||
headers: {
|
{
|
||||||
'Content-Type': ContentTypeEnum.FORM_DATA,
|
headers: {
|
||||||
|
'Content-Type': ContentTypeEnum.FORM_DATA,
|
||||||
|
},
|
||||||
|
isTransformResponse: false,
|
||||||
},
|
},
|
||||||
successMessageMode: 'modal',
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,109 +1,29 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onBeforeUnmount, onMounted, ref } from 'vue';
|
import { Page, useVbenModal } from '@vben/common-ui';
|
||||||
|
import { $t } from '@vben/locales';
|
||||||
|
|
||||||
import { useVbenDrawer, useVbenModal } from '@vben/common-ui';
|
import { userExport } from '#/api/system/user';
|
||||||
|
import { downloadExcel } from '#/utils/file/download';
|
||||||
|
|
||||||
import {
|
import userImportModal from './user-import-modal.vue';
|
||||||
Tag as ATag,
|
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
RadioButton,
|
|
||||||
RadioGroup,
|
|
||||||
Select,
|
|
||||||
Space,
|
|
||||||
} from 'ant-design-vue';
|
|
||||||
|
|
||||||
import { DictTag } from '#/components/dict';
|
const [UserImpotModal, userImportModalApi] = useVbenModal({
|
||||||
import { getDict, getDictOptions } from '#/utils/dict';
|
connectedComponent: userImportModal,
|
||||||
|
|
||||||
import DrawerDemo from './drawer.vue';
|
|
||||||
import ModalDemo from './modal.vue';
|
|
||||||
import TableTest from './table';
|
|
||||||
|
|
||||||
const count = ref(0);
|
|
||||||
let intervalId: null | ReturnType<typeof setInterval> = null;
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
intervalId = setInterval(() => {
|
|
||||||
count.value++;
|
|
||||||
}, 1000);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => intervalId && clearInterval(intervalId));
|
function handleImport() {
|
||||||
|
userImportModalApi.open();
|
||||||
const sexOptions = getDictOptions('sys_user_sex');
|
}
|
||||||
const disabledDict = getDict('sys_normal_disable');
|
|
||||||
const select = ref('pc');
|
|
||||||
const deviceOptions = getDictOptions('sys_device_type');
|
|
||||||
|
|
||||||
const [TestNodal, modalApi] = useVbenModal({
|
|
||||||
connectedComponent: ModalDemo,
|
|
||||||
});
|
|
||||||
|
|
||||||
const [TestDrawer, drawerApi] = useVbenDrawer({
|
|
||||||
connectedComponent: DrawerDemo,
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="m-[16px] flex flex-col gap-[16px]">
|
<Page>
|
||||||
<Card title="测试keepAlive">
|
<div class="flex gap-[8px]">
|
||||||
<template #extra>
|
<a-button @click="downloadExcel(userExport, '用户管理', {})">
|
||||||
<Button type="primary" v-access:code="['system:user:list']">
|
{{ $t('pages.common.export') }}
|
||||||
测试按钮权限system:user:list
|
</a-button>
|
||||||
</Button>
|
<a-button @click="handleImport">{{ $t('pages.common.import') }}</a-button>
|
||||||
</template>
|
</div>
|
||||||
<p>当前计数: {{ count }}</p>
|
<UserImpotModal />
|
||||||
</Card>
|
</Page>
|
||||||
<Card title="字典测试">
|
|
||||||
<div class="flex items-center gap-[16px]">
|
|
||||||
<Select
|
|
||||||
:options="sexOptions"
|
|
||||||
class="w-[200px]"
|
|
||||||
placeholder="请选择性别"
|
|
||||||
/>
|
|
||||||
<div class="flex gap-[6px]">
|
|
||||||
<DictTag :dicts="disabledDict" value="0" />
|
|
||||||
<DictTag :dicts="disabledDict" value="1" />
|
|
||||||
</div>
|
|
||||||
<RadioGroup v-model:value="select" button-style="solid">
|
|
||||||
<RadioButton
|
|
||||||
v-for="item in deviceOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</RadioButton>
|
|
||||||
</RadioGroup>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
<Card title="tag测试">
|
|
||||||
<ATag :bordered="false" color="processing">processing</ATag>
|
|
||||||
<ATag :bordered="false" color="success">success</ATag>
|
|
||||||
<ATag :bordered="false" color="error">error</ATag>
|
|
||||||
<ATag :bordered="false" color="warning">warning</ATag>
|
|
||||||
<ATag :bordered="false" color="magenta">magenta</ATag>
|
|
||||||
<ATag :bordered="false" color="red">red</ATag>
|
|
||||||
<ATag :bordered="false" color="volcano">volcano</ATag>
|
|
||||||
<ATag :bordered="false" color="orange">orange</ATag>
|
|
||||||
<ATag :bordered="false" color="gold">gold</ATag>
|
|
||||||
<ATag :bordered="false" color="lime">lime</ATag>
|
|
||||||
<ATag :bordered="false" color="green">green</ATag>
|
|
||||||
<ATag :bordered="false" color="cyan">cyan</ATag>
|
|
||||||
<ATag :bordered="false" color="blue">blue</ATag>
|
|
||||||
<ATag :bordered="false" color="geekblue">geekblue</ATag>
|
|
||||||
<ATag :bordered="false" color="purple">purple</ATag>
|
|
||||||
</Card>
|
|
||||||
<Card title="table测试">
|
|
||||||
<TableTest />
|
|
||||||
</Card>
|
|
||||||
<Card title="Modal/Drawer测试">
|
|
||||||
<Space>
|
|
||||||
<a-button @click="() => modalApi.open()">打开Modal</a-button>
|
|
||||||
<a-button @click="() => drawerApi.open()">打开Drawer</a-button>
|
|
||||||
</Space>
|
|
||||||
<TestNodal />
|
|
||||||
<TestDrawer />
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
108
apps/web-antd/src/views/system/user/user-import-modal.vue
Normal file
108
apps/web-antd/src/views/system/user/user-import-modal.vue
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { UploadFile } from 'ant-design-vue/es/upload/interface';
|
||||||
|
|
||||||
|
import { h, ref, unref } from 'vue';
|
||||||
|
|
||||||
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
|
||||||
|
import { Modal, Switch, Upload } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { downloadImportTemplate, userImportData } from '#/api/system/user';
|
||||||
|
import { downloadExcel } from '#/utils/file/download';
|
||||||
|
|
||||||
|
const emit = defineEmits<{ reload: [] }>();
|
||||||
|
|
||||||
|
const UploadDragger = Upload.Dragger;
|
||||||
|
|
||||||
|
const [BasicModal, modalApi] = useVbenModal({
|
||||||
|
onCancel: handleCancel,
|
||||||
|
onConfirm: handleSubmit,
|
||||||
|
});
|
||||||
|
|
||||||
|
const fileList = ref<UploadFile[]>([]);
|
||||||
|
const checked = ref(false);
|
||||||
|
|
||||||
|
async function handleSubmit() {
|
||||||
|
try {
|
||||||
|
modalApi.modalLoading(true);
|
||||||
|
if (fileList.value.length !== 1) {
|
||||||
|
handleCancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data = {
|
||||||
|
file: fileList.value[0]!.originFileObj as Blob,
|
||||||
|
updateSupport: unref(checked),
|
||||||
|
};
|
||||||
|
const { code, msg } = await userImportData(data);
|
||||||
|
let modal = Modal.success;
|
||||||
|
if (code === 200) {
|
||||||
|
emit('reload');
|
||||||
|
} else {
|
||||||
|
modal = Modal.error;
|
||||||
|
}
|
||||||
|
handleCancel();
|
||||||
|
modal({
|
||||||
|
content: h('div', {
|
||||||
|
class: 'max-h-[260px] overflow-y-auto',
|
||||||
|
innerHTML: msg,
|
||||||
|
}),
|
||||||
|
title: '提示',
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error);
|
||||||
|
modalApi.close();
|
||||||
|
} finally {
|
||||||
|
modalApi.modalLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCancel() {
|
||||||
|
modalApi.close();
|
||||||
|
fileList.value = [];
|
||||||
|
checked.value = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<BasicModal
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:fullscreen-button="false"
|
||||||
|
class="w-[550px]"
|
||||||
|
title="用户导入"
|
||||||
|
>
|
||||||
|
<!-- z-index不设置会遮挡模板下载loading -->
|
||||||
|
<!-- 手动处理 而不是放入文件就上传 -->
|
||||||
|
<UploadDragger
|
||||||
|
v-model:file-list="fileList"
|
||||||
|
:before-upload="() => false"
|
||||||
|
:max-count="1"
|
||||||
|
:show-upload-list="true"
|
||||||
|
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
|
||||||
|
>
|
||||||
|
<p class="ant-upload-drag-icon">
|
||||||
|
<span
|
||||||
|
class="icon-[ant-design--inbox-outlined] text-primary size-[36px]"
|
||||||
|
></span>
|
||||||
|
</p>
|
||||||
|
<p class="ant-upload-text">点击或者拖拽到此处上传文件</p>
|
||||||
|
</UploadDragger>
|
||||||
|
<div class="mt-2 flex flex-col gap-2">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span>允许导入xlsx, xls文件</span>
|
||||||
|
<a-button
|
||||||
|
link
|
||||||
|
type="link"
|
||||||
|
@click="downloadExcel(downloadImportTemplate, '用户导入模板')"
|
||||||
|
>
|
||||||
|
下载模板
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span :class="{ 'text-red-500': checked }">
|
||||||
|
是否更新/覆盖已存在的用户数据
|
||||||
|
</span>
|
||||||
|
<Switch v-model:checked="checked" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
Loading…
Reference in New Issue
Block a user