refactor: 重构项目结构 - enums/config/types/plugins
- 重构 enums: 按业务域合并为 5 个文件 - 创建 config: storage.ts, vxe-table.ts - 删除 plugins,功能迁移到 main.ts - 创建完整 types 结构 - 新增 utils: validators, websocket, register-components - 创建 router/guards/permission.ts - 更新配置文件
This commit is contained in:
5
src/config/index.ts
Normal file
5
src/config/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* 配置统一导出
|
||||
*/
|
||||
|
||||
export * from "./storage";
|
||||
60
src/config/storage.ts
Normal file
60
src/config/storage.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 本地存储键名配置
|
||||
*
|
||||
* @description
|
||||
* 统一管理 localStorage/sessionStorage 的键名
|
||||
* 命名规范:{prefix}:{namespace}:{key}
|
||||
*/
|
||||
|
||||
export const APP_PREFIX = "vea";
|
||||
|
||||
/**
|
||||
* 存储键名常量
|
||||
*/
|
||||
export const STORAGE_KEYS = {
|
||||
// ===== 认证相关 =====
|
||||
ACCESS_TOKEN: `${APP_PREFIX}:auth:access_token`,
|
||||
REFRESH_TOKEN: `${APP_PREFIX}:auth:refresh_token`,
|
||||
REMEMBER_ME: `${APP_PREFIX}:auth:remember_me`,
|
||||
|
||||
// ===== 租户相关 =====
|
||||
TENANT_ID: `${APP_PREFIX}:tenant:id`,
|
||||
TENANT_INFO: `${APP_PREFIX}:tenant:info`,
|
||||
|
||||
// ===== 系统相关 =====
|
||||
DICT_CACHE: `${APP_PREFIX}:system:dict_cache`,
|
||||
|
||||
// ===== UI 设置 =====
|
||||
SHOW_TAGS_VIEW: `${APP_PREFIX}:ui:show_tags_view`,
|
||||
SHOW_APP_LOGO: `${APP_PREFIX}:ui:show_app_logo`,
|
||||
SHOW_WATERMARK: `${APP_PREFIX}:ui:show_watermark`,
|
||||
ENABLE_AI_ASSISTANT: `${APP_PREFIX}:ui:enable_ai_assistant`,
|
||||
LAYOUT: `${APP_PREFIX}:ui:layout`,
|
||||
SIDEBAR_COLOR_SCHEME: `${APP_PREFIX}:ui:sidebar_color_scheme`,
|
||||
THEME: `${APP_PREFIX}:ui:theme`,
|
||||
THEME_COLOR: `${APP_PREFIX}:ui:theme_color`,
|
||||
|
||||
// ===== 应用状态 =====
|
||||
DEVICE: `${APP_PREFIX}:app:device`,
|
||||
SIZE: `${APP_PREFIX}:app:size`,
|
||||
LANGUAGE: `${APP_PREFIX}:app:language`,
|
||||
SIDEBAR_STATUS: `${APP_PREFIX}:app:sidebar_status`,
|
||||
ACTIVE_TOP_MENU_PATH: `${APP_PREFIX}:app:active_top_menu_path`,
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* 认证相关键名(便于批量操作)
|
||||
*/
|
||||
export const AUTH_KEYS = {
|
||||
ACCESS_TOKEN: STORAGE_KEYS.ACCESS_TOKEN,
|
||||
REFRESH_TOKEN: STORAGE_KEYS.REFRESH_TOKEN,
|
||||
REMEMBER_ME: STORAGE_KEYS.REMEMBER_ME,
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* 租户相关键名(便于批量操作)
|
||||
*/
|
||||
export const TENANT_KEYS = {
|
||||
TENANT_ID: STORAGE_KEYS.TENANT_ID,
|
||||
TENANT_INFO: STORAGE_KEYS.TENANT_INFO,
|
||||
} as const;
|
||||
65
src/config/vxe-table.ts
Normal file
65
src/config/vxe-table.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* VxeTable 全局配置
|
||||
*
|
||||
* @description
|
||||
* VxeTable 是一个基于 Vue 的 PC 端表格组件
|
||||
* @see https://vxetable.cn/v4.6/#/table/start/install
|
||||
*/
|
||||
|
||||
import VXETable from "vxe-table";
|
||||
|
||||
/**
|
||||
* 配置 VxeTable 全局参数
|
||||
*/
|
||||
export function configureVxeTable() {
|
||||
VXETable.setConfig({
|
||||
size: "medium",
|
||||
zIndex: 9999,
|
||||
version: 0,
|
||||
loadingText: null,
|
||||
table: {
|
||||
showHeader: true,
|
||||
showOverflow: "tooltip",
|
||||
showHeaderOverflow: "tooltip",
|
||||
autoResize: true,
|
||||
border: "inner",
|
||||
emptyText: "暂无数据",
|
||||
rowConfig: {
|
||||
isHover: true,
|
||||
isCurrent: true,
|
||||
keyField: "_VXE_ID",
|
||||
},
|
||||
columnConfig: {
|
||||
resizable: false,
|
||||
},
|
||||
align: "center",
|
||||
headerAlign: "center",
|
||||
},
|
||||
pager: {
|
||||
perfect: false,
|
||||
pageSize: 10,
|
||||
pagerCount: 7,
|
||||
pageSizes: [10, 20, 50],
|
||||
layouts: [
|
||||
"Total",
|
||||
"PrevJump",
|
||||
"PrevPage",
|
||||
"Number",
|
||||
"NextPage",
|
||||
"NextJump",
|
||||
"Sizes",
|
||||
"FullJump",
|
||||
],
|
||||
},
|
||||
modal: {
|
||||
minWidth: 500,
|
||||
minHeight: 400,
|
||||
lockView: true,
|
||||
mask: true,
|
||||
dblclickZoom: false,
|
||||
showTitleOverflow: true,
|
||||
transfer: true,
|
||||
draggable: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,172 +1,13 @@
|
||||
/**
|
||||
* 项目常量统一管理
|
||||
* 存储键命名规范:{prefix}:{namespace}:{key}
|
||||
/**
|
||||
* 常量统一导出
|
||||
*
|
||||
* @deprecated 此文件已废弃,请使用以下路径:
|
||||
* - 存储键常量 @/config/storage
|
||||
* - 验证规则 @/utils/validators
|
||||
* - 角色常量 @/enums
|
||||
*/
|
||||
|
||||
export const APP_PREFIX = "vea";
|
||||
|
||||
export const STORAGE_KEYS = {
|
||||
// 用户认证相关
|
||||
ACCESS_TOKEN: `${APP_PREFIX}:auth:access_token`, // JWT访问令牌
|
||||
REFRESH_TOKEN: `${APP_PREFIX}:auth:refresh_token`, // JWT刷新令牌
|
||||
REMEMBER_ME: `${APP_PREFIX}:auth:remember_me`, // 记住登录状态
|
||||
|
||||
// 租户相关
|
||||
TENANT_ID: `${APP_PREFIX}:tenant:id`, // 当前租户ID
|
||||
TENANT_INFO: `${APP_PREFIX}:tenant:info`, // 当前租户信息
|
||||
|
||||
// 系统核心相关
|
||||
DICT_CACHE: `${APP_PREFIX}:system:dict_cache`, // 字典数据缓存
|
||||
|
||||
// UI设置相关
|
||||
SHOW_TAGS_VIEW: `${APP_PREFIX}:ui:show_tags_view`, // 显示标签页视图
|
||||
SHOW_APP_LOGO: `${APP_PREFIX}:ui:show_app_logo`, // 显示应用Logo
|
||||
SHOW_WATERMARK: `${APP_PREFIX}:ui:show_watermark`, // 显示水印
|
||||
ENABLE_AI_ASSISTANT: `${APP_PREFIX}:ui:enable_ai_assistant`, // 启用 AI 助手
|
||||
LAYOUT: `${APP_PREFIX}:ui:layout`, // 布局模式
|
||||
SIDEBAR_COLOR_SCHEME: `${APP_PREFIX}:ui:sidebar_color_scheme`, // 侧边栏配色方案
|
||||
THEME: `${APP_PREFIX}:ui:theme`, // 主题模式
|
||||
THEME_COLOR: `${APP_PREFIX}:ui:theme_color`, // 主题色
|
||||
|
||||
// 应用状态相关
|
||||
DEVICE: `${APP_PREFIX}:app:device`, // 设备类型
|
||||
SIZE: `${APP_PREFIX}:app:size`, // 屏幕尺寸
|
||||
LANGUAGE: `${APP_PREFIX}:app:language`, // 应用语言
|
||||
SIDEBAR_STATUS: `${APP_PREFIX}:app:sidebar_status`, // 侧边栏状态
|
||||
ACTIVE_TOP_MENU_PATH: `${APP_PREFIX}:app:active_top_menu_path`, // 当前激活的顶部菜单路径
|
||||
} as const;
|
||||
|
||||
export const ROLE_ROOT = "ROOT"; // 超级管理员角色
|
||||
|
||||
// 分组键集合(便于批量操作)
|
||||
export const AUTH_KEYS = {
|
||||
ACCESS_TOKEN: STORAGE_KEYS.ACCESS_TOKEN,
|
||||
REFRESH_TOKEN: STORAGE_KEYS.REFRESH_TOKEN,
|
||||
REMEMBER_ME: STORAGE_KEYS.REMEMBER_ME,
|
||||
} as const;
|
||||
|
||||
export const TENANT_KEYS = {
|
||||
TENANT_ID: STORAGE_KEYS.TENANT_ID,
|
||||
TENANT_INFO: STORAGE_KEYS.TENANT_INFO,
|
||||
} as const;
|
||||
|
||||
export const SYSTEM_KEYS = {
|
||||
DICT_CACHE: STORAGE_KEYS.DICT_CACHE,
|
||||
} as const;
|
||||
|
||||
export const SETTINGS_KEYS = {
|
||||
SHOW_TAGS_VIEW: STORAGE_KEYS.SHOW_TAGS_VIEW,
|
||||
SHOW_APP_LOGO: STORAGE_KEYS.SHOW_APP_LOGO,
|
||||
SHOW_WATERMARK: STORAGE_KEYS.SHOW_WATERMARK,
|
||||
ENABLE_AI_ASSISTANT: STORAGE_KEYS.ENABLE_AI_ASSISTANT,
|
||||
SIDEBAR_COLOR_SCHEME: STORAGE_KEYS.SIDEBAR_COLOR_SCHEME,
|
||||
LAYOUT: STORAGE_KEYS.LAYOUT,
|
||||
THEME_COLOR: STORAGE_KEYS.THEME_COLOR,
|
||||
THEME: STORAGE_KEYS.THEME,
|
||||
} as const;
|
||||
|
||||
export const APP_KEYS = {
|
||||
DEVICE: STORAGE_KEYS.DEVICE,
|
||||
SIZE: STORAGE_KEYS.SIZE,
|
||||
LANGUAGE: STORAGE_KEYS.LANGUAGE,
|
||||
SIDEBAR_STATUS: STORAGE_KEYS.SIDEBAR_STATUS,
|
||||
ACTIVE_TOP_MENU_PATH: STORAGE_KEYS.ACTIVE_TOP_MENU_PATH,
|
||||
} as const;
|
||||
|
||||
export const ALL_STORAGE_KEYS = {
|
||||
...AUTH_KEYS,
|
||||
...TENANT_KEYS,
|
||||
...SYSTEM_KEYS,
|
||||
...SETTINGS_KEYS,
|
||||
...APP_KEYS,
|
||||
} as const;
|
||||
|
||||
export type StorageKey = (typeof STORAGE_KEYS)[keyof typeof STORAGE_KEYS];
|
||||
|
||||
/**
|
||||
* 表单验证规则常量
|
||||
* 提供常用的验证规则,减少重复代码
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const rules = reactive({
|
||||
* username: [VALIDATORS.required("用户名不能为空")],
|
||||
* email: [VALIDATORS.email],
|
||||
* mobile: [VALIDATORS.mobile],
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export const VALIDATORS = {
|
||||
/**
|
||||
* 必填验证
|
||||
* @param message 错误提示信息
|
||||
*/
|
||||
required: (message: string) => ({
|
||||
required: true,
|
||||
message,
|
||||
trigger: "blur",
|
||||
}),
|
||||
|
||||
/**
|
||||
* 邮箱格式验证
|
||||
*/
|
||||
email: {
|
||||
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
|
||||
message: "请输入正确的邮箱地址",
|
||||
trigger: "blur",
|
||||
},
|
||||
|
||||
/**
|
||||
* 手机号码验证(中国大陆)
|
||||
*/
|
||||
mobile: {
|
||||
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
|
||||
message: "请输入正确的手机号码",
|
||||
trigger: "blur",
|
||||
},
|
||||
|
||||
/**
|
||||
* 身份证号码验证(中国大陆)
|
||||
*/
|
||||
idCard: {
|
||||
pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,
|
||||
message: "请输入正确的身份证号码",
|
||||
trigger: "blur",
|
||||
},
|
||||
|
||||
/**
|
||||
* URL 格式验证
|
||||
*/
|
||||
url: {
|
||||
pattern: /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/i,
|
||||
message: "请输入正确的URL地址",
|
||||
trigger: "blur",
|
||||
},
|
||||
|
||||
/**
|
||||
* 数字验证
|
||||
*/
|
||||
number: {
|
||||
pattern: /^\d+$/,
|
||||
message: "请输入数字",
|
||||
trigger: "blur",
|
||||
},
|
||||
|
||||
/**
|
||||
* 整数验证(正整数、负整数、0)
|
||||
*/
|
||||
integer: {
|
||||
pattern: /^-?\d+$/,
|
||||
message: "请输入整数",
|
||||
trigger: "blur",
|
||||
},
|
||||
|
||||
/**
|
||||
* 正整数验证
|
||||
*/
|
||||
positiveInteger: {
|
||||
pattern: /^[1-9]\d*$/,
|
||||
message: "请输入正整数",
|
||||
trigger: "blur",
|
||||
},
|
||||
} as const;
|
||||
// 向后兼容导出
|
||||
export * from "@/config/storage";
|
||||
export { ROLE_ROOT } from "@/enums";
|
||||
export { VALIDATORS } from "@/utils/validators";
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
/**
|
||||
* API响应码枚举
|
||||
* API 相关枚举
|
||||
*
|
||||
* @description
|
||||
* 包含 API 响应码、请求状态等枚举定义
|
||||
*/
|
||||
|
||||
/**
|
||||
* API 响应码枚举
|
||||
*/
|
||||
export const enum ApiCodeEnum {
|
||||
/**
|
||||
47
src/enums/business.ts
Normal file
47
src/enums/business.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 业务相关枚举
|
||||
*
|
||||
* @description
|
||||
* 包含菜单、用户、角色等业务实体的枚举定义
|
||||
*/
|
||||
|
||||
/**
|
||||
* 菜单类型枚举
|
||||
*/
|
||||
export enum MenuTypeEnum {
|
||||
CATALOG = "C", // 目录
|
||||
MENU = "M", // 菜单
|
||||
BUTTON = "B", // 按钮
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户性别枚举
|
||||
*/
|
||||
export enum UserGender {
|
||||
/** 未知 */
|
||||
UNKNOWN = 0,
|
||||
/** 男 */
|
||||
MALE = 1,
|
||||
/** 女 */
|
||||
FEMALE = 2,
|
||||
}
|
||||
|
||||
/**
|
||||
* 超级管理员角色标识
|
||||
*
|
||||
* @description
|
||||
* 拥有系统最高权限,可以访问所有资源
|
||||
*/
|
||||
export const ROLE_ROOT = "ROOT";
|
||||
|
||||
/**
|
||||
* 角色类型枚举
|
||||
*/
|
||||
export enum RoleType {
|
||||
/** 超级管理员 */
|
||||
ROOT = "ROOT",
|
||||
/** 管理员 */
|
||||
ADMIN = "ADMIN",
|
||||
/** 普通用户 */
|
||||
USER = "USER",
|
||||
}
|
||||
@@ -1,3 +1,26 @@
|
||||
/**
|
||||
* 代码生成相关枚举
|
||||
*
|
||||
* @description
|
||||
* 包含表单类型、查询类型等代码生成功能的枚举定义
|
||||
*/
|
||||
|
||||
/**
|
||||
* 表单类型枚举
|
||||
*/
|
||||
export const FormTypeEnum: Record<string, OptionType> = {
|
||||
INPUT: { value: 1, label: "输入框" },
|
||||
SELECT: { value: 2, label: "下拉框" },
|
||||
RADIO: { value: 3, label: "单选框" },
|
||||
CHECK_BOX: { value: 4, label: "复选框" },
|
||||
INPUT_NUMBER: { value: 5, label: "数字输入框" },
|
||||
SWITCH: { value: 6, label: "开关" },
|
||||
TEXT_AREA: { value: 7, label: "文本域" },
|
||||
DATE: { value: 8, label: "日期框" },
|
||||
DATE_TIME: { value: 9, label: "日期时间框" },
|
||||
HIDDEN: { value: 10, label: "隐藏域" },
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询类型枚举
|
||||
*/
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* 表单类型枚举
|
||||
*/
|
||||
export const FormTypeEnum: Record<string, OptionType> = {
|
||||
INPUT: { value: 1, label: "输入框" },
|
||||
SELECT: { value: 2, label: "下拉框" },
|
||||
RADIO: { value: 3, label: "单选框" },
|
||||
CHECK_BOX: { value: 4, label: "复选框" },
|
||||
INPUT_NUMBER: { value: 5, label: "数字输入框" },
|
||||
SWITCH: { value: 6, label: "开关" },
|
||||
TEXT_AREA: { value: 7, label: "文本域" },
|
||||
DATE: { value: 8, label: "日期框" },
|
||||
DATE_TIME: { value: 9, label: "日期时间框" },
|
||||
HIDDEN: { value: 10, label: "隐藏域" },
|
||||
};
|
||||
46
src/enums/common.ts
Normal file
46
src/enums/common.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 通用枚举
|
||||
*
|
||||
* @description
|
||||
* 包含对话框模式、通用状态等跨业务的枚举定义
|
||||
*/
|
||||
|
||||
/**
|
||||
* 对话框模式枚举
|
||||
*
|
||||
* @description
|
||||
* 定义对话框的操作模式(创建、编辑、查看)
|
||||
*/
|
||||
export enum DialogMode {
|
||||
/** 创建模式 - 新增数据 */
|
||||
CREATE = "create",
|
||||
/** 编辑模式 - 修改数据 */
|
||||
EDIT = "edit",
|
||||
/** 查看模式 - 只读展示 */
|
||||
VIEW = "view",
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用状态枚举
|
||||
*
|
||||
* @description
|
||||
* 适用于大多数业务实体的启用/禁用状态
|
||||
*/
|
||||
export enum CommonStatus {
|
||||
/** 禁用 */
|
||||
DISABLED = 0,
|
||||
/** 启用 */
|
||||
ENABLED = 1,
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核状态枚举
|
||||
*/
|
||||
export enum AuditStatus {
|
||||
/** 待审核 */
|
||||
PENDING = 0,
|
||||
/** 已通过 */
|
||||
APPROVED = 1,
|
||||
/** 已拒绝 */
|
||||
REJECTED = 2,
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/**
|
||||
* 通用对话框模式枚举
|
||||
* @description 定义对话框的操作模式(创建、编辑、查看)
|
||||
*/
|
||||
export enum DialogMode {
|
||||
/** 创建模式 - 新增数据 */
|
||||
CREATE = "create",
|
||||
/** 编辑模式 - 修改数据 */
|
||||
EDIT = "edit",
|
||||
/** 查看模式 - 只读展示 */
|
||||
VIEW = "view",
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* 通用状态枚举
|
||||
* 适用于大多数业务实体的启用/禁用状态
|
||||
*/
|
||||
export enum CommonStatus {
|
||||
/** 禁用 */
|
||||
DISABLED = 0,
|
||||
/** 启用 */
|
||||
ENABLED = 1,
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核状态枚举
|
||||
*/
|
||||
export enum AuditStatus {
|
||||
/** 待审核 */
|
||||
PENDING = 0,
|
||||
/** 已通过 */
|
||||
APPROVED = 1,
|
||||
/** 已拒绝 */
|
||||
REJECTED = 2,
|
||||
}
|
||||
@@ -1,15 +1,12 @@
|
||||
export * from "./api/code-enum";
|
||||
/**
|
||||
* 枚举统一导出
|
||||
*
|
||||
* @description
|
||||
* 按业务域分组的枚举定义
|
||||
*/
|
||||
|
||||
export * from "./codegen/form-enum";
|
||||
export * from "./codegen/query-enum";
|
||||
|
||||
export * from "./settings/layout-enum";
|
||||
export * from "./settings/theme-enum";
|
||||
export * from "./settings/locale-enum";
|
||||
export * from "./settings/device-enum";
|
||||
|
||||
export * from "./common/dialog-enum";
|
||||
export * from "./common/status-enum";
|
||||
|
||||
export * from "./system/menu-enum";
|
||||
export * from "./system/user-enum";
|
||||
export * from "./api";
|
||||
export * from "./business";
|
||||
export * from "./codegen";
|
||||
export * from "./common";
|
||||
export * from "./settings";
|
||||
|
||||
123
src/enums/settings.ts
Normal file
123
src/enums/settings.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 设置相关枚举
|
||||
*
|
||||
* @description
|
||||
* 包含主题、布局、语言、设备等应用设置的枚举定义
|
||||
*/
|
||||
|
||||
/**
|
||||
* 主题模式枚举
|
||||
*/
|
||||
export const enum ThemeMode {
|
||||
/**
|
||||
* 明亮主题
|
||||
*/
|
||||
LIGHT = "light",
|
||||
/**
|
||||
* 暗黑主题
|
||||
*/
|
||||
DARK = "dark",
|
||||
|
||||
/**
|
||||
* 系统自动
|
||||
*/
|
||||
AUTO = "auto",
|
||||
}
|
||||
|
||||
/**
|
||||
* 侧边栏配色方案枚举
|
||||
*/
|
||||
export const enum SidebarColor {
|
||||
/**
|
||||
* 经典蓝
|
||||
*/
|
||||
CLASSIC_BLUE = "classic-blue",
|
||||
/**
|
||||
* 极简白
|
||||
*/
|
||||
MINIMAL_WHITE = "minimal-white",
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单布局枚举
|
||||
*/
|
||||
export const enum LayoutMode {
|
||||
/**
|
||||
* 左侧菜单布局
|
||||
*/
|
||||
LEFT = "left",
|
||||
/**
|
||||
* 顶部菜单布局
|
||||
*/
|
||||
TOP = "top",
|
||||
|
||||
/**
|
||||
* 混合菜单布局
|
||||
*/
|
||||
MIX = "mix",
|
||||
}
|
||||
|
||||
/**
|
||||
* 侧边栏状态枚举
|
||||
*/
|
||||
export const enum SidebarStatus {
|
||||
/**
|
||||
* 展开
|
||||
*/
|
||||
OPENED = "opened",
|
||||
|
||||
/**
|
||||
* 关闭
|
||||
*/
|
||||
CLOSED = "closed",
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件尺寸枚举
|
||||
*/
|
||||
export const enum ComponentSize {
|
||||
/**
|
||||
* 默认
|
||||
*/
|
||||
DEFAULT = "default",
|
||||
|
||||
/**
|
||||
* 大型
|
||||
*/
|
||||
LARGE = "large",
|
||||
|
||||
/**
|
||||
* 小型
|
||||
*/
|
||||
SMALL = "small",
|
||||
}
|
||||
|
||||
/**
|
||||
* 语言枚举
|
||||
*/
|
||||
export const enum LanguageEnum {
|
||||
/**
|
||||
* 中文
|
||||
*/
|
||||
ZH_CN = "zh-cn",
|
||||
|
||||
/**
|
||||
* 英文
|
||||
*/
|
||||
EN = "en",
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备枚举
|
||||
*/
|
||||
export const enum DeviceEnum {
|
||||
/**
|
||||
* 宽屏设备
|
||||
*/
|
||||
DESKTOP = "desktop",
|
||||
|
||||
/**
|
||||
* 窄屏设备
|
||||
*/
|
||||
MOBILE = "mobile",
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
/**
|
||||
* 设备枚举
|
||||
*/
|
||||
export const enum DeviceEnum {
|
||||
/**
|
||||
* 宽屏设备
|
||||
*/
|
||||
DESKTOP = "desktop",
|
||||
|
||||
/**
|
||||
* 窄屏设备
|
||||
*/
|
||||
MOBILE = "mobile",
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/**
|
||||
* 菜单布局枚举
|
||||
*/
|
||||
export const enum LayoutMode {
|
||||
/**
|
||||
* 左侧菜单布局
|
||||
*/
|
||||
LEFT = "left",
|
||||
/**
|
||||
* 顶部菜单布局
|
||||
*/
|
||||
TOP = "top",
|
||||
|
||||
/**
|
||||
* 混合菜单布局
|
||||
*/
|
||||
MIX = "mix",
|
||||
}
|
||||
|
||||
/**
|
||||
* 侧边栏状态枚举
|
||||
*/
|
||||
export const enum SidebarStatus {
|
||||
/**
|
||||
* 展开
|
||||
*/
|
||||
OPENED = "opened",
|
||||
|
||||
/**
|
||||
* 关闭
|
||||
*/
|
||||
CLOSED = "closed",
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件尺寸枚举
|
||||
*/
|
||||
export const enum ComponentSize {
|
||||
/**
|
||||
* 默认
|
||||
*/
|
||||
DEFAULT = "default",
|
||||
|
||||
/**
|
||||
* 大型
|
||||
*/
|
||||
LARGE = "large",
|
||||
|
||||
/**
|
||||
* 小型
|
||||
*/
|
||||
SMALL = "small",
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
/**
|
||||
* 语言枚举
|
||||
*/
|
||||
export const enum LanguageEnum {
|
||||
/**
|
||||
* 中文
|
||||
*/
|
||||
ZH_CN = "zh-cn",
|
||||
|
||||
/**
|
||||
* 英文
|
||||
*/
|
||||
EN = "en",
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* 主题枚举
|
||||
*/
|
||||
export const enum ThemeMode {
|
||||
/**
|
||||
* 明亮主题
|
||||
*/
|
||||
LIGHT = "light",
|
||||
/**
|
||||
* 暗黑主题
|
||||
*/
|
||||
DARK = "dark",
|
||||
|
||||
/**
|
||||
* 系统自动
|
||||
*/
|
||||
AUTO = "auto",
|
||||
}
|
||||
|
||||
/**
|
||||
* 侧边栏配色方案枚举
|
||||
*/
|
||||
export const enum SidebarColor {
|
||||
/**
|
||||
* 经典蓝
|
||||
*/
|
||||
CLASSIC_BLUE = "classic-blue",
|
||||
/**
|
||||
* 极简白
|
||||
*/
|
||||
MINIMAL_WHITE = "minimal-white",
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// 核心枚举定义
|
||||
export enum MenuTypeEnum {
|
||||
CATALOG = "C", // 目录
|
||||
MENU = "M", // 菜单
|
||||
BUTTON = "B", // 按钮
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* 用户性别枚举
|
||||
*/
|
||||
export enum UserGender {
|
||||
/** 未知 */
|
||||
UNKNOWN = 0,
|
||||
/** 男 */
|
||||
MALE = 1,
|
||||
/** 女 */
|
||||
FEMALE = 2,
|
||||
}
|
||||
58
src/main.ts
58
src/main.ts
@@ -1,19 +1,63 @@
|
||||
/**
|
||||
* 应用启动入口
|
||||
*
|
||||
* @description
|
||||
* Vue3 应用初始化,包括样式、插件、配置的加载
|
||||
*/
|
||||
|
||||
import { createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import setupPlugins from "@/plugins";
|
||||
|
||||
// 暗黑主题样式
|
||||
// ===== 样式导入 =====
|
||||
import "element-plus/theme-chalk/dark/css-vars.css";
|
||||
import "vxe-table/lib/style.css";
|
||||
// 暗黑模式自定义变量
|
||||
import "@/styles/dark/css-vars.css";
|
||||
import "@/styles/index.scss";
|
||||
import "uno.css";
|
||||
|
||||
// 过渡动画
|
||||
import "animate.css";
|
||||
|
||||
// ===== 核心配置 =====
|
||||
import { setupDirective } from "@/directives";
|
||||
import { setupI18n } from "@/lang";
|
||||
import { setupRouter } from "@/router";
|
||||
import { setupStore } from "@/store";
|
||||
|
||||
// ===== 全局组件 =====
|
||||
import { registerElementIcons } from "@/utils/register-components";
|
||||
|
||||
// ===== 第三方插件 =====
|
||||
import VXETable from "vxe-table";
|
||||
import { InstallCodeMirror } from "codemirror-editor-vue3";
|
||||
import { configureVxeTable } from "@/config/vxe-table";
|
||||
|
||||
// ===== 路由守卫 =====
|
||||
import { setupPermissionGuard } from "@/router/guards/permission";
|
||||
|
||||
// ===== 业务服务 =====
|
||||
import { setupWebSocket } from "@/utils/websocket";
|
||||
|
||||
// 创建 Vue 应用实例
|
||||
const app = createApp(App);
|
||||
// 注册插件
|
||||
app.use(setupPlugins);
|
||||
|
||||
// 1️⃣ 核心配置
|
||||
setupDirective(app);
|
||||
setupRouter(app);
|
||||
setupStore(app);
|
||||
setupI18n(app);
|
||||
|
||||
// 2️⃣ 全局组件
|
||||
registerElementIcons(app);
|
||||
|
||||
// 3️⃣ 第三方插件
|
||||
configureVxeTable();
|
||||
app.use(VXETable);
|
||||
app.use(InstallCodeMirror);
|
||||
|
||||
// 4️⃣ 路由守卫
|
||||
setupPermissionGuard();
|
||||
|
||||
// 5️⃣ WebSocket 初始化
|
||||
setupWebSocket();
|
||||
|
||||
// 6️⃣ 挂载应用
|
||||
app.mount("#app");
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import type { App } from "vue";
|
||||
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
|
||||
|
||||
// 注册所有图标
|
||||
export function setupElIcons(app: App<Element>) {
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import type { App } from "vue";
|
||||
|
||||
import { setupDirective } from "@/directives";
|
||||
import { setupI18n } from "@/lang";
|
||||
import { setupRouter } from "@/router";
|
||||
import { setupStore } from "@/store";
|
||||
import { setupElIcons } from "./icons";
|
||||
import { setupPermission } from "./permission";
|
||||
import { setupWebSocket } from "./websocket";
|
||||
import { InstallCodeMirror } from "codemirror-editor-vue3";
|
||||
import { setupVxeTable } from "./vxeTable";
|
||||
|
||||
export default {
|
||||
install(app: App<Element>) {
|
||||
// 自定义指令(directive)
|
||||
setupDirective(app);
|
||||
// 路由(router)
|
||||
setupRouter(app);
|
||||
// 状态管理(store)
|
||||
setupStore(app);
|
||||
// 国际化
|
||||
setupI18n(app);
|
||||
// Element-plus图标
|
||||
setupElIcons(app);
|
||||
// 路由守卫
|
||||
setupPermission();
|
||||
// WebSocket服务
|
||||
setupWebSocket();
|
||||
// vxe-table
|
||||
setupVxeTable(app);
|
||||
// 注册 CodeMirror
|
||||
app.use(InstallCodeMirror);
|
||||
},
|
||||
};
|
||||
@@ -1,70 +0,0 @@
|
||||
import type { App } from "vue";
|
||||
import VXETable from "vxe-table"; // https://vxetable.cn/v4.6/#/table/start/install
|
||||
|
||||
// 全局默认参数
|
||||
VXETable.setConfig({
|
||||
// 全局尺寸
|
||||
size: "medium",
|
||||
// 全局 zIndex 起始值,如果项目的的 z-index 样式值过大时就需要跟随设置更大,避免被遮挡
|
||||
zIndex: 9999,
|
||||
// 版本号,对于某些带数据缓存的功能有用到,上升版本号可以用于重置数据
|
||||
version: 0,
|
||||
// 全局 loading 提示内容,如果为 null 则不显示文本
|
||||
loadingText: null,
|
||||
table: {
|
||||
showHeader: true,
|
||||
showOverflow: "tooltip",
|
||||
showHeaderOverflow: "tooltip",
|
||||
autoResize: true,
|
||||
// stripe: false,
|
||||
border: "inner",
|
||||
// round: false,
|
||||
emptyText: "暂无数据",
|
||||
rowConfig: {
|
||||
isHover: true,
|
||||
isCurrent: true,
|
||||
// 行数据的唯一主键字段名
|
||||
keyField: "_VXE_ID",
|
||||
},
|
||||
columnConfig: {
|
||||
resizable: false,
|
||||
},
|
||||
align: "center",
|
||||
headerAlign: "center",
|
||||
},
|
||||
pager: {
|
||||
// size: "medium",
|
||||
// 配套的样式
|
||||
perfect: false,
|
||||
pageSize: 10,
|
||||
pagerCount: 7,
|
||||
pageSizes: [10, 20, 50],
|
||||
layouts: [
|
||||
"Total",
|
||||
"PrevJump",
|
||||
"PrevPage",
|
||||
"Number",
|
||||
"NextPage",
|
||||
"NextJump",
|
||||
"Sizes",
|
||||
"FullJump",
|
||||
],
|
||||
},
|
||||
modal: {
|
||||
minWidth: 500,
|
||||
minHeight: 400,
|
||||
lockView: true,
|
||||
mask: true,
|
||||
// duration: 3000,
|
||||
// marginSize: 20,
|
||||
dblclickZoom: false,
|
||||
showTitleOverflow: true,
|
||||
transfer: true,
|
||||
draggable: false,
|
||||
},
|
||||
});
|
||||
|
||||
export function setupVxeTable(app: App) {
|
||||
// Vxe Table 组件完整引入
|
||||
app.use(VXETable);
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
import { useDictSync } from "@/composables";
|
||||
import { AuthStorage } from "@/utils/auth";
|
||||
|
||||
/**
|
||||
* WebSocket 服务实例约定接口
|
||||
* 至少包含 disconnect/closeWebSocket/cleanup 三者之一
|
||||
*/
|
||||
type WebSocketService = {
|
||||
disconnect?: () => void;
|
||||
closeWebSocket?: () => void;
|
||||
cleanup?: () => void;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
// 全局 WebSocket 实例管理
|
||||
const websocketInstances = new Map<string, WebSocketService>();
|
||||
|
||||
// 用于防止重复初始化的状态标记
|
||||
let isInitialized = false;
|
||||
let dictWebSocketInstance: ReturnType<typeof useDictSync> | null = null;
|
||||
|
||||
/**
|
||||
* 注册 WebSocket 实例,便于统一清理
|
||||
*/
|
||||
export function registerWebSocketInstance(key: string, instance: WebSocketService) {
|
||||
websocketInstances.set(key, instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 WebSocket 实例
|
||||
*/
|
||||
export function getWebSocketInstance(key: string) {
|
||||
return websocketInstances.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化WebSocket服务
|
||||
*/
|
||||
export function setupWebSocket() {
|
||||
// 检查是否已经初始化
|
||||
if (isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查环境变量是否配置
|
||||
const wsEndpoint = import.meta.env.VITE_APP_WS_ENDPOINT;
|
||||
if (!wsEndpoint) {
|
||||
console.log("[WebSocketPlugin] 未配置WebSocket端点,跳过WebSocket初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否已登录(基于是否存在访问令牌)
|
||||
if (!AuthStorage.getAccessToken()) {
|
||||
console.warn(
|
||||
"[WebSocketPlugin] 未找到访问令牌,WebSocket初始化已跳过。用户登录后将自动重新连接。"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 延迟初始化,确保应用完全启动
|
||||
setTimeout(() => {
|
||||
// 保存实例引用
|
||||
dictWebSocketInstance = useDictSync();
|
||||
registerWebSocketInstance("dictSync", dictWebSocketInstance);
|
||||
|
||||
// 初始化字典WebSocket服务
|
||||
dictWebSocketInstance.initWebSocket();
|
||||
// 初始化在线用户计数WebSocket
|
||||
import("@/composables").then(({ useOnlineCount }) => {
|
||||
const onlineCountInstance = useOnlineCount({ autoInit: false });
|
||||
onlineCountInstance.initWebSocket();
|
||||
});
|
||||
|
||||
// 在窗口关闭前断开WebSocket连接
|
||||
window.addEventListener("beforeunload", handleWindowClose);
|
||||
isInitialized = true;
|
||||
}, 1000); // 延迟1秒初始化
|
||||
} catch (error) {
|
||||
console.error("[WebSocketPlugin] 初始化WebSocket服务失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理窗口关闭
|
||||
*/
|
||||
function handleWindowClose() {
|
||||
cleanupWebSocket();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理WebSocket连接
|
||||
*/
|
||||
export function cleanupWebSocket() {
|
||||
// 清理字典 WebSocket
|
||||
if (dictWebSocketInstance) {
|
||||
try {
|
||||
dictWebSocketInstance.closeWebSocket();
|
||||
} catch (error) {
|
||||
console.error("[WebSocketPlugin] 断开字典WebSocket连接失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// 清理所有注册的 WebSocket 实例
|
||||
websocketInstances.forEach((instance, key) => {
|
||||
try {
|
||||
if (instance && typeof instance.disconnect === "function") {
|
||||
instance.disconnect();
|
||||
} else if (instance && typeof instance.closeWebSocket === "function") {
|
||||
instance.closeWebSocket();
|
||||
} else if (instance && typeof instance.cleanup === "function") {
|
||||
instance.cleanup();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[WebSocketPlugin] 断开 ${key} WebSocket连接失败:`, error);
|
||||
}
|
||||
});
|
||||
|
||||
// 清空实例映射
|
||||
websocketInstances.clear();
|
||||
|
||||
// 移除事件监听器
|
||||
window.removeEventListener("beforeunload", handleWindowClose);
|
||||
|
||||
// 重置状态
|
||||
dictWebSocketInstance = null;
|
||||
isInitialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新初始化WebSocket(用于登录后重连)
|
||||
*/
|
||||
export function reinitializeWebSocket() {
|
||||
// 先清理现有连接
|
||||
cleanupWebSocket();
|
||||
|
||||
// 延迟后重新初始化
|
||||
setTimeout(() => {
|
||||
setupWebSocket();
|
||||
}, 500);
|
||||
}
|
||||
@@ -33,7 +33,7 @@ async function initTenantContextIfEnabled(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
export function setupPermission() {
|
||||
export function setupPermissionGuard() {
|
||||
const whiteList = ["/login"];
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
24
src/types/api/auth.ts
Normal file
24
src/types/api/auth.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 认证相关类型定义
|
||||
*/
|
||||
|
||||
export interface LoginRequest {
|
||||
username: string;
|
||||
password: string;
|
||||
captchaId?: string;
|
||||
captchaCode?: string;
|
||||
rememberMe?: boolean;
|
||||
tenantId?: number;
|
||||
}
|
||||
|
||||
export interface LoginResult {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
tokenType: string;
|
||||
expiresIn: number;
|
||||
}
|
||||
|
||||
export interface CaptchaInfo {
|
||||
captchaId: string;
|
||||
captchaBase64: string;
|
||||
}
|
||||
32
src/types/api/common.ts
Normal file
32
src/types/api/common.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 通用 API 类型定义
|
||||
*/
|
||||
|
||||
export interface ApiResponse<T = any> {
|
||||
code: string;
|
||||
data: T;
|
||||
msg: string;
|
||||
}
|
||||
|
||||
export interface PageQuery {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
export interface PageResult<T> {
|
||||
list: T;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export interface OptionType {
|
||||
value: string | number;
|
||||
label: string;
|
||||
children?: OptionType[];
|
||||
}
|
||||
|
||||
export interface ExcelResult {
|
||||
code: string;
|
||||
invalidCount: number;
|
||||
validCount: number;
|
||||
messageList: string[];
|
||||
}
|
||||
6
src/types/api/index.ts
Normal file
6
src/types/api/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* API 类型统一导出
|
||||
*/
|
||||
|
||||
export * from "./common";
|
||||
export * from "./auth";
|
||||
35
src/types/env.d.ts
vendored
35
src/types/env.d.ts
vendored
@@ -1,35 +0,0 @@
|
||||
// https://cn.vitejs.dev/guide/env-and-mode
|
||||
|
||||
// TypeScript 类型提示都为 string: https://github.com/vitejs/vite/issues/6930
|
||||
interface ImportMetaEnv {
|
||||
/** 应用端口 */
|
||||
VITE_APP_PORT: number;
|
||||
/** 应用名称 */
|
||||
VITE_APP_NAME: string;
|
||||
/** API 基础路径(代理前缀) */
|
||||
VITE_APP_BASE_API: string;
|
||||
/** API 地址 */
|
||||
VITE_APP_API_URL: string;
|
||||
/** 是否开启 Mock 服务 */
|
||||
VITE_MOCK_DEV_SERVER: boolean;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
|
||||
/**
|
||||
* 平台的名称、版本、运行所需的`node`版本、依赖、构建时间的类型提示
|
||||
*/
|
||||
declare const __APP_INFO__: {
|
||||
pkg: {
|
||||
name: string;
|
||||
version: string;
|
||||
engines: {
|
||||
node: string;
|
||||
};
|
||||
dependencies: Record<string, string>;
|
||||
devDependencies: Record<string, string>;
|
||||
};
|
||||
buildTimestamp: number;
|
||||
};
|
||||
121
src/types/global.d.ts
vendored
121
src/types/global.d.ts
vendored
@@ -1,111 +1,16 @@
|
||||
/**
|
||||
* 全局类型声明
|
||||
*
|
||||
* @deprecated 请使用 @/types 下的具名导出
|
||||
*/
|
||||
declare global {
|
||||
/**
|
||||
* 响应数据
|
||||
*/
|
||||
interface ApiResponse<T = any> {
|
||||
code: string;
|
||||
data: T;
|
||||
msg: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询参数
|
||||
*/
|
||||
interface PageQuery {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页响应对象
|
||||
*/
|
||||
interface PageResult<T> {
|
||||
/** 数据列表 */
|
||||
list: T;
|
||||
/** 总数 */
|
||||
total: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 页签对象
|
||||
*/
|
||||
interface TagView {
|
||||
/** 页签名称 */
|
||||
name: string;
|
||||
/** 页签标题 */
|
||||
title: string;
|
||||
/** 页签路由路径 */
|
||||
path: string;
|
||||
/** 页签路由完整路径 */
|
||||
fullPath: string;
|
||||
/** 页签图标 */
|
||||
icon?: string;
|
||||
/** 是否固定页签 */
|
||||
affix?: boolean;
|
||||
/** 是否开启缓存 */
|
||||
keepAlive?: boolean;
|
||||
/** 路由查询参数 */
|
||||
query?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统设置
|
||||
*/
|
||||
interface AppSettings {
|
||||
/** 系统标题 */
|
||||
title: string;
|
||||
/** 系统版本 */
|
||||
version: string;
|
||||
/** 是否显示设置 */
|
||||
showSettings: boolean;
|
||||
/** 是否显示多标签导航 */
|
||||
showTagsView: boolean;
|
||||
/** 是否显示应用Logo */
|
||||
showAppLogo: boolean;
|
||||
/** 导航栏布局(left|top|mix) */
|
||||
layout: "left" | "top" | "mix";
|
||||
/** 主题颜色 */
|
||||
themeColor: string;
|
||||
/** 主题模式(dark|light) */
|
||||
theme: import("@/enums/settings/theme-enum").ThemeMode;
|
||||
/** 布局大小(default |large |small) */
|
||||
size: string;
|
||||
/** 语言( zh-cn| en) */
|
||||
language: string;
|
||||
/** 是否显示水印 */
|
||||
showWatermark: boolean;
|
||||
/** 水印内容 */
|
||||
watermarkContent: string;
|
||||
/** 侧边栏配色方案 */
|
||||
sidebarColorScheme: "classic-blue" | "minimal-white";
|
||||
/** 是否启用 AI 助手 */
|
||||
enableAiAssistant: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下拉选项数据类型
|
||||
*/
|
||||
interface OptionType {
|
||||
/** 值 */
|
||||
value: string | number;
|
||||
/** 文本 */
|
||||
label: string;
|
||||
/** 子列表 */
|
||||
children?: OptionType[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入结果
|
||||
*/
|
||||
interface ExcelResult {
|
||||
/** 状态码 */
|
||||
code: string;
|
||||
/** 无效数据条数 */
|
||||
invalidCount: number;
|
||||
/** 有效数据条数 */
|
||||
validCount: number;
|
||||
/** 错误信息 */
|
||||
messageList: Array<string>;
|
||||
}
|
||||
type ApiResponse<T = any> = import("@/types/api").ApiResponse<T>;
|
||||
type PageQuery = import("@/types/api").PageQuery;
|
||||
type PageResult<T> = import("@/types/api").PageResult<T>;
|
||||
type OptionType = import("@/types/api").OptionType;
|
||||
type ExcelResult = import("@/types/api").ExcelResult;
|
||||
type TagView = import("@/types/ui").TagView;
|
||||
type AppSettings = import("@/types/ui").AppSettings;
|
||||
}
|
||||
|
||||
export {};
|
||||
|
||||
6
src/types/index.ts
Normal file
6
src/types/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* 类型统一导出
|
||||
*/
|
||||
|
||||
export * from "./api";
|
||||
export * from "./ui";
|
||||
54
src/types/router.d.ts
vendored
54
src/types/router.d.ts
vendored
@@ -1,54 +0,0 @@
|
||||
import "vue-router";
|
||||
|
||||
declare module "vue-router" {
|
||||
// https://router.vuejs.org/zh/guide/advanced/meta.html#typescript
|
||||
// 可以通过扩展 RouteMeta 接口来输入 meta 字段
|
||||
interface RouteMeta {
|
||||
/**
|
||||
* 菜单名称
|
||||
* @example 'Dashboard'
|
||||
*/
|
||||
title?: string;
|
||||
|
||||
/**
|
||||
* 菜单图标
|
||||
* @example 'el-icon-edit'
|
||||
*/
|
||||
icon?: string;
|
||||
|
||||
/**
|
||||
* 是否隐藏菜单
|
||||
* true 隐藏, false 显示
|
||||
* @default false
|
||||
*/
|
||||
hidden?: boolean;
|
||||
|
||||
/**
|
||||
* 始终显示父级菜单,即使只有一个子菜单
|
||||
* true 显示父级菜单, false 隐藏父级菜单,显示唯一子节点
|
||||
* @default false
|
||||
*/
|
||||
alwaysShow?: boolean;
|
||||
|
||||
/**
|
||||
* 是否固定在页签上
|
||||
* true 固定, false 不固定
|
||||
* @default false
|
||||
*/
|
||||
affix?: boolean;
|
||||
|
||||
/**
|
||||
* 是否缓存页面
|
||||
* true 缓存, false 不缓存
|
||||
* @default false
|
||||
*/
|
||||
keepAlive?: boolean;
|
||||
|
||||
/**
|
||||
* 是否在面包屑导航中隐藏
|
||||
* true 隐藏, false 显示
|
||||
* @default false
|
||||
*/
|
||||
breadcrumb?: boolean;
|
||||
}
|
||||
}
|
||||
5
src/types/shims-vue.d.ts
vendored
5
src/types/shims-vue.d.ts
vendored
@@ -1,5 +0,0 @@
|
||||
declare module "*.vue" {
|
||||
import type { DefineComponent } from "vue";
|
||||
const component: DefineComponent<{}, {}, any>;
|
||||
export default component;
|
||||
}
|
||||
6
src/types/socket.d.ts
vendored
6
src/types/socket.d.ts
vendored
@@ -1,6 +0,0 @@
|
||||
// https://github.com/sockjs/sockjs-client/issues/565
|
||||
|
||||
declare module "sockjs-client/dist/sockjs.min.js" {
|
||||
import Client from "sockjs-client";
|
||||
export default Client;
|
||||
}
|
||||
6
src/types/ui/index.ts
Normal file
6
src/types/ui/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* UI 类型统一导出
|
||||
*/
|
||||
|
||||
export * from "./tagsview";
|
||||
export * from "./settings";
|
||||
22
src/types/ui/settings.ts
Normal file
22
src/types/ui/settings.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 应用设置相关类型定义
|
||||
*/
|
||||
|
||||
import type { ThemeMode } from "@/enums";
|
||||
|
||||
export interface AppSettings {
|
||||
title: string;
|
||||
version: string;
|
||||
showSettings: boolean;
|
||||
showTagsView: boolean;
|
||||
showAppLogo: boolean;
|
||||
layout: "left" | "top" | "mix";
|
||||
themeColor: string;
|
||||
theme: ThemeMode;
|
||||
size: string;
|
||||
language: string;
|
||||
showWatermark: boolean;
|
||||
watermarkContent: string;
|
||||
sidebarColorScheme: "classic-blue" | "minimal-white";
|
||||
enableAiAssistant: boolean;
|
||||
}
|
||||
14
src/types/ui/tagsview.ts
Normal file
14
src/types/ui/tagsview.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 标签页相关类型定义
|
||||
*/
|
||||
|
||||
export interface TagView {
|
||||
name: string;
|
||||
title: string;
|
||||
path: string;
|
||||
fullPath: string;
|
||||
icon?: string;
|
||||
affix?: boolean;
|
||||
keepAlive?: boolean;
|
||||
query?: any;
|
||||
}
|
||||
18
src/utils/register-components.ts
Normal file
18
src/utils/register-components.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 全局组件注册工具
|
||||
*
|
||||
* @description
|
||||
* 批量注册 Element Plus 图标等全局组件
|
||||
*/
|
||||
|
||||
import type { App } from "vue";
|
||||
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
|
||||
|
||||
/**
|
||||
* 注册 Element Plus 所有图标为全局组件
|
||||
*/
|
||||
export function registerElementIcons(app: App) {
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component);
|
||||
}
|
||||
}
|
||||
69
src/utils/validators.ts
Normal file
69
src/utils/validators.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 表单验证规则工具
|
||||
*
|
||||
* @description
|
||||
* 提供常用的表单验证规则
|
||||
*/
|
||||
|
||||
import type { FormItemRule } from "element-plus";
|
||||
|
||||
/**
|
||||
* 验证规则生成器
|
||||
*/
|
||||
export const VALIDATORS = {
|
||||
/**
|
||||
* 必填项验证
|
||||
*/
|
||||
required(message: string): FormItemRule {
|
||||
return {
|
||||
required: true,
|
||||
message,
|
||||
trigger: "blur",
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 邮箱验证
|
||||
*/
|
||||
email: {
|
||||
type: "email",
|
||||
message: "请输入正确的邮箱地址",
|
||||
trigger: "blur",
|
||||
} as FormItemRule,
|
||||
|
||||
/**
|
||||
* 手机号验证
|
||||
*/
|
||||
mobile: {
|
||||
pattern: /^1[3-9]\d{9}$/,
|
||||
message: "请输入正确的手机号码",
|
||||
trigger: "blur",
|
||||
} as FormItemRule,
|
||||
|
||||
/**
|
||||
* URL 验证
|
||||
*/
|
||||
url: {
|
||||
type: "url",
|
||||
message: "请输入正确的URL地址",
|
||||
trigger: "blur",
|
||||
} as FormItemRule,
|
||||
|
||||
/**
|
||||
* 数字验证
|
||||
*/
|
||||
number: {
|
||||
type: "number",
|
||||
message: "请输入数字",
|
||||
trigger: "blur",
|
||||
} as FormItemRule,
|
||||
|
||||
/**
|
||||
* 整数验证
|
||||
*/
|
||||
integer: {
|
||||
type: "integer",
|
||||
message: "请输入整数",
|
||||
trigger: "blur",
|
||||
} as FormItemRule,
|
||||
};
|
||||
114
src/utils/websocket.ts
Normal file
114
src/utils/websocket.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* WebSocket 服务管理
|
||||
*
|
||||
* @description
|
||||
* 统一管理应用中的所有 WebSocket 连接
|
||||
* - 字典同步 WebSocket
|
||||
* - 在线用户计数 WebSocket
|
||||
* - 其他业务 WebSocket
|
||||
*
|
||||
* @author 有来技术团队
|
||||
*/
|
||||
|
||||
import { useDictSync } from "@/composables";
|
||||
import { AuthStorage } from "@/utils/auth";
|
||||
|
||||
/**
|
||||
* WebSocket 服务实例约定接口
|
||||
*/
|
||||
type WebSocketService = {
|
||||
disconnect?: () => void;
|
||||
closeWebSocket?: () => void;
|
||||
cleanup?: () => void;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
/**
|
||||
* 全局 WebSocket 实例管理
|
||||
*/
|
||||
const websocketInstances = new Map<string, WebSocketService>();
|
||||
|
||||
/**
|
||||
* 防止重复初始化的状态标记
|
||||
*/
|
||||
let isInitialized = false;
|
||||
let dictWebSocketInstance: ReturnType<typeof useDictSync> | null = null;
|
||||
|
||||
/**
|
||||
* 注册 WebSocket 实例
|
||||
*/
|
||||
export function registerWebSocketInstance(key: string, instance: WebSocketService) {
|
||||
websocketInstances.set(key, instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 WebSocket 实例
|
||||
*/
|
||||
export function getWebSocketInstance(key: string) {
|
||||
return websocketInstances.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化 WebSocket 服务
|
||||
*/
|
||||
export function setupWebSocket() {
|
||||
if (isInitialized) {
|
||||
console.warn("[WebSocket] 已初始化,跳过重复初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AuthStorage.getAccessToken()) {
|
||||
console.warn("[WebSocket] 未登录,跳过 WebSocket 初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
dictWebSocketInstance = useDictSync();
|
||||
registerWebSocketInstance("dict-sync", dictWebSocketInstance);
|
||||
isInitialized = true;
|
||||
console.log("[WebSocket] 初始化成功");
|
||||
} catch (error) {
|
||||
console.error("[WebSocket] 初始化失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理所有 WebSocket 连接
|
||||
*/
|
||||
export function cleanupWebSocket() {
|
||||
console.log("[WebSocket] 开始清理连接...");
|
||||
|
||||
websocketInstances.forEach((instance, key) => {
|
||||
try {
|
||||
if (instance.disconnect) {
|
||||
instance.disconnect();
|
||||
} else if (instance.closeWebSocket) {
|
||||
instance.closeWebSocket();
|
||||
} else if (instance.cleanup) {
|
||||
instance.cleanup();
|
||||
}
|
||||
console.log(`[WebSocket] ${key} 已断开`);
|
||||
} catch (error) {
|
||||
console.error(`[WebSocket] ${key} 清理失败:`, error);
|
||||
}
|
||||
});
|
||||
|
||||
websocketInstances.clear();
|
||||
dictWebSocketInstance = null;
|
||||
isInitialized = false;
|
||||
console.log("[WebSocket] 清理完成");
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新初始化 WebSocket
|
||||
*/
|
||||
export function reinitializeWebSocket() {
|
||||
cleanupWebSocket();
|
||||
setupWebSocket();
|
||||
}
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
window.addEventListener("beforeunload", () => {
|
||||
cleanupWebSocket();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user