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:
@@ -64,6 +64,7 @@ export default [
|
|||||||
"**/*.min.*",
|
"**/*.min.*",
|
||||||
"**/auto-imports.d.ts",
|
"**/auto-imports.d.ts",
|
||||||
"**/components.d.ts",
|
"**/components.d.ts",
|
||||||
|
"types/**/*.d.ts",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
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 * from "@/config/storage";
|
||||||
export const STORAGE_KEYS = {
|
export { ROLE_ROOT } from "@/enums";
|
||||||
// 用户认证相关
|
export { VALIDATORS } from "@/utils/validators";
|
||||||
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;
|
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* API响应码枚举
|
* API 相关枚举
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* 包含 API 响应码、请求状态等枚举定义
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 响应码枚举
|
||||||
*/
|
*/
|
||||||
export const enum ApiCodeEnum {
|
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 "./api";
|
||||||
export * from "./codegen/query-enum";
|
export * from "./business";
|
||||||
|
export * from "./codegen";
|
||||||
export * from "./settings/layout-enum";
|
export * from "./common";
|
||||||
export * from "./settings/theme-enum";
|
export * from "./settings";
|
||||||
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";
|
|
||||||
|
|||||||
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 { createApp } from "vue";
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import setupPlugins from "@/plugins";
|
|
||||||
|
|
||||||
// 暗黑主题样式
|
// ===== 样式导入 =====
|
||||||
import "element-plus/theme-chalk/dark/css-vars.css";
|
import "element-plus/theme-chalk/dark/css-vars.css";
|
||||||
import "vxe-table/lib/style.css";
|
import "vxe-table/lib/style.css";
|
||||||
// 暗黑模式自定义变量
|
|
||||||
import "@/styles/dark/css-vars.css";
|
import "@/styles/dark/css-vars.css";
|
||||||
import "@/styles/index.scss";
|
import "@/styles/index.scss";
|
||||||
import "uno.css";
|
import "uno.css";
|
||||||
|
|
||||||
// 过渡动画
|
|
||||||
import "animate.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);
|
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");
|
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"];
|
const whiteList = ["/login"];
|
||||||
|
|
||||||
router.beforeEach(async (to, from, next) => {
|
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 {
|
declare global {
|
||||||
/**
|
type ApiResponse<T = any> = import("@/types/api").ApiResponse<T>;
|
||||||
* 响应数据
|
type PageQuery = import("@/types/api").PageQuery;
|
||||||
*/
|
type PageResult<T> = import("@/types/api").PageResult<T>;
|
||||||
interface ApiResponse<T = any> {
|
type OptionType = import("@/types/api").OptionType;
|
||||||
code: string;
|
type ExcelResult = import("@/types/api").ExcelResult;
|
||||||
data: T;
|
type TagView = import("@/types/ui").TagView;
|
||||||
msg: string;
|
type AppSettings = import("@/types/ui").AppSettings;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页查询参数
|
|
||||||
*/
|
|
||||||
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>;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export {};
|
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();
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"include": [
|
"include": [
|
||||||
|
"types/**/*.d.ts",
|
||||||
"mock/**/*.ts",
|
"mock/**/*.ts",
|
||||||
"src/**/*.ts",
|
"src/**/*.ts",
|
||||||
"src/**/*.vue",
|
"src/**/*.vue",
|
||||||
|
|||||||
29
types/env.d.ts
vendored
Normal file
29
types/env.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vite 环境变量类型定义
|
||||||
|
*/
|
||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly VITE_APP_PORT: number;
|
||||||
|
readonly VITE_APP_NAME: string;
|
||||||
|
readonly VITE_APP_BASE_API: string;
|
||||||
|
readonly VITE_APP_API_URL: string;
|
||||||
|
readonly VITE_MOCK_DEV_SERVER: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const __APP_INFO__: {
|
||||||
|
pkg: {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
engines: {
|
||||||
|
node: string;
|
||||||
|
};
|
||||||
|
dependencies: Record<string, string>;
|
||||||
|
devDependencies: Record<string, string>;
|
||||||
|
};
|
||||||
|
buildTimestamp: number;
|
||||||
|
};
|
||||||
14
types/modules.d.ts
vendored
Normal file
14
types/modules.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* 第三方模块类型声明
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare module "*.vue" {
|
||||||
|
import type { DefineComponent } from "vue";
|
||||||
|
const component: DefineComponent<{}, {}, any>;
|
||||||
|
export default component;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module "sockjs-client/dist/sockjs.min.js" {
|
||||||
|
import Client from "sockjs-client";
|
||||||
|
export default Client;
|
||||||
|
}
|
||||||
16
types/router.d.ts
vendored
Normal file
16
types/router.d.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Vue Router 类型扩展
|
||||||
|
*/
|
||||||
|
import "vue-router";
|
||||||
|
|
||||||
|
declare module "vue-router" {
|
||||||
|
interface RouteMeta {
|
||||||
|
title?: string;
|
||||||
|
icon?: string;
|
||||||
|
hidden?: boolean;
|
||||||
|
alwaysShow?: boolean;
|
||||||
|
affix?: boolean;
|
||||||
|
keepAlive?: boolean;
|
||||||
|
breadcrumb?: boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user