index.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. import type { MockMethod } from "vite-plugin-mock";
  2. // 模拟聊天记录存储(内存中)
  3. interface ChatMessage {
  4. id: string;
  5. role: 'user' | 'assistant';
  6. content: string;
  7. time: string;
  8. }
  9. // 生成模拟历史聊天记录
  10. const generateMockChatHistory = (): ChatMessage[] => {
  11. const history: ChatMessage[] = [
  12. {
  13. id: '1',
  14. role: 'assistant',
  15. content: '您好!我是您的 AI 智能助手,有什么可以帮助您的吗?',
  16. time: new Date(Date.now() - 86400000 * 2).toLocaleString()
  17. },
  18. {
  19. id: '2',
  20. role: 'user',
  21. content: '如何管理系统用户?',
  22. time: new Date(Date.now() - 86400000 * 2 + 60000).toLocaleString()
  23. },
  24. {
  25. id: '3',
  26. role: 'assistant',
  27. content: '系统用户管理在「用户管理」菜单中,您可以进行以下操作:\n1. 查看用户列表\n2. 添加新用户\n3. 编辑用户信息\n4. 禁用/启用用户账号',
  28. time: new Date(Date.now() - 86400000 * 2 + 120000).toLocaleString()
  29. },
  30. {
  31. id: '4',
  32. role: 'user',
  33. content: '系统有哪些功能模块?',
  34. time: new Date(Date.now() - 86400000).toLocaleString()
  35. },
  36. {
  37. id: '5',
  38. role: 'assistant',
  39. content: '本系统包含以下功能模块:\n- 仪表盘:数据概览\n- 用户管理:系统用户管理\n- 系统管理:菜单、角色管理\n- 数据统计:报表分析\n- AI 助手:智能问答',
  40. time: new Date(Date.now() - 86400000 + 60000).toLocaleString()
  41. },
  42. {
  43. id: '6',
  44. role: 'user',
  45. content: '如何导出数据报表?',
  46. time: new Date(Date.now() - 43200000).toLocaleString()
  47. },
  48. {
  49. id: '7',
  50. role: 'assistant',
  51. content: '导出数据报表步骤:\n1. 进入「数据统计」页面\n2. 选择查询条件\n3. 点击「导出」按钮\n4. 选择导出格式(Excel/PDF)\n5. 下载生成的报表文件',
  52. time: new Date(Date.now() - 43200000 + 60000).toLocaleString()
  53. },
  54. {
  55. id: '8',
  56. role: 'user',
  57. content: '如何配置菜单权限?',
  58. time: new Date(Date.now() - 3600000).toLocaleString()
  59. },
  60. {
  61. id: '9',
  62. role: 'assistant',
  63. content: '菜单权限配置在「系统管理 > 菜单管理」中:\n1. 创建菜单项\n2. 设置菜单图标和路径\n3. 为角色分配菜单权限\n4. 保存后权限即时生效',
  64. time: new Date(Date.now() - 3600000 + 60000).toLocaleString()
  65. },
  66. {
  67. id: '10',
  68. role: 'user',
  69. content: '如何修改个人资料?',
  70. time: new Date(Date.now() - 1800000).toLocaleString()
  71. },
  72. {
  73. id: '11',
  74. role: 'assistant',
  75. content: '修改个人资料:\n1. 点击右上角用户名\n2. 选择「个人中心」\n3. 编辑个人信息\n4. 点击「保存」按钮',
  76. time: new Date(Date.now() - 1800000 + 60000).toLocaleString()
  77. },
  78. {
  79. id: '12',
  80. role: 'user',
  81. content: '帮助',
  82. time: new Date(Date.now() - 900000).toLocaleString()
  83. },
  84. {
  85. id: '13',
  86. role: 'assistant',
  87. content: '我可以帮您:\n- 解答系统使用问题\n- 提供操作指导\n- 解释功能说明\n请直接输入您的问题!',
  88. time: new Date(Date.now() - 900000 + 60000).toLocaleString()
  89. }
  90. ];
  91. return history;
  92. };
  93. const chatHistory: ChatMessage[] = generateMockChatHistory();
  94. export default [
  95. // 登录接口
  96. {
  97. url: "/api/upms/auth/login",
  98. method: "post",
  99. response: ({ body }) => {
  100. const { username, password } = body;
  101. if (username === "admin" && password === "123456") {
  102. return {
  103. code: 200,
  104. message: "登录成功",
  105. data: {
  106. token: "mock_token_" + Date.now(),
  107. userInfo: {
  108. id: "1",
  109. username: "admin",
  110. nickname: "管理员",
  111. avatar: "",
  112. roles: ["admin"],
  113. },
  114. },
  115. };
  116. }
  117. return {
  118. code: 401,
  119. message: "用户名或密码错误",
  120. data: null,
  121. };
  122. },
  123. },
  124. // 获取用户信息
  125. {
  126. url: "/api/upms/user/info",
  127. method: "get",
  128. response: () => {
  129. return {
  130. code: 200,
  131. message: "success",
  132. data: {
  133. id: "1",
  134. username: "admin",
  135. nickname: "管理员",
  136. avatar: "",
  137. roles: ["admin"],
  138. email: "admin@example.com",
  139. phone: "13800138000",
  140. },
  141. };
  142. },
  143. },
  144. // 获取菜单列表
  145. {
  146. url: "/api/upms/menu/list",
  147. method: "get",
  148. response: () => {
  149. return {
  150. code: 200,
  151. message: "success",
  152. data: [
  153. {
  154. id: "1",
  155. name: "仪表盘",
  156. path: "/dashboard",
  157. icon: "Odometer",
  158. },
  159. {
  160. id: "2",
  161. name: "用户管理",
  162. path: "/user",
  163. icon: "User",
  164. },
  165. {
  166. id: "3",
  167. name: "系统管理",
  168. path: "/system",
  169. icon: "Setting",
  170. children: [
  171. {
  172. id: "3-1",
  173. name: "菜单管理",
  174. path: "/system/menu",
  175. icon: "Menu",
  176. },
  177. {
  178. id: "3-2",
  179. name: "角色管理",
  180. path: "/system/role",
  181. icon: "UserFilled",
  182. },
  183. ],
  184. },
  185. {
  186. id: "4",
  187. name: "数据统计",
  188. path: "/statistics",
  189. icon: "TrendCharts",
  190. },
  191. {
  192. id: "5",
  193. name: "AI 助手",
  194. path: "/ai-chat",
  195. icon: "ChatDotRound",
  196. },
  197. {
  198. id: "6",
  199. name: "文件管理",
  200. path: "/file",
  201. icon: "Folder",
  202. },
  203. ],
  204. };
  205. },
  206. },
  207. // 用户列表
  208. {
  209. url: "/api/upms/user/list",
  210. method: "get",
  211. response: ({ query }) => {
  212. const { page = 1, size = 10 } = query;
  213. // 生成模拟数据
  214. const list = Array.from({ length: size }, (_, i) => ({
  215. id: String((page - 1) * size + i + 1),
  216. username: `user${(page - 1) * size + i + 1}`,
  217. nickname: `用户${(page - 1) * size + i + 1}`,
  218. email: `user${(page - 1) * size + i + 1}@example.com`,
  219. status: Math.random() > 0.3 ? 1 : 0,
  220. createTime: "2024-01-01 12:00:00",
  221. }));
  222. return {
  223. code: 200,
  224. message: "success",
  225. data: {
  226. list,
  227. total: 100,
  228. },
  229. };
  230. },
  231. },
  232. // 退出登录
  233. {
  234. url: "/api/upms/auth/logout",
  235. method: "post",
  236. response: () => {
  237. return {
  238. code: 200,
  239. message: "退出成功",
  240. data: null,
  241. };
  242. },
  243. },
  244. // 获取聊天记录列表(分页)
  245. {
  246. url: "/api/upms/ai/chat/history",
  247. method: "get",
  248. response: ({ query }) => {
  249. const page = parseInt(query.page as string) || 1;
  250. const size = parseInt(query.size as string) || 10;
  251. // 计算分页
  252. const total = chatHistory.length;
  253. const start = (page - 1) * size;
  254. const end = start + size;
  255. const list = chatHistory.slice(start, end);
  256. return {
  257. code: 200,
  258. message: "success",
  259. data: {
  260. list,
  261. total,
  262. page,
  263. size,
  264. hasMore: end < total
  265. }
  266. };
  267. },
  268. },
  269. // AI 对话接口 (POST - 返回 JSON,适用于代理模式)
  270. {
  271. url: "/api/upms/ai/chat",
  272. method: "post",
  273. response: ({ body }) => {
  274. const { question } = body;
  275. // AI 回复知识库
  276. const knowledgeBase: Record<string, string> = {
  277. "如何管理系统用户?": "系统用户管理在「用户管理」菜单中,您可以进行以下操作:\n1. 查看用户列表\n2. 添加新用户\n3. 编辑用户信息\n4. 禁用/启用用户账号",
  278. "如何配置菜单权限?": "菜单权限配置在「系统管理 > 菜单管理」中:\n1. 创建菜单项\n2. 设置菜单图标和路径\n3. 为角色分配菜单权限\n4. 保存后权限即时生效",
  279. "系统有哪些功能模块?": "本系统包含以下功能模块:\n- 仪表盘:数据概览\n- 用户管理:系统用户管理\n- 系统管理:菜单、角色管理\n- 数据统计:报表分析\n- AI 助手:智能问答",
  280. "如何导出数据报表?": "导出数据报表步骤:\n1. 进入「数据统计」页面\n2. 选择查询条件\n3. 点击「导出」按钮\n4. 选择导出格式(Excel/PDF)\n5. 下载生成的报表文件",
  281. "如何修改个人资料?": "修改个人资料:\n1. 点击右上角用户名\n2. 选择「个人中心」\n3. 编辑个人信息\n4. 点击「保存」按钮",
  282. "你好": "您好!很高兴为您服务,请问有什么可以帮助您的?",
  283. "帮助": "我可以帮您:\n- 解答系统使用问题\n- 提供操作指导\n- 解释功能说明\n请直接输入您的问题!"
  284. };
  285. // 查找回复
  286. let reply = '';
  287. for (const key in knowledgeBase) {
  288. if (question.includes(key) || key.includes(question)) {
  289. reply = knowledgeBase[key];
  290. break;
  291. }
  292. }
  293. // 默认回复
  294. if (!reply) {
  295. reply = `感谢您的提问!关于"${question}",我建议您:\n\n1. 查看相关功能模块的说明文档\n2. 联系系统管理员获取帮助\n3. 或者尝试在快捷问题中寻找类似问题\n\n如果您需要更详细的帮助,请联系技术支持。`;
  296. }
  297. return {
  298. code: 200,
  299. message: "success",
  300. data: { reply }
  301. };
  302. },
  303. },
  304. // AI 对话接口 (GET - SSE 流式输出,适用于 Mock 模式)
  305. {
  306. url: "/api/upms/ai/chat",
  307. method: "get",
  308. rawResponse: async (req, res) => {
  309. // 从 query 参数获取问题
  310. const url = new URL(req.url || '', `http://${req.headers.host}`);
  311. const question = url.searchParams.get('question') || '';
  312. // AI 回复知识库
  313. const knowledgeBase: Record<string, string> = {
  314. "如何管理系统用户?": "系统用户管理在「用户管理」菜单中,您可以进行以下操作:\n1. 查看用户列表\n2. 添加新用户\n3. 编辑用户信息\n4. 禁用/启用用户账号",
  315. "如何配置菜单权限?": "菜单权限配置在「系统管理 > 菜单管理」中:\n1. 创建菜单项\n2. 设置菜单图标和路径\n3. 为角色分配菜单权限\n4. 保存后权限即时生效",
  316. "系统有哪些功能模块?": "本系统包含以下功能模块:\n- 仪表盘:数据概览\n- 用户管理:系统用户管理\n- 系统管理:菜单、角色管理\n- 数据统计:报表分析\n- AI 助手:智能问答",
  317. "如何导出数据报表?": "导出数据报表步骤:\n1. 进入「数据统计」页面\n2. 选择查询条件\n3. 点击「导出」按钮\n4. 选择导出格式(Excel/PDF)\n5. 下载生成的报表文件",
  318. "如何修改个人资料?": "修改个人资料:\n1. 点击右上角用户名\n2. 选择「个人中心」\n3. 编辑个人信息\n4. 点击「保存」按钮",
  319. "你好": "您好!很高兴为您服务,请问有什么可以帮助您的?",
  320. "帮助": "我可以帮您:\n- 解答系统使用问题\n- 提供操作指导\n- 解释功能说明\n请直接输入您的问题!"
  321. };
  322. // 查找回复
  323. let reply = '';
  324. for (const key in knowledgeBase) {
  325. if (question.includes(key) || key.includes(question)) {
  326. reply = knowledgeBase[key];
  327. break;
  328. }
  329. }
  330. // 默认回复
  331. if (!reply) {
  332. reply = `感谢您的提问!关于"${question}",我建议您:\n\n1. 查看相关功能模块的说明文档\n2. 联系系统管理员获取帮助\n3. 或者尝试在快捷问题中寻找类似问题\n\n如果您需要更详细的帮助,请联系技术支持。`;
  333. }
  334. // 设置 SSE 响应头
  335. res.setHeader('Content-Type', 'text/event-stream');
  336. res.setHeader('Cache-Control', 'no-cache');
  337. res.setHeader('Connection', 'keep-alive');
  338. // 流式发送回复,每个字延迟 50ms
  339. const chars = reply.split('');
  340. for (let i = 0; i < chars.length; i++) {
  341. const data = {
  342. content: chars[i],
  343. index: i,
  344. total: chars.length,
  345. done: i === chars.length - 1
  346. };
  347. res.write(`data: ${JSON.stringify(data)}\n\n`);
  348. await new Promise(resolve => setTimeout(resolve, 50));
  349. }
  350. res.end();
  351. },
  352. },
  353. // ========== 文件管理接口 ==========
  354. // 获取文件列表
  355. {
  356. url: "/api/file/list",
  357. method: "get",
  358. response: ({ query }) => {
  359. const page = parseInt(query.page as string) || 1;
  360. const size = parseInt(query.size as string) || 10;
  361. const filename = (query.filename as string) || '';
  362. const fileType = (query.fileType as string) || '';
  363. // 模拟文件数据
  364. const allFiles = [
  365. { id: '1', filename: '项目需求文档.pdf', fileType: 'document', size: 2048576, uploader: '张三', uploadTime: '2026-03-15 10:30:00', url: '' },
  366. { id: '2', filename: '产品原型图.png', fileType: 'image', size: 512000, uploader: '李四', uploadTime: '2026-03-15 09:15:00', url: 'https://via.placeholder.com/800x600.png?text=Product+Prototype' },
  367. { id: '3', filename: '会议记录.docx', fileType: 'document', size: 102400, uploader: '王五', uploadTime: '2026-03-14 16:45:00', url: '' },
  368. { id: '4', filename: '演示视频.mp4', fileType: 'video', size: 52428800, uploader: '赵六', uploadTime: '2026-03-14 14:20:00', url: '' },
  369. { id: '5', filename: '背景音乐.mp3', fileType: 'audio', size: 3145728, uploader: '孙七', uploadTime: '2026-03-13 11:00:00', url: '' },
  370. { id: '6', filename: '数据库备份.sql', fileType: 'other', size: 10485760, uploader: '张三', uploadTime: '2026-03-13 09:30:00', url: '' },
  371. { id: '7', filename: '系统架构图.jpg', fileType: 'image', size: 1536000, uploader: '李四', uploadTime: '2026-03-12 15:20:00', url: 'https://via.placeholder.com/800x600.png?text=Architecture' },
  372. { id: '8', filename: 'API文档.pdf', fileType: 'document', size: 3145728, uploader: '王五', uploadTime: '2026-03-12 10:00:00', url: '' },
  373. { id: '9', filename: '测试报告.xlsx', fileType: 'document', size: 512000, uploader: '赵六', uploadTime: '2026-03-11 16:30:00', url: '' },
  374. { id: '10', filename: '部署脚本.sh', fileType: 'other', size: 10240, uploader: '孙七', uploadTime: '2026-03-11 09:00:00', url: '' },
  375. { id: '11', filename: '用户手册.pdf', fileType: 'document', size: 4194304, uploader: '张三', uploadTime: '2026-03-10 14:00:00', url: '' },
  376. { id: '12', filename: '团队合影.jpg', fileType: 'image', size: 2621440, uploader: '李四', uploadTime: '2026-03-10 10:30:00', url: 'https://via.placeholder.com/800x600.png?text=Team+Photo' },
  377. ];
  378. // 筛选
  379. let filteredFiles = allFiles.filter(file => {
  380. const matchName = filename ? file.filename.toLowerCase().includes(filename.toLowerCase()) : true;
  381. const matchType = fileType ? file.fileType === fileType : true;
  382. return matchName && matchType;
  383. });
  384. // 分页
  385. const total = filteredFiles.length;
  386. const start = (page - 1) * size;
  387. const end = start + size;
  388. const list = filteredFiles.slice(start, end);
  389. return {
  390. code: 200,
  391. message: "success",
  392. data: {
  393. list,
  394. total,
  395. page,
  396. size
  397. }
  398. };
  399. },
  400. },
  401. // 上传文件
  402. {
  403. url: "/api/file/upload",
  404. method: "post",
  405. response: () => {
  406. return {
  407. code: 200,
  408. message: "上传成功",
  409. data: {
  410. id: String(Date.now()),
  411. filename: '新上传文件.pdf',
  412. fileType: 'document',
  413. size: 1024000,
  414. uploader: 'admin',
  415. uploadTime: new Date().toLocaleString(),
  416. url: ''
  417. }
  418. };
  419. },
  420. },
  421. // 删除文件
  422. {
  423. url: "/api/file/delete",
  424. method: "delete",
  425. response: () => {
  426. return {
  427. code: 200,
  428. message: "删除成功",
  429. data: null
  430. };
  431. },
  432. },
  433. // 下载文件
  434. {
  435. url: "/api/file/download",
  436. method: "get",
  437. rawResponse: async (req, res) => {
  438. const url = new URL(req.url || '', `http://${req.headers.host}`);
  439. const id = url.searchParams.get('id') || 'unknown';
  440. const filename = `file_${id}.txt`;
  441. res.setHeader('Content-Type', 'application/octet-stream');
  442. res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
  443. res.write('This is a mock file content for download.');
  444. res.end();
  445. },
  446. },
  447. ] as MockMethod[];