From 26b9994d14d575d80af6670c6d1c175c282fd2a4 Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Thu, 10 Jun 2021 10:53:56 +0800 Subject: [PATCH] =?UTF-8?q?feat=20:=20=E4=BF=9D=E7=95=99mock?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/README.md | 1 + frontend/mock/index.js | 67 ++++++++++++++++++++++++ frontend/mock/mock-server.js | 68 ++++++++++++++++++++++++ frontend/mock/table.js | 29 +++++++++++ frontend/mock/user.js | 84 ++++++++++++++++++++++++++++++ frontend/package.json | 1 + frontend/src/api/table.js | 29 +++++++++++ frontend/src/views/table/index.vue | 79 ++++++++++++++++++++++++++++ frontend/vue.config.js | 4 +- 9 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 frontend/mock/index.js create mode 100644 frontend/mock/mock-server.js create mode 100644 frontend/mock/table.js create mode 100644 frontend/mock/user.js create mode 100644 frontend/src/api/table.js create mode 100644 frontend/src/views/table/index.vue diff --git a/frontend/README.md b/frontend/README.md index f405f912e5..c1b8d92e38 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -39,6 +39,7 @@ ```bash ├── build # 构建相关 +├── mock # 项目mock 模拟数据 ├── public # 静态资源 │ │── favicon.ico # favicon图标 │ └── index.html # html模板 diff --git a/frontend/mock/index.js b/frontend/mock/index.js new file mode 100644 index 0000000000..90e2ffe9ec --- /dev/null +++ b/frontend/mock/index.js @@ -0,0 +1,67 @@ +import Mock from 'mockjs' +import { param2Obj } from '../src/utils' + +import user from './user' +import table from './table' + +const mocks = [ + ...user, + ...table +] + +// for front mock +// please use it cautiously, it will redefine XMLHttpRequest, +// which will cause many of your third-party libraries to be invalidated(like progress event). +export function mockXHR() { + // mock patch + // https://github.com/nuysoft/Mock/issues/300 + Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send + Mock.XHR.prototype.send = function() { + if (this.custom.xhr) { + this.custom.xhr.withCredentials = this.withCredentials || false + + if (this.responseType) { + this.custom.xhr.responseType = this.responseType + } + } + this.proxy_send(...arguments) + } + + function XHR2ExpressReqWrap(respond) { + return function(options) { + let result = null + if (respond instanceof Function) { + const { body, type, url } = options + // https://expressjs.com/en/4x/api.html#req + result = respond({ + method: type, + body: JSON.parse(body), + query: param2Obj(url) + }) + } else { + result = respond + } + return Mock.mock(result) + } + } + + for (const i of mocks) { + Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response)) + } +} + +// for mock server +const responseFake = (url, type, respond) => { + return { + url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`), + type: type || 'get', + response(req, res) { + console.log('request invoke:' + req.path) + res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond)) + } + } +} + +export default mocks.map(route => { + return responseFake(route.url, route.type, route.response) +}) diff --git a/frontend/mock/mock-server.js b/frontend/mock/mock-server.js new file mode 100644 index 0000000000..4c4cb2af83 --- /dev/null +++ b/frontend/mock/mock-server.js @@ -0,0 +1,68 @@ +const chokidar = require('chokidar') +const bodyParser = require('body-parser') +const chalk = require('chalk') +const path = require('path') + +const mockDir = path.join(process.cwd(), 'mock') + +function registerRoutes(app) { + let mockLastIndex + const { default: mocks } = require('./index.js') + for (const mock of mocks) { + app[mock.type](mock.url, mock.response) + mockLastIndex = app._router.stack.length + } + const mockRoutesLength = Object.keys(mocks).length + return { + mockRoutesLength: mockRoutesLength, + mockStartIndex: mockLastIndex - mockRoutesLength + } +} + +function unregisterRoutes() { + Object.keys(require.cache).forEach(i => { + if (i.includes(mockDir)) { + delete require.cache[require.resolve(i)] + } + }) +} + +module.exports = app => { + // es6 polyfill + require('@babel/register') + + // parse app.body + // https://expressjs.com/en/4x/api.html#req.body + app.use(bodyParser.json()) + app.use(bodyParser.urlencoded({ + extended: true + })) + + const mockRoutes = registerRoutes(app) + var mockRoutesLength = mockRoutes.mockRoutesLength + var mockStartIndex = mockRoutes.mockStartIndex + + // watch files, hot reload mock server + chokidar.watch(mockDir, { + ignored: /mock-server/, + ignoreInitial: true + }).on('all', (event, path) => { + if (event === 'change' || event === 'add') { + try { + // remove mock routes stack + app._router.stack.splice(mockStartIndex, mockRoutesLength) + + // clear routes cache + unregisterRoutes() + + const mockRoutes = registerRoutes(app) + mockRoutesLength = mockRoutes.mockRoutesLength + mockStartIndex = mockRoutes.mockStartIndex + + console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`)) + } catch (error) { + console.log(chalk.redBright(error)) + } + } + }) +} diff --git a/frontend/mock/table.js b/frontend/mock/table.js new file mode 100644 index 0000000000..ba95f76426 --- /dev/null +++ b/frontend/mock/table.js @@ -0,0 +1,29 @@ +import Mock from 'mockjs' + +const data = Mock.mock({ + 'items|30': [{ + id: '@id', + title: '@sentence(10, 20)', + 'status|1': ['published', 'draft', 'deleted'], + author: 'name', + display_time: '@datetime', + pageviews: '@integer(300, 5000)' + }] +}) + +export default [ + { + url: '/vue-admin-template/table/list', + type: 'get', + response: config => { + const items = data.items + return { + code: 20000, + data: { + total: items.length, + items: items + } + } + } + } +] diff --git a/frontend/mock/user.js b/frontend/mock/user.js new file mode 100644 index 0000000000..f007cd98d7 --- /dev/null +++ b/frontend/mock/user.js @@ -0,0 +1,84 @@ + +const tokens = { + admin: { + token: 'admin-token' + }, + editor: { + token: 'editor-token' + } +} + +const users = { + 'admin-token': { + roles: ['admin'], + introduction: 'I am a super administrator', + avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', + name: 'Super Admin' + }, + 'editor-token': { + roles: ['editor'], + introduction: 'I am an editor', + avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', + name: 'Normal Editor' + } +} + +export default [ + // user login + { + url: '/vue-admin-template/user/login', + type: 'post', + response: config => { + const { username } = config.body + const token = tokens[username] + + // mock error + if (!token) { + return { + code: 60204, + message: 'Account and password are incorrect.' + } + } + + return { + code: 20000, + data: token + } + } + }, + + // get user info + { + url: '/vue-admin-template/user/info\.*', + type: 'get', + response: config => { + const { token } = config.query + const info = users[token] + + // mock error + if (!info) { + return { + code: 50008, + message: 'Login failed, unable to get user details.' + } + } + + return { + code: 20000, + data: info + } + } + }, + + // user logout + { + url: '/vue-admin-template/user/logout', + type: 'post', + response: _ => { + return { + code: 20000, + data: 'success' + } + } + } +] diff --git a/frontend/package.json b/frontend/package.json index 85d92355b4..abaab1bdb3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -60,6 +60,7 @@ "html-webpack-plugin": "3.2.0", "less": "^4.1.1", "less-loader": "^8.0.0", + "mockjs": "1.0.1-beta3", "runjs": "^4.1.3", "sass": "^1.32.5", "sass-loader": "^10.1.1", diff --git a/frontend/src/api/table.js b/frontend/src/api/table.js new file mode 100644 index 0000000000..7f7d7c9e43 --- /dev/null +++ b/frontend/src/api/table.js @@ -0,0 +1,29 @@ +import Mock from 'mockjs' +const data = Mock.mock({ + 'items|30': [{ + id: '@id', + title: '@sentence(10, 20)', + 'status|1': ['published', 'draft', 'deleted'], + author: 'name', + display_time: '@datetime', + pageviews: '@integer(300, 5000)' + }] +}) +export function getList(params) { +// return request({ +// url: '/vue-admin-template/table/list', +// method: 'get', +// params +// }) + return new Promise((resolve, reject) => { + const items = data.items + const result = { + code: 20000, + data: { + total: items.length, + items: items + } + } + resolve(result) + }) +} diff --git a/frontend/src/views/table/index.vue b/frontend/src/views/table/index.vue new file mode 100644 index 0000000000..9d72557fc4 --- /dev/null +++ b/frontend/src/views/table/index.vue @@ -0,0 +1,79 @@ + + + diff --git a/frontend/vue.config.js b/frontend/vue.config.js index f7c3465e9c..57748c2042 100644 --- a/frontend/vue.config.js +++ b/frontend/vue.config.js @@ -11,6 +11,7 @@ const name = defaultSettings.title || 'vue Admin Template' // page title const port = process.env.port || process.env.npm_config_port || 9528 // dev port module.exports = { productionSourceMap: true, + // 使用mock-server devServer: { port: port, proxy: { @@ -23,7 +24,8 @@ module.exports = { overlay: { warnings: false, errors: true - } + }, + before: require('./mock/mock-server.js') }, pages: { index: {