refactor: 更新API接口与数据结构,统一分页返回格式

This commit is contained in:
Ray.Hao
2026-01-09 00:07:25 +08:00
parent 4a8efc770e
commit a5885d0710
64 changed files with 1085 additions and 910 deletions

View File

@@ -47,55 +47,57 @@ export default defineMock([
return {
code: "00000",
data: {
list: [
{
id: "10001",
userId: 1,
username: "admin",
originalCommand: "跳转到用户管理",
aiProvider: "qwen",
aiModel: "qwen-plus",
parseStatus: 1,
functionCalls: JSON.stringify(
[
{
name: "navigate",
arguments: { path: "/system/user" },
},
],
null,
0
),
explanation: "Mock: 识别到跳转用户管理",
confidence: 0.92,
parseDurationMs: 128,
functionName: "navigate",
functionArguments: JSON.stringify({ path: "/system/user" }),
executeStatus: 1,
ipAddress: "127.0.0.1",
createTime: "2025-12-17 15:00:00",
updateTime: "2025-12-17 15:00:00",
},
{
id: "10002",
userId: 1,
username: "admin",
originalCommand: "获取姓名为张三的用户信息",
aiProvider: "qwen",
aiModel: "qwen-plus",
parseStatus: 0,
functionCalls: "[]",
explanation: "Mock: 解析失败示例",
confidence: 0.2,
parseErrorMessage: "Mock: 无法匹配函数",
parseDurationMs: 256,
executeStatus: 0,
ipAddress: "127.0.0.1",
createTime: "2025-12-17 15:01:00",
updateTime: "2025-12-17 15:01:00",
},
].slice((pageNum - 1) * pageSize, pageNum * pageSize),
data: [
{
id: "10001",
userId: 1,
username: "admin",
originalCommand: "跳转到用户管理",
aiProvider: "qwen",
aiModel: "qwen-plus",
parseStatus: 1,
functionCalls: JSON.stringify(
[
{
name: "navigate",
arguments: { path: "/system/user" },
},
],
null,
0
),
explanation: "Mock: 识别到跳转用户管理",
confidence: 0.92,
parseDurationMs: 128,
functionName: "navigate",
functionArguments: JSON.stringify({ path: "/system/user" }),
executeStatus: 1,
ipAddress: "127.0.0.1",
createTime: "2025-12-17 15:00:00",
updateTime: "2025-12-17 15:00:00",
},
{
id: "10002",
userId: 1,
username: "admin",
originalCommand: "获取姓名为张三的用户信息",
aiProvider: "qwen",
aiModel: "qwen-plus",
parseStatus: 0,
functionCalls: "[]",
explanation: "Mock: 解析失败示例",
confidence: 0.2,
parseErrorMessage: "Mock: 无法匹配函数",
parseDurationMs: 256,
executeStatus: 0,
ipAddress: "127.0.0.1",
createTime: "2025-12-17 15:01:00",
updateTime: "2025-12-17 15:01:00",
},
].slice((pageNum - 1) * pageSize, pageNum * pageSize),
page: {
pageNum,
pageSize,
total,
},
msg: "一切ok",

View File

@@ -2,7 +2,7 @@ import { defineMock } from "./base";
export default defineMock([
{
url: "dept/options",
url: "depts/options",
method: ["GET"],
body: {
code: "00000",
@@ -27,7 +27,7 @@ export default defineMock([
},
{
url: "dept",
url: "depts",
method: ["GET"],
body: {
code: "00000",
@@ -73,7 +73,7 @@ export default defineMock([
// 新增部门
{
url: "dept",
url: "depts",
method: ["POST"],
body({ body }) {
return {
@@ -86,7 +86,7 @@ export default defineMock([
// 获取部门表单数据
{
url: "dept/:id/form",
url: "depts/:id/form",
method: ["GET"],
body: ({ params }) => {
return {
@@ -99,7 +99,7 @@ export default defineMock([
// 修改部门
{
url: "dept/:id",
url: "depts/:id",
method: ["PUT"],
body({ body }) {
return {
@@ -112,7 +112,7 @@ export default defineMock([
// 删除部门
{
url: "dept/:id",
url: "depts/:id",
method: ["DELETE"],
body({ params }) {
return {

View File

@@ -2,19 +2,21 @@ import { defineMock } from "./base";
export default defineMock([
{
url: "dicts/page",
url: "dicts",
method: ["GET"],
body: {
code: "00000",
data: {
list: [
{
id: 1,
name: "性别",
dictCode: "gender",
status: 1,
},
],
data: [
{
id: 1,
name: "性别",
dictCode: "gender",
status: 1,
},
],
page: {
pageNum: 1,
pageSize: 10,
total: 1,
},
msg: "一切ok",
@@ -25,19 +27,16 @@ export default defineMock([
* 字典列表
*/
{
url: "dicts",
url: "dicts/options",
method: ["GET"],
body: {
code: "00000",
data: {
list: [
{
value: "gender",
label: "性别",
},
],
total: 1,
},
data: [
{
value: "gender",
label: "性别",
},
],
msg: "一切ok",
},
},
@@ -100,37 +99,42 @@ export default defineMock([
// 字典项分页列表
{
url: "dicts/:dictCode/items/page",
url: "dicts/:dictCode/items",
method: ["GET"],
body: {
code: "00000",
data: {
list: [
{
id: 1,
dictCode: "gender",
label: "",
value: "1",
sort: 1,
status: 1,
},
{
id: 2,
dictCode: "gender",
label: "女",
value: "2",
sort: 2,
status: 1,
},
{
id: 3,
dictCode: "gender",
label: "保密",
value: "0",
sort: 3,
status: 1,
},
],
data: [
{
id: 1,
dictCode: "gender",
label: "",
value: "1",
sort: 1,
status: 1,
tagType: "P",
},
{
id: 2,
dictCode: "gender",
label: "女",
value: "2",
sort: 2,
status: 1,
tagType: "D",
},
{
id: 3,
dictCode: "gender",
label: "保密",
value: "0",
sort: 3,
status: 1,
tagType: "I",
},
],
page: {
pageNum: 1,
pageSize: 10,
total: 3,
},
msg: "一切ok",
@@ -138,7 +142,7 @@ export default defineMock([
},
// 字典项列表
{
url: "dicts/:dictCode/items",
url: "dicts/:dictCode/items/options",
method: ["GET"],
body: ({ params }) => {
const dictCode = params.dictCode;
@@ -165,17 +169,17 @@ export default defineMock([
{
value: "L",
label: "低",
tag: "info",
tagType: "I",
},
{
value: "M",
label: "中",
tag: "warning",
tagType: "W",
},
{
value: "H",
label: "高",
tag: "danger",
tagType: "D",
},
];
} else if (dictCode == "notice_type") {
@@ -183,32 +187,32 @@ export default defineMock([
{
value: "1",
label: "系统升级",
tag: "success",
tagType: "S",
},
{
value: "2",
label: "系统维护",
tag: "primary",
tagType: "P",
},
{
value: "3",
label: "安全警告",
tag: "danger",
tagType: "D",
},
{
value: "4",
label: "假期通知",
tag: "success",
tagType: "S",
},
{
value: "5",
label: "公司新闻",
tag: "primary",
tagType: "P",
},
{
value: "99",
label: "其他",
tag: "info",
tagType: "I",
},
];
}
@@ -228,7 +232,7 @@ export default defineMock([
return {
code: "00000",
data: null,
msg: "新增字典" + body.name + "成功",
msg: "新增字典" + body.label + "成功",
};
},
},
@@ -254,7 +258,7 @@ export default defineMock([
return {
code: "00000",
data: null,
msg: "修改字典项" + body.name + "成功",
msg: "修改字典项" + body.label + "成功",
};
},
},
@@ -291,7 +295,7 @@ const dictItemMap: Record<string, any> = {
label: "男",
sort: 1,
status: 1,
tagType: "primary",
tagType: "P",
},
2: {
id: 2,
@@ -299,7 +303,7 @@ const dictItemMap: Record<string, any> = {
label: "女",
sort: 2,
status: 1,
tagType: "danger",
tagType: "D",
},
3: {
id: 3,
@@ -307,6 +311,6 @@ const dictItemMap: Record<string, any> = {
label: "保密",
sort: 3,
status: 1,
tagType: "info",
tagType: "I",
},
};

View File

@@ -2,163 +2,165 @@ import { defineMock } from "./base";
export default defineMock([
{
url: "logs/page",
url: "logs",
method: ["GET"],
body: {
code: "00000",
data: {
list: [
{
id: 36192,
module: "菜单",
content: "菜单列表",
requestUri: "/api/v1/menus",
method: null,
ip: "183.156.148.241",
region: "浙江省 杭州市",
browser: "Chrome 109.0.0.0",
os: "OSX",
executionTime: 5,
createBy: null,
createTime: "2024-07-07 20:38:47",
operator: "系统管理员",
},
{
id: 36190,
module: "字典",
content: "字典分页列表",
requestUri: "/api/v1/dict/page",
method: null,
ip: "183.156.148.241",
region: "浙江省 杭州市",
browser: "Chrome 109.0.0.0",
os: "OSX",
executionTime: 9,
createBy: null,
createTime: "2024-07-07 20:38:45",
operator: "系统管理员",
},
{
id: 36193,
module: "部门",
content: "部门列表",
requestUri: "/api/v1/dept",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 27,
createBy: null,
createTime: "2024-07-07 20:38:45",
operator: "系统管理员",
},
{
id: 36191,
module: "菜单",
content: "菜单列表",
requestUri: "/api/v1/menus",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 39,
createBy: null,
createTime: "2024-07-07 20:38:44",
operator: "系统管理员",
},
{
id: 36189,
module: "角色",
content: "角色分页列表",
requestUri: "/api/v1/roles/page",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 55,
createBy: null,
createTime: "2024-07-07 20:38:43",
operator: "系统管理员",
},
{
id: 36188,
module: "用户",
content: "用户分页列表",
requestUri: "/api/v1/users/page",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 92,
createBy: null,
createTime: "2024-07-07 20:38:42",
operator: "系统管理员",
},
{
id: 36187,
module: "登录",
content: "登录",
requestUri: "/api/v1/auth/login",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 19340,
createBy: null,
createTime: "2024-07-07 20:38:09",
operator: "系统管理员",
},
{
id: 36186,
module: "登录",
content: "登录",
requestUri: "/api/v1/auth/login",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 19869,
createBy: null,
createTime: "2024-07-07 20:37:59",
operator: "系统管理员",
},
{
id: 36185,
module: "登录",
content: "登录",
requestUri: "/api/v1/auth/login",
method: null,
ip: "112.103.111.59",
region: "黑龙江省 哈尔滨市",
browser: "Chrome 97.0.4692.98",
os: "Android",
executionTime: 96,
createBy: null,
createTime: "2024-07-07 20:37:21",
operator: "系统管理员",
},
{
id: 36184,
module: "登录",
content: "登录",
requestUri: "/api/v1/auth/login",
method: null,
ip: "114.86.204.190",
region: "上海 上海市",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 89,
createBy: null,
createTime: "2024-07-07 20:29:37",
operator: "系统管理员",
},
],
data: [
{
id: 36192,
module: "菜单",
content: "菜单列表",
requestUri: "/api/v1/menus",
method: null,
ip: "183.156.148.241",
region: "浙江省 杭州市",
browser: "Chrome 109.0.0.0",
os: "OSX",
executionTime: 5,
createBy: null,
createTime: "2024-07-07 20:38:47",
operator: "系统管理员",
},
{
id: 36190,
module: "字典",
content: "字典分页列表",
requestUri: "/api/v1/dicts",
method: null,
ip: "183.156.148.241",
region: "浙江省 杭州市",
browser: "Chrome 109.0.0.0",
os: "OSX",
executionTime: 9,
createBy: null,
createTime: "2024-07-07 20:38:45",
operator: "系统管理员",
},
{
id: 36193,
module: "部门",
content: "部门列表",
requestUri: "/api/v1/depts",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 27,
createBy: null,
createTime: "2024-07-07 20:38:45",
operator: "系统管理员",
},
{
id: 36191,
module: "菜单",
content: "菜单列表",
requestUri: "/api/v1/menus",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 39,
createBy: null,
createTime: "2024-07-07 20:38:44",
operator: "系统管理员",
},
{
id: 36189,
module: "角色",
content: "角色分页列表",
requestUri: "/api/v1/roles",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 55,
createBy: null,
createTime: "2024-07-07 20:38:43",
operator: "系统管理员",
},
{
id: 36188,
module: "用户",
content: "用户分页列表",
requestUri: "/api/v1/users",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 92,
createBy: null,
createTime: "2024-07-07 20:38:42",
operator: "系统管理员",
},
{
id: 36187,
module: "登录",
content: "登录",
requestUri: "/api/v1/auth/login",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 19340,
createBy: null,
createTime: "2024-07-07 20:38:09",
operator: "系统管理员",
},
{
id: 36186,
module: "登录",
content: "登录",
requestUri: "/api/v1/auth/login",
method: null,
ip: "192.168.31.134",
region: "0 内网IP",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 19869,
createBy: null,
createTime: "2024-07-07 20:37:59",
operator: "系统管理员",
},
{
id: 36185,
module: "登录",
content: "登录",
requestUri: "/api/v1/auth/login",
method: null,
ip: "112.103.111.59",
region: "黑龙江省 哈尔滨市",
browser: "Chrome 97.0.4692.98",
os: "Android",
executionTime: 96,
createBy: null,
createTime: "2024-07-07 20:37:21",
operator: "系统管理员",
},
{
id: 36184,
module: "登录",
content: "登录",
requestUri: "/api/v1/auth/login",
method: null,
ip: "114.86.204.190",
region: "上海 上海市",
browser: "Chrome 125.0.0.0",
os: "Windows 10 or Windows Server 2016",
executionTime: 89,
createBy: null,
createTime: "2024-07-07 20:29:37",
operator: "系统管理员",
},
],
page: {
pageNum: 1,
pageSize: 10,
total: 36188,
},
msg: "一切ok",

View File

@@ -2,143 +2,145 @@ import { defineMock } from "./base";
export default defineMock([
{
url: "notices/page",
url: "notices",
method: ["GET"],
body: {
code: "00000",
data: {
list: [
{
id: 1,
title: "v2.12.0 新增系统日志,访问趋势统计功能。",
publishStatus: 1,
type: 1,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:21",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 2,
title: "v2.13.0 新增菜单搜索。",
publishStatus: 1,
type: 1,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:22",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 3,
title: "\r\nv2.14.0 新增个人中心。",
publishStatus: 1,
type: 1,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:23",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 4,
title: "v2.15.0 登录页面改造。",
publishStatus: 1,
type: 1,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:24",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 5,
title: "v2.16.0 通知公告、字典翻译组件。",
publishStatus: 1,
type: 1,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:25",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 6,
title: "系统将于本周六凌晨 2 点进行维护,预计维护时间为 2 小时。",
publishStatus: 1,
type: 2,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:26",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 7,
title: "最近发现一些钓鱼邮件,请大家提高警惕,不要点击陌生链接。",
publishStatus: 1,
type: 3,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:27",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 8,
title: "国庆假期从 10 月 1 日至 10 月 7 日放假,共 7 天。",
publishStatus: 1,
type: 4,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:28",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 9,
title: "公司将在 10 月 15 日举办新产品发布会,敬请期待。",
publishStatus: 1,
type: 5,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:29",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 10,
title: "v2.16.1 版本修复了 WebSocket 重复连接导致的后台线程阻塞问题,优化了通知公告。",
publishStatus: 1,
type: 1,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:30",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
],
data: [
{
id: 1,
title: "v2.12.0 新增系统日志,访问趋势统计功能。",
publishStatus: 1,
type: 1,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:21",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 2,
title: "v2.13.0 新增菜单搜索。",
publishStatus: 1,
type: 1,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:22",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 3,
title: "\r\nv2.14.0 新增个人中心。",
publishStatus: 1,
type: 1,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:23",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 4,
title: "v2.15.0 登录页面改造。",
publishStatus: 1,
type: 1,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:24",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 5,
title: "v2.16.0 通知公告、字典翻译组件。",
publishStatus: 1,
type: 1,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:25",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 6,
title: "系统将于本周六凌晨 2 点进行维护,预计维护时间为 2 小时。",
publishStatus: 1,
type: 2,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:26",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 7,
title: "最近发现一些钓鱼邮件,请大家提高警惕,不要点击陌生链接。",
publishStatus: 1,
type: 3,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:27",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 8,
title: "国庆假期从 10 月 1 日至 10 月 7 日放假,共 7 天。",
publishStatus: 1,
type: 4,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:28",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 9,
title: "公司将在 10 月 15 日举办新产品发布会,敬请期待。",
publishStatus: 1,
type: 5,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:29",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
{
id: 10,
title: "v2.16.1 版本修复了 WebSocket 重复连接导致的后台线程阻塞问题,优化了通知公告。",
publishStatus: 1,
type: 1,
publisherName: "系统管理员",
level: "L",
publishTime: "2024-09-30 17:30",
isRead: null,
targetType: 1,
createTime: "2024-09-28 11:21",
revokeTime: "2024-09-30 17:21",
},
],
page: {
pageNum: 1,
pageSize: 10,
total: 10,
},
msg: "一切ok",
@@ -185,20 +187,20 @@ export default defineMock([
},
// 修改通知
{
url: "roles/:id",
url: "notices/:id",
method: ["PUT"],
body({ body }) {
return {
code: "00000",
data: null,
msg: "修改通知" + body.name + "成功",
msg: "修改通知" + body.title + "成功",
};
},
},
// 删除通知
{
url: "roles/:id",
url: "notices/:id",
method: ["DELETE"],
body({ params }) {
return {
@@ -215,54 +217,56 @@ export default defineMock([
method: ["GET"],
body: {
code: "00000",
data: {
list: [
{
id: 10,
title: "v2.16.1 版本修复了 WebSocket 重复连接导致的后台线程阻塞问题,优化了通知公告。",
type: 1,
level: "L",
publisherName: "系统管理员",
publishTime: "2024-09-30 17:30",
isRead: 0,
},
{
id: 9,
title: "公司将在 10 月 15 日举办新产品发布会,敬请期待。",
type: 5,
level: "L",
publisherName: "系统管理员",
publishTime: "2024-09-30 17:29",
isRead: 0,
},
{
id: 8,
title: "国庆假期从 10 月 1 日至 10 月 7 日放假,共 7 天。",
type: 4,
level: "L",
publisherName: "系统管理员",
publishTime: "2024-09-30 17:28",
isRead: 0,
},
{
id: 7,
title: "最近发现一些钓鱼邮件,请大家提高警惕,不要点击陌生链接。",
type: 3,
level: "L",
publisherName: "系统管理员",
publishTime: "2024-09-30 17:27",
isRead: 0,
},
{
id: 6,
title: "系统将于本周六凌晨 2 点进行维护,预计维护时间为 2 小时。",
type: 2,
level: "L",
publisherName: "系统管理员",
publishTime: "2024-09-30 17:26",
isRead: 0,
},
],
data: [
{
id: 10,
title: "v2.16.1 版本修复了 WebSocket 重复连接导致的后台线程阻塞问题,优化了通知公告。",
type: 1,
level: "L",
publisherName: "系统管理员",
publishTime: "2024-09-30 17:30",
isRead: 0,
},
{
id: 9,
title: "公司将在 10 月 15 日举办新产品发布会,敬请期待。",
type: 5,
level: "L",
publisherName: "系统管理员",
publishTime: "2024-09-30 17:29",
isRead: 0,
},
{
id: 8,
title: "国庆假期从 10 月 1 日至 10 月 7 日放假,共 7 天。",
type: 4,
level: "L",
publisherName: "系统管理员",
publishTime: "2024-09-30 17:28",
isRead: 0,
},
{
id: 7,
title: "最近发现一些钓鱼邮件,请大家提高警惕,不要点击陌生链接。",
type: 3,
level: "L",
publisherName: "系统管理员",
publishTime: "2024-09-30 17:27",
isRead: 0,
},
{
id: 6,
title: "系统将于本周六凌晨 2 点进行维护,预计维护时间为 2 小时。",
type: 2,
level: "L",
publisherName: "系统管理员",
publishTime: "2024-09-30 17:26",
isRead: 0,
},
],
page: {
pageNum: 1,
pageSize: 10,
total: 10,
},
msg: "一切ok",

View File

@@ -57,103 +57,105 @@ export default defineMock([
},
{
url: "roles/page",
url: "roles",
method: ["GET"],
body: {
code: "00000",
data: {
list: [
{
id: 2,
name: "系统管理员",
code: "ADMIN",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 3,
name: "访问游客",
code: "GUEST",
status: 1,
sort: 3,
createTime: "2021-05-26 15:49:05",
updateTime: "2019-05-05 16:00:00",
},
{
id: 4,
name: "系统管理员1",
code: "ADMIN1",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 5,
name: "系统管理员2",
code: "ADMIN2",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 6,
name: "系统管理员3",
code: "ADMIN3",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 7,
name: "系统管理员4",
code: "ADMIN4",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 8,
name: "系统管理员5",
code: "ADMIN5",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 9,
name: "系统管理员6",
code: "ADMIN6",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: "2023-12-04 11:43:15",
},
{
id: 10,
name: "系统管理员7",
code: "ADMIN7",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 11,
name: "系统管理员8",
code: "ADMIN8",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
],
data: [
{
id: 2,
name: "系统管理员",
code: "ADMIN",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 3,
name: "访问游客",
code: "GUEST",
status: 1,
sort: 3,
createTime: "2021-05-26 15:49:05",
updateTime: "2019-05-05 16:00:00",
},
{
id: 4,
name: "系统管理员1",
code: "ADMIN1",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 5,
name: "系统管理员2",
code: "ADMIN2",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 6,
name: "系统管理员3",
code: "ADMIN3",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 7,
name: "系统管理员4",
code: "ADMIN4",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 8,
name: "系统管理员5",
code: "ADMIN5",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 9,
name: "系统管理员6",
code: "ADMIN6",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: "2023-12-04 11:43:15",
},
{
id: 10,
name: "系统管理员7",
code: "ADMIN7",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
{
id: 11,
name: "系统管理员8",
code: "ADMIN8",
status: 1,
sort: 2,
createTime: "2021-03-25 12:39:54",
updateTime: null,
},
],
page: {
pageNum: 1,
pageSize: 10,
total: 10,
},
msg: "一切ok",
@@ -214,7 +216,7 @@ export default defineMock([
{
url: "roles/:id/menuIds",
method: ["GET"],
body: ({}) => {
body: () => {
return {
code: "00000",
data: [

View File

@@ -66,37 +66,39 @@ export default defineMock([
},
{
url: "users/page",
url: "users",
method: ["GET"],
body: {
code: "00000",
data: {
list: [
{
id: 2,
username: "admin",
nickname: "系统管理员",
mobile: "17621210366",
gender: 1,
avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
email: "",
status: 1,
deptId: 1,
roleIds: [2],
},
{
id: 3,
username: "test",
nickname: "测试小用户",
mobile: "17621210366",
gender: 1,
avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
email: "youlaitech@163.com",
status: 1,
deptId: 3,
roleIds: [3],
},
],
data: [
{
id: 2,
username: "admin",
nickname: "系统管理员",
mobile: "17621210366",
gender: 1,
avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
email: "",
status: 1,
deptId: 1,
roleIds: [2],
},
{
id: 3,
username: "test",
nickname: "测试小用户",
mobile: "17621210366",
gender: 1,
avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
email: "youlaitech@163.com",
status: 1,
deptId: 3,
roleIds: [3],
},
],
page: {
pageNum: 1,
pageSize: 10,
total: 2,
},
msg: "一切ok",
@@ -149,7 +151,7 @@ export default defineMock([
return {
code: "00000",
data: null,
msg: "删除用户" + params.id + "成功",
msg: "删除用户" + params.userId + "成功",
};
},
},

View File

@@ -4,8 +4,8 @@ import type {
AiCommandResponse,
AiExecuteRequest,
AiExecuteResponse,
AiCommandRecordPageQuery,
AiCommandRecordVo,
AiAssistantRecordQueryParams,
AiAssistantRecordItem,
} from "@/types/api";
const AI_BASE_URL = "/api/v1/ai/assistant";
@@ -48,8 +48,8 @@ const AiCommandApi = {
* @param queryParams 查询参数
* @returns AI 命令记录分页列表
*/
getPage(queryParams: AiCommandRecordPageQuery) {
return request<any, PageResult<AiCommandRecordVo[]>>({
getPage(queryParams: AiAssistantRecordQueryParams) {
return request<any, PageResult<AiAssistantRecordItem>>({
url: `${AI_BASE_URL}/records`,
method: "get",
params: queryParams,

View File

@@ -1,13 +1,13 @@
import request from "@/utils/request";
import type { GeneratorPreviewVo, TablePageQuery, TablePageVo, GenConfigForm } from "@/types/api";
import type { GeneratorPreviewItem, TableQueryParams, TableItem, GenConfigForm } from "@/types/api";
const GENERATOR_BASE_URL = "/api/v1/codegen";
const GeneratorAPI = {
/** 获取数据表分页列表 */
getTablePage(params: TablePageQuery) {
return request<any, PageResult<TablePageVo[]>>({
url: `${GENERATOR_BASE_URL}/table/page`,
getTablePage(params: TableQueryParams) {
return request<any, PageResult<TableItem>>({
url: `${GENERATOR_BASE_URL}/table`,
method: "get",
params,
});
@@ -32,7 +32,7 @@ const GeneratorAPI = {
/** 获取代码生成预览数据 */
getPreviewData(tableName: string, pageType?: "classic" | "curd") {
return request<any, GeneratorPreviewVo[]>({
return request<any, GeneratorPreviewItem[]>({
url: `${GENERATOR_BASE_URL}/${tableName}/preview`,
method: "get",
params: pageType ? { pageType } : undefined,

View File

@@ -1,13 +1,13 @@
import request from "@/utils/request";
import type { ConfigPageQuery, ConfigForm, ConfigPageVo } from "@/types/api";
import type { ConfigQueryParams, ConfigForm, ConfigItem } from "@/types/api";
const CONFIG_BASE_URL = "/api/v1/configs";
const ConfigAPI = {
/** 获取配置分页数据 */
getPage(queryParams?: ConfigPageQuery) {
return request<any, PageResult<ConfigPageVo[]>>({
url: `${CONFIG_BASE_URL}/page`,
getPage(queryParams?: ConfigQueryParams) {
return request<any, PageResult<ConfigItem>>({
url: `${CONFIG_BASE_URL}`,
method: "get",
params: queryParams,
});

View File

@@ -1,16 +1,20 @@
import request from "@/utils/request";
import type { DeptQuery, DeptVo, DeptForm } from "@/types/api";
import type { DeptQueryParams, DeptItem, DeptForm, OptionItem } from "@/types/api";
const DEPT_BASE_URL = "/api/v1/depts";
const DeptAPI = {
/** 获取部门树形列表 */
getList(queryParams?: DeptQuery) {
return request<any, DeptVo[]>({ url: `${DEPT_BASE_URL}`, method: "get", params: queryParams });
getList(queryParams?: DeptQueryParams) {
return request<any, DeptItem[]>({
url: `${DEPT_BASE_URL}`,
method: "get",
params: queryParams,
});
},
/** 获取部门下拉数据源 */
getOptions() {
return request<any, OptionType[]>({ url: `${DEPT_BASE_URL}/options`, method: "get" });
return request<any, OptionItem[]>({ url: `${DEPT_BASE_URL}/options`, method: "get" });
},
/** 获取部门表单数据 */
getFormData(id: string) {

View File

@@ -1,39 +1,86 @@
import request from "@/utils/request";
import type {
DictPageQuery,
DictPageVo,
DictForm,
DictItemPageQuery,
DictItemPageVo,
DictTypeQueryParams,
DictTypeItem,
DictTypeForm,
DictItemQueryParams,
DictItem,
DictItemForm,
DictItemOption,
OptionItem,
} from "@/types/api";
const DICT_BASE_URL = "/api/v1/dicts";
type DictTagTypeCode = "N" | "P" | "S" | "W" | "I" | "D";
const decodeDictTagType = (code?: unknown): DictItemForm["tagType"] => {
const val = String(code ?? "")
.trim()
.toUpperCase();
switch (val as DictTagTypeCode) {
case "P":
return "primary";
case "S":
return "success";
case "W":
return "warning";
case "I":
return "info";
case "D":
return "danger";
case "N":
default:
return "";
}
};
const encodeDictTagType = (tagType?: unknown): DictTagTypeCode => {
const val = String(tagType ?? "")
.trim()
.toLowerCase();
switch (val) {
case "primary":
return "P";
case "success":
return "S";
case "warning":
return "W";
case "info":
return "I";
case "danger":
case "error":
return "D";
case "default":
case "":
default:
return "N";
}
};
const DictAPI = {
/** 字典分页列表 */
getPage(queryParams: DictPageQuery) {
return request<any, PageResult<DictPageVo[]>>({
url: `${DICT_BASE_URL}/page`,
getPage(queryParams: DictTypeQueryParams) {
return request<any, PageResult<DictTypeItem>>({
url: `${DICT_BASE_URL}`,
method: "get",
params: queryParams,
});
},
/** 字典列表 */
getList() {
return request<any, OptionType[]>({ url: `${DICT_BASE_URL}`, method: "get" });
return request<any, OptionItem[]>({ url: `${DICT_BASE_URL}/options`, method: "get" });
},
/** 字典表单数据 */
getFormData(id: string) {
return request<any, DictForm>({ url: `${DICT_BASE_URL}/${id}/form`, method: "get" });
return request<any, DictTypeForm>({ url: `${DICT_BASE_URL}/${id}/form`, method: "get" });
},
/** 新增字典 */
create(data: DictForm) {
create(data: DictTypeForm) {
return request({ url: `${DICT_BASE_URL}`, method: "post", data });
},
/** 修改字典 */
update(id: string, data: DictForm) {
update(id: string, data: DictTypeForm) {
return request({ url: `${DICT_BASE_URL}/${id}`, method: "put", data });
},
/** 删除字典 */
@@ -42,34 +89,62 @@ const DictAPI = {
},
/** 获取字典项分页列表 */
getDictItemPage(dictCode: string, queryParams: DictItemPageQuery) {
return request<any, PageResult<DictItemPageVo[]>>({
url: `${DICT_BASE_URL}/${dictCode}/items/page`,
getDictItemPage(dictCode: string, queryParams: DictItemQueryParams) {
return request<any, PageResult<DictItem>>({
url: `${DICT_BASE_URL}/${dictCode}/items`,
method: "get",
params: queryParams,
});
}).then((res) => ({
...res,
data: (res.data ?? []).map((item) => ({
...item,
tagType: decodeDictTagType((item as any).tagType),
})),
}));
},
/** 获取字典项列表 */
getDictItems(dictCode: string) {
return request<any, DictItemOption[]>({
url: `${DICT_BASE_URL}/${dictCode}/items`,
url: `${DICT_BASE_URL}/${dictCode}/items/options`,
method: "get",
});
}).then((items) =>
(items ?? []).map((item) => ({
...item,
tagType: decodeDictTagType((item as any).tagType),
}))
);
},
/** 新增字典项 */
createDictItem(dictCode: string, data: DictItemForm) {
return request({ url: `${DICT_BASE_URL}/${dictCode}/items`, method: "post", data });
return request({
url: `${DICT_BASE_URL}/${dictCode}/items`,
method: "post",
data: {
...data,
tagType: encodeDictTagType((data as any).tagType),
},
});
},
/** 获取字典项表单数据 */
getDictItemFormData(dictCode: string, id: string) {
return request<any, DictItemForm>({
url: `${DICT_BASE_URL}/${dictCode}/items/${id}/form`,
method: "get",
});
}).then((form) => ({
...form,
tagType: decodeDictTagType((form as any).tagType),
}));
},
/** 修改字典项 */
updateDictItem(dictCode: string, id: string, data: DictItemForm) {
return request({ url: `${DICT_BASE_URL}/${dictCode}/items/${id}`, method: "put", data });
return request({
url: `${DICT_BASE_URL}/${dictCode}/items/${id}`,
method: "put",
data: {
...data,
tagType: encodeDictTagType((data as any).tagType),
},
});
},
/** 删除字典项 */
deleteDictItems(dictCode: string, ids: string) {

View File

@@ -1,13 +1,13 @@
import request from "@/utils/request";
import type { LogPageQuery, LogPageVo } from "@/types/api";
import type { LogQueryParams, LogItem } from "@/types/api";
const LOG_BASE_URL = "/api/v1/logs";
const LogAPI = {
/** 获取日志分页列表 */
getPage(queryParams: LogPageQuery) {
return request<any, PageResult<LogPageVo[]>>({
url: `${LOG_BASE_URL}/page`,
getPage(queryParams: LogQueryParams) {
return request<any, PageResult<LogItem>>({
url: `${LOG_BASE_URL}`,
method: "get",
params: queryParams,
});

View File

@@ -1,20 +1,24 @@
import request from "@/utils/request";
import type { MenuQuery, MenuVo, MenuForm, RouteVo, OptionType } from "@/types/api";
import type { MenuQueryParams, MenuItem, MenuForm, RouteItem, OptionItem } from "@/types/api";
const MENU_BASE_URL = "/api/v1/menus";
const MenuAPI = {
/** 获取当前用户的路由列表 */
getRoutes() {
return request<any, RouteVo[]>({ url: `${MENU_BASE_URL}/routes`, method: "get" });
return request<any, RouteItem[]>({ url: `${MENU_BASE_URL}/routes`, method: "get" });
},
/** 获取菜单树形列表 */
getList(queryParams: MenuQuery) {
return request<any, MenuVo[]>({ url: `${MENU_BASE_URL}`, method: "get", params: queryParams });
getList(queryParams: MenuQueryParams) {
return request<any, MenuItem[]>({
url: `${MENU_BASE_URL}`,
method: "get",
params: queryParams,
});
},
/** 获取菜单下拉数据源 */
getOptions(onlyParent?: boolean) {
return request<any, OptionType[]>({
return request<any, OptionItem[]>({
url: `${MENU_BASE_URL}/options`,
method: "get",
params: { onlyParent },

View File

@@ -1,13 +1,13 @@
import request from "@/utils/request";
import type { NoticePageQuery, NoticeForm, NoticePageVo, NoticeDetailVo } from "@/types/api";
import type { NoticeQueryParams, NoticeForm, NoticeItem, NoticeDetail } from "@/types/api";
const NOTICE_BASE_URL = "/api/v1/notices";
const NoticeAPI = {
/** 获取通知公告分页数据 */
getPage(queryParams?: NoticePageQuery) {
return request<any, PageResult<NoticePageVo[]>>({
url: `${NOTICE_BASE_URL}/page`,
getPage(queryParams?: NoticeQueryParams) {
return request<any, PageResult<NoticeItem>>({
url: `${NOTICE_BASE_URL}`,
method: "get",
params: queryParams,
});
@@ -38,15 +38,15 @@ const NoticeAPI = {
},
/** 查看通知 */
getDetail(id: string) {
return request<any, NoticeDetailVo>({ url: `${NOTICE_BASE_URL}/${id}/detail`, method: "get" });
return request<any, NoticeDetail>({ url: `${NOTICE_BASE_URL}/${id}/detail`, method: "get" });
},
/** 全部已读 */
readAll() {
return request({ url: `${NOTICE_BASE_URL}/read-all`, method: "put" });
},
/** 获取我的通知分页列表 */
getMyNoticePage(queryParams?: NoticePageQuery) {
return request<any, PageResult<NoticePageVo[]>>({
getMyNoticePage(queryParams?: NoticeQueryParams) {
return request<any, PageResult<NoticeItem>>({
url: `${NOTICE_BASE_URL}/my`,
method: "get",
params: queryParams,

View File

@@ -1,20 +1,20 @@
import request from "@/utils/request";
import type { RolePageQuery, RolePageVo, RoleForm } from "@/types/api";
import type { RoleQueryParams, RoleItem, RoleForm, OptionItem } from "@/types/api";
const ROLE_BASE_URL = "/api/v1/roles";
const RoleAPI = {
/** 获取角色分页数据 */
getPage(queryParams?: RolePageQuery) {
return request<any, PageResult<RolePageVo[]>>({
url: `${ROLE_BASE_URL}/page`,
getPage(queryParams?: RoleQueryParams) {
return request<any, PageResult<RoleItem>>({
url: `${ROLE_BASE_URL}`,
method: "get",
params: queryParams,
});
},
/** 获取角色下拉数据源 */
getOptions() {
return request<any, OptionType[]>({ url: `${ROLE_BASE_URL}/options`, method: "get" });
return request<any, OptionItem[]>({ url: `${ROLE_BASE_URL}/options`, method: "get" });
},
/** 获取角色的菜单ID集合 */
getRoleMenuIds(roleId: string) {

View File

@@ -1,12 +1,12 @@
import request from "@/utils/request";
import type { VisitTrendQuery, VisitTrendVo, VisitStatsVo } from "@/types/api";
import type { VisitTrendQueryParams, VisitTrendDetail, VisitStatsDetail } from "@/types/api";
const STATISTICS_BASE_URL = "/api/v1/statistics";
const StatisticsAPI = {
/** 获取访问趋势统计 */
getVisitTrend(queryParams: VisitTrendQuery) {
return request<any, VisitTrendVo>({
getVisitTrend(queryParams: VisitTrendQueryParams) {
return request<any, VisitTrendDetail>({
url: `${STATISTICS_BASE_URL}/visits/trend`,
method: "get",
params: queryParams,
@@ -14,7 +14,7 @@ const StatisticsAPI = {
},
/** 获取访问概览统计 */
getVisitOverview() {
return request<any, VisitStatsVo>({
return request<any, VisitStatsDetail>({
url: `${STATISTICS_BASE_URL}/visits/overview`,
method: "get",
});

View File

@@ -1,11 +1,11 @@
import request from "@/utils/request";
import type {
TenantCreateForm,
TenantCreateResultVo,
TenantForm,
TenantInfo,
TenantPageQuery,
TenantPageVo,
TenantCreateResult,
TenantQueryParams,
TenantItem,
} from "@/types/api";
const TENANT_BASE_URL = "/api/v1/tenants";
@@ -20,7 +20,7 @@ const TenantAPI = {
*/
getTenantList() {
return request<any, TenantInfo[]>({
url: `${TENANT_BASE_URL}`,
url: `${TENANT_BASE_URL}/options`,
method: "get",
});
},
@@ -48,9 +48,9 @@ const TenantAPI = {
},
/** 获取租户分页数据(平台租户管理) */
getPage(queryParams?: TenantPageQuery) {
return request<any, PageResult<TenantPageVo[]>>({
url: `${TENANT_BASE_URL}/page`,
getPage(queryParams?: TenantQueryParams) {
return request<any, PageResult<TenantItem>>({
url: `${TENANT_BASE_URL}`,
method: "get",
params: queryParams,
});
@@ -66,7 +66,7 @@ const TenantAPI = {
/** 新增租户并初始化默认数据 */
create(data: TenantCreateForm) {
return request<any, TenantCreateResultVo>({
return request<any, TenantCreateResult>({
url: `${TENANT_BASE_URL}`,
method: "post",
data,

View File

@@ -1,14 +1,15 @@
import request from "@/utils/request";
import type {
UserInfo,
UserPageQuery,
UserPageVo,
UserForm,
UserProfileVo,
UserQueryParams,
UserItem,
UserProfileDetail,
UserProfileForm,
PasswordChangeForm,
MobileUpdateForm,
EmailUpdateForm,
OptionItem,
} from "@/types/api";
const USER_BASE_URL = "/api/v1/users";
@@ -31,9 +32,9 @@ const UserAPI = {
*
* @param queryParams 查询参数
*/
getPage(queryParams: UserPageQuery) {
return request<any, PageResult<UserPageVo[]>>({
url: `${USER_BASE_URL}/page`,
getPage(queryParams: UserQueryParams) {
return request<any, PageResult<UserItem>>({
url: `${USER_BASE_URL}`,
method: "get",
params: queryParams,
});
@@ -119,7 +120,7 @@ const UserAPI = {
*
* @param queryParams 查询参数
*/
export(queryParams: UserPageQuery) {
export(queryParams: UserQueryParams) {
return request({
url: `${USER_BASE_URL}/export`,
method: "get",
@@ -150,7 +151,7 @@ const UserAPI = {
/** 获取个人中心用户信息 */
getProfile() {
return request<any, UserProfileVo>({
return request<any, UserProfileDetail>({
url: `${USER_BASE_URL}/profile`,
method: "get",
});
@@ -214,7 +215,7 @@ const UserAPI = {
* 获取用户下拉列表
*/
getOptions() {
return request<any, OptionType[]>({
return request<any, OptionItem[]>({
url: `${USER_BASE_URL}/options`,
method: "get",
});

View File

@@ -870,13 +870,11 @@ function fetchPageData(formData: IObject = {}, isRestart = false) {
)
.then((data) => {
if (showPagination) {
if (props.contentConfig.parseData) {
data = props.contentConfig.parseData(data);
}
pagination.total = data.total;
pageData.value = data.list;
const pageResult = Array.isArray(data) ? { data, page: null } : data;
pagination.total = pageResult.page?.total ?? 0;
pageData.value = pageResult.data ?? [];
} else {
pageData.value = data;
pageData.value = Array.isArray(data) ? data : (data.data ?? []);
}
})
.finally(() => {

View File

@@ -55,7 +55,7 @@ export interface ISearchConfig {
grid?: boolean | "left" | "right";
}
export interface IContentConfig<T = any> {
export interface IContentConfig<TQuery = any, TItem = any> {
// 权限前缀(如sys:user用于组成权限标识),不提供则不进行权限校验
permPrefix?: string;
// table组件属性
@@ -72,18 +72,13 @@ export interface IContentConfig<T = any> {
>
>;
// 列表的网络请求函数(需返回promise)
indexAction: (queryParams: T) => Promise<any>;
indexAction: (queryParams: TQuery) => Promise<PageResult<TItem> | TItem[]>;
// 默认的分页相关的请求参数
request?: {
pageName: string;
limitName: string;
};
// 数据格式解析的回调函数
parseData?: (res: any) => {
total: number;
list: IObject[];
[key: string]: any;
};
// 分页接口统一返回 PageResult { data, page }
// 修改属性的网络请求函数(需返回promise)
modifyAction?: (data: {
[key: string]: any;
@@ -93,9 +88,9 @@ export interface IContentConfig<T = any> {
// 删除的网络请求函数(需返回promise)
deleteAction?: (ids: string) => Promise<any>;
// 后端导出的网络请求函数(需返回promise)
exportAction?: (queryParams: T) => Promise<any>;
exportAction?: (queryParams: TQuery) => Promise<any>;
// 前端全量导出的网络请求函数(需返回promise)
exportsAction?: (queryParams: T) => Promise<IObject[]>;
exportsAction?: (queryParams: TQuery) => Promise<TItem[]>;
// 导入模板
importTemplate?: string | (() => Promise<any>);
// 后端导入的网络请求函数(需返回promise)

View File

@@ -2,7 +2,7 @@
* 通知中心逻辑
*/
import { ref, onMounted, onBeforeUnmount } from "vue";
import type { NoticePageVo, NoticeDetailVo, NoticePageQuery } from "@/types/api";
import type { NoticeItem, NoticeDetail, NoticeQueryParams } from "@/types/api";
import NoticeAPI from "@/api/system/notice";
import { useStomp } from "@/composables";
import router from "@/router";
@@ -13,8 +13,8 @@ export function useNotice() {
const { subscribe, unsubscribe, isConnected } = useStomp();
// 状态
const list = ref<NoticePageVo[]>([]);
const detail = ref<NoticeDetailVo | null>(null);
const list = ref<NoticeItem[]>([]);
const detail = ref<NoticeDetail | null>(null);
const dialogVisible = ref(false);
let subscribed = false;
@@ -23,15 +23,15 @@ export function useNotice() {
// 数据获取
// ============================================
async function fetchList(params?: Partial<NoticePageQuery>) {
const query: NoticePageQuery = {
async function fetchList(params?: Partial<NoticeQueryParams>) {
const query: NoticeQueryParams = {
pageNum: 1,
pageSize: PAGE_SIZE,
isRead: 0,
...params,
} as NoticePageQuery;
};
const page = await NoticeAPI.getMyNoticePage(query);
list.value = page.list || [];
list.value = page.data || [];
}
async function read(id: string) {
@@ -39,7 +39,7 @@ export function useNotice() {
dialogVisible.value = true;
// 从列表中移除已读项
const idx = list.value.findIndex((item: NoticePageVo) => item.id === id);
const idx = list.value.findIndex((item: NoticeItem) => item.id === id);
if (idx >= 0) list.value.splice(idx, 1);
}
@@ -65,14 +65,14 @@ export function useNotice() {
if (!data.id) return;
// 避免重复
if (list.value.some((item: NoticePageVo) => item.id === data.id)) return;
if (list.value.some((item: NoticeItem) => item.id === data.id)) return;
list.value.unshift({
id: data.id,
title: data.title,
type: data.type,
publishTime: data.publishTime,
} as NoticePageVo);
} as NoticeItem);
ElNotification({
title: "您收到一条新的通知消息!",

View File

@@ -261,9 +261,9 @@ function fetchPageData(isRestart = false) {
}
props.selectConfig
.indexAction(queryParams)
.then((data) => {
total.value = data.total;
pageData.value = data.list;
.then((res) => {
total.value = res.page?.total ?? 0;
pageData.value = res.data ?? [];
})
.finally(() => {
loading.value = false;

View File

@@ -8,7 +8,7 @@
/**
* 表单类型枚举
*/
export const FormTypeEnum: Record<string, OptionType> = {
export const FormTypeEnum: Record<string, OptionItem> = {
INPUT: { value: 1, label: "输入框" },
SELECT: { value: 2, label: "下拉框" },
RADIO: { value: 3, label: "单选框" },
@@ -24,7 +24,7 @@ export const FormTypeEnum: Record<string, OptionType> = {
/**
* 查询类型枚举
*/
export const QueryTypeEnum: Record<string, OptionType> = {
export const QueryTypeEnum: Record<string, OptionItem> = {
/** 等于 */
EQ: { value: 1, label: "=" },

View File

@@ -332,6 +332,8 @@ const handleCloseDrawer = () => {
.settings-drawer {
:deep(.el-drawer__body) {
position: relative;
display: flex;
flex-direction: column;
height: 100%;
padding: 0;
overflow: hidden;
@@ -340,7 +342,8 @@ const handleCloseDrawer = () => {
/* 设置内容区域 */
.settings-content {
max-height: calc(100vh - 120px);
/* let drawer body control height with flex and make this area scrollable */
flex: 1 1 auto;
padding: 20px;
overflow-y: auto;
}

View File

@@ -4,7 +4,7 @@ import { store } from "@/store";
import router from "@/router";
import MenuAPI from "@/api/system/menu";
import { RouteVo } from "@/types";
import { RouteItem } from "@/types";
const modules = import.meta.glob("../../views/**/**.vue");
const Layout = () => import("../../layouts/index.vue");
@@ -69,7 +69,7 @@ export const usePermissionStore = defineStore("permission", () => {
* 转换后端路由数据为Vue Router配置
* 处理组件路径映射和Layout层级嵌套
*/
const transformRoutes = (routes: RouteVo[], isTopLevel: boolean = true): RouteRecordRaw[] => {
const transformRoutes = (routes: RouteItem[], isTopLevel: boolean = true): RouteRecordRaw[] => {
return routes.map((route) => {
const { component, children, ...args } = route;

View File

@@ -2,6 +2,8 @@
* AI 模块类型定义
*/
import type { BaseQueryParams } from "./common";
/** AI命令请求参数 */
export interface AiCommandRequest {
/** 用户输入的自然语言命令 */
@@ -81,10 +83,12 @@ export interface AiExecuteResponse {
}
/** AI命令记录分页查询参数 */
export interface AiCommandRecordPageQuery extends PageQuery {
export interface AiAssistantRecordQueryParams extends BaseQueryParams {
/** 搜索关键字 */
keywords?: string;
/** 执行状态 */
status?: string;
/** 执行状态(0:待执行;1:成功;-1:失败) */
executeStatus?: number;
/** 解析状态 */
parseStatus?: number;
@@ -101,7 +105,7 @@ export interface AiCommandRecordPageQuery extends PageQuery {
}
/** AI命令记录视图对象 */
export interface AiCommandRecordVo {
export interface AiAssistantRecordItem {
/** 记录ID */
id: string;
/** 用户ID */

View File

@@ -2,8 +2,10 @@
* CodeGen 代码生成类型定义
*/
import type { BaseQueryParams } from "./common";
/** 代码生成预览对象 */
export interface GeneratorPreviewVo {
export interface GeneratorPreviewItem {
/** 文件生成路径 */
path: string;
/** 文件名称 */
@@ -13,13 +15,13 @@ export interface GeneratorPreviewVo {
}
/** 数据表分页查询参数 */
export interface TablePageQuery extends PageQuery {
export interface TableQueryParams extends BaseQueryParams {
/** 搜索关键字(表名) */
keywords?: string;
}
/** 数据表分页对象 */
export interface TablePageVo {
export interface TableItem {
/** 表名称 */
tableName: string;
/** 表描述 */

View File

@@ -10,32 +10,49 @@ export interface ApiResponse<T = any> {
data: T;
/** 响应消息 */
msg: string;
/** 分页信息(非列表接口通常不存在该字段) */
page?: PageMeta | null;
}
/** 分页查询参数 */
export interface PageQuery {
/** 基础查询参数 */
export interface BaseQueryParams {
/** 页码 */
pageNum: number;
/** 每页记录数 */
pageSize: number;
/** 排序字段 */
sortBy?: string;
/** 排序方式(正序:ASC反序:DESC */
order?: string;
}
/** 分页响应结构 */
export interface PageResult<T> {
/** 数据列表 */
list: T;
/** 总记录数 */
/** 分页元信息 */
export interface PageMeta {
pageNum: number;
pageSize: number;
total: number;
}
/** 列表响应结构(统一) */
export interface PageResult<T> {
/** 数据列表 */
data: T[];
/** 分页信息,不分页时为 null */
page: PageMeta | null;
}
/** 下拉选项 */
export interface OptionType {
export interface OptionItem {
/** 选项值 */
value: string | number;
/** 选项标签 */
label: string;
/** 子选项 */
children?: OptionType[];
children?: OptionItem[];
}
/** Excel 导入结果 */

View File

@@ -2,8 +2,10 @@
* Config 配置类型定义
*/
import type { BaseQueryParams } from "./common";
/** 配置分页查询参数 */
export interface ConfigPageQuery extends PageQuery {
export interface ConfigQueryParams extends BaseQueryParams {
/** 搜索关键字 */
keywords?: string;
}
@@ -23,7 +25,7 @@ export interface ConfigForm {
}
/** 配置分页对象 */
export interface ConfigPageVo {
export interface ConfigItem {
/** 配置ID */
id?: string;
/** 配置名称 */

View File

@@ -3,7 +3,7 @@
*/
/** 部门查询参数 */
export interface DeptQuery {
export interface DeptQueryParams {
/** 搜索关键字 */
keywords?: string;
/** 状态 */
@@ -11,9 +11,9 @@ export interface DeptQuery {
}
/** 部门视图对象 */
export interface DeptVo {
export interface DeptItem {
/** 子部门 */
children?: DeptVo[];
children?: DeptItem[];
/** 创建时间 */
createTime?: Date;
/** 部门ID */

View File

@@ -2,9 +2,11 @@
* Dict 字典类型定义
*/
import type { BaseQueryParams } from "./common";
/** 字典分页查询参数 */
export interface DictPageQuery extends PageQuery {
export interface DictTypeQueryParams extends BaseQueryParams {
/** 搜索关键字 */
keywords?: string;
/** 状态(1:启用;0:禁用) */
@@ -12,7 +14,7 @@ export interface DictPageQuery extends PageQuery {
}
/** 字典分页对象 */
export interface DictPageVo {
export interface DictTypeItem {
/** 字典ID */
id: string;
/** 字典名称 */
@@ -24,7 +26,7 @@ export interface DictPageVo {
}
/** 字典表单对象 */
export interface DictForm {
export interface DictTypeForm {
/** 字典ID */
id?: string;
/** 字典名称 */
@@ -38,7 +40,7 @@ export interface DictForm {
}
/** 字典项分页查询参数 */
export interface DictItemPageQuery extends PageQuery {
export interface DictItemQueryParams extends BaseQueryParams {
/** 搜索关键字 */
keywords?: string;
/** 字典编码 */
@@ -46,7 +48,7 @@ export interface DictItemPageQuery extends PageQuery {
}
/** 字典项分页对象 */
export interface DictItemPageVo {
export interface DictItem {
/** 字典项ID */
id: string;
/** 字典编码 */

View File

@@ -2,8 +2,10 @@
* Log 日志类型定义
*/
import type { BaseQueryParams } from "./common";
/** 日志分页查询参数 */
export interface LogPageQuery extends PageQuery {
export interface LogQueryParams extends BaseQueryParams {
/** 搜索关键字 */
keywords?: string;
/** 操作时间 */
@@ -11,7 +13,7 @@ export interface LogPageQuery extends PageQuery {
}
/** 日志分页对象 */
export interface LogPageVo {
export interface LogItem {
/** 日志ID */
id: string;
/** 日志模块 */

View File

@@ -3,15 +3,15 @@
*/
/** 菜单查询参数 */
export interface MenuQuery {
export interface MenuQueryParams {
/** 搜索关键字 */
keywords?: string;
}
/** 菜单视图对象 */
export interface MenuVo {
export interface MenuItem {
/** 子菜单 */
children?: MenuVo[];
children?: MenuItem[];
/** 组件路径 */
component?: string;
/** ICON */
@@ -79,9 +79,9 @@ export interface MenuOption {
}
/** 路由对象 */
export interface RouteVo {
export interface RouteItem {
/** 子路由列表 */
children: RouteVo[];
children: RouteItem[];
/** 组件路径 */
component?: string;
/** 路由名称 */

View File

@@ -2,8 +2,10 @@
* Notice 通知类型定义
*/
import type { BaseQueryParams } from "./common";
/** 通知分页查询参数 */
export interface NoticePageQuery extends PageQuery {
export interface NoticeQueryParams extends BaseQueryParams {
/** 通知标题 */
title?: string;
/** 发布状态(0:草稿;1:已发布;2:已撤回) */
@@ -33,7 +35,7 @@ export interface NoticeForm {
}
/** 通知分页对象 */
export interface NoticePageVo {
export interface NoticeItem {
/** 通知ID */
id: string;
/** 通知标题 */
@@ -55,7 +57,7 @@ export interface NoticePageVo {
}
/** 通知详情对象 */
export interface NoticeDetailVo {
export interface NoticeDetail {
/** 通知ID */
id?: string;
/** 通知标题 */

View File

@@ -2,14 +2,16 @@
* Role 角色类型定义
*/
import type { BaseQueryParams } from "./common";
/** 角色分页查询参数 */
export interface RolePageQuery extends PageQuery {
export interface RoleQueryParams extends BaseQueryParams {
/** 搜索关键字 */
keywords?: string;
}
/** 角色分页对象 */
export interface RolePageVo {
export interface RoleItem {
/** 角色ID */
id?: string;
/** 角色编码 */

View File

@@ -3,7 +3,7 @@
*/
/** 访问趋势查询参数 */
export interface VisitTrendQuery {
export interface VisitTrendQueryParams {
/** 开始日期 */
startDate: string;
/** 结束日期 */
@@ -11,7 +11,7 @@ export interface VisitTrendQuery {
}
/** 访问趋势视图对象 */
export interface VisitTrendVo {
export interface VisitTrendDetail {
/** 日期列表 */
dates: string[];
/** 浏览量(PV)列表 */
@@ -23,7 +23,7 @@ export interface VisitTrendVo {
}
/** 访问量统计视图对象 */
export interface VisitStatsVo {
export interface VisitStatsDetail {
/** 今日独立访客数(UV) */
todayUvCount: number;
/** 累计独立访客数(UV) */

View File

@@ -2,7 +2,7 @@
* Tenant 租户类型定义
*/
import type { PageQuery } from "./common";
import type { BaseQueryParams } from "./common";
/** 租户信息 */
export interface TenantInfo {
@@ -15,7 +15,7 @@ export interface TenantInfo {
}
/** 租户分页查询参数 */
export interface TenantPageQuery extends PageQuery {
export interface TenantQueryParams extends BaseQueryParams {
/** 关键字(租户名称/租户编码/域名) */
keywords?: string;
/** 租户状态(1-正常 0-禁用) */
@@ -23,7 +23,7 @@ export interface TenantPageQuery extends PageQuery {
}
/** 租户分页对象 */
export interface TenantPageVo {
export interface TenantItem {
id?: string;
name?: string;
code?: string;
@@ -69,7 +69,7 @@ export interface TenantCreateForm {
}
/** 新增租户结果 */
export interface TenantCreateResultVo {
export interface TenantCreateResult {
tenantId?: string;
tenantCode?: string;
tenantName?: string;

View File

@@ -2,6 +2,8 @@
* User 用户类型定义
*/
import type { BaseQueryParams } from "./common";
/** 登录用户信息 */
export interface UserInfo {
/** 用户ID */
@@ -19,7 +21,7 @@ export interface UserInfo {
}
/** 用户分页查询参数 */
export interface UserPageQuery extends PageQuery {
export interface UserQueryParams extends BaseQueryParams {
/** 搜索关键字 */
keywords?: string;
/** 用户状态 */
@@ -31,7 +33,7 @@ export interface UserPageQuery extends PageQuery {
}
/** 用户分页对象 */
export interface UserPageVo {
export interface UserItem {
/** 用户ID */
id: string;
/** 用户头像地址 */
@@ -81,7 +83,7 @@ export interface UserForm {
}
/** 个人中心用户信息 */
export interface UserProfileVo {
export interface UserProfileDetail {
/** 用户ID */
id?: string;
/** 用户名 */

View File

@@ -6,7 +6,7 @@
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {};
export {}
/* prettier-ignore */
declare module 'vue' {

View File

@@ -5,9 +5,9 @@
*/
declare global {
type ApiResponse<T = any> = import("@/types/api").ApiResponse<T>;
type PageQuery = import("@/types/api").PageQuery;
type BaseQueryParams = import("@/types/api").BaseQueryParams;
type PageResult<T> = import("@/types/api").PageResult<T>;
type OptionType = import("@/types/api").OptionType;
type OptionItem = import("@/types/api").OptionItem;
type ExcelResult = import("@/types/api").ExcelResult;
type TagView = import("@/types/ui").TagView;
type AppSettings = import("@/types/ui").AppSettings;

View File

@@ -15,6 +15,21 @@ const http = axios.create({
paramsSerializer: (params) => qs.stringify(params),
});
type PageMeta = { pageNum: number; pageSize: number; total: number };
type PagedApiResponse<T = any> = ApiResponse<T> & { page: PageMeta | null };
function isPagedApiResponse<T>(payload: ApiResponse<T>): payload is PagedApiResponse<T> {
// Treat as paged response only when `page` is a non-null object (contains pagination meta).
// Some APIs return `page: null` for non-paged endpoints; checking for the presence
// of the `page` property alone causes unintended branching (e.g. captcha endpoint).
return (
payload != null &&
typeof payload === "object" &&
payload.page != null &&
typeof (payload as any).page === "object"
);
}
// ============================================
// 请求拦截器
// ============================================
@@ -49,6 +64,11 @@ http.interceptors.response.use(
const { code, data, msg } = response.data;
if (code === ApiCodeEnum.SUCCESS) {
// 分页接口需要同时返回 data 与 page 元信息
if (isPagedApiResponse(response.data)) {
const { page } = response.data;
return { data, page: page ?? null };
}
return data;
}

View File

@@ -259,12 +259,12 @@
<script setup lang="ts">
defineOptions({
name: "AiCommandRecord",
name: "AiAssistantRecord",
inheritAttrs: false,
});
import AiCommandApi from "@/api/ai";
import type { AiCommandRecordVo, AiCommandRecordPageQuery } from "@/types/api";
import type { AiAssistantRecordItem, AiAssistantRecordQueryParams } from "@/types/api";
import { onMounted, reactive, ref } from "vue";
const queryFormRef = ref();
@@ -272,7 +272,7 @@ const queryFormRef = ref();
const loading = ref(false);
const total = ref(0);
const queryParams = reactive<AiCommandRecordPageQuery>({
const queryParams = reactive<AiAssistantRecordQueryParams>({
pageNum: 1,
pageSize: 10,
keywords: "",
@@ -283,10 +283,10 @@ const queryParams = reactive<AiCommandRecordPageQuery>({
createTime: ["", ""],
});
const pageData = ref<AiCommandRecordVo[]>([]);
const pageData = ref<AiAssistantRecordItem[]>([]);
const detailDialogVisible = ref(false);
const currentRow = ref<AiCommandRecordVo>();
const currentRow = ref<AiAssistantRecordItem>();
function getExecuteStatusText(status: number): string {
switch (status) {
@@ -317,9 +317,9 @@ function getExecuteStatusTagType(status: number): "info" | "success" | "danger"
function fetchData() {
loading.value = true;
AiCommandApi.getPage(queryParams)
.then((data) => {
pageData.value = data.list || [];
total.value = data.total || 0;
.then((res) => {
pageData.value = res.data || [];
total.value = res.page?.total ?? 0;
})
.finally(() => {
loading.value = false;
@@ -337,7 +337,7 @@ function handleResetQuery() {
fetchData();
}
function handleViewDetail(row: AiCommandRecordVo) {
function handleViewDetail(row: AiAssistantRecordItem) {
currentRow.value = row;
detailDialogVisible.value = true;
}

View File

@@ -525,7 +525,7 @@ import type { EditorConfiguration } from "codemirror";
import { FormTypeEnum, QueryTypeEnum } from "@/enums/codegen";
import GeneratorAPI from "@/api/codegen";
import type { FieldConfig, GenConfigForm, TablePageQuery, TablePageVo } from "@/api/types";
import type { FieldConfig, GenConfigForm, TableQueryParams, TableItem } from "@/api/types";
import { ElLoading } from "element-plus";
import DictAPI from "@/api/system/dict";
@@ -574,7 +574,7 @@ const filteredTreeData = computed<TreeNode[]>(() => {
});
const queryFormRef = ref();
const queryParams = reactive<TablePageQuery>({
const queryParams = reactive<TableQueryParams>({
pageNum: 1,
pageSize: 10,
});
@@ -582,13 +582,13 @@ const queryParams = reactive<TablePageQuery>({
const loading = ref(false);
const loadingText = ref("loading...");
const pageData = ref<TablePageVo[]>([]);
const pageData = ref<TableItem[]>([]);
const total = ref(0);
const formTypeOptions: Record<string, OptionType> = FormTypeEnum;
const queryTypeOptions: Record<string, OptionType> = QueryTypeEnum;
const dictOptions = ref<OptionType[]>();
const menuOptions = ref<OptionType[]>([]);
const formTypeOptions: Record<string, OptionItem> = FormTypeEnum;
const queryTypeOptions: Record<string, OptionItem> = QueryTypeEnum;
const dictOptions = ref<OptionItem[]>();
const menuOptions = ref<OptionItem[]>([]);
const genConfigFormData = ref<GenConfigForm>({
fieldConfigs: [],
pageType: "classic",
@@ -818,9 +818,9 @@ function handleNextClick() {
function handleQuery() {
loading.value = true;
GeneratorAPI.getTablePage(queryParams)
.then((data) => {
pageData.value = data.list;
total.value = data.total;
.then((res) => {
pageData.value = res.data;
total.value = res.page?.total ?? 0;
})
.finally(() => {
loading.value = false;

View File

@@ -359,7 +359,7 @@ defineOptions({
import { dayjs } from "element-plus";
import { ref } from "vue";
import StatisticsAPI from "@/api/system/statistics";
import type { VisitStatsVo, VisitTrendVo } from "@/types/api";
import type { VisitStatsDetail, VisitTrendDetail } from "@/types/api";
import { useUserStore } from "@/store/modules/user";
import { formatGrowthRate } from "@/utils";
import { useTransition, useDateFormat } from "@vueuse/core";
@@ -447,7 +447,7 @@ const greetings = computed(() => {
// 访客统计数据加载状态
const visitStatsLoading = ref(true);
// 访客统计数据
const visitStatsData = ref<VisitStatsVo>({
const visitStatsData = ref<VisitStatsDetail>({
todayUvCount: 0,
uvGrowthRate: 0,
totalUvCount: 0,
@@ -543,7 +543,7 @@ const fetchVisitTrendData = () => {
*
* @param data - 访问趋势数据
*/
const updateVisitTrendChartOptions = (data: VisitTrendVo) => {
const updateVisitTrendChartOptions = (data: VisitTrendDetail) => {
visitTrendChartOptions.value = {
tooltip: {
trigger: "axis",

View File

@@ -71,7 +71,7 @@
import UserAPI from "@/api/system/user";
import DeptAPI from "@/api/system/dept";
import RoleAPI from "@/api/system/role";
import type { UserForm, UserPageQuery } from "@/types/api";
import type { UserForm, UserQueryParams, UserItem } from "@/types/api";
import type { IObject, IModalConfig, IContentConfig, ISearchConfig } from "@/components/CURD/types";
import { DeviceEnum } from "@/enums/settings";
import { useAppStore } from "@/store";
@@ -83,16 +83,16 @@ defineOptions({
});
// ========================= 选项数据管理 =========================
interface OptionType {
interface OptionItem {
label: string;
value: any;
[key: string]: any;
}
// 共享选项数据
const deptArr = ref<OptionType[]>([]);
const roleArr = ref<OptionType[]>([]);
const stateArr = ref<OptionType[]>([
const deptArr = ref<OptionItem[]>([]);
const roleArr = ref<OptionItem[]>([]);
const stateArr = ref<OptionItem[]>([
{ label: "启用", value: 1 },
{ label: "禁用", value: 0 },
]);
@@ -165,7 +165,7 @@ const searchConfig: ISearchConfig = reactive({
});
// ========================= 内容配置 =========================
const contentConfig: IContentConfig<UserPageQuery> = reactive({
const contentConfig: IContentConfig<UserQueryParams, UserItem> = reactive({
permPrefix: "sys:user",
table: {
border: true,
@@ -177,12 +177,6 @@ const contentConfig: IContentConfig<UserPageQuery> = reactive({
pageSize: 20,
pageSizes: [10, 20, 30, 50],
},
parseData(res: any) {
return {
total: res.total,
list: res.list,
};
},
indexAction(params: any) {
return UserAPI.getPage(params);
},
@@ -198,8 +192,8 @@ const contentConfig: IContentConfig<UserPageQuery> = reactive({
},
async exportsAction(params: any) {
const res = await UserAPI.getPage(params);
console.log("exportsAction", res.list);
return res.list;
console.log("exportsAction", res.data);
return res.data;
},
pk: "id",
toolbar: [

View File

@@ -1,9 +1,9 @@
import UserAPI from "@/api/system/user";
import RoleAPI from "@/api/system/role";
import type { UserPageQuery } from "@/types/api";
import type { UserQueryParams, UserItem } from "@/types/api";
import type { IContentConfig } from "@/components/CURD/types";
const contentConfig: IContentConfig<UserPageQuery> = {
const contentConfig: IContentConfig<UserQueryParams, UserItem> = {
permPrefix: "sys:user", // 不写不进行按钮权限校验
table: {
border: true,
@@ -15,12 +15,6 @@ const contentConfig: IContentConfig<UserPageQuery> = {
pageSize: 20,
pageSizes: [10, 20, 30, 50],
},
parseData(res) {
return {
total: res.total,
list: res.list,
};
},
indexAction(params) {
return UserAPI.getPage(params);
},
@@ -38,8 +32,8 @@ const contentConfig: IContentConfig<UserPageQuery> = {
async exportsAction(params) {
// 模拟获取到的是全量数据
const res = await UserAPI.getPage(params);
console.log("exportsAction", res.list);
return res.list;
console.log("exportsAction", res.data);
return res.data;
},
pk: "id",
toolbar: [

View File

@@ -2,16 +2,16 @@
import DeptAPI from "@/api/system/dept";
import RoleAPI from "@/api/system/role";
interface OptionType {
interface OptionItem {
label: string;
value: any;
[key: string]: any; // 允许其他属性
}
// 明确指定类型为 OptionType[]
export const deptArr = ref<OptionType[]>([]);
export const roleArr = ref<OptionType[]>([]);
export const stateArr = ref<OptionType[]>([
// 明确指定类型为 OptionItem[]
export const deptArr = ref<OptionItem[]>([]);
export const roleArr = ref<OptionItem[]>([]);
export const stateArr = ref<OptionItem[]>([
{ label: "启用", value: 1 },
{ label: "禁用", value: 0 },
]);

View File

@@ -1,6 +1,27 @@
import type { IContentConfig } from "@/components/CURD/types";
const contentConfig: IContentConfig = {
interface DemoQueryParams {
pageNum?: number;
pageSize?: number;
[key: string]: any;
}
interface DemoItem {
id: number;
username: string;
avatar: string;
percent: number;
price: number;
url: string;
icon: string;
gender: number;
status: number;
status2: number;
sort: number;
createTime: number;
}
const contentConfig: IContentConfig<DemoQueryParams, DemoItem> = {
// permPrefix: "sys:demo", // 不写不进行按钮权限校验
table: {
showOverflowTooltip: true,
@@ -10,38 +31,49 @@ const contentConfig: IContentConfig = {
indexAction(params) {
// 模拟发起网络请求获取列表数据
console.log("indexAction:", params);
const list = [
{
id: 1,
username: "root",
avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
percent: 99,
price: 10,
url: "https://www.baidu.com",
icon: "el-icon-setting",
gender: 1,
status: 1,
status2: 1,
sort: 99,
createTime: 1715647982437,
},
{
id: 2,
username: "jerry",
avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
percent: 88,
price: 999,
url: "https://www.google.com",
icon: "el-icon-user",
gender: 0,
status: 0,
status2: 0,
sort: 0,
createTime: 1715648977426,
},
];
const pageNum = Number(params?.pageNum ?? 1) || 1;
const pageSize = Number(params?.pageSize ?? list.length) || list.length;
const start = (pageNum - 1) * pageSize;
const end = start + pageSize;
return Promise.resolve({
total: 2,
list: [
{
id: 1,
username: "root",
avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
percent: 99,
price: 10,
url: "https://www.baidu.com",
icon: "el-icon-setting",
gender: 1,
status: 1,
status2: 1,
sort: 99,
createTime: 1715647982437,
},
{
id: 2,
username: "jerry",
avatar: "https://foruda.gitee.com/images/1723603502796844527/03cdca2a_716974.gif",
percent: 88,
price: 999,
url: "https://www.google.com",
icon: "el-icon-user",
gender: 0,
status: 0,
status2: 0,
sort: 0,
createTime: 1715648977426,
},
],
data: list.slice(start, end),
page: {
pageNum,
pageSize,
total: list.length,
},
});
},
modifyAction(data) {

View File

@@ -56,10 +56,13 @@
border-rd-4px
w-full
h-full
object-contain
block
object-cover
shadow="[0_0_0_1px_var(--el-border-color)_inset]"
:src="captchaBase64"
alt="captchaCode"
title="点击刷新验证码"
@error="getCaptcha"
/>
<el-text v-else type="info" size="small">点击获取验证码</el-text>
</div>

View File

@@ -227,7 +227,8 @@ onBeforeUnmount(() => {
animation: featureFade 0.8s ease-out;
@media (prefers-color-scheme: dark) {
color: rgba(236, 242, 255, 0.92);
/* use theme variable so dark mode colors follow theme variables */
color: var(--el-text-color-primary);
}
}

View File

@@ -226,7 +226,7 @@
<script lang="ts" setup>
import UserAPI from "@/api/system/user";
import type {
UserProfileVo,
UserProfileDetail,
PasswordChangeForm,
MobileUpdateForm,
EmailUpdateForm,
@@ -241,7 +241,7 @@ import { Camera } from "@element-plus/icons-vue";
const userStore = useUserStoreHook();
const userProfile = ref<UserProfileVo>({});
const userProfile = ref<UserProfileDetail>({});
const enum DialogType {
ACCOUNT = "account",

View File

@@ -116,27 +116,27 @@ defineOptions({
import { onMounted, reactive, ref } from "vue";
import { ElMessage } from "element-plus";
import NoticeAPI from "@/api/system/notice";
import type { NoticePageVo, NoticePageQuery } from "@/types/api";
import type { NoticeDetail, NoticeItem, NoticeQueryParams } from "@/types/api";
const queryFormRef = ref();
const pageData = ref<NoticePageVo[]>([]);
const pageData = ref<NoticeItem[]>([]);
const loading = ref(false);
const total = ref(0);
const queryParams = reactive<NoticePageQuery>({
const queryParams = reactive<NoticeQueryParams>({
pageNum: 1,
pageSize: 10,
});
const noticeDialogVisible = ref(false);
const noticeDetail = ref<any>(null);
const noticeDetail = ref<NoticeDetail | null>(null);
async function handleQuery() {
loading.value = true;
try {
const data = await NoticeAPI.getMyNoticePage(queryParams);
pageData.value = data.list;
total.value = data.total;
const res = await NoticeAPI.getMyNoticePage(queryParams);
pageData.value = res.data;
total.value = res.page?.total ?? 0;
} catch (error) {
ElMessage.error("获取通知列表失败");
console.error("获取我的通知失败", error);

View File

@@ -142,7 +142,7 @@ defineOptions({
});
import ConfigAPI from "@/api/system/config";
import type { ConfigPageVo, ConfigForm, ConfigPageQuery } from "@/types/api";
import type { ConfigItem, ConfigForm, ConfigQueryParams } from "@/types/api";
import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core";
@@ -153,14 +153,14 @@ const loading = ref(false);
const selectIds = ref<number[]>([]);
const total = ref(0);
const queryParams = reactive<ConfigPageQuery>({
const queryParams = reactive<ConfigQueryParams>({
pageNum: 1,
pageSize: 10,
keywords: "",
});
// 系统配置表格数据
const pageData = ref<ConfigPageVo[]>([]);
const pageData = ref<ConfigItem[]>([]);
const dialog = reactive({
title: "",
@@ -185,9 +185,9 @@ const rules = reactive({
function fetchData() {
loading.value = true;
ConfigAPI.getPage(queryParams)
.then((data) => {
pageData.value = data.list;
total.value = data.total;
.then((res) => {
pageData.value = res.data;
total.value = res.page?.total ?? 0;
})
.finally(() => {
loading.value = false;

View File

@@ -164,22 +164,22 @@ defineOptions({
});
import DeptAPI from "@/api/system/dept";
import type { DeptVo, DeptForm, DeptQuery } from "@/types/api";
import type { DeptItem, DeptForm, DeptQueryParams } from "@/types/api";
const queryFormRef = ref();
const deptFormRef = ref();
const loading = ref(false);
const selectIds = ref<number[]>([]);
const queryParams = reactive<DeptQuery>({});
const queryParams = reactive<DeptQueryParams>({});
const dialog = reactive({
title: "",
visible: false,
});
const deptList = ref<DeptVo[]>();
const deptOptions = ref<OptionType[]>();
const deptList = ref<DeptItem[]>();
const deptOptions = ref<OptionItem[]>();
const formData = reactive<DeptForm>({
status: 1,
parentId: "0",

View File

@@ -156,7 +156,7 @@
<script setup lang="ts">
import type { TagProps } from "element-plus";
import DictAPI from "@/api/system/dict";
import type { DictItemPageQuery, DictItemPageVo, DictItemForm } from "@/types/api";
import type { DictItemQueryParams, DictItem, DictItemForm } from "@/types/api";
const route = useRoute();
@@ -169,12 +169,12 @@ const loading = ref(false);
const ids = ref<number[]>([]);
const total = ref(0);
const queryParams = reactive<DictItemPageQuery>({
const queryParams = reactive<DictItemQueryParams>({
pageNum: 1,
pageSize: 10,
});
const tableData = ref<DictItemPageVo[]>();
const tableData = ref<DictItem[]>();
const dialog = reactive({
title: "",
@@ -199,9 +199,9 @@ const computedRules = computed(() => {
function fetchData() {
loading.value = true;
DictAPI.getDictItemPage(dictCode.value, queryParams)
.then((data) => {
tableData.value = data.list;
total.value = data.total;
.then((res) => {
tableData.value = res.data;
total.value = res.page?.total ?? 0;
})
.finally(() => {
loading.value = false;
@@ -227,7 +227,7 @@ function handleSelectionChange(selection: any) {
}
// 打开弹窗
function handleOpenDialog(row?: DictItemPageVo) {
function handleOpenDialog(row?: DictItem) {
dialog.visible = true;
dialog.title = row ? "编辑字典值" : "新增字典值";

View File

@@ -1,4 +1,4 @@
<!-- 字典 -->
<!-- 字典 -->
<template>
<div class="app-container">
<!-- 搜索区域 -->
@@ -139,7 +139,7 @@ defineOptions({
import { ref, reactive } from "vue";
import DictAPI from "@/api/system/dict";
import type { DictPageQuery, DictPageVo, DictForm } from "@/types/api";
import type { DictTypeQueryParams, DictTypeItem, DictTypeForm } from "@/types/api";
import router from "@/router";
@@ -150,19 +150,19 @@ const loading = ref(false);
const ids = ref<number[]>([]);
const total = ref(0);
const queryParams = reactive<DictPageQuery>({
const queryParams = reactive<DictTypeQueryParams>({
pageNum: 1,
pageSize: 10,
});
const tableData = ref<DictPageVo[]>();
const tableData = ref<DictTypeItem[]>();
const dialog = reactive({
title: "",
visible: false,
});
const formData = reactive<DictForm>({});
const formData = reactive<DictTypeForm>({});
const computedRules = computed(() => {
const rules: Partial<Record<string, any>> = {
@@ -176,9 +176,9 @@ const computedRules = computed(() => {
function fetchData() {
loading.value = true;
DictAPI.getPage(queryParams)
.then((data) => {
tableData.value = data.list;
total.value = data.total;
.then((res) => {
tableData.value = res.data;
total.value = res.page?.total ?? 0;
})
.finally(() => {
loading.value = false;
@@ -287,7 +287,7 @@ function handleDelete(id?: number) {
}
// 打开字典值"
function handleOpenDictData(row: DictPageVo) {
function handleOpenDictData(row: DictTypeItem) {
router.push({
path: "/system/dict-item",
query: { dictCode: row.dictCode, title: `${row.name}】字典数据` },

View File

@@ -69,14 +69,14 @@ defineOptions({
});
import LogAPI from "@/api/system/log";
import type { LogPageVo, LogPageQuery } from "@/types/api";
import type { LogItem, LogQueryParams } from "@/types/api";
const queryFormRef = ref();
const loading = ref(false);
const total = ref(0);
const queryParams = reactive<LogPageQuery>({
const queryParams = reactive<LogQueryParams>({
pageNum: 1,
pageSize: 10,
keywords: "",
@@ -84,15 +84,15 @@ const queryParams = reactive<LogPageQuery>({
});
// 日志表格数据
const pageData = ref<LogPageVo[]>();
const pageData = ref<LogItem[]>();
/** 获取数据 */
function fetchData() {
loading.value = true;
LogAPI.getPage(queryParams)
.then((data) => {
pageData.value = data.list;
total.value = data.total;
.then((res) => {
pageData.value = res.data;
total.value = res.page?.total ?? 0;
})
.finally(() => {
loading.value = false;

View File

@@ -345,7 +345,7 @@ import { useAppStore } from "@/store/modules/app";
import { DeviceEnum } from "@/enums/settings";
import MenuAPI from "@/api/system/menu";
import type { MenuQuery, MenuForm, MenuVo } from "@/types/api";
import type { MenuQueryParams, MenuForm, MenuItem } from "@/types/api";
import { MenuTypeEnum } from "@/enums/business";
defineOptions({
@@ -366,11 +366,11 @@ const dialog = reactive({
const drawerSize = computed(() => (appStore.device === DeviceEnum.DESKTOP ? "600px" : "90%"));
// 查询参数
const queryParams = reactive<MenuQuery>({});
const queryParams = reactive<MenuQueryParams>({});
// 菜单表格数据
const menuTableData = ref<MenuVo[]>([]);
const menuTableData = ref<MenuItem[]>([]);
// 顶级菜单下拉选项
const menuOptions = ref<OptionType[]>([]);
const menuOptions = ref<OptionItem[]>([]);
// 初始菜单表单数据
const initialMenuFormData = ref<MenuForm>({
id: undefined,
@@ -437,7 +437,7 @@ function handleResetQuery() {
}
// 行点击事件
function handleRowClick(row: MenuVo) {
function handleRowClick(row: MenuItem) {
selectedMenuId.value = row.id;
}

View File

@@ -262,7 +262,7 @@ defineOptions({
import { ref, reactive } from "vue";
import NoticeAPI from "@/api/system/notice";
import type { NoticePageVo, NoticeForm, NoticePageQuery, NoticeDetailVo } from "@/types/api";
import type { NoticeItem, NoticeForm, NoticeQueryParams, NoticeDetail } from "@/types/api";
import UserAPI from "@/api/system/user";
const queryFormRef = ref();
@@ -272,14 +272,14 @@ const loading = ref(false);
const selectIds = ref<number[]>([]);
const total = ref(0);
const queryParams = reactive<NoticePageQuery>({
const queryParams = reactive<NoticeQueryParams>({
pageNum: 1,
pageSize: 10,
});
const userOptions = ref<OptionType[]>([]);
const userOptions = ref<OptionItem[]>([]);
// 通知公告表格数据
const pageData = ref<NoticePageVo[]>([]);
const pageData = ref<NoticeItem[]>([]);
// 弹窗
const dialog = reactive({
@@ -316,7 +316,7 @@ const rules = reactive({
const detailDialog = reactive({
visible: false,
});
const currentNotice = ref<NoticeDetailVo>({});
const currentNotice = ref<NoticeDetail>({});
// 查询通知公告
function handleQuery() {
@@ -328,9 +328,9 @@ function handleQuery() {
function fetchData() {
loading.value = true;
NoticeAPI.getPage(queryParams)
.then((data) => {
pageData.value = data.list;
total.value = data.total;
.then((res) => {
pageData.value = res.data;
total.value = res.page?.total ?? 0;
})
.finally(() => {
loading.value = false;

View File

@@ -63,7 +63,7 @@
size="small"
link
icon="position"
@click="handleOpenAssignPermDialog(scope.row)"
@click="openRolePermissionAssignment(scope.row)"
>
分配权限
</el-button>
@@ -216,7 +216,7 @@ import { useAppStore } from "@/store/modules/app";
import { DeviceEnum } from "@/enums/settings";
import RoleAPI from "@/api/system/role";
import type { RolePageVo, RoleForm, RolePageQuery } from "@/types/api";
import type { RoleItem, RoleForm, RoleQueryParams } from "@/types/api";
import MenuAPI from "@/api/system/menu";
defineOptions({
@@ -234,15 +234,15 @@ const loading = ref(false);
const ids = ref<number[]>([]);
const total = ref(0);
const queryParams = reactive<RolePageQuery>({
const queryParams = reactive<RoleQueryParams>({
pageNum: 1,
pageSize: 10,
});
// 角色表格数据
const roleList = ref<RolePageVo[]>();
const roleList = ref<RoleItem[]>();
// 菜单权限下拉
const menuPermOptions = ref<OptionType[]>([]);
const menuPermOptions = ref<OptionItem[]>([]);
// 弹窗
const dialog = reactive({
@@ -282,9 +282,9 @@ const parentChildLinked = ref(true);
function fetchData() {
loading.value = true;
RoleAPI.getPage(queryParams)
.then((data) => {
roleList.value = data.list;
total.value = data.total;
.then((res) => {
roleList.value = res.data;
total.value = res.page?.total ?? 0;
})
.finally(() => {
loading.value = false;
@@ -390,7 +390,7 @@ function handleDelete(roleId?: number) {
}
// 打开分配菜单权限弹窗
async function handleOpenAssignPermDialog(row: RolePageVo) {
async function openRolePermissionAssignment(row: RoleItem) {
const roleId = row.id;
if (roleId) {
assignPermDialogVisible.value = true;

View File

@@ -204,7 +204,7 @@ import { useDebounceFn } from "@vueuse/core";
import { hasPerm } from "@/utils/auth";
import TenantAPI from "@/api/system/tenant";
import type { TenantCreateForm, TenantForm, TenantPageQuery, TenantPageVo } from "@/types/api";
import type { TenantCreateForm, TenantForm, TenantQueryParams, TenantItem } from "@/types/api";
const queryFormRef = ref();
const dataFormRef = ref();
@@ -213,13 +213,13 @@ const loading = ref(false);
const ids = ref<number[]>([]);
const total = ref(0);
const queryParams = reactive<TenantPageQuery>({
const queryParams = reactive<TenantQueryParams>({
pageNum: 1,
pageSize: 10,
keywords: "",
});
const pageData = ref<TenantPageVo[]>([]);
const pageData = ref<TenantItem[]>([]);
const dialog = reactive({
title: "",
@@ -250,9 +250,9 @@ const hasPermChangeStatus = computed(() => hasPerm("sys:tenant:change-status"));
function fetchData() {
loading.value = true;
TenantAPI.getPage(queryParams)
.then((data) => {
pageData.value = data.list;
total.value = data.total;
.then((res) => {
pageData.value = res.data;
total.value = res.page?.total ?? 0;
})
.finally(() => {
loading.value = false;

View File

@@ -28,7 +28,7 @@ const props = defineProps({
},
});
const deptList = ref<OptionType[]>(); // 部门列表
const deptList = ref<OptionItem[]>(); // 部门列表
const deptTreeRef = ref(); // 部门树
const deptName = ref(); // 部门名称

View File

@@ -116,7 +116,7 @@
</el-tag>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="150" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180" />
<el-table-column label="操作" fixed="right" width="220">
<template #default="scope">
<el-button
@@ -253,7 +253,7 @@ import { useDebounceFn } from "@vueuse/core";
import { ElMessage, ElMessageBox, type FormInstance } from "element-plus";
// ==================== 3. 类型定义 ====================
import type { UserForm, UserPageQuery, UserPageVo } from "@/types/api";
import type { UserForm, UserQueryParams, UserItem } from "@/types/api";
// ==================== 3.5 工具函数 ====================
import { downloadFile, VALIDATORS } from "@/utils";
@@ -292,13 +292,13 @@ const queryFormRef = ref<FormInstance>();
const userFormRef = ref<FormInstance>();
// 列表查询参数
const queryParams = reactive<UserPageQuery>({
const queryParams = reactive<UserQueryParams>({
pageNum: 1,
pageSize: 10,
});
// 列表数据
const userList = ref<UserPageVo[]>([]);
const userList = ref<UserItem[]>([]);
const total = ref(0);
const loading = ref(false);
@@ -318,8 +318,8 @@ const initialFormData: UserForm = {
const formData = reactive<UserForm>({ ...initialFormData });
// 下拉选项数据
const deptOptions = ref<OptionType[]>();
const roleOptions = ref<OptionType[]>();
const deptOptions = ref<OptionItem[]>();
const roleOptions = ref<OptionItem[]>();
// 导入弹窗
const importDialogVisible = ref(false);
@@ -350,9 +350,9 @@ const rules = reactive({
async function fetchUserList(): Promise<void> {
loading.value = true;
try {
const data = await UserAPI.getPage(queryParams);
userList.value = data.list;
total.value = data.total;
const res = await UserAPI.getPage(queryParams);
userList.value = res.data;
total.value = res.page?.total ?? 0;
} catch (error) {
ElMessage.error("获取用户列表失败");
console.error("获取用户列表失败:", error);
@@ -362,7 +362,7 @@ async function fetchUserList(): Promise<void> {
}
// ==================== 表格选择 ====================
const { selectedIds, hasSelection, handleSelectionChange } = useTableSelection<UserPageVo>();
const { selectedIds, hasSelection, handleSelectionChange } = useTableSelection<UserItem>();
// ==================== 查询操作 ====================
@@ -389,7 +389,7 @@ function handleResetQuery(): void {
* 重置用户密码
* @param row 用户数据
*/
function handleResetPassword(row: UserPageVo): void {
function handleResetPassword(row: UserItem): void {
ElMessageBox.prompt(`请输入用户【${row.username}】的新密码`, "重置密码", {
confirmButtonText: "确定",
cancelButtonText: "取消",