diff --git a/.prettierignore b/.prettierignore index d0b0ca13348..e1cb99594ec 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,7 +6,6 @@ node_modules .nvmrc coverage CODEOWNERS -.nitro .output diff --git a/apps/backend-mock/.env b/apps/backend-mock/.env deleted file mode 100644 index 9f0c6237f62..00000000000 --- a/apps/backend-mock/.env +++ /dev/null @@ -1 +0,0 @@ -PORT=5320 diff --git a/apps/backend-mock/.eslintignore b/apps/backend-mock/.eslintignore new file mode 100644 index 00000000000..b33f9b32737 --- /dev/null +++ b/apps/backend-mock/.eslintignore @@ -0,0 +1 @@ +/**/* diff --git a/apps/backend-mock/README.md b/apps/backend-mock/README.md index d303352e721..cd79caee861 100644 --- a/apps/backend-mock/README.md +++ b/apps/backend-mock/README.md @@ -2,14 +2,32 @@ ## Description -Vben Admin 数据 mock 服务,没有对接任何的数据库,所有数据都是模拟的,用于前端开发时提供数据支持。由于 sqlite 安装需要在本地进行编译,所以这里接口是直接返回的。线上环境不再提供mock集成,可自行部署服务或者对接真实数据,同步 mock.js等工具有一些限制,比如上传文件不行、无法模拟复杂的逻辑等,所以这里使用了 真是的后端服务来实现。唯一麻烦的是本地需要同时启动后端服务和前端服务,但是这样可以更好的模拟真实环境。 +Vben Admin 数据 mock 服务,没有对接任何的数据库,所有数据都是模拟的,用于前端开发时提供数据支持。无需安装数据实现基于 json 的类数据库存储。线上环境不再提供mock集成,可自行部署服务或者对接真实数据,避免在前端直接使用 mock.js 存在的一些限制,比如上传文件不行、无法模拟复杂的逻辑等,所以这里使用了真实的后端服务来实现。唯一麻烦的是本地需要同时启动后端服务和前端服务,但是这样可以更好的模拟真实环境。 + +文件说明如下: + +``` +./ + - api/ -- 手动创建的 api + - httpData/ -- 请求记录, 一般不提交到版本库 + - apiWeb.json -- 从 UI 界面上创建的接口数据 + - util.js -- 一些公用方法 + - mm.config.js -- mockm 的配置文件 +``` ## Running the app ```bash # development -$ pnpm run start +pnpm i +pnpm mm # production mode -$ pnpm run build +# 同 development ``` + +## 参考 + +- [mockm 代码仓库](https://github.com/wll8/mockm/) +- [mockm 文档](https://hongqiye.com/doc/mockm/) +- [mockjs 文档](https://wll8.github.io/mockjs-examples/) diff --git a/apps/backend-mock/api/auth.cjs b/apps/backend-mock/api/auth.cjs new file mode 100644 index 00000000000..c862585e89d --- /dev/null +++ b/apps/backend-mock/api/auth.cjs @@ -0,0 +1,43 @@ +/* eslint-disable */ + +const { + wrapApiData, + useResponseSuccess, + useResponseError, + MOCK_USERS, + MOCK_CODES, + MOCK_MENUS, + } = require(`../util.cjs`) + +/** @type {import('mockm/@types/config').Config} */ +module.exports = util => { + const { + libObj: { mockjs }, + } = util + return { + api: { + '/api/auth/codes'(req, res) { + const codes = MOCK_CODES.find((item) => item.username === req.username)?.codes ?? []; + res.json(useResponseSuccess(codes)) + }, + 'post /api/auth/login'(req, res) { + const { password, username } = req.body; + + const findUser = MOCK_USERS.find( + (item) => item.username === username && item.password === password, + ); + + if (!findUser) { + return res.status(403).json(useResponseError('UnauthorizedException', '用户名或密码错误')) + } + + const accessToken = Buffer.from(username).toString('base64'); + res.json(useResponseSuccess({ + accessToken, + // TODO: refresh token + refreshToken: accessToken, + })); + }, + }, + } +} diff --git a/apps/backend-mock/api/auth/codes.ts b/apps/backend-mock/api/auth/codes.ts deleted file mode 100644 index 7e5b597f4bb..00000000000 --- a/apps/backend-mock/api/auth/codes.ts +++ /dev/null @@ -1,15 +0,0 @@ -export default eventHandler((event) => { - const token = getHeader(event, 'Authorization'); - - if (!token) { - setResponseStatus(event, 401); - return useResponseError('UnauthorizedException', 'Unauthorized Exception'); - } - - const username = Buffer.from(token, 'base64').toString('utf8'); - - const codes = - MOCK_CODES.find((item) => item.username === username)?.codes ?? []; - - return useResponseSuccess(codes); -}); diff --git a/apps/backend-mock/api/auth/login.post.ts b/apps/backend-mock/api/auth/login.post.ts deleted file mode 100644 index 2344742ca28..00000000000 --- a/apps/backend-mock/api/auth/login.post.ts +++ /dev/null @@ -1,20 +0,0 @@ -export default defineEventHandler(async (event) => { - const { password, username } = await readBody(event); - - const findUser = MOCK_USERS.find( - (item) => item.username === username && item.password === password, - ); - - if (!findUser) { - setResponseStatus(event, 403); - return useResponseError('UnauthorizedException', '用户名或密码错误'); - } - - const accessToken = Buffer.from(username).toString('base64'); - - return useResponseSuccess({ - accessToken, - // TODO: refresh token - refreshToken: accessToken, - }); -}); diff --git a/apps/backend-mock/api/menu.cjs b/apps/backend-mock/api/menu.cjs new file mode 100644 index 00000000000..e271c49a3f5 --- /dev/null +++ b/apps/backend-mock/api/menu.cjs @@ -0,0 +1,26 @@ +/* eslint-disable */ + +const { + wrapApiData, + useResponseSuccess, + useResponseError, + MOCK_USERS, + MOCK_CODES, + MOCK_MENUS, + } = require(`../util.cjs`) + +/** @type {import('mockm/@types/config').Config} */ +module.exports = util => { + const { + libObj: { mockjs }, + } = util + return { + api: { + '/api/menu/all'(req, res){ + const menus = MOCK_MENUS.find((item) => item.username === req.username)?.menus ?? []; + res.json(useResponseSuccess(menus)) + + }, + }, + } +} diff --git a/apps/backend-mock/api/menu/all.ts b/apps/backend-mock/api/menu/all.ts deleted file mode 100644 index 424d657a5ad..00000000000 --- a/apps/backend-mock/api/menu/all.ts +++ /dev/null @@ -1,14 +0,0 @@ -export default eventHandler((event) => { - const token = getHeader(event, 'Authorization'); - - if (!token) { - setResponseStatus(event, 401); - return useResponseError('UnauthorizedException', 'Unauthorized Exception'); - } - - const username = Buffer.from(token, 'base64').toString('utf8'); - - const menus = - MOCK_MENUS.find((item) => item.username === username)?.menus ?? []; - return useResponseSuccess(menus); -}); diff --git a/apps/backend-mock/api/status.ts b/apps/backend-mock/api/status.ts deleted file mode 100644 index 41773e1d5ce..00000000000 --- a/apps/backend-mock/api/status.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default eventHandler((event) => { - const { status } = getQuery(event); - setResponseStatus(event, Number(status)); - return useResponseError(`${status}`); -}); diff --git a/apps/backend-mock/api/test.get.ts b/apps/backend-mock/api/test.get.ts deleted file mode 100644 index ca4a500bef1..00000000000 --- a/apps/backend-mock/api/test.get.ts +++ /dev/null @@ -1 +0,0 @@ -export default defineEventHandler(() => 'Test get handler'); diff --git a/apps/backend-mock/api/test.post.ts b/apps/backend-mock/api/test.post.ts deleted file mode 100644 index 698cf211ede..00000000000 --- a/apps/backend-mock/api/test.post.ts +++ /dev/null @@ -1 +0,0 @@ -export default defineEventHandler(() => 'Test post handler'); diff --git a/apps/backend-mock/api/user.cjs b/apps/backend-mock/api/user.cjs new file mode 100644 index 00000000000..ca153641eb7 --- /dev/null +++ b/apps/backend-mock/api/user.cjs @@ -0,0 +1,25 @@ +const { + wrapApiData, + useResponseSuccess, + useResponseError, + MOCK_USERS, + MOCK_CODES, + MOCK_MENUS, + } = require(`../util.cjs`) + +/** @type {import('mockm/@types/config').Config} */ +module.exports = util => { + const { + libObj: { mockjs }, + } = util + return { + api: { + '/api/user/info'(req, res) { + const user = MOCK_USERS.find((item) => item.username === req.username); + + const { password: _pwd, ...userInfo } = user; + res.json(useResponseSuccess(user)) + }, + }, + } +} diff --git a/apps/backend-mock/api/user/info.ts b/apps/backend-mock/api/user/info.ts deleted file mode 100644 index 81a141b1249..00000000000 --- a/apps/backend-mock/api/user/info.ts +++ /dev/null @@ -1,14 +0,0 @@ -export default eventHandler((event) => { - const token = getHeader(event, 'Authorization'); - if (!token) { - setResponseStatus(event, 401); - return useResponseError('UnauthorizedException', 'Unauthorized Exception'); - } - - const username = Buffer.from(token, 'base64').toString('utf8'); - - const user = MOCK_USERS.find((item) => item.username === username); - - const { password: _pwd, ...userInfo } = user; - return useResponseSuccess(userInfo); -}); diff --git a/apps/backend-mock/apiWeb.json b/apps/backend-mock/apiWeb.json new file mode 100644 index 00000000000..b576de90e04 --- /dev/null +++ b/apps/backend-mock/apiWeb.json @@ -0,0 +1,4 @@ +{ + "paths": {}, + "disable": [] +} \ No newline at end of file diff --git a/apps/backend-mock/error.ts b/apps/backend-mock/error.ts deleted file mode 100644 index 5d3d247adbc..00000000000 --- a/apps/backend-mock/error.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { NitroErrorHandler } from 'nitropack'; - -const errorHandler: NitroErrorHandler = function (error, event) { - event.res.end(`[error handler] ${error.stack}`); -}; - -export default errorHandler; diff --git a/apps/backend-mock/httpData/.gitignore b/apps/backend-mock/httpData/.gitignore new file mode 100644 index 00000000000..fb1e814dbfe --- /dev/null +++ b/apps/backend-mock/httpData/.gitignore @@ -0,0 +1,6 @@ +openApiHistory/ +request/ +db.json +httpHistory.json +log.err.txt +store.json \ No newline at end of file diff --git a/apps/backend-mock/httpData/apiWeb.json b/apps/backend-mock/httpData/apiWeb.json new file mode 100644 index 00000000000..b576de90e04 --- /dev/null +++ b/apps/backend-mock/httpData/apiWeb.json @@ -0,0 +1,4 @@ +{ + "paths": {}, + "disable": [] +} \ No newline at end of file diff --git a/apps/backend-mock/middleware/1.api.ts b/apps/backend-mock/middleware/1.api.ts deleted file mode 100644 index 315d7e0cd2b..00000000000 --- a/apps/backend-mock/middleware/1.api.ts +++ /dev/null @@ -1,14 +0,0 @@ -export default defineEventHandler((event) => { - // setResponseHeaders(event, { - // 'Access-Control-Allow-Credentials': 'true', - // 'Access-Control-Allow-Headers': '*', - // 'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE', - // 'Access-Control-Allow-Origin': '*', - // 'Access-Control-Expose-Headers': '*', - // }); - if (event.method === 'OPTIONS') { - event.node.res.statusCode = 204; - event.node.res.statusMessage = 'No Content.'; - return 'OK'; - } -}); diff --git a/apps/backend-mock/mm.config.cjs b/apps/backend-mock/mm.config.cjs new file mode 100644 index 00000000000..1a2a6a12404 --- /dev/null +++ b/apps/backend-mock/mm.config.cjs @@ -0,0 +1,63 @@ +const { + wrapApiData, + useResponseSuccess, + useResponseError, +} = require(`./util.cjs`) + +/** + * 配置说明请参考文档: + * https://hongqiye.com/doc/mockm/config/option.html + * @type {import('mockm/@types/config').Config} + */ +module.exports = util => { + return { + watch: [`./api/`], + plugin: [], + proxy: { + '/': `http://www.httpbin.org/`, // 后端接口主域 + }, + api: { + 'use /'(req, res, next){ + const noCheckList = [ + `/`, + `/public`, + `/favicon.ico`, + `/api/test`, + `/api/status`, + `/api/auth/login`, + ] + if( req.path === `/` || noCheckList.some(item => { + return item.startsWith(req.path) + })) { + next() + } else { + const token = req.get(`Authorization`) + if (token) { + const username = Buffer.from(token, 'base64').toString('utf8'); + req.username = username; + } else { + return res.status(401).json(useResponseError('UnauthorizedException', 'Unauthorized Exception')) + } + next() + } + }, + // 跳转到接口列表 + '/api'(req, res){ + const url = `http://127.0.0.1:${globalThis.config.testPort}/#/apiStudio` + res.redirect(url) + }, + ...require(`./api/auth.cjs`)(util).api, + ...require(`./api/menu.cjs`)(util).api, + ...require(`./api/user.cjs`)(util).api, + '/api/status'(req, res) { + const { status } = req.query + res.status(status).json(useResponseError()) + }, + 'get /api/test': `Test get handler`, + 'post /api/test': `Test post handler`, + }, + static: [], + resHandleReplay: ({req, res}) => useResponseSuccess({}), + resHandleJsonApi: ({req, res: {statusCode: code}, data}) => wrapApiData({code, data}), + } +} diff --git a/apps/backend-mock/nitro.config.ts b/apps/backend-mock/nitro.config.ts deleted file mode 100644 index b3013298de4..00000000000 --- a/apps/backend-mock/nitro.config.ts +++ /dev/null @@ -1,18 +0,0 @@ -import errorHandler from './error'; - -export default defineNitroConfig({ - devErrorHandler: errorHandler, - errorHandler: '~/error', - routeRules: { - '/api/**': { - cors: true, - headers: { - 'Access-Control-Allow-Credentials': 'true', - 'Access-Control-Allow-Headers': '*', - 'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE', - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Expose-Headers': '*', - }, - }, - }, -}); diff --git a/apps/backend-mock/package.json b/apps/backend-mock/package.json index 5a45611b94c..1f683a98949 100644 --- a/apps/backend-mock/package.json +++ b/apps/backend-mock/package.json @@ -5,11 +5,11 @@ "private": true, "license": "MIT", "author": "", + "type": "commonjs", "scripts": { - "start": "nitro dev", - "build": "nitro build" + "mm": "npx mockm port=5320 --config=mm.config.cjs" }, - "dependencies": { - "nitropack": "^2.9.7" + "devDependencies": { + "mockm": "1.1.27-alpha.2" } } diff --git a/apps/backend-mock/routes/[...].ts b/apps/backend-mock/routes/[...].ts deleted file mode 100644 index 70c5f7c745d..00000000000 --- a/apps/backend-mock/routes/[...].ts +++ /dev/null @@ -1,12 +0,0 @@ -export default defineEventHandler(() => { - return ` -

