From 9cfa5cb149815de4a706ca1ffc2118d9b8b58019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?old=E6=98=93?= <156663459@qq.com> Date: Thu, 10 Jul 2025 16:07:57 +0800 Subject: [PATCH] a --- mock-db.json | 16 ++++ package-lock.json | 28 ++++++ package.json | 1 + server.js | 240 +++++++++++++++++++++++++--------------------- 4 files changed, 177 insertions(+), 108 deletions(-) create mode 100644 mock-db.json diff --git a/mock-db.json b/mock-db.json new file mode 100644 index 0000000..c5000e3 --- /dev/null +++ b/mock-db.json @@ -0,0 +1,16 @@ +{ + "addresses": [ + { + "id": 1, + "name": "刘先生", + "phone": "134****7788", + "fullAddress": "山东省济南市某某区幸福小区5号10楼1003室", + "isDefault": true, + "locationStatus": "正常", + "canEdit": true, + "canDelete": true + } + ], + "products": [], + "orders": [] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a4063c7..092394f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "dayjs": "^1.11.13", "express": "^5.1.0", "fs-extra": "^11.3.0", + "lowdb": "^3.0.0", "mockjs": "^1.1.0", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.1" @@ -695,6 +696,21 @@ "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", "license": "MIT" }, + "node_modules/lowdb": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/lowdb/-/lowdb-3.0.0.tgz", + "integrity": "sha512-9KZRulmIcU8fZuWiaM0d5e2/nPnrFyXkeXVpqT+MJS+vgbgOf1EbtvgQmba8HwUFgDl1oeZR6XqEJnkJmQdKmg==", + "license": "MIT", + "dependencies": { + "steno": "^2.1.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1082,6 +1098,18 @@ "node": ">= 0.8" } }, + "node_modules/steno": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/steno/-/steno-2.1.0.tgz", + "integrity": "sha512-mauOsiaqTNGFkWqIfwcm3y/fq+qKKaIWf1vf3ocOuTdco9XoHCO2AGF1gFYXuZFSWuP38Q8LBHBGJv2KnJSXyA==", + "license": "MIT", + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/swagger-jsdoc": { "version": "6.2.8", "resolved": "https://registry.npmmirror.com/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz", diff --git a/package.json b/package.json index 540837f..f525b35 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "dayjs": "^1.11.13", "express": "^5.1.0", "fs-extra": "^11.3.0", + "lowdb": "^3.0.0", "mockjs": "^1.1.0", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.1" diff --git a/server.js b/server.js index 2eac948..0590255 100644 --- a/server.js +++ b/server.js @@ -3,21 +3,17 @@ const bodyParser = require('body-parser'); const Mock = require('mockjs'); const fs = require('fs-extra'); const dayjs = require('dayjs'); - -// ✅ 引入 swagger 组件 const swaggerUi = require('swagger-ui-express'); const swaggerJSDoc = require('swagger-jsdoc'); +const { Low, JSONFile } = require('lowdb'); const app = express(); const PORT = 3000; const CONFIG_PATH = './mock-config.json'; +const DB_PATH = './mock-db.json'; app.use(bodyParser.json()); -// 加载配置文件 -let mockConfigs = fs.existsSync(CONFIG_PATH) ? fs.readJsonSync(CONFIG_PATH) : []; - -// ✅ 统一响应结构 function formatResponse(data, code = 200, message = 'success') { return { code, @@ -29,13 +25,54 @@ function formatResponse(data, code = 200, message = 'success') { }; } -// ✅ 注册 mock 接口 function registerMockApi(config) { const { method, path, response } = config; const methodName = method.toLowerCase(); - app[methodName](path, (req, res) => { + app[methodName](path, async (req, res) => { try { + // 地址模块逻辑 + if (path === '/api/user/address/list') { + await global.db.read(); + return res.json(formatResponse({ list: global.db.data.addresses })); + } + if (path === '/api/user/address/add') { + const newItem = { id: Date.now(), ...req.body }; + await global.db.read(); + global.db.data.addresses.push(newItem); + await global.db.write(); + return res.json(formatResponse({ id: newItem.id }, 200, '地址新增成功')); + } + if (path === '/api/user/address/update') { + const { id, ...rest } = req.body; + await global.db.read(); + const item = global.db.data.addresses.find(i => i.id == id); + if (item) Object.assign(item, rest); + await global.db.write(); + return res.json(formatResponse(null, 200, '地址已更新')); + } + if (path === '/api/user/address/delete') { + const { id } = req.body; + await global.db.read(); + global.db.data.addresses = global.db.data.addresses.filter(i => i.id != id); + await global.db.write(); + return res.json(formatResponse(null, 200, '地址已删除')); + } + if (path === '/api/user/address/set-default') { + const { id } = req.body; + await global.db.read(); + global.db.data.addresses.forEach(i => i.isDefault = i.id == id); + await global.db.write(); + return res.json(formatResponse(null, 200, '已设置为默认地址')); + } + if (path === '/api/user/address/detail') { + const { id } = req.query; + await global.db.read(); + const item = global.db.data.addresses.find(i => i.id == id); + return res.json(formatResponse(item || null)); + } + + // 其他静态 mock 响应 const data = Mock.mock(response); res.json(formatResponse(data)); } catch (err) { @@ -44,110 +81,97 @@ function registerMockApi(config) { }); } -// 初始注册全部 -mockConfigs.forEach(registerMockApi); +async function startServer() { + // 初始化 lowdb + const adapter = new JSONFile(DB_PATH); + const db = new Low(adapter); + await db.read(); + db.data ||= { addresses: [], products: [], orders: [] }; + await db.write(); + global.db = db; -// ✅ 添加新接口 -app.post('/mock-api/add', async (req, res) => { - const config = req.body; - if (!config.method || !config.path || !config.response) { - return res.json(formatResponse(null, 400, '参数不完整')); - } + // 加载配置文件 + let mockConfigs = fs.existsSync(CONFIG_PATH) ? fs.readJsonSync(CONFIG_PATH) : []; + global.mockConfigs = mockConfigs; + mockConfigs.forEach(registerMockApi); - registerMockApi(config); - mockConfigs.push(config); - await fs.writeJson(CONFIG_PATH, mockConfigs, { spaces: 2 }); - - res.json(formatResponse({ path: config.path }, 200, '接口已添加')); -}); - -// ✅ 获取全部 mock 定义 -app.get('/mock-api/list', (req, res) => { - res.json(formatResponse(mockConfigs)); -}); - -// ✅ 获取所有 URL 路由(简版) -app.get('/mock-api/routes', (req, res) => { - const list = mockConfigs.map(({ method, path }) => ({ method, path })); - res.json(list); -}); - -// ✅ Swagger 配置 -const swaggerDefinition = { - openapi: '3.0.0', - info: { - title: 'Mock API Docs', - version: '1.0.0', - description: 'Dynamically registered mock APIs' - }, - servers: [] // 将由请求动态生成 -}; - -function buildSwaggerSpecFromMocks(configs) { - const paths = {}; - - configs.forEach(({ method, path, swagger }) => { - const cleanPath = path.replace(/:([^/]+)/g, '{$1}'); - const methodName = method.toLowerCase(); - - const summary = swagger?.summary || `Mocked ${method} ${path}`; - const description = swagger?.description || ''; - const responses = swagger?.responses || { - 200: { - description: 'Mock response', - content: { - 'application/json': { - schema: { type: 'object' } - } - } - } - }; - - paths[cleanPath] = paths[cleanPath] || {}; - paths[cleanPath][methodName] = { - summary, - description, - responses - }; + // 添加 mock 接口 + app.post('/mock-api/add', async (req, res) => { + const config = req.body; + if (!config.method || !config.path || !config.response) { + return res.json(formatResponse(null, 400, '参数不完整')); + } + registerMockApi(config); + global.mockConfigs.push(config); + await fs.writeJson(CONFIG_PATH, global.mockConfigs, { spaces: 2 }); + res.json(formatResponse({ path: config.path }, 200, '接口已添加')); }); - return { - ...swaggerDefinition, - paths + app.get('/mock-api/list', (req, res) => { + res.json(formatResponse(global.mockConfigs)); + }); + + app.get('/mock-api/routes', (req, res) => { + const list = global.mockConfigs.map(({ method, path }) => ({ method, path })); + res.json(list); + }); + + const swaggerDefinition = { + openapi: '3.0.0', + info: { + title: 'Mock API Docs', + version: '1.0.0', + description: 'Dynamically registered mock APIs' + }, + servers: [] }; + + function buildSwaggerSpecFromMocks(configs) { + const paths = {}; + configs.forEach(({ method, path, swagger }) => { + const cleanPath = path.replace(/:([^/]+)/g, '{$1}'); + const methodName = method.toLowerCase(); + const summary = swagger?.summary || `Mocked ${method} ${path}`; + const description = swagger?.description || ''; + const responses = swagger?.responses || { + 200: { + description: 'Mock response', + content: { + 'application/json': { + schema: { type: 'object' } + } + } + } + }; + paths[cleanPath] = paths[cleanPath] || {}; + paths[cleanPath][methodName] = { summary, description, responses }; + }); + return { ...swaggerDefinition, paths }; + } + + app.use('/swagger', (req, res, next) => { + res.setHeader('Cache-Control', 'no-store'); + next(); + }); + + app.use('/swagger', swaggerUi.serve, (req, res, next) => { + const protocol = req.headers['x-forwarded-proto'] || req.protocol; + const host = req.get('host'); + const dynamicSwaggerDefinition = { + ...swaggerDefinition, + servers: [ + { url: `${protocol}://${host}`, description: 'Current host' } + ] + }; + const spec = buildSwaggerSpecFromMocks(global.mockConfigs); + const dynamicSpec = { ...spec, servers: dynamicSwaggerDefinition.servers }; + swaggerUi.setup(dynamicSpec)(req, res, next); + }); + + app.listen(PORT, () => { + console.log(`✅ Mock Server is running at http://localhost:${PORT}`); + console.log(`📚 Swagger UI available at http://localhost:${PORT}/swagger`); + }); } -// ✅ Swagger UI 路由 -app.use('/swagger', (req, res, next) => { - res.setHeader('Cache-Control', 'no-store'); - next(); -}); - -app.use('/swagger', swaggerUi.serve, (req, res, next) => { - const protocol = req.headers['x-forwarded-proto'] || req.protocol; - const host = req.get('host'); - - const dynamicSwaggerDefinition = { - ...swaggerDefinition, - servers: [ - { - url: `${protocol}://${host}`, - description: 'Current host' - } - ] - }; - - const spec = buildSwaggerSpecFromMocks(mockConfigs); - const dynamicSpec = { - ...spec, - servers: dynamicSwaggerDefinition.servers - }; - - swaggerUi.setup(dynamicSpec)(req, res, next); -}); - -// ✅ 启动服务 -app.listen(PORT, () => { - console.log(`✅ Mock Server is running at http://localhost:${PORT}`); - console.log(`📚 Swagger UI available at http://localhost:${PORT}/swagger`); -}); \ No newline at end of file +startServer();