diff --git a/backend/app/api/v1/controllers/system/dict_controller.py b/backend/app/api/v1/controllers/system/dict_controller.py index 8349f8b9..a76d5c77 100644 --- a/backend/app/api/v1/controllers/system/dict_controller.py +++ b/backend/app/api/v1/controllers/system/dict_controller.py @@ -173,10 +173,11 @@ async def batch_set_available_obj_controller( @router.post('/data/export', summary="导出字典数据", description="导出字典数据") async def export_data_list_controller( search: DictDataQueryParams = Depends(), + page: PaginationQueryParams = Depends(), auth: AuthSchema = Depends(AuthPermission(permissions=["system:dict_data:export"])) ) -> StreamingResponse: # 获取全量数据 - result_dict_list = await DictDataService.get_obj_list_service(search=search, auth=auth) + result_dict_list = await DictDataService.get_obj_list_service(auth=auth, search=search, order_by=page.order_by) export_result = await DictDataService.export_obj_service(data_list=result_dict_list) logger.info('导出字典数据成功') diff --git a/backend/app/api/v1/services/monitor/job_service.py b/backend/app/api/v1/services/monitor/job_service.py index 0962a0db..76ac1c6c 100644 --- a/backend/app/api/v1/services/monitor/job_service.py +++ b/backend/app/api/v1/services/monitor/job_service.py @@ -113,6 +113,7 @@ class JobService: data = data_list.copy() for item in data: item['status'] = '已完成' if item['status'] == 0 else '运行中' if item['status'] == 1 else '暂停' + item['creator'] = item.get('creator', {}).get('name', '未知') if isinstance(item.get('creator'), dict) else '未知' return ExcelUtil.export_list2excel(list_data=data_list, mapping_dict=mapping_dict) \ No newline at end of file diff --git a/backend/app/api/v1/services/system/config_service.py b/backend/app/api/v1/services/system/config_service.py index af834142..9337c628 100644 --- a/backend/app/api/v1/services/system/config_service.py +++ b/backend/app/api/v1/services/system/config_service.py @@ -142,6 +142,7 @@ class ConfigService: for item in data: # 处理状态 item['config_type'] = '是' if item.get('config_type') else '否' + item['creator'] = item.get('creator', {}).get('name', '未知') if isinstance(item.get('creator'), dict) else '未知' return ExcelUtil.export_list2excel(list_data=data_list, mapping_dict=mapping_dict) diff --git a/backend/app/api/v1/services/system/dict_service.py b/backend/app/api/v1/services/system/dict_service.py index 2080a326..76f3b055 100644 --- a/backend/app/api/v1/services/system/dict_service.py +++ b/backend/app/api/v1/services/system/dict_service.py @@ -161,6 +161,7 @@ class DictTypeService: for item in data: # 处理状态 item['status'] = '正常' if item.get('status') else '停用' + item['creator'] = item.get('creator', {}).get('name', '未知') if isinstance(item.get('creator'), dict) else '未知' return ExcelUtil.export_list2excel(list_data=data_list, mapping_dict=mapping_dict) @@ -350,5 +351,6 @@ class DictDataService: item['status'] = '正常' if item.get('status') else '停用' # 处理是否默认 item['is_default'] = '是' if item.get('is_default') else '否' + item['creator'] = item.get('creator', {}).get('name', '未知') if isinstance(item.get('creator'), dict) else '未知' return ExcelUtil.export_list2excel(list_data=data_list, mapping_dict=mapping_dict) \ No newline at end of file diff --git a/backend/app/api/v1/services/system/notice_service.py b/backend/app/api/v1/services/system/notice_service.py index 51063e77..8f136ef6 100644 --- a/backend/app/api/v1/services/system/notice_service.py +++ b/backend/app/api/v1/services/system/notice_service.py @@ -89,5 +89,6 @@ class NoticeService: item['status'] = '正常' if item.get('status') else '停用' # 处理公告类型 item['notice_type'] = '通知' if item.get('notice_type') == 1 else '公告' + item['creator'] = item.get('creator', {}).get('name', '未知') if isinstance(item.get('creator'), dict) else '未知' return ExcelUtil.export_list2excel(list_data=notice_list, mapping_dict=mapping_dict) \ No newline at end of file diff --git a/backend/app/api/v1/services/system/operation_log_service.py b/backend/app/api/v1/services/system/operation_log_service.py index a79678f2..d5be0618 100644 --- a/backend/app/api/v1/services/system/operation_log_service.py +++ b/backend/app/api/v1/services/system/operation_log_service.py @@ -90,5 +90,6 @@ class OperationLogService: item['response_code'] = '成功' if item.get('response_code') == 200 else '失败' # 处理日志类型 item['type'] = '操作日志' if item.get('type') == 1 else '登录日志' + item['creator'] = item.get('creator', {}).get('name', '未知') if isinstance(item.get('creator'), dict) else '未知' return ExcelUtil.export_list2excel(list_data=operation_log_list, mapping_dict=mapping_dict) diff --git a/backend/app/api/v1/services/system/position_service.py b/backend/app/api/v1/services/system/position_service.py index 9a8ce736..4a973444 100644 --- a/backend/app/api/v1/services/system/position_service.py +++ b/backend/app/api/v1/services/system/position_service.py @@ -89,5 +89,6 @@ class PositionService: data = post_list.copy() for item in data: item['status'] = '正常' if item.get('status') else '停用' + item['creator'] = item.get('creator', {}).get('name', '未知') if isinstance(item.get('creator'), dict) else '未知' return ExcelUtil.export_list2excel(list_data=post_list, mapping_dict=mapping_dict) \ No newline at end of file diff --git a/backend/app/api/v1/services/system/role_service.py b/backend/app/api/v1/services/system/role_service.py index d1b68c2a..38f50940 100644 --- a/backend/app/api/v1/services/system/role_service.py +++ b/backend/app/api/v1/services/system/role_service.py @@ -118,6 +118,7 @@ class RoleService: for item in data: item['status'] = '正常' if item.get('status') else '停用' item['data_scope'] = data_scope_map.get(item.get('data_scope')) + item['creator'] = item.get('creator', {}).get('name', '未知') if isinstance(item.get('creator'), dict) else '未知' return ExcelUtil.export_list2excel(list_data=role_list, mapping_dict=mapping_dict) \ No newline at end of file diff --git a/backend/app/api/v1/services/system/user_service.py b/backend/app/api/v1/services/system/user_service.py index cd93668a..f5e855b6 100644 --- a/backend/app/api/v1/services/system/user_service.py +++ b/backend/app/api/v1/services/system/user_service.py @@ -427,15 +427,17 @@ class UserService: 'description': '备注', 'created_at': '创建时间', 'updated_at': '更新时间', - 'creator_id': '创建者ID', 'creator': '创建者', } # 复制数据并转换 + # creator = {'id': 1, 'name': '管理员', 'username': 'admin'} data = user_list.copy() for item in data: item['status'] = '启用' if item.get('status') else '停用' gender = item.get('gender') - item['gender'] = '男' if gender == 1 else ('女' if gender == 2 else '未知') + item['gender'] = '男' if gender == '1' else ('女' if gender == '2' else '未知') + item['is_superuser'] = '是' if item.get('is_superuser') else '否' + item['creator'] = item.get('creator', {}).get('name', '未知') if isinstance(item.get('creator'), dict) else '未知' return ExcelUtil.export_list2excel(list_data=user_list, mapping_dict=mapping_dict) diff --git a/frontend/src/api/monitor/job.ts b/frontend/src/api/monitor/job.ts index 857c25a9..2ad220d0 100644 --- a/frontend/src/api/monitor/job.ts +++ b/frontend/src/api/monitor/job.ts @@ -41,7 +41,7 @@ const JobAPI = { }, exportJob(body: JobPageQuery) { - return request({ + return request({ url: `/monitor/job/export`, method: "post", data: body, diff --git a/frontend/src/api/system/config.ts b/frontend/src/api/system/config.ts index 23012300..d1950ac0 100644 --- a/frontend/src/api/system/config.ts +++ b/frontend/src/api/system/config.ts @@ -57,7 +57,7 @@ const ConfigAPI = { }, exportConfig(body: ConfigPageQuery) { - return request({ + return request({ url: `/system/config/export`, method: "post", data: body, diff --git a/frontend/src/api/system/dict.ts b/frontend/src/api/system/dict.ts index 53ecc279..7484088a 100644 --- a/frontend/src/api/system/dict.ts +++ b/frontend/src/api/system/dict.ts @@ -56,7 +56,7 @@ const DictAPI = { }, exportDictType(body: DictPageQuery) { - return request({ + return request({ url: `/system/dict/type/export`, method: "post", data: body, @@ -112,7 +112,7 @@ const DictAPI = { }, exportDictData(body: DictDataPageQuery) { - return request({ + return request({ url: `/system/dict/data/export`, method: "post", data: body, diff --git a/frontend/src/api/system/log.ts b/frontend/src/api/system/log.ts index bdaf1d7a..46d4c445 100644 --- a/frontend/src/api/system/log.ts +++ b/frontend/src/api/system/log.ts @@ -24,11 +24,11 @@ const LogAPI = { }); }, - exportLog(query: LogPageQuery) { - return request({ + exportLog(body: LogPageQuery) { + return request({ url: `/system/log/export`, method: "post", - data: query, + data: body, responseType: "blob", }); }, diff --git a/frontend/src/api/system/notice.ts b/frontend/src/api/system/notice.ts index 37cab34e..11cf9761 100644 --- a/frontend/src/api/system/notice.ts +++ b/frontend/src/api/system/notice.ts @@ -56,7 +56,7 @@ const NoticeAPI = { }, exportNotice(body: NoticePageQuery) { - return request({ + return request({ url: `/system/notice/export`, method: "post", data: body, diff --git a/frontend/src/api/system/position.ts b/frontend/src/api/system/position.ts index eceeefa9..c7074f5e 100644 --- a/frontend/src/api/system/position.ts +++ b/frontend/src/api/system/position.ts @@ -49,7 +49,7 @@ const PositionAPI = { }, exportPosition(body: PositionPageQuery) { - return request({ + return request({ url: `/system/position/export`, method: "post", data: body, diff --git a/frontend/src/api/system/role.ts b/frontend/src/api/system/role.ts index a218ea99..14be86a7 100644 --- a/frontend/src/api/system/role.ts +++ b/frontend/src/api/system/role.ts @@ -56,11 +56,11 @@ const RoleAPI = { }); }, - exportRole(query: TablePageQuery) { - return request({ + exportRole(body: TablePageQuery) { + return request({ url: `/system/role/export`, method: "post", - data: query, + data: body, responseType: "blob", }); }, @@ -79,8 +79,8 @@ export interface TablePageQuery extends PageQuery { export interface RoleTable { index?: number; - id?: number; - name?: string; + id: number; + name: string; order?: number; data_scope?: number; status?: boolean; diff --git a/frontend/src/api/system/user.ts b/frontend/src/api/system/user.ts index 86b04013..d62a8c54 100644 --- a/frontend/src/api/system/user.ts +++ b/frontend/src/api/system/user.ts @@ -105,11 +105,11 @@ export const UserAPI = { }); }, - exportUser(query: UserPageQuery) { - return request({ + exportUser(body: UserPageQuery) { + return request({ url: `/system/user/export`, method: "post", - params: query, + data: body, responseType: "blob", }); }, diff --git a/frontend/src/layouts/components/NavBar/components/NavbarActions.vue b/frontend/src/layouts/components/NavBar/components/NavbarActions.vue index e043912c..fd77b114 100644 --- a/frontend/src/layouts/components/NavBar/components/NavbarActions.vue +++ b/frontend/src/layouts/components/NavBar/components/NavbarActions.vue @@ -32,7 +32,7 @@ @@ -488,8 +551,8 @@ defineOptions({ import JobAPI, { JobTable, JobForm, JobPageQuery } from "@/api/monitor/job"; import IntervalTab from "@/components/IntervalTab/index.vue"; import { useDictStore } from "@/store/index"; -import { vue3CronPlus } from 'vue3-cron-plus' -import 'vue3-cron-plus/dist/index.css' // 引入样式 +import { vue3CronPlus } from "vue3-cron-plus"; +import "vue3-cron-plus/dist/index.css"; // 引入样式 const dictStore = useDictStore(); @@ -575,9 +638,9 @@ const rules = reactive({ }); // 列表刷新 -async function handleRefresh () { +async function handleRefresh() { await loadingData(); -}; +} // 加载表格数据 async function loadingData() { @@ -714,43 +777,41 @@ async function handleExport() { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", - }).then(async () => { - try { - loading.value = true; - const body = { - ...queryFormData, - page_no: 1, - page_size: total.value, - }; - ElMessage.warning("正在导出数据,请稍候..."); + }) + .then(async () => { + try { + loading.value = true; - const response = await JobAPI.exportJob(body); - const blob = new Blob([JSON.stringify(response.data.data)], { - type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8", - }); - // 从响应头获取文件名 - const contentDisposition = response.headers["content-disposition"]; - let fileName = "系统配置.xlsx"; - if (contentDisposition) { - const fileNameMatch = contentDisposition.match(/filename=(.*?)(;|$)/); - if (fileNameMatch) { - fileName = decodeURIComponent(fileNameMatch[1]); - } + ElMessage.warning("正在导出数据,请稍候..."); + + const response = await JobAPI.exportJob(queryFormData); + const fileData = response.data; + const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); + const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"; + + const blob = new Blob([fileData], { type: fileType }); + + // 从响应头获取文件名 + const downloadUrl = window.URL.createObjectURL(blob); + + const downloadLink = document.createElement("a"); + downloadLink.href = downloadUrl; + downloadLink.download = fileName; + + document.body.appendChild(downloadLink); + downloadLink.click(); + ElMessage.success('导出成功'); + document.body.removeChild(downloadLink); + window.URL.revokeObjectURL(downloadUrl); + } catch (error: any) { + console.error("导出错误:", error); + } finally { + loading.value = false; } - const url = window.URL.createObjectURL(blob); - const link = document.createElement("a"); - link.href = url; - link.download = fileName; - document.body.appendChild(link); - link.click(); - } catch (error: any) { - console.error("导出错误:", error); - } finally { - loading.value = false; - } - }).catch(() => { - ElMessageBox.close(); - }); + }) + .catch(() => { + ElMessageBox.close(); + }); } function handleIntervalConfirm(interval: string) { @@ -760,7 +821,7 @@ function handleIntervalConfirm(interval: string) { const handlechangeCron = (cronStr: string) => { // formData.trigger_args = cronStr; - if (typeof (cronStr) == "string") { + if (typeof cronStr == "string") { formData.trigger_args = cronStr; } }; @@ -771,20 +832,22 @@ const handleClear = () => { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", - }).then(async () => { - try { - loading.value = true; - await JobAPI.clearJob(); - ElMessage.success("清空成功"); - handleResetQuery(); - } catch (error: any) { - ElMessage.error(error.message); - } finally { - loading.value = false; - } - }).catch(() => { - ElMessageBox.close(); - }); + }) + .then(async () => { + try { + loading.value = true; + await JobAPI.clearJob(); + ElMessage.success("清空成功"); + handleResetQuery(); + } catch (error: any) { + ElMessage.error(error.message); + } finally { + loading.value = false; + } + }) + .catch(() => { + ElMessageBox.close(); + }); }; // 操作按钮:操作类型 1: 暂停 2: 恢复 3: 重启(暂时移除重启) diff --git a/frontend/src/views/system/auth/components/Login.vue b/frontend/src/views/system/auth/components/Login.vue index 768b8e2e..78650e43 100644 --- a/frontend/src/views/system/auth/components/Login.vue +++ b/frontend/src/views/system/auth/components/Login.vue @@ -105,11 +105,12 @@ import { LocationQuery, RouteLocationRaw, useRoute } from "vue-router"; import { useI18n } from "vue-i18n"; import AuthAPI, {type LoginFormData, type CaptchaInfo } from "@/api/system/auth"; import router from "@/router"; -import { useUserStore } from "@/store"; +import { useAppStore, useUserStore } from "@/store"; import CommonWrapper from "@/components/CommonWrapper/index.vue"; const { t } = useI18n(); const userStore = useUserStore(); +const appStore = useAppStore(); const route = useRoute(); @@ -203,6 +204,10 @@ async function handleLoginSubmit() { // 4. 记住我功能已实现,根据用户选择决定token的存储方式: // - 选中"记住我": token存储在localStorage中,浏览器关闭后仍然有效 // - 未选中"记住我": token存储在sessionStorage中,浏览器关闭后失效 + + // 登录成功后自动开启项目引导 + appStore.showGuide(true); + } catch (error) { // 5. 统一错误处理 getCaptcha(); // 刷新验证码 diff --git a/frontend/src/views/system/config/index.vue b/frontend/src/views/system/config/index.vue index a1a21585..a87e430c 100644 --- a/frontend/src/views/system/config/index.vue +++ b/frontend/src/views/system/config/index.vue @@ -397,30 +397,28 @@ async function handleExport() { }).then(async () => { try { loading.value = true; - const body = { - ...queryFormData, - page_no: 1, - page_size: total.value - }; + ElMessage.warning('正在导出数据,请稍候...'); - const response = await ConfigAPI.exportConfig(body); - const blob = new Blob([JSON.stringify(response.data.data)], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' }); + const response = await ConfigAPI.exportConfig(queryFormData); + const fileData = response.data; + const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); + const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"; + + const blob = new Blob([fileData], { type: fileType }); + // 从响应头获取文件名 - const contentDisposition = response.headers['content-disposition']; - let fileName = '系统配置.xlsx'; - if (contentDisposition) { - const fileNameMatch = contentDisposition.match(/filename=(.*?)(;|$)/); - if (fileNameMatch) { - fileName = decodeURIComponent(fileNameMatch[1]); - } - } - const url = window.URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = fileName; - document.body.appendChild(link); - link.click(); + const downloadUrl = window.URL.createObjectURL(blob); + + const downloadLink = document.createElement("a"); + downloadLink.href = downloadUrl; + downloadLink.download = fileName; + + document.body.appendChild(downloadLink); + downloadLink.click(); + ElMessage.success('导出成功'); + document.body.removeChild(downloadLink); + window.URL.revokeObjectURL(downloadUrl); } catch (error: any) { ElMessage.error('文件处理失败', error.message); console.error('导出错误:', error); diff --git a/frontend/src/views/system/dict/components/DataDrawer.vue b/frontend/src/views/system/dict/components/DataDrawer.vue index d969a47a..afb158c7 100644 --- a/frontend/src/views/system/dict/components/DataDrawer.vue +++ b/frontend/src/views/system/dict/components/DataDrawer.vue @@ -260,7 +260,7 @@ const queryFormData = reactive({ page_no: 1, page_size: 10, dict_label: undefined, - dict_type: undefined, + dict_type: props.dictType, status: undefined, start_time: undefined, end_time: undefined, @@ -309,7 +309,6 @@ async function loadingData() { loading.value = true; try { // 在查询参数中添加 dictType - queryFormData.dict_type = props.dictType; const response = await DictAPI.getDictDataList(queryFormData); pageTableData.value = response.data.data.items; total.value = response.data.data.total; @@ -440,30 +439,28 @@ async function handleExport() { }).then(async () => { try { loading.value = true; - const body = { - ...queryFormData, - page_no: 1, - page_size: total.value - }; + ElMessage.warning('正在导出数据,请稍候...'); - const response = await DictAPI.exportDictData(body); - const blob = new Blob([JSON.stringify(response.data.data)], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' }); + const response = await DictAPI.exportDictData(queryFormData); + const fileData = response.data; + const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); + const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"; + + const blob = new Blob([fileData], { type: fileType }); + // 从响应头获取文件名 - const contentDisposition = response.headers['content-disposition']; - let fileName = '字典数据.xlsx'; - if (contentDisposition) { - const fileNameMatch = contentDisposition.match(/filename=(.*?)(;|$)/); - if (fileNameMatch) { - fileName = decodeURIComponent(fileNameMatch[1]); - } - } - const url = window.URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = fileName; - document.body.appendChild(link); - link.click(); + const downloadUrl = window.URL.createObjectURL(blob); + + const downloadLink = document.createElement("a"); + downloadLink.href = downloadUrl; + downloadLink.download = fileName; + + document.body.appendChild(downloadLink); + downloadLink.click(); + ElMessage.success('导出成功'); + document.body.removeChild(downloadLink); + window.URL.revokeObjectURL(downloadUrl); } catch (error: any) { ElMessage.error('文件处理失败', error.message); console.error('导出错误:', error); diff --git a/frontend/src/views/system/dict/index.vue b/frontend/src/views/system/dict/index.vue index daba75ed..d8af3942 100644 --- a/frontend/src/views/system/dict/index.vue +++ b/frontend/src/views/system/dict/index.vue @@ -419,30 +419,28 @@ async function handleExport() { }).then(async () => { try { loading.value = true; - const body = { - ...queryFormData, - page_no: 1, - page_size: total.value - }; + ElMessage.warning('正在导出数据,请稍候...'); - const response = await DictAPI.exportDictType(body); - const blob = new Blob([JSON.stringify(response.data.data)], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' }); + const response = await DictAPI.exportDictType(queryFormData); + const fileData = response.data; + const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); + const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"; + + const blob = new Blob([fileData], { type: fileType }); + // 从响应头获取文件名 - const contentDisposition = response.headers['content-disposition']; - let fileName = '字典类型.xlsx'; - if (contentDisposition) { - const fileNameMatch = contentDisposition.match(/filename=(.*?)(;|$)/); - if (fileNameMatch) { - fileName = decodeURIComponent(fileNameMatch[1]); - } - } - const url = window.URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = fileName; - document.body.appendChild(link); - link.click(); + const downloadUrl = window.URL.createObjectURL(blob); + + const downloadLink = document.createElement("a"); + downloadLink.href = downloadUrl; + downloadLink.download = fileName; + + document.body.appendChild(downloadLink); + downloadLink.click(); + ElMessage.success('导出成功'); + document.body.removeChild(downloadLink); + window.URL.revokeObjectURL(downloadUrl); } catch (error: any) { ElMessage.error('文件处理失败', error.message); console.error('导出错误:', error); diff --git a/frontend/src/views/system/log/index.vue b/frontend/src/views/system/log/index.vue index 1428ce98..b78fff20 100644 --- a/frontend/src/views/system/log/index.vue +++ b/frontend/src/views/system/log/index.vue @@ -355,30 +355,28 @@ async function handleExport() { }).then(async () => { try { loading.value = true; - const body = { - ...queryFormData, - page_no: 1, - page_size: total.value - }; + ElMessage.warning('正在导出数据,请稍候...'); - const response = await LogAPI.exportLog(body); - const blob = new Blob([JSON.stringify(response.data.data)], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' }); + const response = await LogAPI.exportLog(queryFormData); + const fileData = response.data; + const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); + const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"; + + const blob = new Blob([fileData], { type: fileType }); + // 从响应头获取文件名 - const contentDisposition = response.headers['content-disposition']; - let fileName = '系统配置.xlsx'; - if (contentDisposition) { - const fileNameMatch = contentDisposition.match(/filename=(.*?)(;|$)/); - if (fileNameMatch) { - fileName = decodeURIComponent(fileNameMatch[1]); - } - } - const url = window.URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = fileName; - document.body.appendChild(link); - link.click(); + const downloadUrl = window.URL.createObjectURL(blob); + + const downloadLink = document.createElement("a"); + downloadLink.href = downloadUrl; + downloadLink.download = fileName; + + document.body.appendChild(downloadLink); + downloadLink.click(); + ElMessage.success('导出成功'); + document.body.removeChild(downloadLink); + window.URL.revokeObjectURL(downloadUrl); } catch (error: any) { ElMessage.error('文件处理失败', error.message); console.error('导出错误:', error); diff --git a/frontend/src/views/system/notice/index.vue b/frontend/src/views/system/notice/index.vue index 77e2337a..0bd34e6f 100644 --- a/frontend/src/views/system/notice/index.vue +++ b/frontend/src/views/system/notice/index.vue @@ -445,30 +445,28 @@ async function handleExport() { }).then(async () => { try { loading.value = true; - const body = { - ...queryFormData, - page_no: 1, - page_size: total.value - }; + ElMessage.warning('正在导出数据,请稍候...'); - const response = await NoticeAPI.exportNotice(body); - const blob = new Blob([JSON.stringify(response.data.data)], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' }); + const response = await NoticeAPI.exportNotice(queryFormData); + const fileData = response.data; + const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); + const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"; + + const blob = new Blob([fileData], { type: fileType }); + // 从响应头获取文件名 - const contentDisposition = response.headers['content-disposition']; - let fileName = '系统配置.xlsx'; - if (contentDisposition) { - const fileNameMatch = contentDisposition.match(/filename=(.*?)(;|$)/); - if (fileNameMatch) { - fileName = decodeURIComponent(fileNameMatch[1]); - } - } - const url = window.URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = fileName; - document.body.appendChild(link); - link.click(); + const downloadUrl = window.URL.createObjectURL(blob); + + const downloadLink = document.createElement("a"); + downloadLink.href = downloadUrl; + downloadLink.download = fileName; + + document.body.appendChild(downloadLink); + downloadLink.click(); + ElMessage.success('导出成功'); + document.body.removeChild(downloadLink); + window.URL.revokeObjectURL(downloadUrl); } catch (error: any) { ElMessage.error('文件处理失败', error.message); console.error('导出错误:', error); diff --git a/frontend/src/views/system/position/index.vue b/frontend/src/views/system/position/index.vue index 535a1118..1aef3401 100644 --- a/frontend/src/views/system/position/index.vue +++ b/frontend/src/views/system/position/index.vue @@ -397,30 +397,28 @@ async function handleExport() { }).then(async () => { try { loading.value = true; - const body = { - ...queryFormData, - page_no: 1, - page_size: total.value - }; + ElMessage.warning('正在导出数据,请稍候...'); - const response = await PositionAPI.exportPosition(body); - const blob = new Blob([JSON.stringify(response.data.data)], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' }); + const response = await PositionAPI.exportPosition(queryFormData); + const fileData = response.data; + const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); + const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"; + + const blob = new Blob([fileData], { type: fileType }); + // 从响应头获取文件名 - const contentDisposition = response.headers['content-disposition']; - let fileName = '系统配置.xlsx'; - if (contentDisposition) { - const fileNameMatch = contentDisposition.match(/filename=(.*?)(;|$)/); - if (fileNameMatch) { - fileName = decodeURIComponent(fileNameMatch[1]); - } - } - const url = window.URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = fileName; - document.body.appendChild(link); - link.click(); + const downloadUrl = window.URL.createObjectURL(blob); + + const downloadLink = document.createElement("a"); + downloadLink.href = downloadUrl; + downloadLink.download = fileName; + + document.body.appendChild(downloadLink); + downloadLink.click(); + ElMessage.success('导出成功'); + document.body.removeChild(downloadLink); + window.URL.revokeObjectURL(downloadUrl); } catch (error: any) { ElMessage.error('文件处理失败', error.message); console.error('导出错误:', error); diff --git a/frontend/src/views/system/role/index.vue b/frontend/src/views/system/role/index.vue index 92069826..31b5527a 100644 --- a/frontend/src/views/system/role/index.vue +++ b/frontend/src/views/system/role/index.vue @@ -248,10 +248,10 @@ const tableColumns = ref([ ]) // 详情表单 -const detailFormData = ref({}); +const detailFormData = ref({} as RoleTable); // 选中的角色 -const checkedRole = ref({}); +const checkedRole = ref({} as RoleTable); const queryFormData = reactive({ page_no: 1, @@ -424,30 +424,28 @@ async function handleExport() { }).then(async () => { try { loading.value = true; - const body = { - ...queryFormData, - page_no: 1, - page_size: total.value - }; + ElMessage.warning('正在导出数据,请稍候...'); - const response = await RoleAPI.exportRole(body); - const blob = new Blob([JSON.stringify(response.data.data)], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' }); + const response = await RoleAPI.exportRole(queryFormData); + const fileData = response.data; + const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); + const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"; + + const blob = new Blob([fileData], { type: fileType }); + // 从响应头获取文件名 - const contentDisposition = response.headers['content-disposition']; - let fileName = '系统配置.xlsx'; - if (contentDisposition) { - const fileNameMatch = contentDisposition.match(/filename=(.*?)(;|$)/); - if (fileNameMatch) { - fileName = decodeURIComponent(fileNameMatch[1]); - } - } - const url = window.URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = fileName; - document.body.appendChild(link); - link.click(); + const downloadUrl = window.URL.createObjectURL(blob); + + const downloadLink = document.createElement("a"); + downloadLink.href = downloadUrl; + downloadLink.download = fileName; + + document.body.appendChild(downloadLink); + downloadLink.click(); + ElMessage.success('导出成功'); + document.body.removeChild(downloadLink); + window.URL.revokeObjectURL(downloadUrl); } catch (error: any) { ElMessage.error('文件处理失败', error.message); console.error('导出错误:', error); diff --git a/frontend/src/views/system/user/components/UserImport.vue b/frontend/src/views/system/user/components/UserImport.vue index c1378714..1701862b 100644 --- a/frontend/src/views/system/user/components/UserImport.vue +++ b/frontend/src/views/system/user/components/UserImport.vue @@ -14,9 +14,10 @@ 点击上传 @@ -77,10 +54,6 @@ const importModalVisible = defineModel("modelValue", { default: false, }); -const resultVisible = ref(false); -const resultData = ref([]); -const invalidCount = ref(0); -const validCount = ref(0); const importFormRef = ref(null); const uploadRef = ref(null); @@ -91,15 +64,6 @@ const importFormData = reactive<{ files: [], }); -watch(importModalVisible, (newValue) => { - if (newValue) { - resultData.value = []; - resultVisible.value = false; - invalidCount.value = 0; - validCount.value = 0; - } -}); - const importFormRules = { files: [{ required: true, message: "文件不能为空", trigger: "blur" }], }; @@ -112,7 +76,7 @@ const handleFileExceed = () => { // 下载导入模板 const handleDownloadTemplate = () => { UserAPI.downloadTemplate().then((response: any) => { - const fileData = response.data.data; + const fileData = response.data; const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"; @@ -137,34 +101,20 @@ const handleUpload = async () => { ElMessage.warning("请选择文件"); return; } - try { - const response = await UserAPI.importUser(importFormData.files[0].raw as File); - if (response.data.code === ResultEnum.SUCCESS) { - ElMessage.success("导入成功,导入数据:" + response.data.data.count + "条"); - emit("import-success"); - handleClose(); - } else { - ElMessage.error("上传失败"); - resultVisible.value = true; - resultData.value = response.data.data.messageList; - invalidCount.value = response.data.data.invalidCount; - validCount.value = response.data.data.validCount; + const file = importFormData.files[0].raw as File; + const formData = new FormData(); + formData.append('file', file); + const response = await UserAPI.importUser(formData); + if (response.data.code === ResultEnum.SUCCESS) { + ElMessage.success(`${response.data.msg},${response.data.data}`); + emit("import-success"); + handleClose(); + } + } catch (error: any) { + console.error(error); + ElMessage.error("上传失败:" + error); } - } catch (error: any) { - console.error(error); - ElMessage.error("上传失败:" + error); - } -}; - -// 显示错误信息 -const handleShowResult = () => { - resultVisible.value = true; -}; - -// 关闭错误信息弹窗 -const handleCloseResult = () => { - resultVisible.value = false; }; // 关闭弹窗 diff --git a/frontend/src/views/system/user/index.vue b/frontend/src/views/system/user/index.vue index e7fd1c3d..2e78cedf 100644 --- a/frontend/src/views/system/user/index.vue +++ b/frontend/src/views/system/user/index.vue @@ -86,7 +86,7 @@ - + @@ -560,77 +560,46 @@ async function handleSubmit() { }); } -// 删除、导入、导出 -async function handleOperation(type: 'import' | 'export') { - if (type === 'import') { - const input = document.createElement('input'); - input.type = 'file'; - input.accept = '.xlsx, .xls'; - input.click(); +// 导出 +async function handleExport() { + ElMessageBox.confirm('是否确认导出当前查询结果用户数据?', '警告', { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + }).then(async () => { + try { + loading.value = true; - input.onchange = async (e) => { - const file = (e.target as HTMLInputElement).files?.[0]; - if (file) { - const formData = new FormData(); - formData.append('file', file); - try { - loading.value = true; - await UserAPI.importUser(formData); - ElMessage.success('导入成功'); - handleResetQuery(); - } catch (error: any) { - ElMessage.error(error.message); - } finally { - loading.value = false; - } - } + ElMessage.warning('正在导出数据,请稍候...'); + + const response = await UserAPI.exportUser(queryFormData); + const fileData = response.data; + const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); + const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"; + + const blob = new Blob([fileData], { type: fileType }); + + const downloadUrl = window.URL.createObjectURL(blob); + + const downloadLink = document.createElement("a"); + downloadLink.href = downloadUrl; + downloadLink.download = fileName; + + document.body.appendChild(downloadLink); + downloadLink.click(); + ElMessage.success('导出成功'); + document.body.removeChild(downloadLink); + window.URL.revokeObjectURL(downloadUrl); + + } catch (error: any) { + ElMessage.error('文件处理失败', error.message); + console.error('导出错误:', error); + } finally { + loading.value = false; } - } - else if (type === 'export') { - ElMessageBox.confirm('是否确认导出当前查询结果用户数据?', '警告', { - confirmButtonText: '确定', - cancelButtonText: '取消', - type: 'warning' - }).then(async () => { - try { - loading.value = true; - - ElMessage.warning('正在导出数据,请稍候...'); - - UserAPI.exportUser(queryFormData).then((response: any) => { - // const fileData = JSON.stringify(response.data.data; - const fileData = response.data.data; - const fileName = decodeURI(response.headers["content-disposition"].split(";")[1].split("=")[1]); - const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"; - - const blob = new Blob([fileData], { type: fileType }); - - const downloadUrl = window.URL.createObjectURL(blob); - - const downloadLink = document.createElement("a"); - downloadLink.href = downloadUrl; - downloadLink.download = fileName; - - document.body.appendChild(downloadLink); - downloadLink.click(); - ElMessage.success('导出成功'); - document.body.removeChild(downloadLink); - window.URL.revokeObjectURL(downloadUrl); - }); - - } catch (error: any) { - ElMessage.error('文件处理失败', error.message); - console.error('导出错误:', error); - } finally { - loading.value = false; - } - }).catch(() => { - ElMessageBox.close(); - }); - } - else { - ElMessage.error('未知操作类型'); - } + }).catch(() => { + ElMessageBox.close(); + }); } // 删除、批量删除