Hello Vben Admin

-

Mock service is starting

- -`; -}); diff --git a/apps/backend-mock/tsconfig.build.json b/apps/backend-mock/tsconfig.build.json deleted file mode 100644 index 64f86c6bd2b..00000000000 --- a/apps/backend-mock/tsconfig.build.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "./tsconfig.json", - "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] -} diff --git a/apps/backend-mock/tsconfig.json b/apps/backend-mock/tsconfig.json deleted file mode 100644 index 43008af1c71..00000000000 --- a/apps/backend-mock/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "./.nitro/types/tsconfig.json" -} diff --git a/apps/backend-mock/utils/mock-data.ts b/apps/backend-mock/util.cjs similarity index 83% rename from apps/backend-mock/utils/mock-data.ts rename to apps/backend-mock/util.cjs index 46c0e5a2bbb..9d4a676cedc 100644 --- a/apps/backend-mock/utils/mock-data.ts +++ b/apps/backend-mock/util.cjs @@ -1,4 +1,37 @@ -export const MOCK_USERS = [ +/** + * 包裹 api 的返回值 + * @param {*} param0 + * @param {object} param0.data - 原始数据 + * @param {number|string} [param0.code] - http状态码 + * @returns + */ +function wrapApiData({ code = 200, data }) { + code = String(code); + const res = code.startsWith('2') + ? useResponseSuccess(data) + : useResponseError(`Error`, code); + return res; +} + +function useResponseSuccess(data) { + return { + code: 0, + data, + error: null, + message: 'ok', + }; +} + +function useResponseError(message, error) { + return { + code: -1, + data: null, + error, + message, + }; +} + +const MOCK_USERS = [ { id: 0, password: '123456', @@ -22,7 +55,7 @@ export const MOCK_USERS = [ }, ]; -export const MOCK_CODES = [ +const MOCK_CODES = [ // super { codes: ['AC_100100', 'AC_100110', 'AC_100120', 'AC_100010'], @@ -72,7 +105,7 @@ const dashboardMenus = [ }, ]; -const createDemosMenus = (role: 'admin' | 'super' | 'user') => { +const createDemosMenus = (role) => { const roleWithMenus = { admin: { component: '/demos/access/admin-visible', @@ -162,7 +195,7 @@ const createDemosMenus = (role: 'admin' | 'super' | 'user') => { ]; }; -export const MOCK_MENUS = [ +const MOCK_MENUS = [ { menus: [...dashboardMenus, ...createDemosMenus('super')], username: 'vben', @@ -176,3 +209,12 @@ export const MOCK_MENUS = [ username: 'jack', }, ]; + +module.exports = { + MOCK_CODES, + MOCK_MENUS, + MOCK_USERS, + useResponseError, + useResponseSuccess, + wrapApiData, +}; diff --git a/apps/backend-mock/utils/response.ts b/apps/backend-mock/utils/response.ts deleted file mode 100644 index 83f11d2a247..00000000000 --- a/apps/backend-mock/utils/response.ts +++ /dev/null @@ -1,17 +0,0 @@ -export function useResponseSuccess(data: T) { - return { - code: 0, - data, - error: null, - message: 'ok', - }; -} - -export function useResponseError(message: string, error: any = null) { - return { - code: -1, - data: null, - error, - message, - }; -} diff --git a/apps/web-antd/.env.development b/apps/web-antd/.env.development index dcf361e730e..ed1be02a431 100644 --- a/apps/web-antd/.env.development +++ b/apps/web-antd/.env.development @@ -6,8 +6,8 @@ VITE_BASE=/ # 接口地址 VITE_GLOB_API_URL=/api -# 是否开启 Nitro Mock服务,true 为开启,false 为关闭 -VITE_NITRO_MOCK=true +# 是否开启 Mockm Mock服务,true 为开启,false 为关闭 +VITE_MOCKM_MOCK=true # 是否打开 devtools,true 为打开,false 为关闭 VITE_DEVTOOLS=false diff --git a/apps/web-antd/vite.config.mts b/apps/web-antd/vite.config.mts index b6360f1d4ac..190f530c89b 100644 --- a/apps/web-antd/vite.config.mts +++ b/apps/web-antd/vite.config.mts @@ -10,7 +10,7 @@ export default defineConfig(async () => { changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, ''), // mock代理目标地址 - target: 'http://localhost:5320/api', + target: 'http://127.0.0.1:5320/api', ws: true, }, }, diff --git a/apps/web-ele/.env.development b/apps/web-ele/.env.development index c138f482918..a4d2e7a0dc2 100644 --- a/apps/web-ele/.env.development +++ b/apps/web-ele/.env.development @@ -6,8 +6,8 @@ VITE_BASE=/ # 接口地址 VITE_GLOB_API_URL=/api -# 是否开启 Nitro Mock服务,true 为开启,false 为关闭 -VITE_NITRO_MOCK=true +# 是否开启 Mockm Mock服务,true 为开启,false 为关闭 +VITE_MOCKM_MOCK=true # 是否打开 devtools,true 为打开,false 为关闭 VITE_DEVTOOLS=false diff --git a/apps/web-ele/vite.config.mts b/apps/web-ele/vite.config.mts index 9f1e7235379..9865412e427 100644 --- a/apps/web-ele/vite.config.mts +++ b/apps/web-ele/vite.config.mts @@ -17,7 +17,7 @@ export default defineConfig(async () => { changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, ''), // mock代理目标地址 - target: 'http://localhost:5320/api', + target: 'http://127.0.0.1:5320/api', ws: true, }, }, diff --git a/apps/web-naive/.env.development b/apps/web-naive/.env.development index 8bcb432e6d0..6a02e40c272 100644 --- a/apps/web-naive/.env.development +++ b/apps/web-naive/.env.development @@ -6,8 +6,8 @@ VITE_BASE=/ # 接口地址 VITE_GLOB_API_URL=/api -# 是否开启 Nitro Mock服务,true 为开启,false 为关闭 -VITE_NITRO_MOCK=true +# 是否开启 Mockm Mock服务,true 为开启,false 为关闭 +VITE_MOCKM_MOCK=true # 是否打开 devtools,true 为打开,false 为关闭 VITE_DEVTOOLS=false diff --git a/apps/web-naive/vite.config.mts b/apps/web-naive/vite.config.mts index b6360f1d4ac..190f530c89b 100644 --- a/apps/web-naive/vite.config.mts +++ b/apps/web-naive/vite.config.mts @@ -10,7 +10,7 @@ export default defineConfig(async () => { changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, ''), // mock代理目标地址 - target: 'http://localhost:5320/api', + target: 'http://127.0.0.1:5320/api', ws: true, }, }, diff --git a/docs/src/en/index.md b/docs/src/en/index.md index 8249a2b2fdd..bc0cb2e042e 100644 --- a/docs/src/en/index.md +++ b/docs/src/en/index.md @@ -48,10 +48,10 @@ features: icon: src: /logos/turborepo.svg details: 规范且标准的大仓架构,使用 pnpm + monorepo + turbo 工程管理模式,提供企业级开发规范。 - - title: Nitro Mock Server + - title: Mockm Mock Server icon: src: /logos/nitro.svg - details: 内置 Nitro Mock 服务,让你的 mock 服务更加强大。 + details: 内置 Mockm Mock 服务,让你的 mock 服务更加强大。 ---