From c260d39b1c35af9516db71548e3e31d5b51cae9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=9D=E5=85=88=E7=91=9E?= <1490493387@qq.com> Date: Wed, 13 Apr 2022 00:18:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA=E5=92=8C=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E4=B8=8B=E8=BD=BD=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/system/user.ts | 55 +++- src/types/api/system/user.d.ts | 9 + src/utils/request.ts | 6 + src/views/system/user/index.vue | 446 +++++++++++++++++--------------- 4 files changed, 301 insertions(+), 215 deletions(-) diff --git a/src/api/system/user.ts b/src/api/system/user.ts index 929e322a..973d788c 100644 --- a/src/api/system/user.ts +++ b/src/api/system/user.ts @@ -1,6 +1,6 @@ import request from "@/utils/request"; import { AxiosPromise } from "axios"; -import { UserFormData, UserInfo, UserPageResult, UserQueryParam } from "@/types"; +import { UserFormData, UserImportFormData, UserInfo, UserPageResult, UserQueryParam } from "@/types"; /** * 登录成功后获取用户信息(昵称、头像、权限集合和角色集合) @@ -30,9 +30,9 @@ export function listUsersPage(queryParams: UserQueryParam): AxiosPromise { +export function getUserDetail(userId: number): AxiosPromise { return request({ - url: '/youlai-admin/api/v1/users/' + userId + '/form_detail', + url: '/youlai-admin/api/v1/users/' + userId, method: 'get' }) } @@ -80,6 +80,7 @@ export function updateUserPart(id: number, data: any) { /** * 删除用户 + * * @param ids */ export function deleteUsers(ids: string) { @@ -88,3 +89,51 @@ export function deleteUsers(ids: string) { method: 'delete', }) } + +/** + * 下载用户导入模板 + * + * @returns + */ +export function downloadTemplate() { + return request({ + url: '/youlai-admin/api/v1/users/template', + method: 'get', + responseType: "arraybuffer" + }) +} + +/** + * 导出用户 + * + * @param queryParams + * @returns + */ +export function exportUser(queryParams: UserQueryParam) { + return request({ + url: '/youlai-admin/api/v1/users/_export', + method: 'get', + responseType: "arraybuffer" + }) +} + +/** + * 导入用户 + * + * @param file + */ +export function importUser(deptId: number, roleIds: string, file: File) { + let formData = new FormData() + formData.append('file', file) + formData.append('deptId',deptId.toString()) + formData.append('roleIds',roleIds) + return request( + { + url: '/youlai-admin/api/v1/users/_import', + method: 'post', + data:formData, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} \ No newline at end of file diff --git a/src/types/api/system/user.d.ts b/src/types/api/system/user.d.ts index 70823948..337eef02 100644 --- a/src/types/api/system/user.d.ts +++ b/src/types/api/system/user.d.ts @@ -58,4 +58,13 @@ export interface UserFormData { status: number, remark: string, roleIds: number[] +} + + +/** + * 用户导入表单类型声明 + */ + export interface UserImportFormData { + deptId: number, + roleIds: number[] } \ No newline at end of file diff --git a/src/utils/request.ts b/src/utils/request.ts index 8a3f51dc..edf75d05 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -33,6 +33,12 @@ service.interceptors.response.use( if (code === '00000') { return response.data; } else { + + // 响应数据为二进制流处理(Excel导出) + if (response.data instanceof ArrayBuffer) { + return response + } + ElMessage({ message: msg || '系统出错', type: 'error' diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue index 0f301135..e6ced7d2 100644 --- a/src/views/system/user/index.vue +++ b/src/views/system/user/index.vue @@ -4,23 +4,10 @@ - - - + + @@ -28,202 +15,105 @@ - - - 新增 - - - 删除 - - + + + + 新增 + 删除 + - - - + + + - - - - - - + + + + + + - - - 搜索 - - 重置 - + + 搜索 + 重置 + + + + + + + 导入 + + + 导出 + + + - + - - - - - + + + + + + + + - - + - + - - + + - + - - + + - + - + @@ -243,19 +133,52 @@ - + + + + + + + + + + + + + + + + + + + + +
+ 将文件拖到此处,或 + 点击上传 +
+ +
+
+
+
@@ -267,27 +190,29 @@ import { reactive, ref, - unref, watchEffect, onMounted, getCurrentInstance, - toRefs, + toRefs } from "vue"; -// API依赖 +// 导入API import { listUsersPage, - getUserFormDetail, + getUserDetail, deleteUsers, addUser, updateUser, updateUserPart, + downloadTemplate, + exportUser, + importUser } from "@/api/system/user"; import { listSelectDepartments } from "@/api/system/dept"; import { listRoles } from "@/api/system/role"; // 组件依赖 -import { ElMessage, ElMessageBox, ElTree, ElForm } from "element-plus"; +import { ElMessage, ElMessageBox, ElTree, ElForm, UploadRequestOptions } from "element-plus"; import { Search, Plus, @@ -295,6 +220,9 @@ import { Refresh, Delete, Lock, + Download, + Top, + UploadFilled } from "@element-plus/icons-vue"; import TreeSelect from "@/components/TreeSelect/index.vue"; import { @@ -303,13 +231,16 @@ import { UserFormData, Option, RoleItem, - Dialog + Dialog, + UserImportFormData } from "@/types"; +import { assertFile } from "@babel/types"; -// DOM元素的引用声明定义 -const deptTreeRef = ref(ElTree); // 变量名和DOM的ref属性值一致 -const queryFormRef = ref(ElForm); -const dataFormRef = ref(ElForm); +// DOM元素的引用声明定义 ,变量名和DOM的ref属性值一致 +const deptTreeRef = ref(ElTree); // 部门树 +const queryFormRef = ref(ElForm); // 部门树 +const dataFormRef = ref(ElForm); // 部门树 +const importFormRef = ref(ElForm); // 导入 const { proxy }: any = getCurrentInstance(); @@ -352,7 +283,7 @@ const state = reactive({ { required: true, message: "用户昵称不能为空", trigger: "blur" }, ], deptId: [{ required: true, message: "归属部门不能为空", trigger: "blur" }], - roleId: [{ required: true, message: "用户角色不能为空", trigger: "blur" }], + roleIds: [{ required: true, message: "用户角色不能为空", trigger: "blur" }], email: [ { pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/, @@ -367,7 +298,16 @@ const state = reactive({ trigger: "blur", }, ], + }, + + importDialog: { + title: '用户导出', + visible: false, + } as Dialog, + importFormData: {} as UserImportFormData, + excelFile: undefined as any, + excelFilelist: [] as File[] }); const { @@ -383,6 +323,9 @@ const { deptName, deptOptions, roleOptions, + importDialog, + importFormData, + excelFilelist } = toRefs(state); /** @@ -397,6 +340,9 @@ watchEffect( } ); +/** + * 部门列表筛选 + */ function filterDeptNode(value: string, data: any) { if (!value) { return true; @@ -498,7 +444,7 @@ function resetPassword(row: { [key: string]: any }) { ElMessage.success("修改成功,新密码是:" + value); }); }) - .catch(() => {}); + .catch(() => { }); } /** @@ -524,7 +470,7 @@ async function handleUpdate(row: { [key: string]: any }) { title: "修改用户", visible: true, }; - getUserFormDetail(userId).then(({ data }) => { + getUserDetail(userId).then(({ data }) => { state.formData = data; }); } @@ -539,15 +485,13 @@ function submitForm() { if (userId) { updateUser(userId, state.formData).then(() => { ElMessage.success("修改用户成功"); - state.dialog.visible = false; - resetForm(); + cancel() handleQuery(); }); } else { addUser(state.formData).then((response: any) => { ElMessage.success("新增用户成功"); - state.dialog.visible = false; - resetForm(); + cancel() handleQuery(); }); } @@ -555,14 +499,6 @@ function submitForm() { }); } -/** - * 重置表单 - */ -function resetForm() { - state.formData.id = undefined; - dataFormRef.value.resetFields(); -} - /** * 删除用户 */ @@ -591,7 +527,8 @@ function handleDelete(row: { [key: string]: any }) { */ function cancel() { state.dialog.visible = false; - resetForm(); + state.formData.id = undefined; + dataFormRef.value.resetFields(); } /** @@ -612,6 +549,90 @@ function loadGenderOptions() { }); } +/** + * 下载用户导入模板 + */ +function handleDownloadTemplate() { + downloadTemplate().then((response: any) => { + const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' }) + const a = document.createElement('a') + const href = window.URL.createObjectURL(blob) // 下载链接 + a.href = href + a.download = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); // 获取后台设置的文件名称 + document.body.appendChild(a) + a.click() // 点击下载 + document.body.removeChild(a) // 下载完成移除元素 + window.URL.revokeObjectURL(href) // 释放掉blob对象 + }) +} + +/** + * 导入用户表单弹窗 + */ +async function showImportDialog() { + await loadDeptOptions(); + await loadRoleOptions(); + state.importDialog.visible = true +} + + +function handleExcelChange(file: any, fileList: File[]) { + const fileName = file.name; + if (!/\.(xlsx|xls|XLSX|XLS)$/.test(file.name)) { + ElMessage.warning('上传Excel只能为xlsx、xls格式'); + state.excelFile = undefined + state.excelFilelist = [] + return false; + } + state.excelFile = file.raw +} + +function submitImportForm() { + importFormRef.value.validate((valid: any) => { + if (valid) { + if (!state.excelFile) { + ElMessage.warning('上传Excel文件不能为空'); + return false + } + + const deptId = state.importFormData.deptId + const roleIds = state.importFormData.roleIds.join(',') + importUser(deptId, roleIds, state.excelFile).then((response) => { + ElMessage.success(response.data); + closeImportDialog(); + handleQuery(); + }) + } + }); +} + +/** + * 关闭导入弹窗 + */ +function closeImportDialog() { + state.importDialog.visible = false + state.excelFile = undefined + state.excelFilelist = [] + importFormRef.value.resetFields(); +} + +/** + * 导出用户 + */ +function handleExport() { + exportUser(queryParams.value).then((response: any) => { + const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' }) + const a = document.createElement('a') + const href = window.URL.createObjectURL(blob) // 下载的链接 + a.href = href + a.download = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); // 获取后台设置的文件名称 + document.body.appendChild(a) + a.click() // 点击导出 + document.body.removeChild(a) // 下载完成移除元素 + window.URL.revokeObjectURL(href) // 释放掉blob对象 + }) +} + /** * 初始化数据 */ @@ -628,5 +649,6 @@ onMounted(() => { loadData(); }); +