refactor: 优化代码规范和可读性
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
npx --no-install commitlint --edit $1
|
#!/usr/bin/env sh
|
||||||
|
npx --no-install commitlint --edit "$1"
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
npm run lint:lint-staged
|
#!/usr/bin/env sh
|
||||||
|
npm run lint:lint-staged
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||

|

|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a target="_blank" href="https://vue.youlai.tech">🖥️ 在线预览</a> | <a target="_blank" href="https://app.youlai.tech">📲 移动端预览</a> | <a target="_blank" href="https://juejin.cn/post/7228990409909108793">📑 阅读文档</a>| <a target="_blank" href="https://www.youlai.tech//vue3-element-admin">🌐 官网</a> | <a href="./README.en-US.md">💬 English
|
<a target="_blank" href="https://vue.youlai.tech">🖥️ 在线预览</a> | <a target="_blank" href="https://app.youlai.tech">📲 移动端预览</a> | <a target="_blank" href="https://juejin.cn/post/7228990409909108793">📑 阅读文档</a>| <a target="_blank" href="https://www.youlai.tech/docs/web/">🌐 官网</a> | <a href="./README.en-US.md">💬 English
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## 项目简介
|
## 项目简介
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
| -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
| -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| 视频教程 | [https://www.bilibili.com/video/BV1eFUuYyEFj](https://www.bilibili.com/video/BV1eFUuYyEFj) |
|
| 视频教程 | [https://www.bilibili.com/video/BV1eFUuYyEFj](https://www.bilibili.com/video/BV1eFUuYyEFj) |
|
||||||
| 项目搭建 | [基于 Vue3 + Vite + TypeScript + Element-Plus 从0到1搭建后台管理系统](https://blog.csdn.net/u013737132/article/details/130191394) |
|
| 项目搭建 | [基于 Vue3 + Vite + TypeScript + Element-Plus 从0到1搭建后台管理系统](https://blog.csdn.net/u013737132/article/details/130191394) |
|
||||||
| 官方文档 | [https://www.youlai.tech/vue3-element-admin](https://www.youlai.tech/vue3-element-admin/) |
|
| 官方文档 | [https://www.youlai.tech/docs/web/](https://www.youlai.tech/docs/web/) |
|
||||||
| 代码规范 | [ESLint V9 + Prettier + Stylelint + EditorConfig 约束和统一前端代码规范](https://youlai.blog.csdn.net/article/details/145608723) |
|
| 代码规范 | [ESLint V9 + Prettier + Stylelint + EditorConfig 约束和统一前端代码规范](https://youlai.blog.csdn.net/article/details/145608723) |
|
||||||
| 提交规范 | [Husky + Lint-staged + Commitlint + Commitizen + cz-git 配置 Git 提交规范](https://youlai.blog.csdn.net/article/details/145615236) |
|
| 提交规范 | [Husky + Lint-staged + Commitlint + Commitizen + cz-git 配置 Git 提交规范](https://youlai.blog.csdn.net/article/details/145615236) |
|
||||||
| 接口文档 | [https://www.apifox.cn](https://www.apifox.cn/apidoc/shared-195e783f-4d85-4235-a038-eec696de4ea5) |
|
| 接口文档 | [https://www.apifox.cn](https://www.apifox.cn/apidoc/shared-195e783f-4d85-4235-a038-eec696de4ea5) |
|
||||||
@@ -177,7 +177,7 @@ server {
|
|||||||
|
|
||||||
1. 获取基于 `Java` 和 `SpringBoot` 开发的后端 [youlai-boot](https://gitee.com/youlaiorg/youlai-boot.git) 源码。
|
1. 获取基于 `Java` 和 `SpringBoot` 开发的后端 [youlai-boot](https://gitee.com/youlaiorg/youlai-boot.git) 源码。
|
||||||
2. 根据后端工程的说明文档 [README.md](https://gitee.com/youlaiorg/youlai-boot#%E9%A1%B9%E7%9B%AE%E8%BF%90%E8%A1%8C) 完成本地启动。
|
2. 根据后端工程的说明文档 [README.md](https://gitee.com/youlaiorg/youlai-boot#%E9%A1%B9%E7%9B%AE%E8%BF%90%E8%A1%8C) 完成本地启动。
|
||||||
3. 修改 `.env.development` 文件中的 `VITE_APP_API_URL` 的值,将其从 https://api.youlai.tech 更改为 http://localhost:8989 即可。
|
3. 修改 `.env.development` 文件中的 `VITE_APP_API_URL` 的值,将其从 https://api.youlai.tech 更改为 http://localhost:8000 即可。
|
||||||
|
|
||||||
## 注意事项
|
## 注意事项
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ Thanks to all the contributors!
|
|||||||
<table align="center">
|
<table align="center">
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<img src="./src/assets/images/qr/wechat-offical.png" height="180" alt="公众号「有来技术」"><br>
|
<img src="./src/assets/images/qr/wechat-official.png" height="180" alt="公众号「有来技术」"><br>
|
||||||
<sub>公众号「有来技术」</sub>
|
<sub>公众号「有来技术」</sub>
|
||||||
</td>
|
</td>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ export default [
|
|||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
// 基础规则
|
// 基础规则
|
||||||
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
|
"no-console": ["error", { allow: ["warn", "error", "debug"] }],
|
||||||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
|
"no-debugger": "error",
|
||||||
|
|
||||||
// ES6+ 规则
|
// ES6+ 规则
|
||||||
"prefer-const": "error",
|
"prefer-const": "error",
|
||||||
@@ -116,7 +116,7 @@ export default [
|
|||||||
"object-shorthand": "error",
|
"object-shorthand": "error",
|
||||||
|
|
||||||
// 最佳实践
|
// 最佳实践
|
||||||
eqeqeq: "off",
|
eqeqeq: ["error", "always", { null: "ignore" }],
|
||||||
"no-multi-spaces": "error",
|
"no-multi-spaces": "error",
|
||||||
"no-multiple-empty-lines": ["error", { max: 1, maxBOF: 0, maxEOF: 0 }],
|
"no-multiple-empty-lines": ["error", { max: 1, maxBOF: 0, maxEOF: 0 }],
|
||||||
|
|
||||||
@@ -171,7 +171,7 @@ export default [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"vue/component-name-in-template-casing": ["error", "PascalCase"],
|
"vue/component-name-in-template-casing": ["error", "PascalCase"],
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
"@typescript-eslint/no-explicit-any": "warn",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ export default [
|
|||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
// TypeScript 规则
|
// TypeScript 规则
|
||||||
"@typescript-eslint/no-explicit-any": "off", // 允许使用any类型,方便开发
|
"@typescript-eslint/no-explicit-any": "warn", // 逐步收敛 any 类型
|
||||||
"@typescript-eslint/no-empty-function": "off",
|
"@typescript-eslint/no-empty-function": "off",
|
||||||
"@typescript-eslint/no-empty-object-type": "off",
|
"@typescript-eslint/no-empty-object-type": "off",
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
"@typescript-eslint/ban-ts-comment": "off",
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ export default defineMock([
|
|||||||
|
|
||||||
let list = null;
|
let list = null;
|
||||||
|
|
||||||
if (dictCode == "gender") {
|
if (dictCode === "gender") {
|
||||||
list = [
|
list = [
|
||||||
{
|
{
|
||||||
value: "1",
|
value: "1",
|
||||||
@@ -160,7 +160,7 @@ export default defineMock([
|
|||||||
label: "保密",
|
label: "保密",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
} else if (dictCode == "notice_level") {
|
} else if (dictCode === "notice_level") {
|
||||||
list = [
|
list = [
|
||||||
{
|
{
|
||||||
value: "L",
|
value: "L",
|
||||||
@@ -178,7 +178,7 @@ export default defineMock([
|
|||||||
tagType: "D",
|
tagType: "D",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
} else if (dictCode == "notice_type") {
|
} else if (dictCode === "notice_type") {
|
||||||
list = [
|
list = [
|
||||||
{
|
{
|
||||||
value: "1",
|
value: "1",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-config-provider :locale="locale" :size="size">
|
<el-config-provider :locale="locale" :size="size">
|
||||||
<!-- 开启水印-->
|
|
||||||
<el-watermark
|
<el-watermark
|
||||||
:font="{ color: fontColor }"
|
:font="{ color: fontColor }"
|
||||||
:content="showWatermark ? watermarkContent : ''"
|
:content="showWatermark ? watermarkContent : ''"
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ const AUTH_BASE_URL = "/api/v1/auth";
|
|||||||
const AuthAPI = {
|
const AuthAPI = {
|
||||||
/** 登录接口*/
|
/** 登录接口*/
|
||||||
login(data: LoginRequest) {
|
login(data: LoginRequest) {
|
||||||
const payload: Record<string, any> = {
|
const payload: Pick<
|
||||||
|
LoginRequest,
|
||||||
|
"username" | "password" | "captchaId" | "captchaCode" | "tenantId"
|
||||||
|
> = {
|
||||||
username: data.username,
|
username: data.username,
|
||||||
password: data.password,
|
password: data.password,
|
||||||
captchaId: data.captchaId,
|
captchaId: data.captchaId,
|
||||||
@@ -18,7 +21,7 @@ const AuthAPI = {
|
|||||||
payload.tenantId = data.tenantId;
|
payload.tenantId = data.tenantId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return request<any, LoginResponse>({
|
return request<unknown, LoginResponse>({
|
||||||
url: `${AUTH_BASE_URL}/login`,
|
url: `${AUTH_BASE_URL}/login`,
|
||||||
method: "post",
|
method: "post",
|
||||||
data: payload,
|
data: payload,
|
||||||
@@ -27,7 +30,7 @@ const AuthAPI = {
|
|||||||
|
|
||||||
/** 切换租户(平台用户) - 返回新的 token */
|
/** 切换租户(平台用户) - 返回新的 token */
|
||||||
switchTenant(tenantId: number) {
|
switchTenant(tenantId: number) {
|
||||||
return request<any, LoginResponse>({
|
return request<unknown, LoginResponse>({
|
||||||
url: `${AUTH_BASE_URL}/switch-tenant`,
|
url: `${AUTH_BASE_URL}/switch-tenant`,
|
||||||
method: "post",
|
method: "post",
|
||||||
params: { tenantId },
|
params: { tenantId },
|
||||||
@@ -36,7 +39,7 @@ const AuthAPI = {
|
|||||||
|
|
||||||
/** 刷新 token 接口*/
|
/** 刷新 token 接口*/
|
||||||
refreshToken(refreshToken: string) {
|
refreshToken(refreshToken: string) {
|
||||||
return request<any, LoginResponse>({
|
return request<unknown, LoginResponse>({
|
||||||
url: `${AUTH_BASE_URL}/refresh-token`,
|
url: `${AUTH_BASE_URL}/refresh-token`,
|
||||||
method: "post",
|
method: "post",
|
||||||
params: { refreshToken },
|
params: { refreshToken },
|
||||||
@@ -56,7 +59,7 @@ const AuthAPI = {
|
|||||||
|
|
||||||
/** 获取验证码接口*/
|
/** 获取验证码接口*/
|
||||||
getCaptcha() {
|
getCaptcha() {
|
||||||
return request<any, CaptchaInfo>({
|
return request<unknown, CaptchaInfo>({
|
||||||
url: `${AUTH_BASE_URL}/captcha`,
|
url: `${AUTH_BASE_URL}/captcha`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const GENERATOR_BASE_URL = "/api/v1/codegen";
|
|||||||
const GeneratorAPI = {
|
const GeneratorAPI = {
|
||||||
/** 获取数据表分页列表 */
|
/** 获取数据表分页列表 */
|
||||||
getTablePage(params: TableQueryParams) {
|
getTablePage(params: TableQueryParams) {
|
||||||
return request<any, PageResult<TableItem>>({
|
return request<unknown, PageResult<TableItem>>({
|
||||||
url: `${GENERATOR_BASE_URL}/table`,
|
url: `${GENERATOR_BASE_URL}/table`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params,
|
params,
|
||||||
@@ -15,7 +15,7 @@ const GeneratorAPI = {
|
|||||||
|
|
||||||
/** 获取代码生成配置 */
|
/** 获取代码生成配置 */
|
||||||
getGenConfig(tableName: string) {
|
getGenConfig(tableName: string) {
|
||||||
return request<any, GenConfigForm>({
|
return request<unknown, GenConfigForm>({
|
||||||
url: `${GENERATOR_BASE_URL}/${tableName}/config`,
|
url: `${GENERATOR_BASE_URL}/${tableName}/config`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
@@ -39,7 +39,7 @@ const GeneratorAPI = {
|
|||||||
if (type) {
|
if (type) {
|
||||||
params.type = type;
|
params.type = type;
|
||||||
}
|
}
|
||||||
return request<any, GeneratorPreviewItem[]>({
|
return request<unknown, GeneratorPreviewItem[]>({
|
||||||
url: `${GENERATOR_BASE_URL}/${tableName}/preview`,
|
url: `${GENERATOR_BASE_URL}/${tableName}/preview`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: Object.keys(params).length ? params : undefined,
|
params: Object.keys(params).length ? params : undefined,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/** API 响应结构 */
|
/** API 响应结构 */
|
||||||
export interface ApiResponse<T = any> {
|
export interface ApiResponse<T = unknown> {
|
||||||
/** 响应码 */
|
/** 响应码 */
|
||||||
code: string;
|
code: string;
|
||||||
/** 响应数据 */
|
/** 响应数据 */
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type { FileInfo } from "./types";
|
|||||||
const FileAPI = {
|
const FileAPI = {
|
||||||
/** 上传文件 (传入 FormData,上传进度回调) */
|
/** 上传文件 (传入 FormData,上传进度回调) */
|
||||||
upload(formData: FormData, onProgress?: (percent: number) => void) {
|
upload(formData: FormData, onProgress?: (percent: number) => void) {
|
||||||
return request<any, FileInfo>({
|
return request<unknown, FileInfo>({
|
||||||
url: "/api/v1/files",
|
url: "/api/v1/files",
|
||||||
method: "post",
|
method: "post",
|
||||||
data: formData,
|
data: formData,
|
||||||
@@ -22,7 +22,7 @@ const FileAPI = {
|
|||||||
uploadFile(file: File) {
|
uploadFile(file: File) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("file", file);
|
formData.append("file", file);
|
||||||
return request<any, FileInfo>({
|
return request<unknown, FileInfo>({
|
||||||
url: "/api/v1/files",
|
url: "/api/v1/files",
|
||||||
method: "post",
|
method: "post",
|
||||||
data: formData,
|
data: formData,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const CONFIG_BASE_URL = "/api/v1/configs";
|
|||||||
const ConfigAPI = {
|
const ConfigAPI = {
|
||||||
/** 获取配置分页数据 */
|
/** 获取配置分页数据 */
|
||||||
getPage(queryParams?: ConfigQueryParams) {
|
getPage(queryParams?: ConfigQueryParams) {
|
||||||
return request<any, PageResult<ConfigItem>>({
|
return request<unknown, PageResult<ConfigItem>>({
|
||||||
url: `${CONFIG_BASE_URL}`,
|
url: `${CONFIG_BASE_URL}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
@@ -14,7 +14,7 @@ const ConfigAPI = {
|
|||||||
},
|
},
|
||||||
/** 获取配置表单数据 */
|
/** 获取配置表单数据 */
|
||||||
getFormData(id: string) {
|
getFormData(id: string) {
|
||||||
return request<any, ConfigForm>({
|
return request<unknown, ConfigForm>({
|
||||||
url: `${CONFIG_BASE_URL}/${id}/form`,
|
url: `${CONFIG_BASE_URL}/${id}/form`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const DEPT_BASE_URL = "/api/v1/depts";
|
|||||||
const DeptAPI = {
|
const DeptAPI = {
|
||||||
/** 获取部门树形列表 */
|
/** 获取部门树形列表 */
|
||||||
getList(queryParams?: DeptQueryParams) {
|
getList(queryParams?: DeptQueryParams) {
|
||||||
return request<any, DeptItem[]>({
|
return request<unknown, DeptItem[]>({
|
||||||
url: `${DEPT_BASE_URL}`,
|
url: `${DEPT_BASE_URL}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
@@ -15,11 +15,11 @@ const DeptAPI = {
|
|||||||
},
|
},
|
||||||
/** 获取部门下拉数据源 */
|
/** 获取部门下拉数据源 */
|
||||||
getOptions() {
|
getOptions() {
|
||||||
return request<any, OptionItem[]>({ url: `${DEPT_BASE_URL}/options`, method: "get" });
|
return request<unknown, OptionItem[]>({ url: `${DEPT_BASE_URL}/options`, method: "get" });
|
||||||
},
|
},
|
||||||
/** 获取部门表单数据 */
|
/** 获取部门表单数据 */
|
||||||
getFormData(id: string) {
|
getFormData(id: string) {
|
||||||
return request<any, DeptForm>({ url: `${DEPT_BASE_URL}/${id}/form`, method: "get" });
|
return request<unknown, DeptForm>({ url: `${DEPT_BASE_URL}/${id}/form`, method: "get" });
|
||||||
},
|
},
|
||||||
/** 新增部门 */
|
/** 新增部门 */
|
||||||
create(data: DeptForm) {
|
create(data: DeptForm) {
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ import type { OptionItem } from "@/api/common";
|
|||||||
|
|
||||||
const DICT_BASE_URL = "/api/v1/dicts";
|
const DICT_BASE_URL = "/api/v1/dicts";
|
||||||
|
|
||||||
|
type DictTagType = DictItemForm["tagType"];
|
||||||
type DictTagTypeCode = "N" | "P" | "S" | "W" | "I" | "D";
|
type DictTagTypeCode = "N" | "P" | "S" | "W" | "I" | "D";
|
||||||
|
|
||||||
const decodeDictTagType = (code?: unknown): DictItemForm["tagType"] => {
|
// 将后端标签类型转换为前端标签类型
|
||||||
|
const decodeDictTagType = (code?: unknown): DictTagType => {
|
||||||
const val = String(code ?? "")
|
const val = String(code ?? "")
|
||||||
.trim()
|
.trim()
|
||||||
.toUpperCase();
|
.toUpperCase();
|
||||||
@@ -35,6 +37,7 @@ const decodeDictTagType = (code?: unknown): DictItemForm["tagType"] => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 将前端标签类型转换为后端标签类型
|
||||||
const encodeDictTagType = (tagType?: unknown): DictTagTypeCode => {
|
const encodeDictTagType = (tagType?: unknown): DictTagTypeCode => {
|
||||||
const val = String(tagType ?? "")
|
const val = String(tagType ?? "")
|
||||||
.trim()
|
.trim()
|
||||||
@@ -58,10 +61,20 @@ const encodeDictTagType = (tagType?: unknown): DictTagTypeCode => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 统一转换字典项标签类型
|
||||||
|
const normalizeDictTagType = <T extends { tagType?: unknown }>(
|
||||||
|
item: T
|
||||||
|
): Omit<T, "tagType"> & {
|
||||||
|
tagType: DictTagType;
|
||||||
|
} => ({
|
||||||
|
...item,
|
||||||
|
tagType: decodeDictTagType(item.tagType),
|
||||||
|
});
|
||||||
|
|
||||||
const DictAPI = {
|
const DictAPI = {
|
||||||
/** 字典分页列表 */
|
/** 字典分页列表 */
|
||||||
getPage(queryParams: DictTypeQueryParams) {
|
getPage(queryParams: DictTypeQueryParams) {
|
||||||
return request<any, PageResult<DictTypeItem>>({
|
return request<unknown, PageResult<DictTypeItem>>({
|
||||||
url: `${DICT_BASE_URL}`,
|
url: `${DICT_BASE_URL}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
@@ -69,11 +82,11 @@ const DictAPI = {
|
|||||||
},
|
},
|
||||||
/** 字典列表 */
|
/** 字典列表 */
|
||||||
getList() {
|
getList() {
|
||||||
return request<any, OptionItem[]>({ url: `${DICT_BASE_URL}/options`, method: "get" });
|
return request<unknown, OptionItem[]>({ url: `${DICT_BASE_URL}/options`, method: "get" });
|
||||||
},
|
},
|
||||||
/** 字典表单数据 */
|
/** 字典表单数据 */
|
||||||
getFormData(id: string) {
|
getFormData(id: string) {
|
||||||
return request<any, DictTypeForm>({ url: `${DICT_BASE_URL}/${id}/form`, method: "get" });
|
return request<unknown, DictTypeForm>({ url: `${DICT_BASE_URL}/${id}/form`, method: "get" });
|
||||||
},
|
},
|
||||||
/** 新增字典 */
|
/** 新增字典 */
|
||||||
create(data: DictTypeForm) {
|
create(data: DictTypeForm) {
|
||||||
@@ -90,29 +103,21 @@ const DictAPI = {
|
|||||||
|
|
||||||
/** 获取字典项分页列表 */
|
/** 获取字典项分页列表 */
|
||||||
getDictItemPage(dictCode: string, queryParams: DictItemQueryParams) {
|
getDictItemPage(dictCode: string, queryParams: DictItemQueryParams) {
|
||||||
return request<any, PageResult<DictItem>>({
|
return request<unknown, PageResult<DictItem>>({
|
||||||
url: `${DICT_BASE_URL}/${dictCode}/items`,
|
url: `${DICT_BASE_URL}/${dictCode}/items`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
}).then((data) => ({
|
}).then((data) => ({
|
||||||
...data,
|
...data,
|
||||||
list: (data.list ?? []).map((item: DictItem & { tagType?: string }) => ({
|
list: (data.list ?? []).map(normalizeDictTagType),
|
||||||
...item,
|
|
||||||
tagType: decodeDictTagType(item.tagType),
|
|
||||||
})),
|
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
/** 获取字典项列表 */
|
/** 获取字典项列表 */
|
||||||
getDictItems(dictCode: string) {
|
getDictItems(dictCode: string) {
|
||||||
return request<any, DictItemOption[]>({
|
return request<unknown, DictItemOption[]>({
|
||||||
url: `${DICT_BASE_URL}/${dictCode}/items/options`,
|
url: `${DICT_BASE_URL}/${dictCode}/items/options`,
|
||||||
method: "get",
|
method: "get",
|
||||||
}).then((items) =>
|
}).then((items) => (items ?? []).map(normalizeDictTagType));
|
||||||
(items ?? []).map((item) => ({
|
|
||||||
...item,
|
|
||||||
tagType: decodeDictTagType((item as any).tagType),
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
/** 新增字典项 */
|
/** 新增字典项 */
|
||||||
createDictItem(dictCode: string, data: DictItemForm) {
|
createDictItem(dictCode: string, data: DictItemForm) {
|
||||||
@@ -121,19 +126,16 @@ const DictAPI = {
|
|||||||
method: "post",
|
method: "post",
|
||||||
data: {
|
data: {
|
||||||
...data,
|
...data,
|
||||||
tagType: encodeDictTagType((data as any).tagType),
|
tagType: encodeDictTagType(data.tagType),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 获取字典项表单数据 */
|
/** 获取字典项表单数据 */
|
||||||
getDictItemFormData(dictCode: string, id: string) {
|
getDictItemFormData(dictCode: string, id: string) {
|
||||||
return request<any, DictItemForm>({
|
return request<unknown, DictItemForm>({
|
||||||
url: `${DICT_BASE_URL}/${dictCode}/items/${id}/form`,
|
url: `${DICT_BASE_URL}/${dictCode}/items/${id}/form`,
|
||||||
method: "get",
|
method: "get",
|
||||||
}).then((form) => ({
|
}).then(normalizeDictTagType);
|
||||||
...form,
|
|
||||||
tagType: decodeDictTagType((form as any).tagType),
|
|
||||||
}));
|
|
||||||
},
|
},
|
||||||
/** 修改字典项 */
|
/** 修改字典项 */
|
||||||
updateDictItem(dictCode: string, id: string, data: DictItemForm) {
|
updateDictItem(dictCode: string, id: string, data: DictItemForm) {
|
||||||
@@ -142,7 +144,7 @@ const DictAPI = {
|
|||||||
method: "put",
|
method: "put",
|
||||||
data: {
|
data: {
|
||||||
...data,
|
...data,
|
||||||
tagType: encodeDictTagType((data as any).tagType),
|
tagType: encodeDictTagType(data.tagType),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const LOG_BASE_URL = "/api/v1/logs";
|
|||||||
const LogAPI = {
|
const LogAPI = {
|
||||||
/** 获取日志分页列表 */
|
/** 获取日志分页列表 */
|
||||||
getPage(queryParams: LogQueryParams) {
|
getPage(queryParams: LogQueryParams) {
|
||||||
return request<any, PageResult<LogItem>>({
|
return request<unknown, PageResult<LogItem>>({
|
||||||
url: `${LOG_BASE_URL}`,
|
url: `${LOG_BASE_URL}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
@@ -21,7 +21,7 @@ const LogAPI = {
|
|||||||
|
|
||||||
/** 获取访问趋势统计 */
|
/** 获取访问趋势统计 */
|
||||||
getVisitTrend(queryParams: VisitTrendQueryParams) {
|
getVisitTrend(queryParams: VisitTrendQueryParams) {
|
||||||
return request<any, VisitTrendDetail>({
|
return request<unknown, VisitTrendDetail>({
|
||||||
url: `${LOG_BASE_URL}/analytics/trend`,
|
url: `${LOG_BASE_URL}/analytics/trend`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
@@ -30,7 +30,7 @@ const LogAPI = {
|
|||||||
|
|
||||||
/** 获取访问概览统计 */
|
/** 获取访问概览统计 */
|
||||||
getVisitOverview() {
|
getVisitOverview() {
|
||||||
return request<any, VisitOverviewDetail>({
|
return request<unknown, VisitOverviewDetail>({
|
||||||
url: `${LOG_BASE_URL}/analytics/overview`,
|
url: `${LOG_BASE_URL}/analytics/overview`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ const MENU_BASE_URL = "/api/v1/menus";
|
|||||||
const MenuAPI = {
|
const MenuAPI = {
|
||||||
/** 获取当前用户的路由列表 */
|
/** 获取当前用户的路由列表 */
|
||||||
getRoutes() {
|
getRoutes() {
|
||||||
return request<any, RouteItem[]>({ url: `${MENU_BASE_URL}/routes`, method: "get" });
|
return request<unknown, RouteItem[]>({ url: `${MENU_BASE_URL}/routes`, method: "get" });
|
||||||
},
|
},
|
||||||
/** 获取菜单树形列表 */
|
/** 获取菜单树形列表 */
|
||||||
getList(queryParams: MenuQueryParams) {
|
getList(queryParams: MenuQueryParams) {
|
||||||
return request<any, MenuItem[]>({
|
return request<unknown, MenuItem[]>({
|
||||||
url: `${MENU_BASE_URL}`,
|
url: `${MENU_BASE_URL}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
@@ -19,7 +19,7 @@ const MenuAPI = {
|
|||||||
},
|
},
|
||||||
/** 获取菜单下拉数据源 */
|
/** 获取菜单下拉数据源 */
|
||||||
getOptions(onlyParent?: boolean, scope?: number) {
|
getOptions(onlyParent?: boolean, scope?: number) {
|
||||||
return request<any, OptionItem[]>({
|
return request<unknown, OptionItem[]>({
|
||||||
url: `${MENU_BASE_URL}/options`,
|
url: `${MENU_BASE_URL}/options`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: { onlyParent, scope },
|
params: { onlyParent, scope },
|
||||||
@@ -27,7 +27,7 @@ const MenuAPI = {
|
|||||||
},
|
},
|
||||||
/** 获取菜单表单数据 */
|
/** 获取菜单表单数据 */
|
||||||
getFormData(id: string) {
|
getFormData(id: string) {
|
||||||
return request<any, MenuForm>({ url: `${MENU_BASE_URL}/${id}/form`, method: "get" });
|
return request<unknown, MenuForm>({ url: `${MENU_BASE_URL}/${id}/form`, method: "get" });
|
||||||
},
|
},
|
||||||
/** 新增菜单 */
|
/** 新增菜单 */
|
||||||
create(data: MenuForm) {
|
create(data: MenuForm) {
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export interface Meta {
|
|||||||
/** 【菜单】是否开启页面缓存 */
|
/** 【菜单】是否开启页面缓存 */
|
||||||
keepAlive?: boolean;
|
keepAlive?: boolean;
|
||||||
/** 路由参数 */
|
/** 路由参数 */
|
||||||
params?: Record<string, any>;
|
params?: Record<string, unknown>;
|
||||||
/** 角色集合 */
|
/** 角色集合 */
|
||||||
roles?: string[];
|
roles?: string[];
|
||||||
/** 路由title */
|
/** 路由title */
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const NOTICE_BASE_URL = "/api/v1/notices";
|
|||||||
const NoticeAPI = {
|
const NoticeAPI = {
|
||||||
/** 获取通知公告分页数据 */
|
/** 获取通知公告分页数据 */
|
||||||
getPage(queryParams?: NoticeQueryParams) {
|
getPage(queryParams?: NoticeQueryParams) {
|
||||||
return request<any, PageResult<NoticeItem>>({
|
return request<unknown, PageResult<NoticeItem>>({
|
||||||
url: `${NOTICE_BASE_URL}`,
|
url: `${NOTICE_BASE_URL}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
@@ -14,7 +14,7 @@ const NoticeAPI = {
|
|||||||
},
|
},
|
||||||
/** 获取通知公告表单数据 */
|
/** 获取通知公告表单数据 */
|
||||||
getFormData(id: string) {
|
getFormData(id: string) {
|
||||||
return request<any, NoticeForm>({ url: `${NOTICE_BASE_URL}/${id}/form`, method: "get" });
|
return request<unknown, NoticeForm>({ url: `${NOTICE_BASE_URL}/${id}/form`, method: "get" });
|
||||||
},
|
},
|
||||||
/** 添加通知公告 */
|
/** 添加通知公告 */
|
||||||
create(data: NoticeForm) {
|
create(data: NoticeForm) {
|
||||||
@@ -38,7 +38,10 @@ const NoticeAPI = {
|
|||||||
},
|
},
|
||||||
/** 查看通知 */
|
/** 查看通知 */
|
||||||
getDetail(id: string) {
|
getDetail(id: string) {
|
||||||
return request<any, NoticeDetail>({ url: `${NOTICE_BASE_URL}/${id}/detail`, method: "get" });
|
return request<unknown, NoticeDetail>({
|
||||||
|
url: `${NOTICE_BASE_URL}/${id}/detail`,
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
},
|
},
|
||||||
/** 全部已读 */
|
/** 全部已读 */
|
||||||
readAll() {
|
readAll() {
|
||||||
@@ -46,7 +49,7 @@ const NoticeAPI = {
|
|||||||
},
|
},
|
||||||
/** 获取我的通知分页列表 */
|
/** 获取我的通知分页列表 */
|
||||||
getMyNoticePage(queryParams?: NoticeQueryParams) {
|
getMyNoticePage(queryParams?: NoticeQueryParams) {
|
||||||
return request<any, PageResult<NoticeItem>>({
|
return request<unknown, PageResult<NoticeItem>>({
|
||||||
url: `${NOTICE_BASE_URL}/my`,
|
url: `${NOTICE_BASE_URL}/my`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const ROLE_BASE_URL = "/api/v1/roles";
|
|||||||
const RoleAPI = {
|
const RoleAPI = {
|
||||||
/** 获取角色分页数据 */
|
/** 获取角色分页数据 */
|
||||||
getPage(queryParams?: RoleQueryParams) {
|
getPage(queryParams?: RoleQueryParams) {
|
||||||
return request<any, PageResult<RoleItem>>({
|
return request<unknown, PageResult<RoleItem>>({
|
||||||
url: `${ROLE_BASE_URL}`,
|
url: `${ROLE_BASE_URL}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
@@ -15,11 +15,14 @@ const RoleAPI = {
|
|||||||
},
|
},
|
||||||
/** 获取角色下拉数据源 */
|
/** 获取角色下拉数据源 */
|
||||||
getOptions() {
|
getOptions() {
|
||||||
return request<any, OptionItem[]>({ url: `${ROLE_BASE_URL}/options`, method: "get" });
|
return request<unknown, OptionItem[]>({ url: `${ROLE_BASE_URL}/options`, method: "get" });
|
||||||
},
|
},
|
||||||
/** 获取角色的菜单ID集合 */
|
/** 获取角色的菜单ID集合 */
|
||||||
getRoleMenuIds(roleId: string) {
|
getRoleMenuIds(roleId: string) {
|
||||||
return request<any, string[]>({ url: `${ROLE_BASE_URL}/${roleId}/menu-ids`, method: "get" });
|
return request<unknown, string[]>({
|
||||||
|
url: `${ROLE_BASE_URL}/${roleId}/menu-ids`,
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
},
|
},
|
||||||
/** 分配菜单权限 */
|
/** 分配菜单权限 */
|
||||||
updateRoleMenus(roleId: string, data: number[]) {
|
updateRoleMenus(roleId: string, data: number[]) {
|
||||||
@@ -27,11 +30,14 @@ const RoleAPI = {
|
|||||||
},
|
},
|
||||||
/** 获取角色表单数据 */
|
/** 获取角色表单数据 */
|
||||||
getFormData(id: string) {
|
getFormData(id: string) {
|
||||||
return request<any, RoleForm>({ url: `${ROLE_BASE_URL}/${id}/form`, method: "get" });
|
return request<unknown, RoleForm>({ url: `${ROLE_BASE_URL}/${id}/form`, method: "get" });
|
||||||
},
|
},
|
||||||
/** 获取角色的部门ID集合(自定义数据权限) */
|
/** 获取角色的部门ID集合(自定义数据权限) */
|
||||||
getRoleDeptIds(roleId: string) {
|
getRoleDeptIds(roleId: string) {
|
||||||
return request<any, string[]>({ url: `${ROLE_BASE_URL}/${roleId}/dept-ids`, method: "get" });
|
return request<unknown, string[]>({
|
||||||
|
url: `${ROLE_BASE_URL}/${roleId}/dept-ids`,
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
},
|
},
|
||||||
/** 新增角色 */
|
/** 新增角色 */
|
||||||
create(data: RoleForm) {
|
create(data: RoleForm) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const TENANT_PLAN_BASE_URL = "/api/v1/tenant-plans";
|
|||||||
const TenantPlanAPI = {
|
const TenantPlanAPI = {
|
||||||
/** 获取租户套餐分页数据 */
|
/** 获取租户套餐分页数据 */
|
||||||
getPage(queryParams?: TenantPlanQueryParams) {
|
getPage(queryParams?: TenantPlanQueryParams) {
|
||||||
return request<any, PageResult<TenantPlanItem>>({
|
return request<unknown, PageResult<TenantPlanItem>>({
|
||||||
url: `${TENANT_PLAN_BASE_URL}`,
|
url: `${TENANT_PLAN_BASE_URL}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
@@ -16,7 +16,7 @@ const TenantPlanAPI = {
|
|||||||
|
|
||||||
/** 获取租户套餐表单数据 */
|
/** 获取租户套餐表单数据 */
|
||||||
getFormData(planId: string) {
|
getFormData(planId: string) {
|
||||||
return request<any, TenantPlanForm>({
|
return request<unknown, TenantPlanForm>({
|
||||||
url: `${TENANT_PLAN_BASE_URL}/${planId}/form`,
|
url: `${TENANT_PLAN_BASE_URL}/${planId}/form`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
@@ -39,7 +39,7 @@ const TenantPlanAPI = {
|
|||||||
|
|
||||||
/** 获取租户方案下拉选项 */
|
/** 获取租户方案下拉选项 */
|
||||||
getOptions() {
|
getOptions() {
|
||||||
return request<any, OptionItem[]>({
|
return request<unknown, OptionItem[]>({
|
||||||
url: `${TENANT_PLAN_BASE_URL}/options`,
|
url: `${TENANT_PLAN_BASE_URL}/options`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
@@ -47,7 +47,7 @@ const TenantPlanAPI = {
|
|||||||
|
|
||||||
/** 获取方案菜单ID集合 */
|
/** 获取方案菜单ID集合 */
|
||||||
getPlanMenuIds(planId: number) {
|
getPlanMenuIds(planId: number) {
|
||||||
return request<any, number[]>({
|
return request<unknown, number[]>({
|
||||||
url: `${TENANT_PLAN_BASE_URL}/${planId}/menuIds`,
|
url: `${TENANT_PLAN_BASE_URL}/${planId}/menuIds`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const TenantAPI = {
|
|||||||
* 获取当前用户可访问的租户列表
|
* 获取当前用户可访问的租户列表
|
||||||
*/
|
*/
|
||||||
getTenantList() {
|
getTenantList() {
|
||||||
return request<any, TenantInfo[]>({
|
return request<unknown, TenantInfo[]>({
|
||||||
url: `${TENANT_BASE_URL}/options`,
|
url: `${TENANT_BASE_URL}/options`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
@@ -29,7 +29,7 @@ const TenantAPI = {
|
|||||||
* 获取当前租户信息
|
* 获取当前租户信息
|
||||||
*/
|
*/
|
||||||
getCurrentTenant() {
|
getCurrentTenant() {
|
||||||
return request<any, TenantInfo>({
|
return request<unknown, TenantInfo>({
|
||||||
url: `${TENANT_BASE_URL}/current`,
|
url: `${TENANT_BASE_URL}/current`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
@@ -41,7 +41,7 @@ const TenantAPI = {
|
|||||||
* @param tenantId 目标租户ID
|
* @param tenantId 目标租户ID
|
||||||
*/
|
*/
|
||||||
switchTenant(tenantId: number) {
|
switchTenant(tenantId: number) {
|
||||||
return request<any, TenantInfo>({
|
return request<unknown, TenantInfo>({
|
||||||
url: `${TENANT_BASE_URL}/${tenantId}/switch`,
|
url: `${TENANT_BASE_URL}/${tenantId}/switch`,
|
||||||
method: "post",
|
method: "post",
|
||||||
});
|
});
|
||||||
@@ -49,7 +49,7 @@ const TenantAPI = {
|
|||||||
|
|
||||||
/** 获取租户分页数据(平台租户管理) */
|
/** 获取租户分页数据(平台租户管理) */
|
||||||
getPage(queryParams?: TenantQueryParams) {
|
getPage(queryParams?: TenantQueryParams) {
|
||||||
return request<any, PageResult<TenantItem>>({
|
return request<unknown, PageResult<TenantItem>>({
|
||||||
url: `${TENANT_BASE_URL}`,
|
url: `${TENANT_BASE_URL}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
@@ -58,7 +58,7 @@ const TenantAPI = {
|
|||||||
|
|
||||||
/** 获取租户表单数据 */
|
/** 获取租户表单数据 */
|
||||||
getFormData(tenantId: string) {
|
getFormData(tenantId: string) {
|
||||||
return request<any, TenantForm>({
|
return request<unknown, TenantForm>({
|
||||||
url: `${TENANT_BASE_URL}/${tenantId}/form`,
|
url: `${TENANT_BASE_URL}/${tenantId}/form`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
@@ -66,7 +66,7 @@ const TenantAPI = {
|
|||||||
|
|
||||||
/** 新增租户并初始化默认数据 */
|
/** 新增租户并初始化默认数据 */
|
||||||
create(data: TenantCreateForm) {
|
create(data: TenantCreateForm) {
|
||||||
return request<any, TenantCreateResult>({
|
return request<unknown, TenantCreateResult>({
|
||||||
url: `${TENANT_BASE_URL}`,
|
url: `${TENANT_BASE_URL}`,
|
||||||
method: "post",
|
method: "post",
|
||||||
data,
|
data,
|
||||||
@@ -101,7 +101,7 @@ const TenantAPI = {
|
|||||||
|
|
||||||
/** 获取租户菜单ID集合 */
|
/** 获取租户菜单ID集合 */
|
||||||
getTenantMenuIds(tenantId: number) {
|
getTenantMenuIds(tenantId: number) {
|
||||||
return request<any, number[]>({
|
return request<unknown, number[]>({
|
||||||
url: `${TENANT_BASE_URL}/${tenantId}/menuIds`,
|
url: `${TENANT_BASE_URL}/${tenantId}/menuIds`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const UserAPI = {
|
|||||||
* @returns 登录用户昵称、头像信息,包括角色和权限
|
* @returns 登录用户昵称、头像信息,包括角色和权限
|
||||||
*/
|
*/
|
||||||
getInfo() {
|
getInfo() {
|
||||||
return request<any, UserInfo>({
|
return request<unknown, UserInfo>({
|
||||||
url: `${USER_BASE_URL}/me`,
|
url: `${USER_BASE_URL}/me`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
@@ -34,7 +34,7 @@ const UserAPI = {
|
|||||||
* @param queryParams 查询参数
|
* @param queryParams 查询参数
|
||||||
*/
|
*/
|
||||||
getPage(queryParams: UserQueryParams) {
|
getPage(queryParams: UserQueryParams) {
|
||||||
return request<any, PageResult<UserItem>>({
|
return request<unknown, PageResult<UserItem>>({
|
||||||
url: `${USER_BASE_URL}`,
|
url: `${USER_BASE_URL}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
@@ -48,7 +48,7 @@ const UserAPI = {
|
|||||||
* @returns 用户表单详情
|
* @returns 用户表单详情
|
||||||
*/
|
*/
|
||||||
getFormData(userId: string) {
|
getFormData(userId: string) {
|
||||||
return request<any, UserForm>({
|
return request<unknown, UserForm>({
|
||||||
url: `${USER_BASE_URL}/${userId}/form`,
|
url: `${USER_BASE_URL}/${userId}/form`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
@@ -138,7 +138,7 @@ const UserAPI = {
|
|||||||
import(file: File) {
|
import(file: File) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("file", file);
|
formData.append("file", file);
|
||||||
return request<any, ExcelResult>({
|
return request<unknown, ExcelResult>({
|
||||||
url: `${USER_BASE_URL}/import`,
|
url: `${USER_BASE_URL}/import`,
|
||||||
method: "post",
|
method: "post",
|
||||||
data: formData,
|
data: formData,
|
||||||
@@ -150,7 +150,7 @@ const UserAPI = {
|
|||||||
|
|
||||||
/** 获取个人中心用户信息 */
|
/** 获取个人中心用户信息 */
|
||||||
getProfile() {
|
getProfile() {
|
||||||
return request<any, UserProfileDetail>({
|
return request<unknown, UserProfileDetail>({
|
||||||
url: `${USER_BASE_URL}/profile`,
|
url: `${USER_BASE_URL}/profile`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
@@ -232,7 +232,7 @@ const UserAPI = {
|
|||||||
* 获取用户下拉列表
|
* 获取用户下拉列表
|
||||||
*/
|
*/
|
||||||
getOptions() {
|
getOptions() {
|
||||||
return request<any, OptionItem[]>({
|
return request<unknown, OptionItem[]>({
|
||||||
url: `${USER_BASE_URL}/options`,
|
url: `${USER_BASE_URL}/options`,
|
||||||
method: "get",
|
method: "get",
|
||||||
});
|
});
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.1 MiB After Width: | Height: | Size: 4.1 MiB |
@@ -15,56 +15,72 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RouteLocationMatched } from "vue-router";
|
import type { RouteLocationMatched } from "vue-router";
|
||||||
import { compile } from "path-to-regexp";
|
import { compile } from "path-to-regexp";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import { translateRouteTitle } from "@/lang/utils";
|
import { translateRouteTitle } from "@/lang/utils";
|
||||||
|
|
||||||
|
type BreadcrumbRoute = {
|
||||||
|
path: string;
|
||||||
|
name?: RouteLocationMatched["name"];
|
||||||
|
redirect?: string;
|
||||||
|
meta: RouteLocationMatched["meta"];
|
||||||
|
};
|
||||||
|
|
||||||
const currentRoute = useRoute();
|
const currentRoute = useRoute();
|
||||||
|
// 默认补一个首页面包屑
|
||||||
|
const dashboardRoute: BreadcrumbRoute = { path: "/dashboard", meta: { title: "dashboard" } };
|
||||||
|
|
||||||
|
// 根据当前路由参数生成跳转路径
|
||||||
const pathCompile = (path: string) => {
|
const pathCompile = (path: string) => {
|
||||||
const { params } = currentRoute;
|
const { params } = currentRoute;
|
||||||
const toPath = compile(path);
|
const toPath = compile(path);
|
||||||
return toPath(params);
|
return toPath(params);
|
||||||
};
|
};
|
||||||
|
|
||||||
const breadcrumbs = ref<Array<RouteLocationMatched>>([]);
|
const breadcrumbs = ref<BreadcrumbRoute[]>([]);
|
||||||
|
|
||||||
|
// 生成面包屑列表
|
||||||
function getBreadcrumb() {
|
function getBreadcrumb() {
|
||||||
let matched = currentRoute.matched.filter((item) => item.meta && item.meta.title);
|
let matched: BreadcrumbRoute[] = currentRoute.matched
|
||||||
|
.filter((item) => item.meta && item.meta.title)
|
||||||
|
.map(({ path, name, redirect, meta }) => ({
|
||||||
|
path,
|
||||||
|
name,
|
||||||
|
redirect: typeof redirect === "string" ? redirect : undefined,
|
||||||
|
meta,
|
||||||
|
}));
|
||||||
|
|
||||||
const first = matched[0];
|
const first = matched[0];
|
||||||
if (!isDashboard(first)) {
|
if (!isDashboard(first)) {
|
||||||
matched = [{ path: "/dashboard", meta: { title: "dashboard" } } as any].concat(matched);
|
matched = [dashboardRoute].concat(matched);
|
||||||
}
|
}
|
||||||
breadcrumbs.value = matched.filter((item) => {
|
breadcrumbs.value = matched.filter((item) => {
|
||||||
return item.meta && item.meta.title && item.meta.breadcrumb !== false;
|
return item.meta && item.meta.title && item.meta.breadcrumb !== false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isDashboard(route: RouteLocationMatched) {
|
// 判断是否为首页路由
|
||||||
const name = route && route.name;
|
function isDashboard(route?: BreadcrumbRoute) {
|
||||||
|
const name = route?.name;
|
||||||
if (!name) {
|
if (!name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return name.toString().trim().toLocaleLowerCase() === "Dashboard".toLocaleLowerCase();
|
return name.toString().trim().toLocaleLowerCase() === "Dashboard".toLocaleLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleLink(item: any) {
|
// 处理面包屑跳转
|
||||||
|
function handleLink(item: BreadcrumbRoute) {
|
||||||
const { redirect, path } = item;
|
const { redirect, path } = item;
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
router.push(redirect).then(
|
router.push(redirect).catch((err) => {
|
||||||
() => {},
|
console.warn(err);
|
||||||
(err) => {
|
});
|
||||||
console.warn(err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
router.push(pathCompile(path)).then(
|
router.push(pathCompile(path)).catch((err) => {
|
||||||
() => {},
|
console.warn(err);
|
||||||
(err) => {
|
});
|
||||||
console.warn(err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="flex flex-col md:flex-row justify-between gap-y-2.5 mb-2.5">
|
<div class="flex flex-col md:flex-row justify-between gap-y-2.5 mb-2.5">
|
||||||
<!-- 左侧工具 -->
|
<!-- 左侧工具 -->
|
||||||
<div class="toolbar-left flex gap-y-2.5 gap-x-2 md:gap-x-3 flex-wrap">
|
<div class="toolbar-left flex gap-y-2.5 gap-x-2 md:gap-x-3 flex-wrap">
|
||||||
<template v-for="(btn, index) in toolbarLeftBtn" :key="index">
|
<template v-for="(btn, index) in leftToolbarButtons" :key="index">
|
||||||
<el-button
|
<el-button
|
||||||
v-hasPerm="btn.perm ?? '*:*:*'"
|
v-hasPerm="btn.perm ?? '*:*:*'"
|
||||||
v-bind="btn.attrs"
|
v-bind="btn.attrs"
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 右侧工具 -->
|
<!-- 右侧工具 -->
|
||||||
<div class="toolbar-right flex gap-y-2.5 gap-x-2 md:gap-x-3 flex-wrap">
|
<div class="toolbar-right flex gap-y-2.5 gap-x-2 md:gap-x-3 flex-wrap">
|
||||||
<template v-for="(btn, index) in toolbarRightBtn" :key="index">
|
<template v-for="(btn, index) in rightToolbarButtons" :key="index">
|
||||||
<el-popover v-if="btn.name === 'filter'" placement="bottom" trigger="click">
|
<el-popover v-if="btn.name === 'filter'" placement="bottom" trigger="click">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button v-bind="btn.attrs"></el-button>
|
<el-button v-bind="btn.attrs"></el-button>
|
||||||
@@ -412,13 +412,13 @@ function createToolbar(toolbar: Array<string | IToolsButton>, attr = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 左侧工具栏按钮
|
// 左侧工具栏按钮
|
||||||
const toolbarLeftBtn = computed(() => {
|
const leftToolbarButtons = computed(() => {
|
||||||
if (!config.value.toolbar || config.value.toolbar.length === 0) return [];
|
if (!config.value.toolbar || config.value.toolbar.length === 0) return [];
|
||||||
return createToolbar(config.value.toolbar, {});
|
return createToolbar(config.value.toolbar, {});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 右侧工具栏按钮
|
// 右侧工具栏按钮
|
||||||
const toolbarRightBtn = computed(() => {
|
const rightToolbarButtons = computed(() => {
|
||||||
if (!config.value.defaultToolbar || config.value.defaultToolbar.length === 0) return [];
|
if (!config.value.defaultToolbar || config.value.defaultToolbar.length === 0) return [];
|
||||||
return createToolbar(config.value.defaultToolbar, { circle: true });
|
return createToolbar(config.value.defaultToolbar, { circle: true });
|
||||||
});
|
});
|
||||||
@@ -602,7 +602,7 @@ function handleExports() {
|
|||||||
(buffer) => {
|
(buffer) => {
|
||||||
saveXlsx(buffer, filename as string);
|
saveXlsx(buffer, filename as string);
|
||||||
},
|
},
|
||||||
(error) => console.log(error)
|
(error) => console.error(error)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -616,7 +616,7 @@ function handleExports() {
|
|||||||
(buffer) => {
|
(buffer) => {
|
||||||
saveXlsx(buffer, filename as string);
|
saveXlsx(buffer, filename as string);
|
||||||
},
|
},
|
||||||
(error) => console.log(error)
|
(error) => console.error(error)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -750,7 +750,7 @@ function handleImports() {
|
|||||||
handleRefresh(true);
|
handleRefresh(true);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
(error) => console.log(error)
|
(error) => console.error(error)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error("读取文件失败");
|
ElMessage.error("读取文件失败");
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ const {
|
|||||||
|
|
||||||
const displayList = computed(() => (results.value.length ? results.value : history.value));
|
const displayList = computed(() => (results.value.length ? results.value : history.value));
|
||||||
|
|
||||||
const handleInputKeydown: (evt: KeyboardEvent | Event) => any = (evt) => {
|
const handleInputKeydown: (evt: KeyboardEvent | Event) => void = (evt) => {
|
||||||
if (!(evt instanceof KeyboardEvent)) return;
|
if (!(evt instanceof KeyboardEvent)) return;
|
||||||
const e = evt;
|
const e = evt;
|
||||||
const key = e.key.toLowerCase();
|
const key = e.key.toLowerCase();
|
||||||
|
|||||||
@@ -31,13 +31,13 @@ const dictStore = useDictStore();
|
|||||||
* @param value 字典项的值
|
* @param value 字典项的值
|
||||||
* @returns 包含 label 和 tagType 的对象
|
* @returns 包含 label 和 tagType 的对象
|
||||||
*/
|
*/
|
||||||
const getLabelAndTagByValue = async (dictCode: string, value: any) => {
|
const getLabelAndTagByValue = async (dictCode: string, value: string | number) => {
|
||||||
// 按需加载字典数据
|
// 按需加载字典数据
|
||||||
await dictStore.loadDictItems(dictCode);
|
await dictStore.loadDictItems(dictCode);
|
||||||
// 从缓存中获取字典数据
|
// 从缓存中获取字典数据
|
||||||
const dictItems = dictStore.getDictItems(dictCode);
|
const dictItems = dictStore.getDictItems(dictCode);
|
||||||
// 查找对应的字典项
|
// 查找对应的字典项
|
||||||
const dictItem = dictItems.find((item) => item.value == value);
|
const dictItem = dictItems.find((item) => String(item.value) === String(value));
|
||||||
return {
|
return {
|
||||||
label: dictItem?.label || "",
|
label: dictItem?.label || "",
|
||||||
tagType: dictItem?.tagType,
|
tagType: dictItem?.tagType,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<el-dropdown-item
|
<el-dropdown-item
|
||||||
v-for="item of sizeOptions"
|
v-for="item of sizeOptions"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:disabled="appStore.size == item.value"
|
:disabled="appStore.size === item.value"
|
||||||
:command="item.value"
|
:command="item.value"
|
||||||
>
|
>
|
||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
|
|||||||
@@ -190,9 +190,11 @@ const handleSuccess = (fileInfo: FileInfo, uploadFile: UploadUserFile) => {
|
|||||||
/**
|
/**
|
||||||
* 上传失败回调
|
* 上传失败回调
|
||||||
*/
|
*/
|
||||||
const handleError = (error: any) => {
|
const getErrorMessage = (error: unknown) =>
|
||||||
console.log("handleError");
|
error instanceof Error ? error.message : String(error);
|
||||||
ElMessage.error("上传失败: " + error.message);
|
|
||||||
|
const handleError = (error: unknown) => {
|
||||||
|
ElMessage.error("上传失败: " + getErrorMessage(error));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
class="single-upload__image"
|
class="single-upload__image"
|
||||||
:src="modelValue"
|
:src="modelValue"
|
||||||
:preview-src-list="[modelValue]"
|
:preview-src-list="[modelValue]"
|
||||||
@click.stop="handlePreview"
|
@click.stop
|
||||||
/>
|
/>
|
||||||
<el-icon class="single-upload__delete-btn" @click.stop="handleDelete">
|
<el-icon class="single-upload__delete-btn" @click.stop="handleDelete">
|
||||||
<CircleCloseFilled />
|
<CircleCloseFilled />
|
||||||
@@ -148,13 +148,6 @@ function handleUpload(options: UploadRequestOptions) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 预览图片
|
|
||||||
*/
|
|
||||||
function handlePreview() {
|
|
||||||
console.log("预览图片,停止冒泡");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除图片
|
* 删除图片
|
||||||
*/
|
*/
|
||||||
@@ -175,9 +168,11 @@ const onSuccess = (fileInfo: FileInfo) => {
|
|||||||
/**
|
/**
|
||||||
* 上传失败回调
|
* 上传失败回调
|
||||||
*/
|
*/
|
||||||
const onError = (error: any) => {
|
const getErrorMessage = (error: unknown) =>
|
||||||
console.log("onError");
|
error instanceof Error ? error.message : String(error);
|
||||||
ElMessage.error("上传失败: " + error.message);
|
|
||||||
|
const onError = (error: unknown) => {
|
||||||
|
ElMessage.error("上传失败: " + getErrorMessage(error));
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,13 @@ export interface UseSseOptions {
|
|||||||
maxReconnectAttempts?: number; // 最大重试次数,超过后停止重连
|
maxReconnectAttempts?: number; // 最大重试次数,超过后停止重连
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventHandler = (data: any) => void;
|
type EventHandler = (data: unknown) => void;
|
||||||
|
|
||||||
|
type SseParseState = {
|
||||||
|
currentEvent: string;
|
||||||
|
currentData: string;
|
||||||
|
buffer: string;
|
||||||
|
};
|
||||||
|
|
||||||
export enum SseConnectionState {
|
export enum SseConnectionState {
|
||||||
DISCONNECTED = "DISCONNECTED", // 未连接
|
DISCONNECTED = "DISCONNECTED", // 未连接
|
||||||
@@ -46,9 +52,14 @@ function createSseConnection(options: UseSseOptions = {}) {
|
|||||||
|
|
||||||
const eventHandlers = new Map<string, Set<EventHandler>>();
|
const eventHandlers = new Map<string, Set<EventHandler>>();
|
||||||
|
|
||||||
const log = (...args: any[]) => console.log("[SSE]", ...args);
|
const log = (...args: unknown[]) => {
|
||||||
const logError = (...args: any[]) => console.error("[SSE]", ...args);
|
if (config.debug) {
|
||||||
|
console.debug("[SSE]", ...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const logError = (...args: unknown[]) => console.error("[SSE]", ...args);
|
||||||
|
|
||||||
|
// 清理定时器并返回空值
|
||||||
const clearTimer = (timer: typeof connectionTimeoutTimer) => {
|
const clearTimer = (timer: typeof connectionTimeoutTimer) => {
|
||||||
if (timer) {
|
if (timer) {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
@@ -57,6 +68,74 @@ function createSseConnection(options: UseSseOptions = {}) {
|
|||||||
return timer;
|
return timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 重置重连计数和间隔
|
||||||
|
const resetReconnectState = () => {
|
||||||
|
reconnectAttempts = 0;
|
||||||
|
currentReconnectInterval = config.reconnectInterval;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 更新下一次重连间隔
|
||||||
|
const advanceReconnectState = () => {
|
||||||
|
currentReconnectInterval = Math.min(currentReconnectInterval * 2, config.maxReconnectInterval);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 分发一条完整的 SSE 事件
|
||||||
|
const flushSseEvent = (eventName: string, data: string) => {
|
||||||
|
if (!data) return;
|
||||||
|
const handlers = eventHandlers.get(eventName);
|
||||||
|
if (handlers) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(data);
|
||||||
|
handlers.forEach((handler) => handler(parsed));
|
||||||
|
} catch {
|
||||||
|
handlers.forEach((handler) => handler(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log(`收到事件[${eventName}]:`, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 解析单行 SSE 文本并更新当前事件状态
|
||||||
|
const handleSseLine = (line: string, state: SseParseState) => {
|
||||||
|
if (line.startsWith(":")) return;
|
||||||
|
if (line.startsWith("event:")) {
|
||||||
|
state.currentEvent = line.slice(6).trim() || "message";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (line.startsWith("data:")) {
|
||||||
|
const dataLine = line.slice(5).trim();
|
||||||
|
state.currentData = state.currentData ? `${state.currentData}\n${dataLine}` : dataLine;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (line === "") {
|
||||||
|
flushSseEvent(state.currentEvent, state.currentData);
|
||||||
|
state.currentEvent = "message";
|
||||||
|
state.currentData = "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 持续读取 SSE 流并按行解析
|
||||||
|
const consumeSseStream = async (streamReader: ReadableStreamDefaultReader<Uint8Array>) => {
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
const state: SseParseState = { currentEvent: "message", currentData: "", buffer: "" };
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await streamReader.read();
|
||||||
|
if (done) {
|
||||||
|
connectionState.value = SseConnectionState.DISCONNECTED;
|
||||||
|
log("SSE 连接已关闭");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.buffer += decoder.decode(value, { stream: true });
|
||||||
|
const lines = state.buffer.split("\n");
|
||||||
|
state.buffer = lines.pop() || "";
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
handleSseLine(line, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 指数退避重连
|
// 指数退避重连
|
||||||
const scheduleReconnect = () => {
|
const scheduleReconnect = () => {
|
||||||
if (isManualDisconnect) return;
|
if (isManualDisconnect) return;
|
||||||
@@ -70,13 +149,11 @@ function createSseConnection(options: UseSseOptions = {}) {
|
|||||||
|
|
||||||
reconnectTimer = setTimeout(() => {
|
reconnectTimer = setTimeout(() => {
|
||||||
connect();
|
connect();
|
||||||
currentReconnectInterval = Math.min(
|
advanceReconnectState();
|
||||||
currentReconnectInterval * 2,
|
|
||||||
config.maxReconnectInterval
|
|
||||||
);
|
|
||||||
}, currentReconnectInterval);
|
}, currentReconnectInterval);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 建立 SSE 连接
|
||||||
const connect = () => {
|
const connect = () => {
|
||||||
isManualDisconnect = false;
|
isManualDisconnect = false;
|
||||||
|
|
||||||
@@ -122,66 +199,17 @@ function createSseConnection(options: UseSseOptions = {}) {
|
|||||||
}
|
}
|
||||||
connectionTimeoutTimer = clearTimer(connectionTimeoutTimer);
|
connectionTimeoutTimer = clearTimer(connectionTimeoutTimer);
|
||||||
connectionState.value = SseConnectionState.CONNECTED;
|
connectionState.value = SseConnectionState.CONNECTED;
|
||||||
reconnectAttempts = 0;
|
resetReconnectState();
|
||||||
currentReconnectInterval = config.reconnectInterval;
|
|
||||||
log("SSE 连接已建立");
|
log("SSE 连接已建立");
|
||||||
return response.body?.getReader();
|
return response.body?.getReader();
|
||||||
})
|
})
|
||||||
.then((r) => {
|
.then((streamReader) => {
|
||||||
if (!r) return;
|
if (!streamReader) return;
|
||||||
reader = r;
|
reader = streamReader;
|
||||||
const decoder = new TextDecoder();
|
return consumeSseStream(streamReader);
|
||||||
let buffer = "";
|
|
||||||
let currentEvent = "message";
|
|
||||||
let currentData = "";
|
|
||||||
|
|
||||||
// SSE 文本协议解析:event / data / 空行分隔
|
|
||||||
const processChunk = ({
|
|
||||||
done,
|
|
||||||
value,
|
|
||||||
}: ReadableStreamReadResult<Uint8Array>): Promise<void> | void => {
|
|
||||||
if (done) {
|
|
||||||
connectionState.value = SseConnectionState.DISCONNECTED;
|
|
||||||
log("SSE 连接已关闭");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer += decoder.decode(value, { stream: true });
|
|
||||||
const lines = buffer.split("\n");
|
|
||||||
buffer = lines.pop() || "";
|
|
||||||
|
|
||||||
for (const line of lines) {
|
|
||||||
if (line.startsWith(":")) continue;
|
|
||||||
if (line.startsWith("event:")) {
|
|
||||||
currentEvent = line.slice(6).trim();
|
|
||||||
} else if (line.startsWith("data:")) {
|
|
||||||
const dataLine = line.slice(5).trim();
|
|
||||||
currentData = currentData ? `${currentData}\n${dataLine}` : dataLine;
|
|
||||||
} else if (line === "") {
|
|
||||||
if (currentData) {
|
|
||||||
const handlers = eventHandlers.get(currentEvent);
|
|
||||||
if (handlers) {
|
|
||||||
try {
|
|
||||||
const data = JSON.parse(currentData);
|
|
||||||
handlers.forEach((h) => h(data));
|
|
||||||
} catch {
|
|
||||||
handlers.forEach((h) => h(currentData));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log(`收到事件[${currentEvent}]:`, currentData);
|
|
||||||
}
|
|
||||||
currentEvent = "message";
|
|
||||||
currentData = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reader!.read().then(processChunk);
|
|
||||||
};
|
|
||||||
|
|
||||||
return reader.read().then(processChunk);
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err: unknown) => {
|
||||||
if (err.name === "AbortError") {
|
if (err instanceof Error && err.name === "AbortError") {
|
||||||
log("SSE 连接已主动断开");
|
log("SSE 连接已主动断开");
|
||||||
} else {
|
} else {
|
||||||
logError("SSE 连接错误:", err);
|
logError("SSE 连接错误:", err);
|
||||||
@@ -192,17 +220,18 @@ function createSseConnection(options: UseSseOptions = {}) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 订阅事件,返回取消函数
|
// 订阅事件,返回取消函数
|
||||||
const on = (eventName: string, handler: EventHandler): (() => void) => {
|
const on = <T = unknown>(eventName: string, handler: (data: T) => void): (() => void) => {
|
||||||
if (!eventHandlers.has(eventName)) {
|
if (!eventHandlers.has(eventName)) {
|
||||||
eventHandlers.set(eventName, new Set());
|
eventHandlers.set(eventName, new Set());
|
||||||
}
|
}
|
||||||
eventHandlers.get(eventName)!.add(handler);
|
const wrappedHandler: EventHandler = (data) => handler(data as T);
|
||||||
|
eventHandlers.get(eventName)!.add(wrappedHandler);
|
||||||
log(`已订阅事件: ${eventName}`);
|
log(`已订阅事件: ${eventName}`);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const handlers = eventHandlers.get(eventName);
|
const handlers = eventHandlers.get(eventName);
|
||||||
if (handlers) {
|
if (handlers) {
|
||||||
handlers.delete(handler);
|
handlers.delete(wrappedHandler);
|
||||||
if (handlers.size === 0) {
|
if (handlers.size === 0) {
|
||||||
eventHandlers.delete(eventName);
|
eventHandlers.delete(eventName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import "animate.css";
|
|||||||
import { setupDirective } from "@/directives";
|
import { setupDirective } from "@/directives";
|
||||||
import { setupRouter } from "@/router";
|
import { setupRouter } from "@/router";
|
||||||
import { setupStore } from "@/stores";
|
import { setupStore } from "@/stores";
|
||||||
|
import { setupI18n } from "@/lang";
|
||||||
|
|
||||||
// ===== 全局组件 =====
|
// ===== 全局组件 =====
|
||||||
import * as ElementPlusIcons from "@element-plus/icons-vue";
|
import * as ElementPlusIcons from "@element-plus/icons-vue";
|
||||||
@@ -40,6 +41,7 @@ const app = createApp(App);
|
|||||||
|
|
||||||
// 1️⃣ 核心配置
|
// 1️⃣ 核心配置
|
||||||
setupDirective(app);
|
setupDirective(app);
|
||||||
|
setupI18n(app);
|
||||||
setupRouter(app);
|
setupRouter(app);
|
||||||
setupStore(app);
|
setupStore(app);
|
||||||
|
|
||||||
|
|||||||
2
src/types/global.d.ts
vendored
2
src/types/global.d.ts
vendored
@@ -4,7 +4,7 @@
|
|||||||
* @deprecated 请使用 @/types 下的具名导出
|
* @deprecated 请使用 @/types 下的具名导出
|
||||||
*/
|
*/
|
||||||
declare global {
|
declare global {
|
||||||
type ApiResponse<T = any> = import("@/types/api").ApiResponse<T>;
|
type ApiResponse<T = unknown> = import("@/types/api").ApiResponse<T>;
|
||||||
type BaseQueryParams = import("@/types/api").BaseQueryParams;
|
type BaseQueryParams = import("@/types/api").BaseQueryParams;
|
||||||
type PageResult<T> = import("@/types/api").PageResult<T>;
|
type PageResult<T> = import("@/types/api").PageResult<T>;
|
||||||
type OptionItem = import("@/types/api").OptionItem;
|
type OptionItem = import("@/types/api").OptionItem;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import type { LocationQuery } from "vue-router";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标签页相关类型定义
|
* 标签页相关类型定义
|
||||||
*/
|
*/
|
||||||
@@ -10,5 +12,5 @@ export interface TagView {
|
|||||||
icon?: string;
|
icon?: string;
|
||||||
affix?: boolean;
|
affix?: boolean;
|
||||||
keepAlive?: boolean;
|
keepAlive?: boolean;
|
||||||
query?: any;
|
query?: LocationQuery;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export class Storage {
|
|||||||
/**
|
/**
|
||||||
* 存储数据到 localStorage
|
* 存储数据到 localStorage
|
||||||
*/
|
*/
|
||||||
static set(key: string, value: any): void {
|
static set(key: string, value: unknown): void {
|
||||||
localStorage.setItem(key, JSON.stringify(value));
|
localStorage.setItem(key, JSON.stringify(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ export class Storage {
|
|||||||
/**
|
/**
|
||||||
* 存储数据到 sessionStorage
|
* 存储数据到 sessionStorage
|
||||||
*/
|
*/
|
||||||
static sessionSet(key: string, value: any): void {
|
static sessionSet(key: string, value: unknown): void {
|
||||||
sessionStorage.setItem(key, JSON.stringify(value));
|
sessionStorage.setItem(key, JSON.stringify(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@
|
|||||||
<el-table-column label="字段信息" min-width="360">
|
<el-table-column label="字段信息" min-width="360">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="flex items-start gap-3">
|
<div class="flex items-start gap-3">
|
||||||
<div class="field-info" style=" flex-shrink: 0;width: 140px">
|
<div class="field-info" style="flex-shrink: 0; width: 140px">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<span class="font-medium text-sm">{{ row.columnName }}</span>
|
<span class="font-medium text-sm">{{ row.columnName }}</span>
|
||||||
<el-tag v-if="row.isPrimaryKey" size="small" type="warning" effect="dark">
|
<el-tag v-if="row.isPrimaryKey" size="small" type="warning" effect="dark">
|
||||||
|
|||||||
@@ -30,8 +30,8 @@
|
|||||||
@filter-change="handleFilterChange"
|
@filter-change="handleFilterChange"
|
||||||
>
|
>
|
||||||
<template #status="scope">
|
<template #status="scope">
|
||||||
<el-tag :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
|
<el-tag :type="scope.row[scope.prop] === 1 ? 'success' : 'info'">
|
||||||
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
{{ scope.row[scope.prop] === 1 ? "启用" : "禁用" }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #gender="scope">
|
<template #gender="scope">
|
||||||
@@ -187,13 +187,11 @@ const contentConfig: IContentConfig<UserQueryParams, UserItem> = reactive({
|
|||||||
},
|
},
|
||||||
exportAction: UserAPI.export,
|
exportAction: UserAPI.export,
|
||||||
importTemplate: UserAPI.downloadTemplate,
|
importTemplate: UserAPI.downloadTemplate,
|
||||||
importsAction(data: any) {
|
importsAction() {
|
||||||
console.log("importsAction", data);
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
},
|
},
|
||||||
async exportsAction(params: any) {
|
async exportsAction(params: any) {
|
||||||
const data = await UserAPI.getPage(params);
|
const data = await UserAPI.getPage(params);
|
||||||
console.log("exportsAction", data.list);
|
|
||||||
return data.list;
|
return data.list;
|
||||||
},
|
},
|
||||||
pk: "id",
|
pk: "id",
|
||||||
@@ -299,9 +297,6 @@ const addModalConfig: IModalConfig<UserForm> = reactive({
|
|||||||
labelWidth: 100,
|
labelWidth: 100,
|
||||||
},
|
},
|
||||||
formAction: UserAPI.create,
|
formAction: UserAPI.create,
|
||||||
beforeSubmit(data: any) {
|
|
||||||
console.log("提交之前处理", data);
|
|
||||||
},
|
|
||||||
formItems: [
|
formItems: [
|
||||||
{
|
{
|
||||||
label: "用户名",
|
label: "用户名",
|
||||||
@@ -415,9 +410,6 @@ const editModalConfig: IModalConfig<UserForm> = reactive({
|
|||||||
size: useAppStore().device === DeviceEnum.MOBILE ? "80%" : 500,
|
size: useAppStore().device === DeviceEnum.MOBILE ? "80%" : 500,
|
||||||
},
|
},
|
||||||
pk: "id",
|
pk: "id",
|
||||||
beforeSubmit(data: any) {
|
|
||||||
console.log("beforeSubmit", data);
|
|
||||||
},
|
|
||||||
formAction(data: any) {
|
formAction(data: any) {
|
||||||
return UserAPI.update(data.id as string, data);
|
return UserAPI.update(data.id as string, data);
|
||||||
},
|
},
|
||||||
@@ -539,7 +531,6 @@ const {
|
|||||||
|
|
||||||
// 其他工具
|
// 其他工具
|
||||||
function handleToolbarClick(name: string) {
|
function handleToolbarClick(name: string) {
|
||||||
console.log(name);
|
|
||||||
if (name === "custom1") {
|
if (name === "custom1") {
|
||||||
ElMessage.success("点击了自定义1按钮");
|
ElMessage.success("点击了自定义1按钮");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,6 @@ const modalConfig: IModalConfig<UserForm> = {
|
|||||||
labelWidth: 100,
|
labelWidth: 100,
|
||||||
},
|
},
|
||||||
formAction: UserAPI.create,
|
formAction: UserAPI.create,
|
||||||
beforeSubmit(data) {
|
|
||||||
console.log("提交之前处理", data);
|
|
||||||
},
|
|
||||||
formItems: [
|
formItems: [
|
||||||
{
|
{
|
||||||
label: "用户名",
|
label: "用户名",
|
||||||
|
|||||||
@@ -24,15 +24,13 @@ const contentConfig: IContentConfig<UserQueryParams, UserItem> = {
|
|||||||
},
|
},
|
||||||
exportAction: UserAPI.export,
|
exportAction: UserAPI.export,
|
||||||
importTemplate: UserAPI.downloadTemplate,
|
importTemplate: UserAPI.downloadTemplate,
|
||||||
importsAction(data) {
|
importsAction() {
|
||||||
// 模拟导入数据
|
// 模拟导入数据
|
||||||
console.log("importsAction", data);
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
},
|
},
|
||||||
async exportsAction(params) {
|
async exportsAction(params) {
|
||||||
// 模拟获取到的是全量数据
|
// 模拟获取到的是全量数据
|
||||||
const data = await UserAPI.getPage(params);
|
const data = await UserAPI.getPage(params);
|
||||||
console.log("exportsAction", data.list);
|
|
||||||
return data.list;
|
return data.list;
|
||||||
},
|
},
|
||||||
pk: "id",
|
pk: "id",
|
||||||
|
|||||||
@@ -13,9 +13,6 @@ const modalConfig: IModalConfig<UserForm> = {
|
|||||||
size: useAppStore().device === DeviceEnum.MOBILE ? "80%" : 500,
|
size: useAppStore().device === DeviceEnum.MOBILE ? "80%" : 500,
|
||||||
},
|
},
|
||||||
pk: "id",
|
pk: "id",
|
||||||
beforeSubmit(data) {
|
|
||||||
console.log("beforeSubmit", data);
|
|
||||||
},
|
|
||||||
formAction(data) {
|
formAction(data) {
|
||||||
return UserAPI.update(data.id as string, data);
|
return UserAPI.update(data.id as string, data);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ const contentConfig: IContentConfig<DemoQueryParams, DemoItem> = {
|
|||||||
toolbar: [],
|
toolbar: [],
|
||||||
indexAction(params) {
|
indexAction(params) {
|
||||||
// 模拟发起网络请求获取列表数据
|
// 模拟发起网络请求获取列表数据
|
||||||
console.log("indexAction:", params);
|
|
||||||
const list = [
|
const list = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
@@ -74,7 +73,6 @@ const contentConfig: IContentConfig<DemoQueryParams, DemoItem> = {
|
|||||||
},
|
},
|
||||||
modifyAction(data) {
|
modifyAction(data) {
|
||||||
// 模拟发起网络请求修改字段
|
// 模拟发起网络请求修改字段
|
||||||
// console.log("modifyAction:", data);
|
|
||||||
ElMessage.success(JSON.stringify(data));
|
ElMessage.success(JSON.stringify(data));
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ const modalConfig: IModalConfig = {
|
|||||||
size: useAppStore().device === DeviceEnum.MOBILE ? "80%" : 500,
|
size: useAppStore().device === DeviceEnum.MOBILE ? "80%" : 500,
|
||||||
},
|
},
|
||||||
form: { labelPosition: "right", labelWidth: "auto" },
|
form: { labelPosition: "right", labelWidth: "auto" },
|
||||||
beforeSubmit(data) {
|
|
||||||
console.log("beforeSubmit", data);
|
|
||||||
},
|
|
||||||
formAction(data) {
|
formAction(data) {
|
||||||
// return UserAPI.update(data.id as string, data);
|
// return UserAPI.update(data.id as string, data);
|
||||||
// 模拟发起网络请求修改字段
|
// 模拟发起网络请求修改字段
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ const searchConfig: ISearchConfig = {
|
|||||||
prop: "testInput",
|
prop: "testInput",
|
||||||
attrs: { placeholder: "请输入", clearable: true },
|
attrs: { placeholder: "请输入", clearable: true },
|
||||||
events: {
|
events: {
|
||||||
change: (e) => {
|
change: () => {
|
||||||
console.log("输入框的值: ", e);
|
|
||||||
// 级联操作示例,需要使用reactive提前定义数组
|
// 级联操作示例,需要使用reactive提前定义数组
|
||||||
// selectOptions.push({ label: e, value: e });
|
// selectOptions.push({ label: e, value: e });
|
||||||
},
|
},
|
||||||
@@ -35,9 +34,7 @@ const searchConfig: ISearchConfig = {
|
|||||||
attrs: { placeholder: "全部", clearable: true },
|
attrs: { placeholder: "全部", clearable: true },
|
||||||
options: stateArr as any,
|
options: stateArr as any,
|
||||||
events: {
|
events: {
|
||||||
change(e) {
|
change() {},
|
||||||
console.log("选中的值: ", e);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,8 +33,8 @@
|
|||||||
@filter-change="handleFilterChange"
|
@filter-change="handleFilterChange"
|
||||||
>
|
>
|
||||||
<template #status="scope">
|
<template #status="scope">
|
||||||
<el-tag :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
|
<el-tag :type="scope.row[scope.prop] === 1 ? 'success' : 'info'">
|
||||||
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
{{ scope.row[scope.prop] === 1 ? "启用" : "禁用" }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #gender="scope">
|
<template #gender="scope">
|
||||||
@@ -91,8 +91,8 @@
|
|||||||
@operate-click="handleOperateClick2"
|
@operate-click="handleOperateClick2"
|
||||||
>
|
>
|
||||||
<template #status="scope">
|
<template #status="scope">
|
||||||
<el-tag :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
|
<el-tag :type="scope.row[scope.prop] === 1 ? 'success' : 'info'">
|
||||||
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
{{ scope.row[scope.prop] === 1 ? "启用" : "禁用" }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</page-content>
|
</page-content>
|
||||||
@@ -145,7 +145,6 @@ const {
|
|||||||
|
|
||||||
// 其他工具
|
// 其他工具
|
||||||
function handleToolbarClick(name: string) {
|
function handleToolbarClick(name: string) {
|
||||||
console.log(name);
|
|
||||||
if (name === "custom1") {
|
if (name === "custom1") {
|
||||||
ElMessage.success("点击了自定义1按钮");
|
ElMessage.success("点击了自定义1按钮");
|
||||||
}
|
}
|
||||||
@@ -203,8 +202,7 @@ const addModalRef2 = ref();
|
|||||||
const openSecondModal = () => {
|
const openSecondModal = () => {
|
||||||
handleAddClick(addModalRef2 as Ref<PageModalInstance>);
|
handleAddClick(addModalRef2 as Ref<PageModalInstance>);
|
||||||
};
|
};
|
||||||
const secondSubmit = (formData: any) => {
|
const secondSubmit = () => {
|
||||||
console.log("secondSubmit", formData);
|
|
||||||
ElMessage.success("二级弹窗提交成功");
|
ElMessage.success("二级弹窗提交成功");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ defineOptions({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
console.log(route);
|
|
||||||
|
|
||||||
const value = ref("");
|
const value = ref("");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -17,7 +17,4 @@ import MultiLevel2 from "../level2.vue";
|
|||||||
defineOptions({ name: "MultiLevel31" });
|
defineOptions({ name: "MultiLevel31" });
|
||||||
|
|
||||||
const value = ref("");
|
const value = ref("");
|
||||||
onMounted(() => {
|
|
||||||
console.log("Multilevel31 onMounted");
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -17,7 +17,4 @@ import MultiLevel2 from "../level2.vue";
|
|||||||
|
|
||||||
defineOptions({ name: "MultiLevel32" });
|
defineOptions({ name: "MultiLevel32" });
|
||||||
const value = ref("");
|
const value = ref("");
|
||||||
onMounted(() => {
|
|
||||||
console.log("Multilevel32 onMounted");
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,8 +6,4 @@
|
|||||||
defineOptions({ name: "MultiLevel2" });
|
defineOptions({ name: "MultiLevel2" });
|
||||||
|
|
||||||
const value = ref("");
|
const value = ref("");
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
console.log("MultiLevel2 mounted");
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,8 +3,4 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineOptions({ name: "MultiLevel1" });
|
defineOptions({ name: "MultiLevel1" });
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
console.log("MultiLevel1 mounted");
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ const isCanvasBlank = (canvas: HTMLCanvasElement) => {
|
|||||||
const blank = document.createElement("canvas"); //系统获取一个空canvas对象
|
const blank = document.createElement("canvas"); //系统获取一个空canvas对象
|
||||||
blank.width = canvas.width;
|
blank.width = canvas.width;
|
||||||
blank.height = canvas.height;
|
blank.height = canvas.height;
|
||||||
return canvas.toDataURL() == blank.toDataURL(); //比较值相等则为空
|
return canvas.toDataURL() === blank.toDataURL(); //比较值相等则为空
|
||||||
};
|
};
|
||||||
|
|
||||||
// 保存为图片
|
// 保存为图片
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
</el-link>
|
</el-link>
|
||||||
<table-select :text="text" :select-config="selectConfig" @confirm-click="handleConfirm">
|
<table-select :text="text" :select-config="selectConfig" @confirm-click="handleConfirm">
|
||||||
<template #status="scope">
|
<template #status="scope">
|
||||||
<el-tag :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
|
<el-tag :type="scope.row[scope.prop] === 1 ? 'success' : 'info'">
|
||||||
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
|
{{ scope.row[scope.prop] === 1 ? "启用" : "禁用" }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #gender="scope">
|
<template #gender="scope">
|
||||||
@@ -46,7 +46,9 @@ function handleConfirm(data: IUser[]) {
|
|||||||
const text = computed(() => {
|
const text = computed(() => {
|
||||||
// 获取字典数据
|
// 获取字典数据
|
||||||
const dictData = dictStore.getDictItems("gender");
|
const dictData = dictStore.getDictItems("gender");
|
||||||
const genderLabel = dictData.find((item: any) => item.value == selectedUser.value?.gender)?.label;
|
const genderLabel = dictData.find(
|
||||||
|
(item) => String(item.value) === String(selectedUser.value?.gender)
|
||||||
|
)?.label;
|
||||||
return selectedUser.value
|
return selectedUser.value
|
||||||
? `${selectedUser.value.username} - ${genderLabel} - ${selectedUser.value.deptName}`
|
? `${selectedUser.value.username} - ${genderLabel} - ${selectedUser.value.deptName}`
|
||||||
: "";
|
: "";
|
||||||
|
|||||||
@@ -348,8 +348,7 @@ const gridOptions = reactive<VxeGridProps<RowMeta>>({
|
|||||||
},
|
},
|
||||||
ajax: {
|
ajax: {
|
||||||
// 接收 Promise
|
// 接收 Promise
|
||||||
query: ({ page: { currentPage, pageSize }, form, filters, sort, sorts }) => {
|
query: ({ page: { currentPage, pageSize } }) => {
|
||||||
console.log({ currentPage, pageSize, form, filters, sort, sorts });
|
|
||||||
return new Promise<{ total: number; result: RowMeta[] }>((resolve) => {
|
return new Promise<{ total: number; result: RowMeta[] }>((resolve) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const list = [
|
const list = [
|
||||||
@@ -465,9 +464,7 @@ const gridOptions = reactive<VxeGridProps<RowMeta>>({
|
|||||||
});
|
});
|
||||||
const gridEvents: VxeGridListeners<RowMeta> = {
|
const gridEvents: VxeGridListeners<RowMeta> = {
|
||||||
// 只对 form-config 配置时有效,表单重置时会触发该事件
|
// 只对 form-config 配置时有效,表单重置时会触发该事件
|
||||||
formReset() {
|
formReset() {},
|
||||||
console.log("Form Reset");
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
@@ -593,7 +590,10 @@ const curd = {
|
|||||||
},
|
},
|
||||||
/** 确定并保存 */
|
/** 确定并保存 */
|
||||||
onSubmitForm: () => {
|
onSubmitForm: () => {
|
||||||
console.log("提交表单");
|
VXETable.modal.message({
|
||||||
|
content: "提交成功",
|
||||||
|
status: "success",
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onDelete: (row?: RowMeta) => {
|
onDelete: (row?: RowMeta) => {
|
||||||
let ids = [];
|
let ids = [];
|
||||||
@@ -614,7 +614,10 @@ const curd = {
|
|||||||
VXETable.modal.confirm("确定要删除吗?").then((type) => {
|
VXETable.modal.confirm("确定要删除吗?").then((type) => {
|
||||||
if (type === "confirm") {
|
if (type === "confirm") {
|
||||||
// 执行删除操作
|
// 执行删除操作
|
||||||
console.log("删除的ID", ids);
|
VXETable.modal.message({
|
||||||
|
content: `已删除 ${ids.length} 条数据`,
|
||||||
|
status: "success",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -186,7 +186,7 @@
|
|||||||
|
|
||||||
<footer class="login-card__footer">
|
<footer class="login-card__footer">
|
||||||
<el-text size="small">
|
<el-text size="small">
|
||||||
Copyright © 2021 - 2025 youlai.tech
|
Copyright © 2021 - 2026 youlai.tech
|
||||||
<a href="http://beian.miit.gov.cn/" target="_blank">皖ICP备00064962号</a>
|
<a href="http://beian.miit.gov.cn/" target="_blank">皖ICP备00064962号</a>
|
||||||
</el-text>
|
</el-text>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
<el-table-column align="center" label="发布人" prop="publisherName" width="150" />
|
<el-table-column align="center" label="发布人" prop="publisherName" width="150" />
|
||||||
<el-table-column align="center" label="状态" width="100">
|
<el-table-column align="center" label="状态" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag v-if="scope.row.isRead == 1" type="success">已读</el-tag>
|
<el-tag v-if="scope.row.isRead === 1" type="success">已读</el-tag>
|
||||||
<el-tag v-else type="info">未读</el-tag>
|
<el-tag v-else type="info">未读</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
<el-table-column prop="code" label="部门编号" width="200" />
|
<el-table-column prop="code" label="部门编号" width="200" />
|
||||||
<el-table-column prop="status" label="状态" width="100">
|
<el-table-column prop="status" label="状态" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag v-if="scope.row.status == 1" type="success">正常</el-tag>
|
<el-tag v-if="scope.row.status === 1" type="success">正常</el-tag>
|
||||||
<el-tag v-else type="info">禁用</el-tag>
|
<el-tag v-else type="info">禁用</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
<el-table-column fixed="right" align="center" label="操作" width="220">
|
<el-table-column fixed="right" align="center" label="操作" width="220">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button
|
<el-button
|
||||||
v-if="scope.row.type == MenuTypeEnum.CATALOG || scope.row.type == MenuTypeEnum.MENU"
|
v-if="scope.row.type === MenuTypeEnum.CATALOG || scope.row.type === MenuTypeEnum.MENU"
|
||||||
v-hasPerm="['sys:menu:create']"
|
v-hasPerm="['sys:menu:create']"
|
||||||
type="primary"
|
type="primary"
|
||||||
link
|
link
|
||||||
@@ -155,7 +155,10 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item v-if="formData.type == MenuTypeEnum.MENU && !isExternalLink" prop="routeName">
|
<el-form-item
|
||||||
|
v-if="formData.type === MenuTypeEnum.MENU && !isExternalLink"
|
||||||
|
prop="routeName"
|
||||||
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<div class="flex-y-center">
|
<div class="flex-y-center">
|
||||||
路由名称
|
路由名称
|
||||||
@@ -173,7 +176,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="formData.type == MenuTypeEnum.CATALOG || formData.type == MenuTypeEnum.MENU"
|
v-if="formData.type === MenuTypeEnum.CATALOG || formData.type === MenuTypeEnum.MENU"
|
||||||
prop="routePath"
|
prop="routePath"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
@@ -191,14 +194,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-input
|
<el-input
|
||||||
v-if="formData.type == MenuTypeEnum.CATALOG"
|
v-if="formData.type === MenuTypeEnum.CATALOG"
|
||||||
v-model="formData.routePath"
|
v-model="formData.routePath"
|
||||||
placeholder="system"
|
placeholder="system"
|
||||||
/>
|
/>
|
||||||
<el-input v-else v-model="formData.routePath" placeholder="user 或 https://example.com" />
|
<el-input v-else v-model="formData.routePath" placeholder="user 或 https://example.com" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item v-if="formData.type == MenuTypeEnum.MENU && !isExternalLink" prop="component">
|
<el-form-item
|
||||||
|
v-if="formData.type === MenuTypeEnum.MENU && !isExternalLink"
|
||||||
|
prop="component"
|
||||||
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<div class="flex-y-center">
|
<div class="flex-y-center">
|
||||||
组件路径
|
组件路径
|
||||||
@@ -214,12 +220,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-input v-model="formData.component" placeholder="system/user/index" style="width: 95%">
|
<el-input v-model="formData.component" placeholder="system/user/index" style="width: 95%">
|
||||||
<template v-if="formData.type == MenuTypeEnum.MENU" #prepend>src/views/</template>
|
<template v-if="formData.type === MenuTypeEnum.MENU" #prepend>src/views/</template>
|
||||||
<template v-if="formData.type == MenuTypeEnum.MENU" #append>.vue</template>
|
<template v-if="formData.type === MenuTypeEnum.MENU" #append>.vue</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item v-if="formData.type == MenuTypeEnum.MENU && !isExternalLink">
|
<el-form-item v-if="formData.type === MenuTypeEnum.MENU && !isExternalLink">
|
||||||
<template #label>
|
<template #label>
|
||||||
<div class="flex-y-center">
|
<div class="flex-y-center">
|
||||||
路由参数
|
路由参数
|
||||||
@@ -332,7 +338,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- 权限标识 -->
|
<!-- 权限标识 -->
|
||||||
<el-form-item v-if="formData.type == MenuTypeEnum.BUTTON" label="权限标识" prop="perm">
|
<el-form-item v-if="formData.type === MenuTypeEnum.BUTTON" label="权限标识" prop="perm">
|
||||||
<el-input v-model="formData.perm" placeholder="sys:user:create" />
|
<el-input v-model="formData.perm" placeholder="sys:user:create" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@@ -341,7 +347,7 @@
|
|||||||
<icon-select v-model="formData.icon" />
|
<icon-select v-model="formData.icon" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item v-if="formData.type == MenuTypeEnum.CATALOG" label="跳转路由">
|
<el-form-item v-if="formData.type === MenuTypeEnum.CATALOG" label="跳转路由">
|
||||||
<el-input v-model="formData.redirect" placeholder="跳转路由" />
|
<el-input v-model="formData.redirect" placeholder="跳转路由" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -529,7 +535,7 @@ function handleSubmit(): void {
|
|||||||
if (isValid) {
|
if (isValid) {
|
||||||
const menuId = formData.value.id;
|
const menuId = formData.value.id;
|
||||||
if (menuId) {
|
if (menuId) {
|
||||||
if (formData.value.parentId == menuId) {
|
if (formData.value.parentId === menuId) {
|
||||||
ElMessage.error("父级菜单不能为当前菜单");
|
ElMessage.error("父级菜单不能为当前菜单");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,15 +77,15 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="center" label="通告目标类型" prop="targetType" min-width="100">
|
<el-table-column align="center" label="通告目标类型" prop="targetType" min-width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag v-if="scope.row.targetType == 1" type="warning">全体</el-tag>
|
<el-tag v-if="scope.row.targetType === 1" type="warning">全体</el-tag>
|
||||||
<el-tag v-if="scope.row.targetType == 2" type="success">指定</el-tag>
|
<el-tag v-if="scope.row.targetType === 2" type="success">指定</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="center" label="发布状态" min-width="100">
|
<el-table-column align="center" label="发布状态" min-width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag v-if="scope.row.publishStatus == 0" type="info">未发布</el-tag>
|
<el-tag v-if="scope.row.publishStatus === 0" type="info">未发布</el-tag>
|
||||||
<el-tag v-if="scope.row.publishStatus == 1" type="success">已发布</el-tag>
|
<el-tag v-if="scope.row.publishStatus === 1" type="success">已发布</el-tag>
|
||||||
<el-tag v-if="scope.row.publishStatus == -1" type="warning">已撤回</el-tag>
|
<el-tag v-if="scope.row.publishStatus === -1" type="warning">已撤回</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作时间" width="250">
|
<el-table-column label="操作时间" width="250">
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
查看
|
查看
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="scope.row.publishStatus != 1"
|
v-if="scope.row.publishStatus !== 1"
|
||||||
v-hasPerm="['sys:notice:publish']"
|
v-hasPerm="['sys:notice:publish']"
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
发布
|
发布
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="scope.row.publishStatus == 1"
|
v-if="scope.row.publishStatus === 1"
|
||||||
v-hasPerm="['sys:notice:revoke']"
|
v-hasPerm="['sys:notice:revoke']"
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -131,7 +131,7 @@
|
|||||||
撤回
|
撤回
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="scope.row.publishStatus != 1"
|
v-if="scope.row.publishStatus !== 1"
|
||||||
v-hasPerm="['sys:notice:update']"
|
v-hasPerm="['sys:notice:update']"
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -141,7 +141,7 @@
|
|||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="scope.row.publishStatus != 1"
|
v-if="scope.row.publishStatus !== 1"
|
||||||
v-hasPerm="['sys:notice:delete']"
|
v-hasPerm="['sys:notice:delete']"
|
||||||
type="danger"
|
type="danger"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -207,7 +207,7 @@
|
|||||||
<el-radio :value="2">指定</el-radio>
|
<el-radio :value="2">指定</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-if="formData.targetType == 2" label="指定用户" prop="targetUsers">
|
<el-form-item v-if="formData.targetType === 2" label="指定用户" prop="targetUsers">
|
||||||
<el-select v-model="formData.targetUsers" multiple search placeholder="请选择指定用户">
|
<el-select v-model="formData.targetUsers" multiple search placeholder="请选择指定用户">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in userOptions"
|
v-for="item in userOptions"
|
||||||
@@ -252,9 +252,9 @@
|
|||||||
{{ currentNotice.title }}
|
{{ currentNotice.title }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="发布状态:">
|
<el-descriptions-item label="发布状态:">
|
||||||
<el-tag v-if="currentNotice.publishStatus == 0" type="info">未发布</el-tag>
|
<el-tag v-if="currentNotice.publishStatus === 0" type="info">未发布</el-tag>
|
||||||
<el-tag v-else-if="currentNotice.publishStatus == 1" type="success">已发布</el-tag>
|
<el-tag v-else-if="currentNotice.publishStatus === 1" type="success">已发布</el-tag>
|
||||||
<el-tag v-else-if="currentNotice.publishStatus == -1" type="warning">已撤回</el-tag>
|
<el-tag v-else-if="currentNotice.publishStatus === -1" type="warning">已撤回</el-tag>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="发布人:">
|
<el-descriptions-item label="发布人:">
|
||||||
{{ currentNotice.publisherName }}
|
{{ currentNotice.publisherName }}
|
||||||
|
|||||||
Reference in New Issue
Block a user