chore: 整理项目资源和配置
1
LICENSE
@@ -1,5 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-present PanJiaChen
|
||||
Copyright (c) 2021-present 有来开源组织
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
||||
@@ -226,17 +226,17 @@ Thanks to all the contributors!
|
||||
<table align="center">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="./src/assets/images/qr/wechat-offical.png" height="180" alt="WeChat Official Account"><br>
|
||||
<img src="./public/images/qr/wechat-official.png" height="180" alt="WeChat Official Account"><br>
|
||||
<sub>WeChat Official Account</sub>
|
||||
</td>
|
||||
<td> </td>
|
||||
<td align="center">
|
||||
<img src="./src/assets/images/qr/wechat-mp.jpg" height="180" alt="Mini Program"><br>
|
||||
<img src="./public/images/qr/wechat-mp.jpg" height="180" alt="Mini Program"><br>
|
||||
<sub>Mini Program</sub>
|
||||
</td>
|
||||
<td> </td>
|
||||
<td align="center">
|
||||
<img src="./src/assets/images/qr/wechat-personal.png" height="180" alt="Add Author WeChat"><br>
|
||||
<img src="./public/images/qr/wechat-personal.png" height="180" alt="Add Author WeChat"><br>
|
||||
<sub>Add Author WeChat</sub>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -223,17 +223,17 @@ Thanks to all the contributors!
|
||||
<table align="center">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="./src/assets/images/qr/wechat-official.png" height="180" alt="公众号「有来技术」"><br>
|
||||
<img src="./public/images/qr/wechat-official.png" height="180" alt="公众号「有来技术」"><br>
|
||||
<sub>公众号「有来技术」</sub>
|
||||
</td>
|
||||
<td> </td>
|
||||
<td align="center">
|
||||
<img src="./src/assets/images/qr/wechat-mp.jpg" height="180" alt="小程序「有来技术」"><br>
|
||||
<img src="./public/images/qr/wechat-mp.jpg" height="180" alt="小程序「有来技术」"><br>
|
||||
<sub>小程序「有来技术」</sub>
|
||||
</td>
|
||||
<td> </td>
|
||||
<td align="center">
|
||||
<img src="./src/assets/images/qr/wechat-personal.png" height="180" alt="添加作者微信"><br>
|
||||
<img src="./public/images/qr/wechat-personal.png" height="180" alt="添加作者微信"><br>
|
||||
<sub>添加作者微信</sub>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
33
deploy.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 部署管理后台到服务器 | 用法:pnpm run deploy
|
||||
*
|
||||
* 前置:SSH 免密登录(只需一次)
|
||||
* 1. 如果 %USERPROFILE%\.ssh\id_rsa 已存在跳过,否则 ssh-keygen -t rsa 回车到底
|
||||
*
|
||||
* 2. 拷贝公钥到服务器(会提示输一次服务器密码):
|
||||
* Windows: type %USERPROFILE%\.ssh\id_rsa.pub | ssh root@server "cat >> ~/.ssh/authorized_keys"
|
||||
* Mac: ssh-copy-id root@server
|
||||
*
|
||||
* 3. ssh root@server 输完不弹密码直接连上即成功
|
||||
*/
|
||||
import { execSync } from "node:child_process";
|
||||
|
||||
|
||||
|
||||
// ==================== 改为你的服务器信息 ====================
|
||||
const HOST = "127.0.0.1"; // 服务器 IP,改为你的
|
||||
const USER = "root"; // SSH 用户名,改为你的
|
||||
const PORT = 22; // SSH 端口,改为你的
|
||||
const TARGET = "/data/www/vue3-element-admin"; // 部署目录,改为你的
|
||||
// =========================================================
|
||||
|
||||
console.log("构建中...");
|
||||
execSync("pnpm build-only", { stdio: "inherit" });
|
||||
|
||||
console.log(`部署 → ${USER}@${HOST}:${TARGET}`);
|
||||
execSync(
|
||||
`scp -o StrictHostKeyChecking=no -P ${PORT} -r "dist/." "${USER}@${HOST}:${TARGET}/"`,
|
||||
{ stdio: "inherit", shell: true }
|
||||
);
|
||||
|
||||
console.log("部署完成");
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-present PanJiaChen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-present 有来开源组织
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -17,7 +17,8 @@
|
||||
"lint": "npm run lint:eslint && npm run lint:prettier && npm run lint:stylelint",
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"prepare": "husky",
|
||||
"commit": "git-cz"
|
||||
"commit": "git-cz",
|
||||
"deploy": "node deploy.mjs"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.5 MiB |
|
Before Width: | Height: | Size: 487 KiB After Width: | Height: | Size: 487 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 4.1 MiB After Width: | Height: | Size: 4.1 MiB |
|
Before Width: | Height: | Size: 306 KiB After Width: | Height: | Size: 306 KiB |
@@ -49,10 +49,8 @@
|
||||
</span>
|
||||
<!-- 内容全屏 -->
|
||||
<span class="tags-actions__btn" @click="appStore.toggleContentFullscreen()">
|
||||
<el-icon :size="16">
|
||||
<FullScreen v-if="!appStore.contentFullscreen" />
|
||||
<Close v-else />
|
||||
</el-icon>
|
||||
<div v-if="!appStore.contentFullscreen" class="i-svg:fullscreen icon-16" />
|
||||
<div v-else class="i-svg:fullscreen-exit icon-16" />
|
||||
</span>
|
||||
<!-- 下拉菜单 -->
|
||||
<el-dropdown trigger="click" @command="handleActionCommand">
|
||||
@@ -62,39 +60,27 @@
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="refresh">
|
||||
<el-icon :size="14" class="tags-actions__dropdown-icon">
|
||||
<Refresh />
|
||||
</el-icon>
|
||||
<el-icon :size="14" class="icon-14"><Refresh /></el-icon>
|
||||
<span>刷新当前</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="currentTag && !currentTag.affix" command="closeCurrent">
|
||||
<el-icon :size="14" class="tags-actions__dropdown-icon">
|
||||
<Close />
|
||||
</el-icon>
|
||||
<div class="i-svg:close icon-14" />
|
||||
<span>关闭当前</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided command="closeOthers">
|
||||
<el-icon :size="14" class="tags-actions__dropdown-icon">
|
||||
<Remove />
|
||||
</el-icon>
|
||||
<el-dropdown-item divided command="closeOtherTags">
|
||||
<div class="i-svg:close_other icon-14" />
|
||||
<span>关闭其它</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="closeLeft">
|
||||
<el-icon :size="14" class="tags-actions__dropdown-icon">
|
||||
<DArrowLeft />
|
||||
</el-icon>
|
||||
<el-dropdown-item command="closeLeftTags">
|
||||
<div class="i-svg:close_left icon-14" />
|
||||
<span>关闭左侧</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item command="closeRight">
|
||||
<el-icon :size="14" class="tags-actions__dropdown-icon">
|
||||
<DArrowRight />
|
||||
</el-icon>
|
||||
<el-dropdown-item command="closeRightTags">
|
||||
<div class="i-svg:close_right icon-14" />
|
||||
<span>关闭右侧</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided command="closeAll">
|
||||
<el-icon :size="14" class="tags-actions__dropdown-icon">
|
||||
<CircleClose />
|
||||
</el-icon>
|
||||
<el-dropdown-item divided command="closeAllTags">
|
||||
<div class="i-svg:close_all icon-14" />
|
||||
<span>关闭所有</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
@@ -114,25 +100,25 @@
|
||||
class="contextmenu__danger"
|
||||
@click="closeSelectedTag(selectedTag)"
|
||||
>
|
||||
<el-icon :size="16" class="contextmenu__icon"><Close /></el-icon>
|
||||
<div class="i-svg:close contextmenu__icon" />
|
||||
<span>关闭</span>
|
||||
</li>
|
||||
<li class="contextmenu__divider" />
|
||||
<li @click="closeOtherTags">
|
||||
<el-icon :size="16" class="contextmenu__icon"><Remove /></el-icon>
|
||||
<div class="i-svg:close_other contextmenu__icon" />
|
||||
<span>关闭其它</span>
|
||||
</li>
|
||||
<li v-if="!isFirstView" @click="closeLeftTags">
|
||||
<el-icon :size="16" class="contextmenu__icon"><DArrowLeft /></el-icon>
|
||||
<div class="i-svg:close_left contextmenu__icon" />
|
||||
<span>关闭左侧</span>
|
||||
</li>
|
||||
<li v-if="!isLastView" @click="closeRightTags">
|
||||
<el-icon :size="16" class="contextmenu__icon"><DArrowRight /></el-icon>
|
||||
<div class="i-svg:close_right contextmenu__icon" />
|
||||
<span>关闭右侧</span>
|
||||
</li>
|
||||
<li class="contextmenu__divider" />
|
||||
<li @click="closeAllTags(selectedTag)">
|
||||
<el-icon :size="16" class="contextmenu__icon"><CircleClose /></el-icon>
|
||||
<div class="i-svg:close_all contextmenu__icon" />
|
||||
<span>关闭所有</span>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -212,16 +198,16 @@ const handleActionCommand = (command: string) => {
|
||||
case "closeCurrent":
|
||||
closeSelectedTag(currentTag.value);
|
||||
break;
|
||||
case "closeOthers":
|
||||
case "closeOtherTags":
|
||||
closeOtherTagsForActive();
|
||||
break;
|
||||
case "closeLeft":
|
||||
case "closeLeftTags":
|
||||
closeLeftTagsForActive();
|
||||
break;
|
||||
case "closeRight":
|
||||
case "closeRightTags":
|
||||
closeRightTagsForActive();
|
||||
break;
|
||||
case "closeAll":
|
||||
case "closeAllTags":
|
||||
closeAllTags(currentTag.value);
|
||||
break;
|
||||
}
|
||||
@@ -379,9 +365,7 @@ const closeSelectedTag = (tag: TagView | null) => {
|
||||
});
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 批量关闭标签(左/右/其它方向) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
// 批量关闭标签(左/右/其它方向)
|
||||
|
||||
/**
|
||||
* 按方向批量关闭标签的通用执行器。
|
||||
@@ -407,7 +391,9 @@ function closeDirectional(
|
||||
});
|
||||
}
|
||||
|
||||
/** 关闭当前激活标签之外的其它标签 */
|
||||
/**
|
||||
* 关闭当前激活标签之外的其它标签。
|
||||
*/
|
||||
const closeOtherTagsForActive = () => {
|
||||
if (!currentTag.value) return;
|
||||
tagsViewStore.delOtherViews(currentTag.value).then(() => {
|
||||
@@ -646,19 +632,33 @@ useContextMenuManager();
|
||||
background-color: var(--el-fill-color-light);
|
||||
}
|
||||
|
||||
:deep(.el-icon) {
|
||||
:deep(.el-icon),
|
||||
:deep(div) {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
&:hover :deep(.el-icon) {
|
||||
&:hover :deep(.el-icon),
|
||||
&:hover :deep(div) {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__dropdown-icon {
|
||||
flex-shrink: 0;
|
||||
margin-right: 6px;
|
||||
opacity: 0.55;
|
||||
.icon-16 {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.icon-14 {
|
||||
flex-shrink: 0;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-right: 6px;
|
||||
opacity: 0.55;
|
||||
|
||||
&.el-icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,6 +697,8 @@ useContextMenuManager();
|
||||
|
||||
&__icon {
|
||||
flex-shrink: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
/**
|
||||
* 混合布局菜单逻辑
|
||||
*
|
||||
* 从 MixLayout.vue 提取,负责:
|
||||
* - 顶部菜单项扁平化(单子菜单向上合并 title/icon)
|
||||
* - 侧边菜单路径解析与激活判定
|
||||
* - 菜单切换导航(自动跳转到第一个可访问子菜单)
|
||||
* - 路由变化时同步顶部菜单激活态与侧边菜单数据
|
||||
*
|
||||
* 模板只绑定返回值,无需关心内部实现。
|
||||
*/
|
||||
import type { LocationQueryRaw, RouteRecordRaw } from "vue-router";
|
||||
import { useLayout } from "../useLayout";
|
||||
@@ -15,10 +7,6 @@ import { useAppStore, usePermissionStore, useSettingsStore } from "@/stores";
|
||||
import { isExternal } from "@/utils/index";
|
||||
import { ElIcon } from "element-plus";
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* MenuIcon — 菜单图标渲染组件(Element Plus / SVG 双模式) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
const MenuIcon = defineComponent({
|
||||
props: { icon: String },
|
||||
setup(props) {
|
||||
@@ -39,9 +27,6 @@ const MenuIcon = defineComponent({
|
||||
},
|
||||
});
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* useMixMenu */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
export function useMixMenu() {
|
||||
const route = useRoute();
|
||||
@@ -53,7 +38,6 @@ export function useMixMenu() {
|
||||
|
||||
const { activeTopMenuPath, sideMenuRoutes } = useLayout();
|
||||
|
||||
/* ------ 顶部菜单 ------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* 顶部菜单项。
|
||||
@@ -84,9 +68,12 @@ export function useMixMenu() {
|
||||
});
|
||||
});
|
||||
|
||||
/* ------ 侧边菜单 ------------------------------------------------- */
|
||||
|
||||
/** 当前路由对应的侧边菜单激活路径(优先取 meta.activeMenu) */
|
||||
/**
|
||||
* 当前路由对应的侧边菜单激活路径。
|
||||
*
|
||||
* 优先取 meta.activeMenu,否则使用当前路由路径。
|
||||
*/
|
||||
const activeSideMenuPath = computed(() => {
|
||||
const { meta, path } = route;
|
||||
return typeof meta?.activeMenu === "string" ? meta.activeMenu : path;
|
||||
@@ -105,8 +92,6 @@ export function useMixMenu() {
|
||||
return `${activeTopMenuPath.value}/${routePath}`;
|
||||
}
|
||||
|
||||
/* ------ 路径工具 ------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* 从完整路径中提取第一段作为顶级菜单路径。
|
||||
*
|
||||
@@ -114,14 +99,15 @@ export function useMixMenu() {
|
||||
* "/dashboard" → "/"
|
||||
*/
|
||||
function extractTopMenuPath(path: string): string {
|
||||
return path.split("/").filter(Boolean).length > 1
|
||||
? path.match(/^\/[^/]+/)?.[0] || "/"
|
||||
: "/";
|
||||
return path.split("/").filter(Boolean).length > 1 ? path.match(/^\/[^/]+/)?.[0] || "/" : "/";
|
||||
}
|
||||
|
||||
/* ------ 菜单切换 ------------------------------------------------- */
|
||||
|
||||
/** 顶部菜单点击:切换侧边菜单数据,并导航到第一个可访问叶子菜单 */
|
||||
/**
|
||||
* 顶部菜单点击。
|
||||
*
|
||||
* 切换侧边菜单数据,并导航到第一个可访问叶子菜单。
|
||||
*/
|
||||
function handleTopMenuSelect(menuPath: string) {
|
||||
if (menuPath === activeTopMenuPath.value) return;
|
||||
|
||||
@@ -153,7 +139,7 @@ export function useMixMenu() {
|
||||
}
|
||||
}
|
||||
|
||||
/* ------ 路由同步 ------------------------------------------------- */
|
||||
// 路由同步
|
||||
|
||||
/**
|
||||
* 监听路由变化,保持顶部菜单激活态和侧边菜单数据同步。
|
||||
|
||||
@@ -58,16 +58,30 @@ export function useLayout() {
|
||||
// 菜单数据
|
||||
// ============================================
|
||||
|
||||
/** 路由列表(左侧/顶部菜单) */
|
||||
/**
|
||||
* 路由列表。
|
||||
*
|
||||
* 左侧/顶部菜单共用,由权限 store 生成。
|
||||
*/
|
||||
const routes = computed(() => permissionStore.routes);
|
||||
|
||||
/** 混合布局侧边菜单 */
|
||||
/**
|
||||
* 混合布局侧边菜单。
|
||||
*
|
||||
* 根据当前激活的顶部菜单路径动态计算。
|
||||
*/
|
||||
const sideMenuRoutes = computed(() => permissionStore.mixLayoutSideMenus);
|
||||
|
||||
/** 顶部菜单激活路径 */
|
||||
/**
|
||||
* 顶部菜单激活路径。
|
||||
*/
|
||||
const activeTopMenuPath = computed(() => appStore.activeTopMenuPath);
|
||||
|
||||
/** 当前激活菜单 */
|
||||
/**
|
||||
* 当前激活菜单。
|
||||
*
|
||||
* 优先取路由 meta.activeMenu,否则取当前路径。
|
||||
*/
|
||||
const activeMenu = computed(() => {
|
||||
const { meta, path } = route;
|
||||
return meta?.activeMenu || path;
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
export interface PageQueryParams {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface OptionItem {
|
||||
label: string;
|
||||
value: string | number;
|
||||
meta?: any;
|
||||
children?: OptionItem[];
|
||||
}
|
||||
|
||||
export interface ExcelResult {
|
||||
/** 状态码 */
|
||||
code: number;
|
||||
/** 无效数据条数 */
|
||||
invalidCount: number;
|
||||
/** 有效数据条数 */
|
||||
validCount: number;
|
||||
/** 错误信息 */
|
||||
messageList: Array<string>;
|
||||
}
|
||||
|
||||
export interface PageResult<T> {
|
||||
total: number;
|
||||
list: T[];
|
||||
params: PageQueryParams;
|
||||
}
|
||||
|
||||
export interface ApiResponse<T = any> {
|
||||
code: number | string;
|
||||
msg: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
export interface BaseEntity {
|
||||
id: number;
|
||||
createTime: string;
|
||||
updateTime: string;
|
||||
}
|
||||
5
src/types/global.d.ts
vendored
@@ -4,11 +4,6 @@
|
||||
* @deprecated 请使用 @/types 下的具名导出
|
||||
*/
|
||||
declare global {
|
||||
type ApiResponse<T = unknown> = import("@/types/api").ApiResponse<T>;
|
||||
type BaseQueryParams = import("@/types/api").BaseQueryParams;
|
||||
type PageResult<T> = import("@/types/api").PageResult<T>;
|
||||
type OptionItem = import("@/types/api").OptionItem;
|
||||
type ExcelResult = import("@/types/api").ExcelResult;
|
||||
type TagView = import("@/types/ui").TagView;
|
||||
type AppSettings = import("@/types/ui").AppSettings;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ function extractFileName(contentDisposition: string): string {
|
||||
* downloadFile(response, "用户列表.xlsx");
|
||||
* ```
|
||||
*/
|
||||
export function downloadFile(response: any, customFileName?: string): void {
|
||||
export function downloadFile(response: { data: any; headers: Record<string, string> }, customFileName?: string): void {
|
||||
try {
|
||||
const fileData = response.data;
|
||||
const contentDisposition = response.headers["content-disposition"];
|
||||
|
||||
@@ -579,11 +579,8 @@ $radius: 10px;
|
||||
|
||||
&__end {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
gap: 20px;
|
||||
align-items: center;
|
||||
padding: 10px 14px;
|
||||
background: var(--el-color-primary-light-9);
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
</el-button>
|
||||
<el-button
|
||||
v-hasPerm="['sys:config:refresh']"
|
||||
color="#626aef"
|
||||
type="primary"
|
||||
icon="RefreshLeft"
|
||||
@click="refreshCache"
|
||||
>
|
||||
|
||||
@@ -328,17 +328,10 @@ function handleQuery(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置查询条件
|
||||
*/
|
||||
function resetQuery(): void {
|
||||
queryFormRef.value?.resetFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置查询条件并重新查询
|
||||
* 重置搜索条件并重新查询。
|
||||
*/
|
||||
function handleResetQuery(): void {
|
||||
resetQuery();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
导入
|
||||
</el-button>
|
||||
|
||||
<el-button v-hasPerm="'sys:user:export'" icon="download" @click="exportUsers">
|
||||
<el-button v-hasPerm="'sys:user:export'" icon="download" @click="handleExport">
|
||||
导出
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -347,19 +347,12 @@ function handleQuery(): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置查询条件
|
||||
* 重置搜索条件并重新查询。
|
||||
*/
|
||||
function resetQuery(): void {
|
||||
function handleResetQuery(): void {
|
||||
queryFormRef.value?.resetFields();
|
||||
tableData.params.deptId = undefined;
|
||||
tableData.params.createTime = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置查询条件并重新查询
|
||||
*/
|
||||
function handleResetQuery(): void {
|
||||
resetQuery();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
@@ -509,10 +502,7 @@ function handleDelete(id?: string): void {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出用户列表
|
||||
*/
|
||||
async function exportUsers(): Promise<void> {
|
||||
async function handleExport(): Promise<void> {
|
||||
const response = await UserAPI.export(tableData.params);
|
||||
downloadFile(response);
|
||||
ElMessage.success("导出成功");
|
||||
|
||||