diff --git a/Dockerfile b/Dockerfile index ddeffbad..877c5c46 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,12 +21,11 @@ COPY . /xiaoju-survey RUN npm config set registry https://registry.npmjs.org/ # 安装项目依赖 -RUN cd /xiaoju-survey/web && npm install -RUN cd /xiaoju-survey/server && npm install +RUN cd /xiaoju-survey/web && npm install && npm run build -# 构建项目,并把产物推送到服务公共目录 -RUN cd /xiaoju-survey/web && npm run build -RUN cd /xiaoju-survey && cp -af ./web/dist/* ./server/src/apps/ui/public/ +RUN cd /xiaoju-survey/server && npm install && npm run build + +RUN cd /xiaoju-survey && mkdir -p ./build/apps/ui/public/ && cp -af ./web/dist/* ./server/build/apps/ui/public/ # 暴露端口 需要跟server的port一致 EXPOSE 3000 diff --git a/server/.eslintrc.json b/server/.eslintrc.json new file mode 100644 index 00000000..ae361159 --- /dev/null +++ b/server/.eslintrc.json @@ -0,0 +1,42 @@ +{ + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "indent": [ + "error", + 2 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "always" + ], + "space-in-parens": ["error", "never"], + "key-spacing": ["error", { "mode": "strict" }], + "comma-spacing": ["error", { "before": false, "after": true }], + "arrow-spacing": ["error", { "before": true, "after": true }], + "space-before-blocks": 2, + "object-curly-spacing": ["error", "always"] + } +} \ No newline at end of file diff --git a/server/package.json b/server/package.json index 8a6cc097..f8bfe74b 100644 --- a/server/package.json +++ b/server/package.json @@ -5,9 +5,9 @@ "main": "index.js", "scripts": { "build": "tsc", - "start:stable": "npm run build && SERVER_ENV=stable node ./build/index.js", - "start:preonline": "npm run build && SERVER_ENV=preonline node ./build/index.js", - "start:online": "npm run build && SERVER_ENV=online node ./build/index.js", + "start:stable": "SERVER_ENV=stable node ./build/index.js", + "start:preonline": "SERVER_ENV=preonline node ./build/index.js", + "start:online": "SERVER_ENV=online node ./build/index.js", "start": "npm run start:online", "local": "npx ts-node scripts/run-local.ts", "dev": "npx ts-node-dev ./src/index.ts" @@ -17,7 +17,11 @@ "@types/koa": "^2.13.8", "@types/koa-bodyparser": "^4.3.10", "@types/koa-router": "^7.4.4", + "@types/koa-static": "^4.0.4", + "@typescript-eslint/eslint-plugin": "^6.15.0", + "@typescript-eslint/parser": "^6.15.0", "cross-env": "^7.0.3", + "eslint": "^8.56.0", "mongodb-memory-server": "^9.0.1", "nodemon": "^2.0.20", "ts-node": "^10.9.2", @@ -26,12 +30,14 @@ }, "dependencies": { "crypto-js": "^4.2.0", + "glob": "^10.3.10", "joi": "^17.9.2", "jsonwebtoken": "^9.0.1", "koa": "^2.14.2", "koa-bodyparser": "^4.4.1", "koa-pino-logger": "^4.0.0", "koa-router": "^12.0.0", + "koa-static": "^4.0.3", "lodash": "^4.17.21", "moment": "^2.29.4", "mongodb": "^5.7.0", diff --git a/server/src/apps/security/config/index.ts b/server/src/apps/security/config/index.ts index 80fc5f03..e13a5b72 100644 --- a/server/src/apps/security/config/index.ts +++ b/server/src/apps/security/config/index.ts @@ -1,10 +1,10 @@ const config = { - mongo: { - url: process.env.xiaojuSurveyMongoUrl || 'mongodb://localhost:27017', - dbName: 'xiaojuSurvey' - } -} + mongo: { + url: process.env.xiaojuSurveyMongoUrl || 'mongodb://localhost:27017', + dbName: 'xiaojuSurvey' + } +}; export function getConfig() { - return config + return config; } \ No newline at end of file diff --git a/server/src/apps/security/db/mongo.ts b/server/src/apps/security/db/mongo.ts index f39032bc..cc3ec119 100644 --- a/server/src/apps/security/db/mongo.ts +++ b/server/src/apps/security/db/mongo.ts @@ -1,7 +1,7 @@ -import { getConfig } from '../config/index' +import { getConfig } from '../config/index'; -import MongoService from '../../../utils/mongoService' +import MongoService from '../../../utils/mongoService'; -const config = getConfig() +const config = getConfig(); -export const mongo = new MongoService({ url: config.mongo.url, dbName: config.mongo.dbName }) \ No newline at end of file +export const mongo = new MongoService({ url: config.mongo.url, dbName: config.mongo.dbName }); \ No newline at end of file diff --git a/server/src/apps/security/index.ts b/server/src/apps/security/index.ts index 0247ad51..ad1e695f 100644 --- a/server/src/apps/security/index.ts +++ b/server/src/apps/security/index.ts @@ -1,16 +1,17 @@ -import { SurveyServer } from '../../decorator' -import { securityService } from './service/securityService' +import { SurveyApp, SurveyServer } from '../../decorator'; +import { securityService } from './service/securityService'; +@SurveyApp('/api/security') export default class Security { @SurveyServer({ type: 'rpc' }) - async isHitKeys({ params, context }: { params: any, context: any }) { + async isHitKeys({ params, context }) { const data = securityService.isHitKeys({ content: params.content, dictType: params.dictType, - }) + }); return { result: data, context, // 上下文主要是传递调用方信息使用,比如traceid - } + }; } } \ No newline at end of file diff --git a/server/src/apps/security/service/securityService.ts b/server/src/apps/security/service/securityService.ts index 24160750..cfe0fb4a 100644 --- a/server/src/apps/security/service/securityService.ts +++ b/server/src/apps/security/service/securityService.ts @@ -1,14 +1,14 @@ -import { mongo } from '../db/mongo' -import { DICT_TYPE } from '../../../types' -import { participle } from '../utils/index' +import { mongo } from '../db/mongo'; +import { DICT_TYPE } from '../../../types'; +import { participle } from '../utils/index'; class SecurityService { - async isHitKeys({ content, dictType }: { content: string, dictType: DICT_TYPE }) { - const securityDictModel = await mongo.getCollection({ collectionName: 'securityDict' }) - const keywordList = participle({ content }) - const hitCount = await securityDictModel.countDocuments({ keyword: { $in: keywordList }, type: dictType }) - return hitCount > 0 - } + async isHitKeys({ content, dictType }: { content: string, dictType: DICT_TYPE }) { + const securityDictModel = await mongo.getCollection({ collectionName: 'securityDict' }); + const keywordList = participle({ content }); + const hitCount = await securityDictModel.countDocuments({ keyword: { $in: keywordList }, type: dictType }); + return hitCount > 0; + } } -export const securityService = new SecurityService() \ No newline at end of file +export const securityService = new SecurityService(); \ No newline at end of file diff --git a/server/src/apps/security/utils/index.ts b/server/src/apps/security/utils/index.ts index f3adb1ab..5e73cdf4 100644 --- a/server/src/apps/security/utils/index.ts +++ b/server/src/apps/security/utils/index.ts @@ -1,16 +1,16 @@ export function participle({ content, minLen, maxLen }: { content: string, minLen?: number, maxLen?: number }) { - const keys: Array = [] - minLen = minLen || 2 - maxLen = maxLen || 13 - for (let i = 0; i < content.length; i++) { - let tempStr = content[i] - for (let j = 1; j < maxLen && i + j < content.length; j++) { - tempStr += content[i + j] - if (j >= minLen - 1) { - keys.push(tempStr) - } - } + const keys: Array = []; + minLen = minLen || 2; + maxLen = maxLen || 13; + for (let i = 0; i < content.length; i++) { + let tempStr = content[i]; + for (let j = 1; j < maxLen && i + j < content.length; j++) { + tempStr += content[i + j]; + if (j >= minLen - 1) { + keys.push(tempStr); + } } - return keys + } + return keys; } \ No newline at end of file diff --git a/server/src/apps/surveyManage/config/index.ts b/server/src/apps/surveyManage/config/index.ts index 6a9f2e5f..41f62e8e 100644 --- a/server/src/apps/surveyManage/config/index.ts +++ b/server/src/apps/surveyManage/config/index.ts @@ -1,10 +1,10 @@ const config = { - mongo: { - url: process.env.xiaojuSurveyMongoUrl || 'mongodb://localhost:27017', - dbName: 'xiaojuSurvey', - } -} + mongo: { + url: process.env.xiaojuSurveyMongoUrl || 'mongodb://localhost:27017', + dbName: 'xiaojuSurvey', + } +}; export function getConfig() { - return config + return config; } \ No newline at end of file diff --git a/server/src/apps/surveyManage/db/mongo.ts b/server/src/apps/surveyManage/db/mongo.ts index 53a25257..e368f475 100644 --- a/server/src/apps/surveyManage/db/mongo.ts +++ b/server/src/apps/surveyManage/db/mongo.ts @@ -1,6 +1,6 @@ -import { getConfig } from '../config/index' -import MongoService from '../../../utils/mongoService' +import { getConfig } from '../config/index'; +import MongoService from '../../../utils/mongoService'; -const config = getConfig() +const config = getConfig(); -export const mongo = new MongoService({ url: config.mongo.url, dbName: config.mongo.dbName }) \ No newline at end of file +export const mongo = new MongoService({ url: config.mongo.url, dbName: config.mongo.dbName }); \ No newline at end of file diff --git a/server/src/apps/surveyManage/index.ts b/server/src/apps/surveyManage/index.ts index 7b715928..bc0d0ab4 100644 --- a/server/src/apps/surveyManage/index.ts +++ b/server/src/apps/surveyManage/index.ts @@ -1,184 +1,185 @@ -import { SurveyServer } from '../../decorator' -import { Request, Response } from 'koa' -import { surveyService } from './service/surveyService' -import { userService } from './service/userService' -import { surveyHistoryService } from './service/surveyHistoryService' -import { HISTORY_TYPE } from '../../types/index' -import { getValidateValue } from './utils/index' -import * as Joi from 'joi' +import { SurveyApp, SurveyServer } from '../../decorator'; +import { surveyService } from './service/surveyService'; +import { userService } from './service/userService'; +import { surveyHistoryService } from './service/surveyHistoryService'; +import { HISTORY_TYPE } from '../../types/index'; +import { getValidateValue } from './utils/index'; +import * as Joi from 'joi'; +@SurveyApp('/api/surveyManage') export default class SurveyManage { - @SurveyServer({type:'http',method:'get',routerName:'/getBannerData'}) - async getBannerData({req,res}:{req:Request, res:Response}) { - const data = await surveyService.getBannerData() - return { - code:200, - data, - } - } - @SurveyServer({type:'http',method:'post',routerName:'/add'}) - async add({req,res}:{req:Request, res:Response}) { - const params = getValidateValue(Joi.object({ - remark: Joi.string().required(), - questionType: Joi.string().required(), - title: Joi.string().required(), - }).validate(req.body,{allowUnknown: true})); - params.userData = await userService.checkLogin({req}) - const addRes = await surveyService.add(params) - return { - code:200, - data: { - id: addRes.pageId, - }, - } - } + @SurveyServer({ type: 'http', method: 'get', routerName: '/getBannerData' }) + async getBannerData() { + const data = await surveyService.getBannerData(); + return { + code: 200, + data, + }; + } - @SurveyServer({type:'http',method:'post',routerName:'/update'}) - async update({req,res}:{req:Request, res:Response}) { - const surveyParams = getValidateValue(Joi.object({ - surveyId: Joi.string().required(), - remark: Joi.string().required(), - title: Joi.string().required(), - }).validate(req.body,{allowUnknown: true})); - const userData = await userService.checkLogin({req}) - surveyParams.userData = userData - const data = await surveyService.update(surveyParams) - return { - code:200, - data, - } - } + @SurveyServer({ type: 'http', method: 'post', routerName: '/add' }) + async add({ req }) { + const params = getValidateValue(Joi.object({ + remark: Joi.string().required(), + questionType: Joi.string().required(), + title: Joi.string().required(), + }).validate(req.body, { allowUnknown: true })); + params.userData = await userService.checkLogin({ req }); + const addRes = await surveyService.add(params); + return { + code: 200, + data: { + id: addRes.pageId, + }, + }; + } - @SurveyServer({type:'http',method:'post',routerName:'/delete'}) - async delete({req,res}:{req:Request, res:Response}) { - const surveyParams = getValidateValue(Joi.object({ - surveyId: Joi.string().required(), - }).validate(req.body,{allowUnknown: true})); - const userData = await userService.checkLogin({req}) - surveyParams.userData = userData - const data = await surveyService.delete(surveyParams) - return { - code:200, - data, - } - } - @SurveyServer({type:'http',method:'get',routerName:'/list'}) - async list({req,res}:{req:Request, res:Response}) { - const condition = getValidateValue(Joi.object({ - curPage: Joi.number().default(1), - pageSize: Joi.number().default(10), - }).validate(req.query,{allowUnknown: true})); - const userData = await userService.checkLogin({req}) - const listRes = await surveyService.list({ - pageNum:condition.curPage, - pageSize:condition.pageSize, - userData - }) - return { - code:200, - data: listRes, - } - } - @SurveyServer({type:'http',method:'post',routerName:'/saveConf'}) - async saveConf({req,res}:{req:Request, res:Response}) { - const surveyData = getValidateValue(Joi.object({ - surveyId: Joi.string().required(), - configData: Joi.object().required(), - }).validate(req.body,{allowUnknown: true})); - const userData = await userService.checkLogin({req}) - // 保存数据 - const saveRes = await surveyService.saveConf(surveyData); - // 保存历史 - const historyRes = await surveyHistoryService.addHistory({ - surveyId:surveyData.surveyId, - configData:surveyData.configData, - type:HISTORY_TYPE.dailyHis, - userData - }); - return { - code:200, - data:{ - saveRes, - historyRes - } - } - } + @SurveyServer({ type: 'http', method: 'post', routerName: '/update' }) + async update({ req }) { + const surveyParams = getValidateValue(Joi.object({ + surveyId: Joi.string().required(), + remark: Joi.string().required(), + title: Joi.string().required(), + }).validate(req.body, { allowUnknown: true })); + const userData = await userService.checkLogin({ req }); + surveyParams.userData = userData; + const data = await surveyService.update(surveyParams); + return { + code: 200, + data, + }; + } - @SurveyServer({type:'http',method:'get',routerName:'/get'}) - async get({req,res}:{req:Request, res:Response}) { - const params = getValidateValue(Joi.object({ - surveyId: Joi.string().required(), - }).validate(req.query,{allowUnknown: true})); - const userData = await userService.checkLogin({req}) - const data = await surveyService.get({ - surveyId:params.surveyId, - userData - }) - return { - code:200, - data, - } - } - - @SurveyServer({type:'http',method:'get',routerName:'/getHistoryList'}) - async getHistoryList({req,res}:{req:Request, res:Response}) { - const historyParams = getValidateValue(Joi.object({ - surveyId: Joi.string().required(), - historyType: Joi.string().required(), - }).validate(req.query,{allowUnknown: true})); - const data = await surveyHistoryService.getHistoryList(historyParams) - return { - code:200, - data + @SurveyServer({ type: 'http', method: 'post', routerName: '/delete' }) + async delete({ req }) { + const surveyParams = getValidateValue(Joi.object({ + surveyId: Joi.string().required(), + }).validate(req.body, { allowUnknown: true })); + const userData = await userService.checkLogin({ req }); + surveyParams.userData = userData; + const data = await surveyService.delete(surveyParams); + return { + code: 200, + data, + }; + } + @SurveyServer({ type: 'http', method: 'get', routerName: '/list' }) + async list({ req }) { + const condition = getValidateValue(Joi.object({ + curPage: Joi.number().default(1), + pageSize: Joi.number().default(10), + }).validate(req.query, { allowUnknown: true })); + const userData = await userService.checkLogin({ req }); + const listRes = await surveyService.list({ + pageNum: condition.curPage, + pageSize: condition.pageSize, + userData + }); + return { + code: 200, + data: listRes, + }; + } + @SurveyServer({ type: 'http', method: 'post', routerName: '/saveConf' }) + async saveConf({ req }) { + const surveyData = getValidateValue(Joi.object({ + surveyId: Joi.string().required(), + configData: Joi.object().required(), + }).validate(req.body, { allowUnknown: true })); + const userData = await userService.checkLogin({ req }); + // 保存数据 + const saveRes = await surveyService.saveConf(surveyData); + // 保存历史 + const historyRes = await surveyHistoryService.addHistory({ + surveyId: surveyData.surveyId, + configData: surveyData.configData, + type: HISTORY_TYPE.dailyHis, + userData + }); + return { + code: 200, + data: { + saveRes, + historyRes } - } + }; + } - @SurveyServer({type:'http',method:'post',routerName:'/publish'}) - async publish({req,res}:{req:Request, res:Response}) { - const surveyParams = getValidateValue(Joi.object({ - surveyId: Joi.string().required(), - }).validate(req.body,{allowUnknown: true})); - // 鉴权 - const userData = await userService.checkLogin({req}) - // 发布 - surveyParams.userData = userData - const surveyData = await surveyService.publish(surveyParams) - // 保存历史 - const historyRes = await surveyHistoryService.addHistory({ - surveyId:surveyData.surveyConfRes.pageId, - configData:surveyData.surveyConfRes.code, - type:HISTORY_TYPE.publishHis, - userData - }); - return { - code:200, - data:{ - ...surveyData, - historyRes - } - } - } + @SurveyServer({ type: 'http', method: 'get', routerName: '/get' }) + async get({ req }) { + const params = getValidateValue(Joi.object({ + surveyId: Joi.string().required(), + }).validate(req.query, { allowUnknown: true })); + const userData = await userService.checkLogin({ req }); + const data = await surveyService.get({ + surveyId: params.surveyId, + userData + }); + return { + code: 200, + data, + }; + } - @SurveyServer({type:'http',method:'get',routerName:'/data'}) - async data({req,res}:{req:Request, res:Response}) { - const surveyParams = getValidateValue(Joi.object({ - surveyId: Joi.string().required(), - isShowSecret:Joi.boolean().default(true), // 默认true就是需要脱敏 - page: Joi.number().default(1), - pageSize: Joi.number().default(10), - }).validate(req.query,{allowUnknown: true})); - const userData = await userService.checkLogin({req}) - const data = await surveyService.data({ - userData, - surveyId:surveyParams.surveyId, - isShowSecret:surveyParams.isShowSecret, - pageNum:surveyParams.page, - pageSize:surveyParams.pageSize, - }) - return { - code:200, - data + @SurveyServer({ type: 'http', method: 'get', routerName: '/getHistoryList' }) + async getHistoryList({ req }) { + const historyParams = getValidateValue(Joi.object({ + surveyId: Joi.string().required(), + historyType: Joi.string().required(), + }).validate(req.query, { allowUnknown: true })); + const data = await surveyHistoryService.getHistoryList(historyParams); + return { + code: 200, + data + }; + } + + @SurveyServer({ type: 'http', method: 'post', routerName: '/publish' }) + async publish({ req }) { + const surveyParams = getValidateValue(Joi.object({ + surveyId: Joi.string().required(), + }).validate(req.body, { allowUnknown: true })); + // 鉴权 + const userData = await userService.checkLogin({ req }); + // 发布 + surveyParams.userData = userData; + const surveyData = await surveyService.publish(surveyParams); + // 保存历史 + const historyRes = await surveyHistoryService.addHistory({ + surveyId: surveyData.surveyConfRes.pageId, + configData: surveyData.surveyConfRes.code, + type: HISTORY_TYPE.publishHis, + userData + }); + return { + code: 200, + data: { + ...surveyData, + historyRes } - } + }; + } + + @SurveyServer({ type: 'http', method: 'get', routerName: '/data' }) + async data({ req }) { + const surveyParams = getValidateValue(Joi.object({ + surveyId: Joi.string().required(), + isShowSecret: Joi.boolean().default(true), // 默认true就是需要脱敏 + page: Joi.number().default(1), + pageSize: Joi.number().default(10), + }).validate(req.query, { allowUnknown: true })); + const userData = await userService.checkLogin({ req }); + const data = await surveyService.data({ + userData, + surveyId: surveyParams.surveyId, + isShowSecret: surveyParams.isShowSecret, + pageNum: surveyParams.page, + pageSize: surveyParams.pageSize, + }); + return { + code: 200, + data + }; + } } \ No newline at end of file diff --git a/server/src/apps/surveyManage/service/surveyHistoryService.ts b/server/src/apps/surveyManage/service/surveyHistoryService.ts index e3eca567..0bd8122c 100644 --- a/server/src/apps/surveyManage/service/surveyHistoryService.ts +++ b/server/src/apps/surveyManage/service/surveyHistoryService.ts @@ -1,37 +1,37 @@ -import { mongo } from '../db/mongo' -import { getStatusObject } from '../utils/index' -import { SURVEY_STATUS, HISTORY_TYPE, UserType } from '../../../types/index' +import { mongo } from '../db/mongo'; +import { getStatusObject } from '../utils/index'; +import { SURVEY_STATUS, HISTORY_TYPE, UserType } from '../../../types/index'; class SurveyHistoryService { - async addHistory(surveyData: { surveyId: string, configData: any, type: HISTORY_TYPE, userData: UserType }) { - const surveyHistory = await mongo.getCollection({ collectionName: 'surveyHistory' }); - const surveyHistoryRes = await surveyHistory.insertOne({ - curStatus: getStatusObject({ status: SURVEY_STATUS.new }), - pageId: surveyData.surveyId, - type: surveyData.type, - code: { - data: surveyData.configData - }, - createDate: Date.now(), - operator: { - _id: surveyData.userData._id, - username: surveyData.userData.username, - } - }) - return surveyHistoryRes - } + async addHistory(surveyData: { surveyId: string, configData: unknown, type: HISTORY_TYPE, userData: UserType }) { + const surveyHistory = await mongo.getCollection({ collectionName: 'surveyHistory' }); + const surveyHistoryRes = await surveyHistory.insertOne({ + curStatus: getStatusObject({ status: SURVEY_STATUS.new }), + pageId: surveyData.surveyId, + type: surveyData.type, + code: { + data: surveyData.configData + }, + createDate: Date.now(), + operator: { + _id: surveyData.userData._id, + username: surveyData.userData.username, + } + }); + return surveyHistoryRes; + } - async getHistoryList(historyParams: { surveyId: string, historyType: HISTORY_TYPE }) { - const surveyHistory = await mongo.getCollection({ collectionName: 'surveyHistory' }); - const surveyHistoryListRes = await surveyHistory.find({ - pageId: historyParams.surveyId, - type: historyParams.historyType, - }) - .sort({ createDate: -1 }) - .limit(100) - .toArray() - return mongo.convertId2StringByList(surveyHistoryListRes) - } + async getHistoryList(historyParams: { surveyId: string, historyType: HISTORY_TYPE }) { + const surveyHistory = await mongo.getCollection({ collectionName: 'surveyHistory' }); + const surveyHistoryListRes = await surveyHistory.find({ + pageId: historyParams.surveyId, + type: historyParams.historyType, + }) + .sort({ createDate: -1 }) + .limit(100) + .toArray(); + return mongo.convertId2StringByList(surveyHistoryListRes); + } } -export const surveyHistoryService = new SurveyHistoryService() \ No newline at end of file +export const surveyHistoryService = new SurveyHistoryService(); \ No newline at end of file diff --git a/server/src/apps/surveyManage/service/surveyService.ts b/server/src/apps/surveyManage/service/surveyService.ts index 81537049..e6895f4a 100644 --- a/server/src/apps/surveyManage/service/surveyService.ts +++ b/server/src/apps/surveyManage/service/surveyService.ts @@ -1,351 +1,356 @@ -import { mongo } from '../db/mongo' -import { rpcInvote } from '../../../rpc' -import { SURVEY_STATUS, QUESTION_TYPE, CommonError, UserType, DICT_TYPE } from '../../../types/index' -import { getStatusObject, genSurveyPath, getMapByKey, hanleSensitiveDate } from '../utils/index' -import * as path from "path"; -import * as _ from "lodash"; -import * as moment from "moment"; +import { mongo } from '../db/mongo'; +import { rpcInvote } from '../../../rpc'; +import { SURVEY_STATUS, QUESTION_TYPE, CommonError, UserType, DICT_TYPE } from '../../../types/index'; +import { getStatusObject, genSurveyPath, hanleSensitiveDate } from '../utils/index'; +import * as path from 'path'; +import * as _ from 'lodash'; +import * as moment from 'moment'; +import { getFile } from '../utils/index'; +import { DataItem } from '../../../types/survey'; class SurveyService { - async checkSecurity({ content, dictType }: { content: string, dictType: DICT_TYPE }) { - const rpcResult = await rpcInvote('security.isHitKeys', { - params: { content, dictType }, - context: {} - }) - return rpcResult.result - } + async checkSecurity({ content, dictType }: { content: string, dictType: DICT_TYPE }) { + const rpcResult = await rpcInvote('security.isHitKeys', { + params: { content, dictType }, + context: {} + }); + return rpcResult.result; + } - async getBannerData() { - const bannerConfPath = path.resolve(__dirname, "../template/banner/index.json"); - return require(bannerConfPath) - } + async getBannerData() { + const bannerConfPath = path.resolve(__dirname, '../template/banner/index.json'); + return require(bannerConfPath); + } - async getCodeData({ - questionType, - }: { questionType: QUESTION_TYPE }): Promise { - const baseConfPath = path.resolve(__dirname, "../template/surveyTemplate/templateBase.json"); - const templateConfPath = path.resolve( - __dirname, - `../template/surveyTemplate/survey/${questionType}.json`, - ); - const baseConf = _.cloneDeep(require(baseConfPath)) - const templateConf = _.cloneDeep(require(templateConfPath)) - const codeData = _.merge(baseConf, templateConf); - const nowMoment = moment() - codeData.baseConf.begTime = nowMoment.format("YYYY-MM-DD HH:mm:ss") - codeData.baseConf.endTime = nowMoment.add(10, 'years').format("YYYY-MM-DD HH:mm:ss") - return codeData; - } - async getNewSurveyPath() { - const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); - const surveyPath = genSurveyPath() - const surveyPathCount = await surveyMeta.countDocuments({ surveyPath }) - if (surveyPathCount > 0) { return await this.getNewSurveyPath() } - return surveyPath - } + async getCodeData({ + questionType, + }: { questionType: QUESTION_TYPE }): Promise { + const baseConfPath = path.resolve(__dirname, '../template/surveyTemplate/templateBase.json'); + const templateConfPath = path.resolve( + __dirname, + `../template/surveyTemplate/survey/${questionType}.json`, + ); - async add(surveyMetaInfo: { remark: string, questionType: QUESTION_TYPE, title: string, userData: UserType }) { - const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); - const now = Date.now() - const surveyPath = await this.getNewSurveyPath() - const surveyMetaRes = await surveyMeta.insertOne({ - surveyPath, - remark: surveyMetaInfo.remark, - questionType: surveyMetaInfo.questionType, - title: surveyMetaInfo.title, - creator: surveyMetaInfo.userData.username, - owner: surveyMetaInfo.userData.username, - curStatus: getStatusObject({ status: SURVEY_STATUS.new }), - createDate: now, - updateDate: now, - }) - const pageId = surveyMetaRes.insertedId.toString() - const surveyConf = await mongo.getCollection({ collectionName: 'surveyConf' }); - const surveyConfRes = await surveyConf.insertOne({ - pageId, - pageType: surveyMetaInfo.questionType, - curStatus: getStatusObject({ status: SURVEY_STATUS.new }), - code: await this.getCodeData({ - questionType: surveyMetaInfo.questionType, - }) - }) - return { - pageId, - surveyMetaRes, - surveyConfRes + const [baseConfStr, templateConfStr] = await Promise.all([getFile(baseConfPath), getFile(templateConfPath)]); + + const baseConf = JSON.parse(baseConfStr); + const templateConf = JSON.parse(templateConfStr); + const codeData = _.merge(baseConf, templateConf); + const nowMoment = moment(); + codeData.baseConf.begTime = nowMoment.format('YYYY-MM-DD HH:mm:ss'); + codeData.baseConf.endTime = nowMoment.add(10, 'years').format('YYYY-MM-DD HH:mm:ss'); + return codeData; + } + async getNewSurveyPath() { + const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); + const surveyPath = genSurveyPath(); + const surveyPathCount = await surveyMeta.countDocuments({ surveyPath }); + if (surveyPathCount > 0) { return await this.getNewSurveyPath(); } + return surveyPath; + } + + async add(surveyMetaInfo: { remark: string, questionType: QUESTION_TYPE, title: string, userData: UserType }) { + const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); + const now = Date.now(); + const surveyPath = await this.getNewSurveyPath(); + const surveyMetaRes = await surveyMeta.insertOne({ + surveyPath, + remark: surveyMetaInfo.remark, + questionType: surveyMetaInfo.questionType, + title: surveyMetaInfo.title, + creator: surveyMetaInfo.userData.username, + owner: surveyMetaInfo.userData.username, + curStatus: getStatusObject({ status: SURVEY_STATUS.new }), + createDate: now, + updateDate: now, + }); + const pageId = surveyMetaRes.insertedId.toString(); + const surveyConf = await mongo.getCollection({ collectionName: 'surveyConf' }); + const surveyConfRes = await surveyConf.insertOne({ + pageId, + pageType: surveyMetaInfo.questionType, + curStatus: getStatusObject({ status: SURVEY_STATUS.new }), + code: await this.getCodeData({ + questionType: surveyMetaInfo.questionType, + }) + }); + return { + pageId, + surveyMetaRes, + surveyConfRes + }; + } + + async update(surveyParams: { surveyId: string, remark: string, title: string, userData: UserType }) { + const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); + const _id = mongo.getObjectIdByStr(surveyParams.surveyId); + const surveyMetaUpdateRes = await surveyMeta.updateOne({ + _id, + owner: surveyParams.userData.username, + }, [{ + $set: { + remark: surveyParams.remark, + title: surveyParams.title, + updateDate: Date.now(), + } + }, { + $set: { + 'curStatus': { + $cond: { + if: { + $eq: ['$curStatus.status', 'new'] + }, + then: '$curStatus', + else: getStatusObject({ status: SURVEY_STATUS.editing }) + } } + } + }]); + if (surveyMetaUpdateRes.matchedCount < 1) { + throw new CommonError('更新问卷信息失败,问卷不存在或您不是该问卷所有者'); } + return { + surveyMetaUpdateRes + }; + } - async update(surveyParams: { surveyId: string, remark: string, title: string, userData: UserType }) { - const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); - const _id = mongo.getObjectIdByStr(surveyParams.surveyId) - const surveyMetaUpdateRes = await surveyMeta.updateOne({ - _id, - owner: surveyParams.userData.username, - }, [{ - $set: { - remark: surveyParams.remark, - title: surveyParams.title, - updateDate: Date.now(), - } - }, { - $set: { - "curStatus": { - $cond: { - if: { - $eq: ["$curStatus.status", "new"] - }, - then: "$curStatus", - else: getStatusObject({ status: SURVEY_STATUS.editing }) - } - } - } - }]) - if (surveyMetaUpdateRes.matchedCount < 1) { - throw new CommonError("更新问卷信息失败,问卷不存在或您不是该问卷所有者") - } - return { - surveyMetaUpdateRes - } + async delete(surveyParams: { surveyId: string, userData: UserType }) { + const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); + const _id = mongo.getObjectIdByStr(surveyParams.surveyId); + const surveyMetaDeleteRes = await surveyMeta.deleteOne({ + _id, + owner: surveyParams.userData.username, + }); + if (surveyMetaDeleteRes.deletedCount < 1) { + throw new CommonError('删除问卷失败,问卷已被删除或您不是该问卷所有者'); } + return { + surveyMetaDeleteRes + }; + } - async delete(surveyParams: { surveyId: string, userData: UserType }) { - const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); - const _id = mongo.getObjectIdByStr(surveyParams.surveyId) - const surveyMetaDeleteRes = await surveyMeta.deleteOne({ - _id, - owner: surveyParams.userData.username, - }) - if (surveyMetaDeleteRes.deletedCount < 1) { - throw new CommonError("删除问卷失败,问卷已被删除或您不是该问卷所有者") - } - return { - surveyMetaDeleteRes - } - } + async list(condition: { pageNum: number, pageSize: number, userData: UserType }) { + const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); + const cond = { + owner: condition.userData.username + }; + const data = await surveyMeta.find(cond) + .sort({ createDate: -1 }) + .limit(condition.pageSize) + .skip((condition.pageNum - 1) * condition.pageSize) + .toArray(); + const count = await surveyMeta.countDocuments(cond); + return { data: mongo.convertId2StringByList(data), count }; + } - async list(condition: { pageNum: number, pageSize: number, userData: UserType }) { - const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); - const cond = { - owner: condition.userData.username + getListHeadByDataList(dataList) { + const listHead = dataList.map(surveyItem => { + let othersCode; + if (surveyItem.type === 'radio-star') { + const rangeConfigKeys = Object.keys(surveyItem.rangeConfig); + if (rangeConfigKeys.length > 0) { + othersCode = [{ code: `${surveyItem.field}_custom`, option: '填写理由' }]; } - const data = await surveyMeta.find(cond) - .sort({ createDate: -1 }) - .limit(condition.pageSize) - .skip((condition.pageNum - 1) * condition.pageSize) - .toArray() - const count = await surveyMeta.countDocuments(cond); - return { data: mongo.convertId2StringByList(data), count } - } - - getListHeadByDataList(dataList) { - const listHead = dataList.map(surveyItem => { - let othersCode; - if (surveyItem.type === 'radio-star') { - const rangeConfigKeys = Object.keys(surveyItem.rangeConfig) - if (rangeConfigKeys.length > 0) { - othersCode = [{ code: `${surveyItem.field}_custom`, option: "填写理由" }] - } - } else { - othersCode = (surveyItem.options || []) - .filter(optionItem => optionItem.othersKey) - .map((optionItem) => { - return { - code: optionItem.othersKey, - option: optionItem.text - } - }) - } + } else { + othersCode = (surveyItem.options || []) + .filter(optionItem => optionItem.othersKey) + .map((optionItem) => { return { - field: surveyItem.field, - title: surveyItem.title, - type: surveyItem.type, - othersCode - } - }) - listHead.push({ - field: 'difTime', - title: '答题耗时(秒)', - type: 'text', - }) - listHead.push({ - field: 'createDate', - title: '提交时间', - type: 'text', - }) - return listHead + code: optionItem.othersKey, + option: optionItem.text + }; + }); + } + return { + field: surveyItem.field, + title: surveyItem.title, + type: surveyItem.type, + othersCode + }; + }); + listHead.push({ + field: 'difTime', + title: '答题耗时(秒)', + type: 'text', + }); + listHead.push({ + field: 'createDate', + title: '提交时间', + type: 'text', + }); + return listHead; + } + + async data(condition: { userData: UserType, surveyId: string, pageNum: number, pageSize: number, isShowSecret: boolean }) { + const surveyObjectId = mongo.getObjectIdByStr(condition.surveyId); + const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); + const surveyMetaData = await surveyMeta.findOne({ _id: surveyObjectId }); + if (surveyMetaData.owner !== condition.userData.username) { + throw new CommonError('问卷回收数据列表仅所有人才能打开'); } + const surveyPublish = await mongo.getCollection({ collectionName: 'surveyPublish' }); + const publishConf = await surveyPublish.findOne({ pageId: condition.surveyId }); + const dataList = publishConf?.code?.dataConf?.dataList || []; + const listHead = this.getListHeadByDataList(dataList); + const dataListMap = _.keyBy(dataList, 'field'); + const surveySubmit = await mongo.getCollection({ collectionName: 'surveySubmit' }); + const surveySubmitData = await surveySubmit.find({ pageId: condition.surveyId }) + .sort({ createDate: -1 }) + .limit(condition.pageSize) + .skip((condition.pageNum - 1) * condition.pageSize) + .toArray(); + const listBody = surveySubmitData.map((surveySubmitResList) => { + const data = surveySubmitResList.data; + const dataKeys = Object.keys(data); + for (const itemKey of dataKeys) { + if (typeof itemKey !== 'string') { continue; } + if (itemKey.indexOf('data') !== 0) { continue; } + const itemConfigKey = itemKey.split('_')[0]; + const itemConfig: DataItem = dataListMap[itemConfigKey]; + // 题目删除会出现,数据列表报错 + if (!itemConfig) { continue; } + const doSecretData = (data) => { + if (condition.isShowSecret) { + return hanleSensitiveDate(data); + } else { + return data; + } + }; + data[itemKey] = doSecretData(data[itemKey]); + // 处理选项 + if (itemConfig.type === 'radio-star' && !data[`${itemConfigKey}_custom`]) { + data[`${itemConfigKey}_custom`] = data[`${itemConfigKey}_${data[itemConfigKey]}`]; + } + if (!itemConfig?.options?.length) { continue; } + const options = itemConfig.options; + const optionsMap = _.keyBy(options, 'hash'); + const getText = e => doSecretData(optionsMap?.[e]?.text || e); + if (Array.isArray(data[itemKey])) { + data[itemKey] = data[itemKey].map(getText); + } else { + data[itemKey] = getText(data[itemKey]); + } + } + return { + ...data, + difTime: (surveySubmitResList.difTime / 1000).toFixed(2), + createDate: moment(surveySubmitResList.createDate).format('YYYY-MM-DD HH:mm:ss') + }; + }); + const total = await surveySubmit.countDocuments({ pageId: condition.surveyId }); + return { + total, + listHead, + listBody + }; + } - async data(condition: { userData: UserType, surveyId: string, pageNum: number, pageSize: number, isShowSecret: boolean }) { - const surveyObjectId = mongo.getObjectIdByStr(condition.surveyId) - const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); - const surveyMetaData = await surveyMeta.findOne({ _id: surveyObjectId }) - if (surveyMetaData.owner !== condition.userData.username) { - throw new CommonError("问卷回收数据列表仅所有人才能打开") - } - const surveyPublish = await mongo.getCollection({ collectionName: 'surveyPublish' }); - const publishConf = await surveyPublish.findOne({ pageId: condition.surveyId }) - const dataList = publishConf?.code?.dataConf?.dataList || [] - const listHead = this.getListHeadByDataList(dataList) - const dataListMap = getMapByKey({ data: dataList, key: 'field' }) - const surveySubmit = await mongo.getCollection({ collectionName: 'surveySubmit' }); - const surveySubmitData = await surveySubmit.find({ pageId: condition.surveyId }) - .sort({ createDate: -1 }) - .limit(condition.pageSize) - .skip((condition.pageNum - 1) * condition.pageSize) - .toArray() - const listBody = surveySubmitData.map((surveySubmitResList) => { - const data = surveySubmitResList.data - const dataKeys = Object.keys(data) - for (const itemKey of dataKeys) { - if (typeof itemKey !== 'string') { continue } - if (itemKey.indexOf("data") !== 0) { continue } - const itemConfigKey = itemKey.split("_")[0]; - const itemConfig = dataListMap[itemConfigKey]; - // 题目删除会出现,数据列表报错 - if (!itemConfig) { continue } - const doSecretData = (data) => { - if (itemConfig.isSecret && condition.isShowSecret) { - return hanleSensitiveDate(data) - } else { - return data; - } - } - data[itemKey] = doSecretData(data[itemKey]) - // 处理选项 - if (itemConfig.type === 'radio-star' && !data[`${itemConfigKey}_custom`]) { - data[`${itemConfigKey}_custom`] = data[`${itemConfigKey}_${data[itemConfigKey]}`] - } - if (!itemConfig?.options?.length) { continue } - const options = itemConfig.options - const optionsMap = getMapByKey({ data: options, key: 'hash' }) - const getText = e => doSecretData(optionsMap?.[e]?.text || e); - if (Array.isArray(data[itemKey])) { - data[itemKey] = data[itemKey].map(getText) - } else { - data[itemKey] = getText(data[itemKey]) - } - } - return { - ...data, - difTime: (surveySubmitResList.difTime / 1000).toFixed(2), - createDate: moment(surveySubmitResList.createDate).format("YYYY-MM-DD HH:mm:ss") - } - }) - const total = await surveySubmit.countDocuments({ pageId: condition.surveyId }); - return { - total, - listHead, - listBody - } + + async get({ surveyId, userData }: { surveyId: string, userData: UserType }) { + const surveyObjectId = mongo.getObjectIdByStr(surveyId); + const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); + const surveyMetaData = await surveyMeta.findOne({ _id: surveyObjectId }); + if (!surveyMetaData) { + throw new CommonError('问卷不存在或已被删除'); } - - - async get({ surveyId, userData }: { surveyId: string, userData: UserType }) { - const surveyObjectId = mongo.getObjectIdByStr(surveyId) - const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); - const surveyMetaData = await surveyMeta.findOne({ _id: surveyObjectId }) - if (!surveyMetaData) { - throw new CommonError("问卷不存在或已被删除") - } - if (surveyMetaData.owner !== userData.username) { - throw new CommonError("问卷仅所有人才能打开") - } - const surveyMetaRes = mongo.convertId2StringByDoc(surveyMetaData) - const surveyConf = await mongo.getCollection({ collectionName: 'surveyConf' }); - const surveyConfData = await surveyConf.findOne({ pageId: surveyId }) - if (!surveyConfData) { - throw new CommonError("问卷配置不存在或已被删除") - } - const surveyConfRes = mongo.convertId2StringByDoc(surveyConfData) - return { - surveyMetaRes, - surveyConfRes - } + if (surveyMetaData.owner !== userData.username) { + throw new CommonError('问卷仅所有人才能打开'); } - - - async saveConf(surveyData: { surveyId: string, configData: any }) { - const surveyConf = await mongo.getCollection({ collectionName: 'surveyConf' }); - const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); - const saveRes = await surveyConf.updateOne({ - pageId: surveyData.surveyId - }, { - $set: { - code: surveyData.configData, - } - }) - const _id = mongo.getObjectIdByStr(surveyData.surveyId) - surveyMeta.updateOne({ - _id, - }, [{ - $set: { - "curStatus": { - $cond: { - if: { - $eq: ["$curStatus.status", "new"] - }, - then: "$curStatus", - else: getStatusObject({ status: SURVEY_STATUS.editing }) - } - } - } - }]) - return saveRes + const surveyMetaRes = mongo.convertId2StringByDoc(surveyMetaData); + const surveyConf = await mongo.getCollection({ collectionName: 'surveyConf' }); + const surveyConfData = await surveyConf.findOne({ pageId: surveyId }); + if (!surveyConfData) { + throw new CommonError('问卷配置不存在或已被删除'); } + const surveyConfRes = mongo.convertId2StringByDoc(surveyConfData); + return { + surveyMetaRes, + surveyConfRes + }; + } - async publish({ surveyId, userData }: { surveyId: string, userData: UserType }) { - const surveyObjectId = mongo.getObjectIdByStr(surveyId) - const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); - const surveyConf = await mongo.getCollection({ collectionName: 'surveyConf' }); - const surveyMetaRes = await surveyMeta.findOne({ _id: surveyObjectId }) - if (!surveyMetaRes) { - throw new CommonError("问卷不存在或已被删除,无法发布") - } - if (surveyMetaRes.owner !== userData.username) { - throw new CommonError("只有问卷的所有者才能发布该问卷") - } - const surveyConfRes = await surveyConf.findOne({ pageId: surveyId }) - if (!surveyConfRes) { - throw new CommonError("问卷配置不存在或已被删除,无法发布") - } - const surveyPublish = await mongo.getCollection({ collectionName: 'surveyPublish' }); - // 清除id存储发布 - delete surveyConfRes._id; - surveyConfRes.title = surveyMetaRes.title - surveyConfRes.curStatus = surveyMetaRes.curStatus - surveyConfRes.surveyPath = surveyMetaRes.surveyPath - const dataList = surveyConfRes?.code?.dataConf?.dataList || [] - for (const data of dataList) { - const isDangerKey = await this.checkSecurity({ content: data.title, dictType: DICT_TYPE.danger }) - if (isDangerKey) { - throw new CommonError("问卷存在非法关键字,不允许发布") - } - const isSecretKey = await this.checkSecurity({ content: data.title, dictType: DICT_TYPE.secret }) - if (isSecretKey) { - data.isSecret = true - } - } - const publishRes = await surveyPublish.updateOne({ - pageId: surveyId - }, { - $set: surveyConfRes - }, { - upsert: true //如果不存在则插入 - }); - const updateMetaRes = await surveyMeta.updateOne({ - _id: surveyObjectId - }, { - $set: { - curStatus: getStatusObject({ status: SURVEY_STATUS.published }), - } - }) - return { - updateMetaRes, - surveyConfRes, - publishRes + + async saveConf(surveyData: { surveyId: string, configData: unknown }) { + const surveyConf = await mongo.getCollection({ collectionName: 'surveyConf' }); + const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); + const saveRes = await surveyConf.updateOne({ + pageId: surveyData.surveyId + }, { + $set: { + code: surveyData.configData, + } + }); + const _id = mongo.getObjectIdByStr(surveyData.surveyId); + surveyMeta.updateOne({ + _id, + }, [{ + $set: { + 'curStatus': { + $cond: { + if: { + $eq: ['$curStatus.status', 'new'] + }, + then: '$curStatus', + else: getStatusObject({ status: SURVEY_STATUS.editing }) + } } + } + }]); + return saveRes; + } + + async publish({ surveyId, userData }: { surveyId: string, userData: UserType }) { + const surveyObjectId = mongo.getObjectIdByStr(surveyId); + const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); + const surveyConf = await mongo.getCollection({ collectionName: 'surveyConf' }); + const surveyMetaRes = await surveyMeta.findOne({ _id: surveyObjectId }); + if (!surveyMetaRes) { + throw new CommonError('问卷不存在或已被删除,无法发布'); } + if (surveyMetaRes.owner !== userData.username) { + throw new CommonError('只有问卷的所有者才能发布该问卷'); + } + const surveyConfRes = await surveyConf.findOne({ pageId: surveyId }); + if (!surveyConfRes) { + throw new CommonError('问卷配置不存在或已被删除,无法发布'); + } + const surveyPublish = await mongo.getCollection({ collectionName: 'surveyPublish' }); + // 清除id存储发布 + delete surveyConfRes._id; + surveyConfRes.title = surveyMetaRes.title; + surveyConfRes.curStatus = surveyMetaRes.curStatus; + surveyConfRes.surveyPath = surveyMetaRes.surveyPath; + const dataList = surveyConfRes?.code?.dataConf?.dataList || []; + for (const data of dataList) { + const isDangerKey = await this.checkSecurity({ content: data.title, dictType: DICT_TYPE.danger }); + if (isDangerKey) { + throw new CommonError('问卷存在非法关键字,不允许发布'); + } + const isSecretKey = await this.checkSecurity({ content: data.title, dictType: DICT_TYPE.secret }); + if (isSecretKey) { + data.isSecret = true; + } + } + const publishRes = await surveyPublish.updateOne({ + pageId: surveyId + }, { + $set: surveyConfRes + }, { + upsert: true //如果不存在则插入 + }); + const updateMetaRes = await surveyMeta.updateOne({ + _id: surveyObjectId + }, { + $set: { + curStatus: getStatusObject({ status: SURVEY_STATUS.published }), + } + }); + return { + updateMetaRes, + surveyConfRes, + publishRes + }; + } } -export const surveyService = new SurveyService() \ No newline at end of file +export const surveyService = new SurveyService(); \ No newline at end of file diff --git a/server/src/apps/surveyManage/service/userService.ts b/server/src/apps/surveyManage/service/userService.ts index 59ba0fe4..cbe795d9 100644 --- a/server/src/apps/surveyManage/service/userService.ts +++ b/server/src/apps/surveyManage/service/userService.ts @@ -1,19 +1,19 @@ -import { rpcInvote } from '../../../rpc' -import { Request } from 'koa' -import { UserType, CommonError } from '../../../types/index' +import { rpcInvote } from '../../../rpc'; +import { Request } from 'koa'; +import { UserType, CommonError } from '../../../types/index'; class UserService { - async checkLogin({ req }: { req: Request }) { - if (!req.headers['authorization']) { - throw new CommonError('请先登录', 403) - } - const token = (String(req.headers['authorization']) || '').replace("Bearer ", "") - const rpcResult = await rpcInvote('user.getUserByToken', { - params: { token }, - context: req - }) - return rpcResult.result + async checkLogin({ req }: { req: Request }) { + if (!req.headers['authorization']) { + throw new CommonError('请先登录', 403); } + const token = (String(req.headers['authorization']) || '').replace('Bearer ', ''); + const rpcResult = await rpcInvote('user.getUserByToken', { + params: { token }, + context: req + }); + return rpcResult.result; + } } -export const userService = new UserService() \ No newline at end of file +export const userService = new UserService(); \ No newline at end of file diff --git a/server/src/apps/surveyManage/template/surveyTemplate/survey/normal.json b/server/src/apps/surveyManage/template/surveyTemplate/survey/normal.json index 0902a6e4..f1d25af3 100644 --- a/server/src/apps/surveyManage/template/surveyTemplate/survey/normal.json +++ b/server/src/apps/surveyManage/template/surveyTemplate/survey/normal.json @@ -40,7 +40,6 @@ "addressType": 3, "isAuto": false, "urlKey": "", - "othersKeyMap": {}, "textRange": { "min": { "placeholder": "0", @@ -103,7 +102,6 @@ "exclude": false, "addressType": 3, "isAuto": false, - "othersKeyMap": {}, "textRange": { "min": { "placeholder": "0", diff --git a/server/src/apps/surveyManage/template/surveyTemplate/survey/nps.json b/server/src/apps/surveyManage/template/surveyTemplate/survey/nps.json index 0fdd2347..1321bdf4 100644 --- a/server/src/apps/surveyManage/template/surveyTemplate/survey/nps.json +++ b/server/src/apps/surveyManage/template/surveyTemplate/survey/nps.json @@ -68,7 +68,6 @@ "valid": "", "title": "标题1", "answer": "", - "othersKeyMap": {}, "textRange": { "min": { "placeholder": "0", @@ -118,7 +117,6 @@ "type": "radio-star", "title": "标题2", "answer": "", - "othersKeyMap": {}, "options": [], "textRange": { "min": { diff --git a/server/src/apps/surveyManage/template/surveyTemplate/survey/register.json b/server/src/apps/surveyManage/template/surveyTemplate/survey/register.json index a9604f4c..9566d53e 100644 --- a/server/src/apps/surveyManage/template/surveyTemplate/survey/register.json +++ b/server/src/apps/surveyManage/template/surveyTemplate/survey/register.json @@ -48,7 +48,6 @@ "jumpTo": "", "startDate": "", "endDate": "", - "othersKeyMap": {}, "textRange": { "min": { "placeholder": "0", @@ -134,7 +133,6 @@ }, "startDate": "", "endDate": "", - "othersKeyMap": {}, "textRange": { "min": { "placeholder": "0", diff --git a/server/src/apps/surveyManage/template/surveyTemplate/survey/vote.json b/server/src/apps/surveyManage/template/surveyTemplate/survey/vote.json index 19f73227..e2a1a414 100644 --- a/server/src/apps/surveyManage/template/surveyTemplate/survey/vote.json +++ b/server/src/apps/surveyManage/template/surveyTemplate/survey/vote.json @@ -64,7 +64,6 @@ "addressType": 3, "isAuto": false, "urlKey": "", - "othersKeyMap": {}, "textRange": { "min": { "placeholder": "0", @@ -122,7 +121,6 @@ }, "star": 5, "addressType": 3, - "othersKeyMap": {}, "textRange": { "min": { "placeholder": "0", diff --git a/server/src/apps/surveyManage/utils/base58.ts b/server/src/apps/surveyManage/utils/base58.ts index c2a62162..78b6b6da 100644 --- a/server/src/apps/surveyManage/utils/base58.ts +++ b/server/src/apps/surveyManage/utils/base58.ts @@ -1,37 +1,37 @@ const base58KeysObject = { - "1":0,"2":1,"3":2,"4":3,"5":4,"6":5,"7":6,"8":7,"9":8, - "A":9,"B":10,"C":11,"D":12,"E":13,"F":14,"G":15,"H":16,"J":17, - "K":18,"L":19,"M":20,"N":21,"P":22,"Q":23,"R":24,"S":25,"T":26, - "U":27,"V":28,"W":29,"X":30,"Y":31,"Z":32, - "a":33,"b":34,"c":35,"d":36,"e":37,"f":38,"g":39,"h":40,"i":41,"j":42, - "k":43,"m":44,"n":45,"o":46,"p":47,"q":48,"r":49,"s":50,"t":51, - "u":52,"v":53,"w":54,"x":55,"y":56,"z":57 + '1': 0, '2': 1, '3': 2, '4': 3, '5': 4, '6': 5, '7': 6, '8': 7, '9': 8, + 'A': 9, 'B': 10, 'C': 11, 'D': 12, 'E': 13, 'F': 14, 'G': 15, 'H': 16, 'J': 17, + 'K': 18, 'L': 19, 'M': 20, 'N': 21, 'P': 22, 'Q': 23, 'R': 24, 'S': 25, 'T': 26, + 'U': 27, 'V': 28, 'W': 29, 'X': 30, 'Y': 31, 'Z': 32, + 'a': 33, 'b': 34, 'c': 35, 'd': 36, 'e': 37, 'f': 38, 'g': 39, 'h': 40, 'i': 41, 'j': 42, + 'k': 43, 'm': 44, 'n': 45, 'o': 46, 'p': 47, 'q': 48, 'r': 49, 's': 50, 't': 51, + 'u': 52, 'v': 53, 'w': 54, 'x': 55, 'y': 56, 'z': 57 }; const base58Keys = Object.keys(base58KeysObject); const base58Len = 58n; export function hex2Base58(hexNum:string):string { - let base58NumArray =[]; - let bigHexNumber = BigInt(`0x${hexNum}`); - while (bigHexNumber>=58n) - { - base58NumArray.unshift(base58Keys[(bigHexNumber % base58Len).toString()]); - bigHexNumber = bigHexNumber / base58Len; - } - base58NumArray.unshift(base58Keys[bigHexNumber.toString()]); - return base58NumArray.join(''); + const base58NumArray =[]; + let bigHexNumber = BigInt(`0x${hexNum}`); + while (bigHexNumber>=58n) + { + base58NumArray.unshift(base58Keys[(bigHexNumber % base58Len).toString()]); + bigHexNumber = bigHexNumber / base58Len; + } + base58NumArray.unshift(base58Keys[bigHexNumber.toString()]); + return base58NumArray.join(''); } export function base582Hex(base58Num:string):string { - let base58NumArray =base58Num.split(''); - let big58Number = 0n; - let len = base58NumArray.length; - for(let i = 1;i<=len;i++) - { - let big58NumberTemp = BigInt(base58KeysObject[base58NumArray[len-i]])*(base58Len** BigInt(i-1)); - big58Number += big58NumberTemp; - } - return big58Number.toString(16); + const base58NumArray =base58Num.split(''); + let big58Number = 0n; + const len = base58NumArray.length; + for(let i = 1;i<=len;i++) + { + const big58NumberTemp = BigInt(base58KeysObject[base58NumArray[len-i]])*(base58Len** BigInt(i-1)); + big58Number += big58NumberTemp; + } + return big58Number.toString(16); } \ No newline at end of file diff --git a/server/src/apps/surveyManage/utils/index.ts b/server/src/apps/surveyManage/utils/index.ts index a1928da4..80d2b5a4 100644 --- a/server/src/apps/surveyManage/utils/index.ts +++ b/server/src/apps/surveyManage/utils/index.ts @@ -1,8 +1,9 @@ -import { SURVEY_STATUS, CommonError } from '../../../types/index' -import { hex2Base58 } from './base58' -import * as Joi from 'joi' +import { SURVEY_STATUS, CommonError } from '../../../types/index'; +import { hex2Base58 } from './base58'; +import * as Joi from 'joi'; +import * as fs from 'fs'; -export function getStatusObject({status}:{status:SURVEY_STATUS}) { +export function getStatusObject({ status }: { status: SURVEY_STATUS }) { return { status, id: status, @@ -10,39 +11,51 @@ export function getStatusObject({status}:{status:SURVEY_STATUS}) { }; } -export function getValidateValue(validationResult:Joi.ValidationResult):T { - if(validationResult.error) { - throw new CommonError(validationResult.error.details.map(e=>e.message).join()) +export function getValidateValue(validationResult: Joi.ValidationResult): T { + if (validationResult.error) { + throw new CommonError(validationResult.error.details.map(e => e.message).join()); } return validationResult.value; } export function genSurveyPath() { - return hex2Base58(process.hrtime.bigint().toString(16)) + return hex2Base58(process.hrtime.bigint().toString(16)); } -export function getMapByKey({data,key}:{data:Array,key:string}) { - const datamap = {} - for(const item of data) { - datamap[item[key]] = item - } - return datamap -} - -export function hanleSensitiveDate(value:string = ''): string { +export function hanleSensitiveDate(value: string = ''): string { if (!value) { - return '*' + return '*'; } - let str = '' + value + let str = '' + value; if (str.length === 1) { - str = '*' + str = '*'; } if (str.length === 2) { - str = str[0] + '*' + str = str[0] + '*'; } if (str.length >= 3) { - str = str[0] + '***' + str.slice(str.length - 1) + str = str[0] + '***' + str.slice(str.length - 1); } - return str -} \ No newline at end of file + return str; +} + +export const getFile = function(path, { encoding }: { encoding } = { encoding: 'utf-8' }): Promise { + return new Promise((resolve, reject) => { + + fs.stat(path, err => { + if (!err) { + fs.readFile(path, { encoding }, (err, data) => { + if (err) { + reject(err); + } else { + resolve(data.toString()); + } + }); + } else { + reject(err); + } + }); + }); + +}; \ No newline at end of file diff --git a/server/src/apps/surveyPublish/config/index.ts b/server/src/apps/surveyPublish/config/index.ts index a57641a5..5ded0551 100644 --- a/server/src/apps/surveyPublish/config/index.ts +++ b/server/src/apps/surveyPublish/config/index.ts @@ -1,17 +1,17 @@ const config = { - mongo:{ - url: process.env.xiaojuSurveyMongoUrl ||'mongodb://localhost:27017', - dbName:'xiaojuSurvey', - }, - session:{ - expireTime: parseInt(process.env.xiaojuSurveySessionExpireTime) || 8*3600*1000 - }, - encrypt:{ - type: process.env.xiaojuSurveyEncryptType ||'aes', - aesCodelength: parseInt(process.env.xiaojuSurveyAesCodelength) || 10 //aes密钥长度 - } -} + mongo: { + url: process.env.xiaojuSurveyMongoUrl ||'mongodb://localhost:27017', + dbName: 'xiaojuSurvey', + }, + session: { + expireTime: parseInt(process.env.xiaojuSurveySessionExpireTime) || 8*3600*1000 + }, + encrypt: { + type: process.env.xiaojuSurveyEncryptType ||'aes', + aesCodelength: parseInt(process.env.xiaojuSurveyAesCodelength) || 10 //aes密钥长度 + } +}; export function getConfig() { - return config + return config; } \ No newline at end of file diff --git a/server/src/apps/surveyPublish/db/mongo.ts b/server/src/apps/surveyPublish/db/mongo.ts index 53a25257..e368f475 100644 --- a/server/src/apps/surveyPublish/db/mongo.ts +++ b/server/src/apps/surveyPublish/db/mongo.ts @@ -1,6 +1,6 @@ -import { getConfig } from '../config/index' -import MongoService from '../../../utils/mongoService' +import { getConfig } from '../config/index'; +import MongoService from '../../../utils/mongoService'; -const config = getConfig() +const config = getConfig(); -export const mongo = new MongoService({ url: config.mongo.url, dbName: config.mongo.dbName }) \ No newline at end of file +export const mongo = new MongoService({ url: config.mongo.url, dbName: config.mongo.dbName }); \ No newline at end of file diff --git a/server/src/apps/surveyPublish/index.ts b/server/src/apps/surveyPublish/index.ts index 7f0a3d7e..dcd06ac9 100644 --- a/server/src/apps/surveyPublish/index.ts +++ b/server/src/apps/surveyPublish/index.ts @@ -1,52 +1,52 @@ -import { SurveyServer } from '../../decorator' -import { Request, Response } from 'koa' -import { surveySubmitService } from './service/surveySubmitService' -import { surveyPublishService } from './service/surveyPublishService' -import { getValidateValue } from './utils/index' -import { checkSign } from './utils/checkSign' -import * as Joi from 'joi' +import { SurveyApp, SurveyServer } from '../../decorator'; +import { surveySubmitService } from './service/surveySubmitService'; +import { surveyPublishService } from './service/surveyPublishService'; +import { getValidateValue } from './utils/index'; +import { checkSign } from './utils/checkSign'; +import * as Joi from 'joi'; +@SurveyApp('/api/surveyPublish') export default class SurveyPublish { // 获取发布配置 @SurveyServer({ type: 'http', method: 'get', routerName: '/getSurveyPublish' }) - async getSurveyPublish({ req, res }: { req: Request, res: Response }) { + async getSurveyPublish({ req }) { const surveySubmitData = getValidateValue(Joi.object({ surveyPath: Joi.string().required(), }).validate(req.query, { allowUnknown: true })); - const data = await surveyPublishService.get(surveySubmitData) + const data = await surveyPublishService.get(surveySubmitData); return { code: 200, data: data.surveyPublishRes, - } + }; } // 获取投票 @SurveyServer({ type: 'http', method: 'get', routerName: '/queryVote' }) - async queryVote({ req, res }: { req: Request, res: Response }) { + async queryVote({ req }) { const params = getValidateValue(Joi.object({ surveyPath: Joi.string().required(), voteKeyList: Joi.string().required(), }).validate(req.query, { allowUnknown: true })); - params.voteKeyList = params.voteKeyList.split(',') - const data = await surveyPublishService.queryVote(params) + params.voteKeyList = params.voteKeyList.split(','); + const data = await surveyPublishService.queryVote(params); return { code: 200, data: data, - } + }; } @SurveyServer({ type: 'http', method: 'get', routerName: '/getEncryptInfo' }) - async getEncryptInfo({ req, res }: { req: Request, res: Response }) { - const data = await surveySubmitService.getEncryptInfo() + async getEncryptInfo() { + const data = await surveySubmitService.getEncryptInfo(); return { code: 200, data: data, - } + }; } // 提交问卷 @SurveyServer({ type: 'http', method: 'post', routerName: '/submit' }) - async submit({ req, res }: { req: Request, res: Response }) { + async submit({ req }) { // 检查签名 - checkSign(req.body) + checkSign(req.body); // 校验参数 const surveySubmitData = getValidateValue(Joi.object({ surveyPath: Joi.string().required(), @@ -54,10 +54,10 @@ export default class SurveyPublish { encryptType: Joi.string(), sessionId: Joi.string(), }).validate(req.body, { allowUnknown: true })); - await surveySubmitService.submit({ surveySubmitData }) + await surveySubmitService.submit({ surveySubmitData }); return { code: 200, - msg: "提交成功", - } + msg: '提交成功', + }; } } \ No newline at end of file diff --git a/server/src/apps/surveyPublish/service/surveyKeyStoreService.ts b/server/src/apps/surveyPublish/service/surveyKeyStoreService.ts index b501e96c..fe9cf63f 100644 --- a/server/src/apps/surveyPublish/service/surveyKeyStoreService.ts +++ b/server/src/apps/surveyPublish/service/surveyKeyStoreService.ts @@ -1,56 +1,66 @@ -import { mongo } from '../db/mongo' - +import { mongo } from '../db/mongo'; +import { KeyStore } from '../../../types/keyStore'; // 该服务用于模拟redis class SurveyKeyStoreService { - getKeyStoreResult(surveyKeyStoreData: Array) { - const surveyKeyStoreReult = {} - for (const surveyKeyStoreItem of surveyKeyStoreData) { - surveyKeyStoreReult[surveyKeyStoreItem.key] = surveyKeyStoreItem.data - } - return surveyKeyStoreReult + getKeyStoreResult(surveyKeyStoreData: Array) { + const surveyKeyStoreReult = {}; + for (const surveyKeyStoreItem of surveyKeyStoreData) { + surveyKeyStoreReult[surveyKeyStoreItem.key] = surveyKeyStoreItem.data; } + return surveyKeyStoreReult; + } - async set({ surveyPath, key, data, type }) { - const surveyKeyStore = await mongo.getCollection({ collectionName: 'surveyKeyStore' }); - const setResult = await surveyKeyStore.updateOne({ - key, - surveyPath, - type - }, { - $set: { - key, - surveyPath, - type, - data, - createDate: Date.now(), - updateDate: Date.now(), - } - }, { - upsert: true //如果不存在则插入 - }) - return setResult - } + async set({ surveyPath, key, data, type }) { + const surveyKeyStore = await mongo.getCollection({ collectionName: 'surveyKeyStore' }); + const setResult = await surveyKeyStore.updateOne({ + key, + surveyPath, + type + }, { + $set: { + key, + surveyPath, + type, + data, + createDate: Date.now(), + updateDate: Date.now(), + } + }, { + upsert: true //如果不存在则插入 + }); + return setResult; + } - async get({ surveyPath, key, type }) { - const surveyKeyStore = await mongo.getCollection({ collectionName: 'surveyKeyStore' }); - const surveyKeyStoreData = await surveyKeyStore.findOne({ - key, - surveyPath, - type - }) - return surveyKeyStoreData?.data - } + async get({ surveyPath, key, type }) { + const surveyKeyStore = await mongo.getCollection({ collectionName: 'surveyKeyStore' }); + const surveyKeyStoreData = await surveyKeyStore.findOne({ + key, + surveyPath, + type + }); + return surveyKeyStoreData?.data; + } - async getAll({ surveyPath, keyList, type }) { - const surveyKeyStore = await mongo.getCollection({ collectionName: 'surveyKeyStore' }); - const surveyKeyStoreData = await surveyKeyStore.find({ - key: { $in: keyList }, - surveyPath, - type - }).toArray() - return this.getKeyStoreResult(surveyKeyStoreData) - } + async getAll({ surveyPath, keyList, type }) { + const surveyKeyStore = await mongo.getCollection({ collectionName: 'surveyKeyStore' }); + const res = await surveyKeyStore.find({ + key: { $in: keyList }, + surveyPath, + type + }).toArray(); + const surveyKeyStoreData : Array = res.map(doc => { + return { + key: doc.key, + surveyPath: doc.surveyPath, + type: doc.type, + data: doc.data, + createDate: doc.createDate, + updateDate: doc.updateDate, + }; + }); + return this.getKeyStoreResult(surveyKeyStoreData); + } } -export const surveyKeyStoreService = new SurveyKeyStoreService() \ No newline at end of file +export const surveyKeyStoreService = new SurveyKeyStoreService(); \ No newline at end of file diff --git a/server/src/apps/surveyPublish/service/surveyPublishService.ts b/server/src/apps/surveyPublish/service/surveyPublishService.ts index fc08d312..7c94e130 100644 --- a/server/src/apps/surveyPublish/service/surveyPublishService.ts +++ b/server/src/apps/surveyPublish/service/surveyPublishService.ts @@ -1,31 +1,31 @@ -import { mongo } from '../db/mongo' -import { surveyKeyStoreService } from './surveyKeyStoreService' -import { CommonError } from '../../../types/index' +import { mongo } from '../db/mongo'; +import { surveyKeyStoreService } from './surveyKeyStoreService'; +import { CommonError } from '../../../types/index'; class SurveyPublishService { - async get({ surveyPath }: { surveyPath: string }) { - const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); - const surveyMetaData = await surveyMeta.findOne({ surveyPath }) - if (!surveyMetaData) { - throw new CommonError('该问卷已不存在') - } - const surveyMetaRes = mongo.convertId2StringByDoc(surveyMetaData) - const surveyPublish = await mongo.getCollection({ collectionName: 'surveyPublish' }); - const surveyPublishData = await surveyPublish.findOne({ pageId: surveyMetaRes._id.toString() }, { sort: { createDate: -1 } }) - if (!surveyPublishData) { - throw new CommonError('该问卷未发布') - } - const surveyPublishRes = mongo.convertId2StringByDoc(surveyPublishData) - return { - surveyMetaRes, - surveyPublishRes - } + async get({ surveyPath }: { surveyPath: string }) { + const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); + const surveyMetaData = await surveyMeta.findOne({ surveyPath }); + if (!surveyMetaData) { + throw new CommonError('该问卷已不存在'); } + const surveyMetaRes = mongo.convertId2StringByDoc(surveyMetaData); + const surveyPublish = await mongo.getCollection({ collectionName: 'surveyPublish' }); + const surveyPublishData = await surveyPublish.findOne({ pageId: surveyMetaRes._id.toString() }, { sort: { createDate: -1 } }); + if (!surveyPublishData) { + throw new CommonError('该问卷未发布'); + } + const surveyPublishRes = mongo.convertId2StringByDoc(surveyPublishData); + return { + surveyMetaRes, + surveyPublishRes + }; + } - async queryVote({ surveyPath, voteKeyList }: { surveyPath: string, voteKeyList: Array }) { - return await surveyKeyStoreService.getAll({ surveyPath, keyList: voteKeyList, type: 'vote' }) - } + async queryVote({ surveyPath, voteKeyList }: { surveyPath: string, voteKeyList: Array }) { + return await surveyKeyStoreService.getAll({ surveyPath, keyList: voteKeyList, type: 'vote' }); + } } -export const surveyPublishService = new SurveyPublishService() \ No newline at end of file +export const surveyPublishService = new SurveyPublishService(); \ No newline at end of file diff --git a/server/src/apps/surveyPublish/service/surveySubmitService.ts b/server/src/apps/surveyPublish/service/surveySubmitService.ts index ffe1c585..8fd97ba1 100644 --- a/server/src/apps/surveyPublish/service/surveySubmitService.ts +++ b/server/src/apps/surveyPublish/service/surveySubmitService.ts @@ -1,130 +1,132 @@ -import { mongo } from '../db/mongo' -import { getStatusObject, getMapByKey, randomCode } from '../utils/index' -import { SURVEY_STATUS, CommonError } from '../../../types/index' -import { surveyKeyStoreService } from './surveyKeyStoreService' -import { getConfig } from '../config/index' -import * as CryptoJS from 'crypto-js' +import { mongo } from '../db/mongo'; +import { getStatusObject, randomCode } from '../utils/index'; +import { SURVEY_STATUS, CommonError } from '../../../types/index'; +import { surveyKeyStoreService } from './surveyKeyStoreService'; +import { getConfig } from '../config/index'; +import * as CryptoJS from 'crypto-js'; import * as aes from 'crypto-js/aes'; -import * as moment from 'moment' -const config = getConfig() +import * as moment from 'moment'; +import { keyBy } from 'lodash'; + +const config = getConfig(); class SurveySubmitService { - async addSessionData(data) { - const surveySession = await mongo.getCollection({ collectionName: 'surveySession' }); - const surveySessionRes = await surveySession.insertOne({ - data, - expireDate: Date.now() + config.session.expireTime - }) - return { - sessionId: surveySessionRes.insertedId.toString(), - ...data - } - } + async addSessionData(data) { + const surveySession = await mongo.getCollection({ collectionName: 'surveySession' }); + const surveySessionRes = await surveySession.insertOne({ + data, + expireDate: Date.now() + config.session.expireTime + }); + return { + sessionId: surveySessionRes.insertedId.toString(), + ...data + }; + } - async getSessionData(sessionId) { - const surveySession = await mongo.getCollection({ collectionName: 'surveySession' }); - const sessionObjectId = mongo.getObjectIdByStr(sessionId) - const surveySessionRes = await surveySession.findOne({ _id: sessionObjectId }) - await surveySession.deleteMany({ expireDate: { $lt: Date.now() } }) - return { sessionId, data: surveySessionRes.data } - } + async getSessionData(sessionId) { + const surveySession = await mongo.getCollection({ collectionName: 'surveySession' }); + const sessionObjectId = mongo.getObjectIdByStr(sessionId); + const surveySessionRes = await surveySession.findOne({ _id: sessionObjectId }); + await surveySession.deleteMany({ expireDate: { $lt: Date.now() } }); + return { sessionId, data: surveySessionRes.data }; + } - async getEncryptInfo() { - const encryptType = config.encrypt.type - let data = {} - if (encryptType === 'aes') { - data = await this.addSessionData({ - code: randomCode(config.encrypt.aesCodelength) - }) - } - return { - encryptType, - data - } + async getEncryptInfo() { + const encryptType = config.encrypt.type; + let data = {}; + if (encryptType === 'aes') { + data = await this.addSessionData({ + code: randomCode(config.encrypt.aesCodelength) + }); } + return { + encryptType, + data + }; + } - async submit({ surveySubmitData }: { surveySubmitData: any }) { - const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); - const surveyMetaRes = mongo.convertId2StringByDoc( - await surveyMeta.findOne({ surveyPath: surveySubmitData.surveyPath }) - ) - if (!surveyMetaRes) { - throw new CommonError('该问卷已不存在,无法提交') - } - const pageId = surveyMetaRes._id.toString() - const surveyPublish = await mongo.getCollection({ collectionName: 'surveyPublish' }); - const publishConf = await surveyPublish.findOne({ pageId }) - const surveySubmit = await mongo.getCollection({ collectionName: 'surveySubmit' }); - if (surveySubmitData.encryptType === 'base64') { - surveySubmitData.data = JSON.parse(decodeURIComponent(Buffer.from(surveySubmitData.data, "base64").toString())) - } else if (surveySubmitData.encryptType === 'aes') { - const sessionData = await this.getSessionData(surveySubmitData.sessionId) - surveySubmitData.data = JSON.parse(decodeURIComponent(aes.decrypt(surveySubmitData.data, sessionData.data.code).toString(CryptoJS.enc.Utf8))) - } else { - surveySubmitData.data = JSON.parse(surveySubmitData.data) - } - // 提交时间限制 - const begTime = publishConf?.code?.baseConf?.begTime || 0 - const endTime = publishConf?.code?.baseConf?.endTime || 0 - if (begTime && endTime) { - const nowStamp = Date.now() - const begTimeStamp = new Date(begTime).getTime() - const endTimeStamp = new Date(endTime).getTime() - if (nowStamp < begTimeStamp || nowStamp > endTimeStamp) { - throw new CommonError('不在答题有效期内') - } - } - // 提交时间段限制 - const answerBegTime = publishConf?.code?.baseConf?.answerBegTime || "00:00:00" - const answerEndTime = publishConf?.code?.baseConf?.answerEndTime || "23:59:59" - if (answerBegTime && answerEndTime) { - const nowStamp = Date.now() - const ymdString = moment().format('YYYY-MM-DD'); - const answerBegTimeStamp = new Date(`${ymdString} ${answerBegTime}`).getTime() - const answerEndTimeStamp = new Date(`${ymdString} ${answerEndTime}`).getTime() - if (nowStamp < answerBegTimeStamp || nowStamp > answerEndTimeStamp) { - throw new CommonError('不在答题时段内') - } - } - // 提交总数限制 - const tLimit = publishConf?.code?.baseConf?.tLimit || 0 - if (tLimit > 0) { - // 提升性能可以使用redis - let nowSubmitCount = await surveySubmit.countDocuments({ surveyPath: surveySubmitData.surveyPath }) || 0 - if (nowSubmitCount >= tLimit) { - throw new CommonError('超出提交总数限制') - } - } - // 投票信息保存 - const dataList = publishConf?.code?.dataConf?.dataList || [] - const dataListMap = getMapByKey({ data: dataList, key: 'field' }) - const surveySubmitDataKeys = Object.keys(surveySubmitData.data) - for (const field of surveySubmitDataKeys) { - const configData = dataListMap[field] - if (configData && /vote/.exec(configData.type)) { - const voteData = (await surveyKeyStoreService.get({ surveyPath: surveySubmitData.surveyPath, key: field, type: 'vote' })) || { total: 0 } - const fields = Array.isArray(surveySubmitData.data[field]) ? surveySubmitData.data[field] : [surveySubmitData.data[field]] - for (const field of fields) { - voteData.total++; - if (!voteData[field]) { - voteData[field] = 1 - } else { - voteData[field]++; - } - } - await surveyKeyStoreService.set({ surveyPath: surveySubmitData.surveyPath, key: field, data: voteData, type: 'vote' }) - } - } - // 提交问卷 - const surveySubmitRes = await surveySubmit.insertOne({ - ...surveySubmitData, - pageId, - curStatus: getStatusObject({ status: SURVEY_STATUS.new }), - createDate: Date.now() - }) - return surveySubmitRes + async submit({ surveySubmitData }) { + const surveyMeta = await mongo.getCollection({ collectionName: 'surveyMeta' }); + const surveyMetaRes = mongo.convertId2StringByDoc( + await surveyMeta.findOne({ surveyPath: surveySubmitData.surveyPath }) + ); + if (!surveyMetaRes) { + throw new CommonError('该问卷已不存在,无法提交'); } + const pageId = surveyMetaRes._id.toString(); + const surveyPublish = await mongo.getCollection({ collectionName: 'surveyPublish' }); + const publishConf = await surveyPublish.findOne({ pageId }); + const surveySubmit = await mongo.getCollection({ collectionName: 'surveySubmit' }); + if (surveySubmitData.encryptType === 'base64') { + surveySubmitData.data = JSON.parse(decodeURIComponent(Buffer.from(surveySubmitData.data, 'base64').toString())); + } else if (surveySubmitData.encryptType === 'aes') { + const sessionData = await this.getSessionData(surveySubmitData.sessionId); + surveySubmitData.data = JSON.parse(decodeURIComponent(aes.decrypt(surveySubmitData.data, sessionData.data.code).toString(CryptoJS.enc.Utf8))); + } else { + surveySubmitData.data = JSON.parse(surveySubmitData.data); + } + // 提交时间限制 + const begTime = publishConf?.code?.baseConf?.begTime || 0; + const endTime = publishConf?.code?.baseConf?.endTime || 0; + if (begTime && endTime) { + const nowStamp = Date.now(); + const begTimeStamp = new Date(begTime).getTime(); + const endTimeStamp = new Date(endTime).getTime(); + if (nowStamp < begTimeStamp || nowStamp > endTimeStamp) { + throw new CommonError('不在答题有效期内'); + } + } + // 提交时间段限制 + const answerBegTime = publishConf?.code?.baseConf?.answerBegTime || '00:00:00'; + const answerEndTime = publishConf?.code?.baseConf?.answerEndTime || '23:59:59'; + if (answerBegTime && answerEndTime) { + const nowStamp = Date.now(); + const ymdString = moment().format('YYYY-MM-DD'); + const answerBegTimeStamp = new Date(`${ymdString} ${answerBegTime}`).getTime(); + const answerEndTimeStamp = new Date(`${ymdString} ${answerEndTime}`).getTime(); + if (nowStamp < answerBegTimeStamp || nowStamp > answerEndTimeStamp) { + throw new CommonError('不在答题时段内'); + } + } + // 提交总数限制 + const tLimit = publishConf?.code?.baseConf?.tLimit || 0; + if (tLimit > 0) { + // 提升性能可以使用redis + const nowSubmitCount = await surveySubmit.countDocuments({ surveyPath: surveySubmitData.surveyPath }) || 0; + if (nowSubmitCount >= tLimit) { + throw new CommonError('超出提交总数限制'); + } + } + // 投票信息保存 + const dataList = publishConf?.code?.dataConf?.dataList || []; + const dataListMap = keyBy(dataList, 'field'); + const surveySubmitDataKeys = Object.keys(surveySubmitData.data); + for (const field of surveySubmitDataKeys) { + const configData = dataListMap[field]; + if (configData && /vote/.exec(configData.type)) { + const voteData = (await surveyKeyStoreService.get({ surveyPath: surveySubmitData.surveyPath, key: field, type: 'vote' })) || { total: 0 }; + voteData.total++; + const fields = Array.isArray(surveySubmitData.data[field]) ? surveySubmitData.data[field] : [surveySubmitData.data[field]]; + for (const field of fields) { + if (!voteData[field]) { + voteData[field] = 1; + } else { + voteData[field]++; + } + } + await surveyKeyStoreService.set({ surveyPath: surveySubmitData.surveyPath, key: field, data: voteData, type: 'vote' }); + } + } + // 提交问卷 + const surveySubmitRes = await surveySubmit.insertOne({ + ...surveySubmitData, + pageId, + curStatus: getStatusObject({ status: SURVEY_STATUS.new }), + createDate: Date.now() + }); + return surveySubmitRes; + } } -export const surveySubmitService = new SurveySubmitService() \ No newline at end of file +export const surveySubmitService = new SurveySubmitService(); \ No newline at end of file diff --git a/server/src/apps/surveyPublish/utils/checkSign.ts b/server/src/apps/surveyPublish/utils/checkSign.ts index 44b2b39f..978e02cf 100644 --- a/server/src/apps/surveyPublish/utils/checkSign.ts +++ b/server/src/apps/surveyPublish/utils/checkSign.ts @@ -1,48 +1,48 @@ import { - createHash + createHash } from 'crypto'; -import { CommonError } from '../../../types/index' +import { CommonError } from '../../../types/index'; const hash256 = (text) => { - return createHash('sha256').update(text).digest('hex') -} + return createHash('sha256').update(text).digest('hex'); +}; const undefinedToString = (data) => { - const res = {} - for (const key in data) { - if (data[key] === undefined) { - res[key] = '' - } else { - res[key] = data[key] - } + const res = {}; + for (const key in data) { + if (data[key] === undefined) { + res[key] = ''; + } else { + res[key] = data[key]; } - return res; } + return res; +}; - const getSignByData = (sourceData, ts) => { - const data = undefinedToString(sourceData) - const keysArr = Object.keys(data) - keysArr.sort() - let signArr = keysArr.map(key => { - if (typeof data[key] === 'string') { - return `${key}=${encodeURIComponent(data[key])}` - } - return `${key}=${JSON.stringify(data[key])}` - }) - const sign = hash256(signArr.join('') + ts) - return `${sign}` - } +const getSignByData = (sourceData, ts) => { + const data = undefinedToString(sourceData); + const keysArr = Object.keys(data); + keysArr.sort(); + const signArr = keysArr.map(key => { + if (typeof data[key] === 'string') { + return `${key}=${encodeURIComponent(data[key])}`; + } + return `${key}=${JSON.stringify(data[key])}`; + }); + const sign = hash256(signArr.join('') + ts); + return `${sign}`; +}; - export const checkSign = (sourceData) =>{ - const sign = sourceData.sign - if(!sign) { - throw new CommonError('请求签名不存在') - } - delete sourceData.sign - const [inSign, ts] = sign.split('.'); - const realSign = getSignByData(sourceData, ts) - if(inSign!==realSign) { - throw new CommonError('请求签名异常') - } - return true; +export const checkSign = (sourceData) => { + const sign = sourceData.sign; + if(!sign) { + throw new CommonError('请求签名不存在'); } + delete sourceData.sign; + const [inSign, ts] = sign.split('.'); + const realSign = getSignByData(sourceData, ts); + if(inSign!==realSign) { + throw new CommonError('请求签名异常'); + } + return true; +}; \ No newline at end of file diff --git a/server/src/apps/surveyPublish/utils/index.ts b/server/src/apps/surveyPublish/utils/index.ts index b071279d..d0e062b5 100644 --- a/server/src/apps/surveyPublish/utils/index.ts +++ b/server/src/apps/surveyPublish/utils/index.ts @@ -1,32 +1,24 @@ -import { SURVEY_STATUS, CommonError } from '../../../types/index' -import * as Joi from 'joi' +import { SURVEY_STATUS, CommonError } from '../../../types/index'; +import * as Joi from 'joi'; -export function getMapByKey({data,key}:{data:Array,key:string}) { - const datamap = {} - for(const item of data) { - datamap[item[key]] = item - } - return datamap -} - -export function getStatusObject({status}:{status:SURVEY_STATUS}) { +export function getStatusObject({ status }: { status: SURVEY_STATUS }) { return { status, id: status, date: Date.now(), }; } -export function getValidateValue(validationResult:Joi.ValidationResult):T { - if(validationResult.error) { - throw new CommonError(validationResult.error.details.map(e=>e.message).join()) +export function getValidateValue(validationResult: Joi.ValidationResult): T { + if (validationResult.error) { + throw new CommonError(validationResult.error.details.map(e => e.message).join()); } return validationResult.value; } export function randomCode(length) { - let charList:Array = [] - for(let i=0;i = []; + for (let i = 0; i < length; i++) { + charList.push(Math.floor(Math.random() * 16).toString(16)); } - return charList.join('') + return charList.join(''); } \ No newline at end of file diff --git a/server/src/apps/ui/index.ts b/server/src/apps/ui/index.ts index d97a045a..edb95db9 100644 --- a/server/src/apps/ui/index.ts +++ b/server/src/apps/ui/index.ts @@ -1,29 +1,25 @@ -import { SurveyServer } from '../../decorator' -import { Request, Response } from 'koa' -import { createReadStream } from 'fs' -import * as path from 'path' +import { SurveyApp, SurveyServer } from '../../decorator'; +import { createReadStream } from 'fs'; +import * as path from 'path'; +@SurveyApp('') export default class UI { -@SurveyServer({ type: 'http', method: 'get', routerName: '/render/(.*)' }) - async render({ req, res }: {req:Request, res:Response}) { + @SurveyServer({ type: 'http', method: 'get', routerName: '/render/(.*)' }) + async render({ res }) { const filePath = path.join(__dirname, 'public', 'render.html'); - res.type = path.extname(filePath) - return createReadStream(filePath) + res.type = path.extname(filePath); + return createReadStream(filePath); } - @SurveyServer({ type: 'http', method: 'get', routerName: '/management/(.*)' }) - async management({ req, res }: {req:Request, res:Response}) { + @SurveyServer({ type: 'http', method: 'get', routerName: '/management/(.*)' }) + async management({ res }) { const filePath = path.join(__dirname, 'public', 'management.html'); - res.type = path.extname(filePath) - return createReadStream(filePath) + res.type = path.extname(filePath); + return createReadStream(filePath); } - @SurveyServer({ type: 'http', method: 'get', routerName: '/(.*)' }) - async index({ req, res }: {req:Request, res:Response}) { - let reqPath = req.path; - if (req.path === '/') { - reqPath = '/management.html' - } - const filePath = path.join(__dirname, 'public', reqPath); - res.type = path.extname(filePath) - return createReadStream(filePath) + @SurveyServer({ type: 'http', method: 'get', routerName: '/' }) + async index({ res }) { + const filePath = path.join(__dirname, 'public', 'management.html'); + res.type = path.extname(filePath); + return createReadStream(filePath); } } \ No newline at end of file diff --git a/server/src/apps/user/config/index.ts b/server/src/apps/user/config/index.ts index adab92a3..265b6c9d 100644 --- a/server/src/apps/user/config/index.ts +++ b/server/src/apps/user/config/index.ts @@ -1,14 +1,14 @@ const config = { - mongo:{ - url: process.env.xiaojuSurveyMongoUrl ||'mongodb://localhost:27017', - dbName:'xiaojuSurvey', - }, - jwt:{ - secret: process.env.xiaojuSurveyJwtSecret || 'xiaojuSurveyJwtSecret', - expiresIn: process.env.xiaojuSurveyJwtExpiresIn || '8h', - } -} + mongo: { + url: process.env.xiaojuSurveyMongoUrl ||'mongodb://localhost:27017', + dbName: 'xiaojuSurvey', + }, + jwt: { + secret: process.env.xiaojuSurveyJwtSecret || 'xiaojuSurveyJwtSecret', + expiresIn: process.env.xiaojuSurveyJwtExpiresIn || '8h', + } +}; export function getConfig() { - return config + return config; } \ No newline at end of file diff --git a/server/src/apps/user/db/mongo.ts b/server/src/apps/user/db/mongo.ts index bc3fc2ed..d0885a09 100644 --- a/server/src/apps/user/db/mongo.ts +++ b/server/src/apps/user/db/mongo.ts @@ -1,6 +1,6 @@ -import { getConfig } from '../config/index' -import MongoService from '../../../utils/mongoService' +import { getConfig } from '../config/index'; +import MongoService from '../../../utils/mongoService'; -const config = getConfig() +const config = getConfig(); -export const mongo = new MongoService({ url: config.mongo.url, dbName: config.mongo.dbName }) +export const mongo = new MongoService({ url: config.mongo.url, dbName: config.mongo.dbName }); diff --git a/server/src/apps/user/index.ts b/server/src/apps/user/index.ts index 746079f0..117bb5c2 100644 --- a/server/src/apps/user/index.ts +++ b/server/src/apps/user/index.ts @@ -1,83 +1,85 @@ -import { SurveyServer } from '../../decorator' -import { Request, Response } from 'koa' -import * as Joi from 'joi' -import { userService } from './service/userService' -import { captchaService } from './service/captchaService' -import { getValidateValue } from './utils/index' +import { SurveyApp, SurveyServer } from '../../decorator'; +import { Request, Response } from 'koa'; +import * as Joi from 'joi'; +import { userService } from './service/userService'; +import { captchaService } from './service/captchaService'; +import { getValidateValue } from './utils/index'; -import { CommonError } from '../../types/index' +import { CommonError } from '../../types/index'; + +@SurveyApp('/api/user') export default class User { - @SurveyServer({ type: 'http', method: 'post', routerName: '/register' }) - async register({ req, res }: { req: Request, res: Response }) { - const userInfo = getValidateValue(Joi.object({ - username: Joi.string().required(), - password: Joi.string().required(), - captchaId: Joi.string().required(), - captcha: Joi.string().required(), - }).validate(req.body, { allowUnknown: true })); - const isCorrect = await captchaService.checkCaptchaIsCorrect({ captcha: userInfo.captcha, id: userInfo.captchaId }) - if (!isCorrect) { - throw new CommonError('验证码不正确') - } - const userRegisterRes = await userService.register({ - username: userInfo.username, - password: userInfo.password, - }) - // 删除验证码 - captchaService.deleteCaptcha({ id: userInfo.captchaId }) - return { - code: 200, - data: userRegisterRes, - } + @SurveyServer({ type: 'http', method: 'post', routerName: '/register' }) + async register({ req }: { req: Request, res: Response }) { + const userInfo = getValidateValue(Joi.object({ + username: Joi.string().required(), + password: Joi.string().required(), + captchaId: Joi.string().required(), + captcha: Joi.string().required(), + }).validate(req.body, { allowUnknown: true })); + const isCorrect = await captchaService.checkCaptchaIsCorrect({ captcha: userInfo.captcha, id: userInfo.captchaId }); + if (!isCorrect) { + throw new CommonError('验证码不正确'); } + const userRegisterRes = await userService.register({ + username: userInfo.username, + password: userInfo.password, + }); + // 删除验证码 + captchaService.deleteCaptcha({ id: userInfo.captchaId }); + return { + code: 200, + data: userRegisterRes, + }; + } - @SurveyServer({ type: 'http', method: 'post', routerName: '/login' }) - async login({ req, res }: { req: Request, res: Response }) { - const userInfo = getValidateValue(Joi.object({ - username: Joi.string().required(), - password: Joi.string().required(), - captchaId: Joi.string().required(), - captcha: Joi.string().required(), - }).validate(req.body, { allowUnknown: true })); - const isCorrect = await captchaService.checkCaptchaIsCorrect({ captcha: userInfo.captcha, id: userInfo.captchaId }) - if (!isCorrect) { - throw new CommonError('验证码不正确') - } - const data = await userService.login({ - username: userInfo.username, - password: userInfo.password, - }) - // 删除验证码 - captchaService.deleteCaptcha({ id: userInfo.captchaId }) - return { - code: 200, - data, - } + @SurveyServer({ type: 'http', method: 'post', routerName: '/login' }) + async login({ req }: { req: Request, res: Response }) { + const userInfo = getValidateValue(Joi.object({ + username: Joi.string().required(), + password: Joi.string().required(), + captchaId: Joi.string().required(), + captcha: Joi.string().required(), + }).validate(req.body, { allowUnknown: true })); + const isCorrect = await captchaService.checkCaptchaIsCorrect({ captcha: userInfo.captcha, id: userInfo.captchaId }); + if (!isCorrect) { + throw new CommonError('验证码不正确'); } + const data = await userService.login({ + username: userInfo.username, + password: userInfo.password, + }); + // 删除验证码 + captchaService.deleteCaptcha({ id: userInfo.captchaId }); + return { + code: 200, + data, + }; + } - @SurveyServer({ type: 'rpc' }) - async getUserByToken({ params, context }: { params: any, context: any }) { - const data = await userService.getUserByToken({ token: params.token }) - return { - result: data, - context, // 上下文主要是传递调用方信息使用,比如traceid - } - } + @SurveyServer({ type: 'rpc' }) + async getUserByToken({ params, context }) { + const data = await userService.getUserByToken({ token: params.token }); + return { + result: data, + context, // 上下文主要是传递调用方信息使用,比如traceid + }; + } - @SurveyServer({ type: 'http', method: 'post', routerName: '/captcha' }) - async refreshCaptcha({ req }) { - const captchaData = captchaService.createCaptcha() - const res = await captchaService.addCaptchaData({ text: captchaData.text }) - if (req.body && req.body.captchaId) { - // 删除验证码 - captchaService.deleteCaptcha({ id: req.body.captchaId }) - } - return { - code: 200, - data: { - id: res.insertedId, - img: captchaData.data, - }, - } + @SurveyServer({ type: 'http', method: 'post', routerName: '/captcha' }) + async refreshCaptcha({ req }) { + const captchaData = captchaService.createCaptcha(); + const res = await captchaService.addCaptchaData({ text: captchaData.text }); + if (req.body && req.body.captchaId) { + // 删除验证码 + captchaService.deleteCaptcha({ id: req.body.captchaId }); } + return { + code: 200, + data: { + id: res.insertedId, + img: captchaData.data, + }, + }; + } } \ No newline at end of file diff --git a/server/src/apps/user/service/captchaService.ts b/server/src/apps/user/service/captchaService.ts index d3a4a2de..75599fc5 100644 --- a/server/src/apps/user/service/captchaService.ts +++ b/server/src/apps/user/service/captchaService.ts @@ -1,5 +1,5 @@ -import { mongo } from '../db/mongo' -import { create } from 'svg-captcha' +import { mongo } from '../db/mongo'; +import { create } from 'svg-captcha'; class CaptchaService { createCaptcha() { @@ -9,7 +9,7 @@ class CaptchaService { noise: 3, // 干扰线数量 color: true, // 启用彩色 background: '#f0f0f0', // 背景色 - }) + }); } async addCaptchaData({ text }) { @@ -30,11 +30,11 @@ class CaptchaService { async deleteCaptcha({ id }) { const captchaDb = await mongo.getCollection({ collectionName: 'captcha' }); - const _id = mongo.getObjectIdByStr(id) + const _id = mongo.getObjectIdByStr(id); await captchaDb.deleteOne({ _id - }) + }); } } -export const captchaService = new CaptchaService() \ No newline at end of file +export const captchaService = new CaptchaService(); diff --git a/server/src/apps/user/service/userService.ts b/server/src/apps/user/service/userService.ts index 169d9676..96d25867 100644 --- a/server/src/apps/user/service/userService.ts +++ b/server/src/apps/user/service/userService.ts @@ -1,81 +1,81 @@ import { - verify as jwtVerify, - sign as jwtSign + verify as jwtVerify, + sign as jwtSign } from 'jsonwebtoken'; import { - createHash + createHash } from 'crypto'; -import { mongo } from '../db/mongo' -import { getStatusObject } from '../utils/index' -import { SURVEY_STATUS, CommonError } from '../../../types/index' -import { getConfig } from '../config/index' -const config = getConfig() +import { mongo } from '../db/mongo'; +import { getStatusObject } from '../utils/index'; +import { SURVEY_STATUS, CommonError } from '../../../types/index'; +import { getConfig } from '../config/index'; +const config = getConfig(); class UserService { - hash256(text) { - return createHash('sha256').update(text).digest('hex') - } + hash256(text) { + return createHash('sha256').update(text).digest('hex'); + } - getToken(userInfo) { - return jwtSign(userInfo, config.jwt.secret, { expiresIn: config.jwt.expiresIn }); - } + getToken(userInfo) { + return jwtSign(userInfo, config.jwt.secret, { expiresIn: config.jwt.expiresIn }); + } - async register(userInfo: { username: string, password: string }) { - const user = await mongo.getCollection({ collectionName: 'user' }); - const userRes = await user.findOne({ - username: userInfo.username, - }) - if (userRes) { - throw new CommonError('该用户已存在') - } - const userInsertRes = await user.insertOne({ - username: userInfo.username, - password: this.hash256(userInfo.password), - curStatus: getStatusObject({ status: SURVEY_STATUS.new }), - createDate: Date.now() - }) - const token = this.getToken({ - _id: userInsertRes.insertedId.toString(), - username: userInfo.username - }); - return { userInsertRes, token, username: userInfo.username } + async register(userInfo: { username: string, password: string }) { + const user = await mongo.getCollection({ collectionName: 'user' }); + const userRes = await user.findOne({ + username: userInfo.username, + }); + if (userRes) { + throw new CommonError('该用户已存在'); } + const userInsertRes = await user.insertOne({ + username: userInfo.username, + password: this.hash256(userInfo.password), + curStatus: getStatusObject({ status: SURVEY_STATUS.new }), + createDate: Date.now() + }); + const token = this.getToken({ + _id: userInsertRes.insertedId.toString(), + username: userInfo.username + }); + return { userInsertRes, token, username: userInfo.username }; + } - async login(userInfo: { username: string, password: string }) { - const user = await mongo.getCollection({ collectionName: 'user' }); - const userRes = await user.findOne({ - username: userInfo.username, - password: this.hash256(userInfo.password), - }) - if (!userRes) { - throw new CommonError('用户名或密码错误') - } - const token = this.getToken({ - _id: userRes._id.toString(), - username: userInfo.username - }); - return { token, username: userInfo.username } + async login(userInfo: { username: string, password: string }) { + const user = await mongo.getCollection({ collectionName: 'user' }); + const userRes = await user.findOne({ + username: userInfo.username, + password: this.hash256(userInfo.password), + }); + if (!userRes) { + throw new CommonError('用户名或密码错误'); } + const token = this.getToken({ + _id: userRes._id.toString(), + username: userInfo.username + }); + return { token, username: userInfo.username }; + } - async getUserByToken(tokenInfo: { token: string }) { - let userInfo; - try { - userInfo = jwtVerify(tokenInfo.token, config.jwt.secret) - } catch (err) { - throw new CommonError('用户凭证无效或已过期', 403) - } - const user = await mongo.getCollection({ collectionName: 'user' }); - const userRes = await user.findOne({ - _id: mongo.getObjectIdByStr(userInfo._id), - }) - if (!userRes) { - throw new CommonError('用户已不存在') - } - return mongo.convertId2StringByDoc(userRes); + async getUserByToken(tokenInfo: { token: string }) { + let userInfo; + try { + userInfo = jwtVerify(tokenInfo.token, config.jwt.secret); + } catch (err) { + throw new CommonError('用户凭证无效或已过期', 403); } + const user = await mongo.getCollection({ collectionName: 'user' }); + const userRes = await user.findOne({ + _id: mongo.getObjectIdByStr(userInfo._id), + }); + if (!userRes) { + throw new CommonError('用户已不存在'); + } + return mongo.convertId2StringByDoc(userRes); + } } -export const userService = new UserService() \ No newline at end of file +export const userService = new UserService(); \ No newline at end of file diff --git a/server/src/apps/user/utils/index.ts b/server/src/apps/user/utils/index.ts index 98861030..8233dbca 100644 --- a/server/src/apps/user/utils/index.ts +++ b/server/src/apps/user/utils/index.ts @@ -1,5 +1,5 @@ -import { SURVEY_STATUS, CommonError } from '../../../types/index' -import * as Joi from 'joi' +import { SURVEY_STATUS, CommonError } from '../../../types/index'; +import * as Joi from 'joi'; export function getStatusObject({ status }: { status: SURVEY_STATUS }) { return { status, @@ -7,9 +7,9 @@ export function getStatusObject({ status }: { status: SURVEY_STATUS }) { date: Date.now(), }; } -export function getValidateValue(validationResult: Joi.ValidationResult): T { +export function getValidateValue(validationResult: Joi.ValidationResult): T { if (validationResult.error) { - throw new CommonError(validationResult.error.details.map(e => e.message).join()) + throw new CommonError(validationResult.error.details.map(e => e.message).join()); } return validationResult.value; } \ No newline at end of file diff --git a/server/src/decorator.ts b/server/src/decorator.ts index 49c6173e..8bcbae2e 100644 --- a/server/src/decorator.ts +++ b/server/src/decorator.ts @@ -1,19 +1,29 @@ type ServerType = 'http' | 'websocket' | 'rpc' -export interface ServerValue { +export interface RouterOptions { type: ServerType, - method: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options'; - routerName: string; + method?: 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options'; + routerName?: string; } -export const SurveyServerConfigKey = Symbol('appConfig') // vm环境和worker环境上下文不一致导致不能使用Symbol -export function SurveyServer(surveyServer) { - return function (target: any, propertyKey: string, _descriptor: PropertyDescriptor) { - if (!target[SurveyServerConfigKey]) { - target[SurveyServerConfigKey] = new Map() +export const surveyServerKey = Symbol('surveyServer'); // vm环境和worker环境上下文不一致导致不能使用Symbol +export const surveyAppKey = Symbol('surveyApp'); + +export function SurveyApp(routerName) { + return (target: unknown) => { + if (!target[surveyAppKey]) { + target[surveyAppKey] = routerName; } - target[SurveyServerConfigKey].set( + }; +} + +export function SurveyServer(options: RouterOptions) { + return function(target: unknown, propertyKey: string) { + if (!target[surveyServerKey]) { + target[surveyServerKey] = new Map(); + } + target[surveyServerKey].set( propertyKey, - surveyServer - ) - } + options + ); + }; } \ No newline at end of file diff --git a/server/src/index.ts b/server/src/index.ts index e659de04..0331d2cc 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -1,21 +1,30 @@ -import * as os from 'os' +import * as os from 'os'; import * as Koa from 'koa'; -import * as KoaBodyparser from 'koa-bodyparser' -import * as logger from 'koa-pino-logger' -import { getRouter } from './router' -import { outputCatch } from './middleware/outputCatch' +import * as KoaBodyparser from 'koa-bodyparser'; +import * as KoaStatic from 'koa-static'; +import * as logger from 'koa-pino-logger'; +import { initRouter } from './router'; +import { outputCatch } from './middleware/outputCatch'; +import * as path from 'path'; -const app = new Koa(); -app.use(outputCatch({ showErrorStack: true })) -app.use(logger()) -app.use(KoaBodyparser({ +async function main() { + const app = new Koa(); + app.use(outputCatch({ showErrorStack: true })); + app.use(logger()); + app.use(KoaBodyparser({ formLimit: '30mb', jsonLimit: '30mb', textLimit: '30mb', xmlLimit: '30mb', -})) + })); -app.use(getRouter().routes()) -const port = process.env.PORT || 3000 -app.listen(port) -process.stdout.write(`${os.EOL}server run: http://127.0.0.1:${port} ${os.EOL}`) \ No newline at end of file + await initRouter(app); + + app.use(KoaStatic(path.join(__dirname, './apps/ui/public'))); + + const port = process.env.PORT || 3000; + app.listen(port); + process.stdout.write(`${os.EOL}server run: http://127.0.0.1:${port} ${os.EOL}`); +} + +main(); diff --git a/server/src/middleware/outputCatch.ts b/server/src/middleware/outputCatch.ts index 06b804ff..0e973930 100644 --- a/server/src/middleware/outputCatch.ts +++ b/server/src/middleware/outputCatch.ts @@ -1,13 +1,13 @@ export function outputCatch({ showErrorStack }: { showErrorStack: boolean }) { - return async function (ctx, next) { - try { - await next() - } catch (err) { - const outputData = { ...err } - if (showErrorStack) { - outputData.stack = err.stack; - } - return ctx.body = outputData - } + return async function(ctx, next) { + try { + await next(); + } catch (err) { + const outputData = { ...err }; + if (showErrorStack) { + outputData.stack = err.stack; + } + return ctx.body = outputData; } + }; } \ No newline at end of file diff --git a/server/src/registry.ts b/server/src/registry.ts new file mode 100644 index 00000000..24845529 --- /dev/null +++ b/server/src/registry.ts @@ -0,0 +1,21 @@ +class AppRegistry { + private apps: Record; + + constructor() { + this.apps = {}; + } + + registerApp(name: string, service: unknown) { + if (!this.apps[name]) { + this.apps[name] = service; + } + } + + getApp(name: string) { + return this.apps[name]; + } +} + +const appRegistry = new AppRegistry(); + +export default appRegistry; diff --git a/server/src/router.ts b/server/src/router.ts index 13839d8b..70b24d0d 100644 --- a/server/src/router.ts +++ b/server/src/router.ts @@ -1,39 +1,37 @@ import * as Router from 'koa-router'; -import { Context } from 'koa' -import { SurveyServerConfigKey } from './decorator'; - -import Ui from './apps/ui/index' -import SurveyManage from './apps/surveyManage/index' -import SurveyPublish from './apps/surveyPublish/index' -import User from './apps/user/index' +import { Context } from 'koa'; +import { RouterOptions, surveyAppKey, surveyServerKey } from './decorator'; +import { glob } from 'glob'; +import * as path from 'path'; +import appRegistry from './registry'; -function loadAppRouter(app, appRouter) { - const appServerConfigMap = app[SurveyServerConfigKey] - for (const [serveName, serveValue] of appServerConfigMap) { - const middleware = async (ctx: Context) => { - const data = await app[serveName]({ req: ctx.request, res: ctx.response }) - return ctx.body = data - } - const method = serveValue.method || 'all' - const routerName = serveValue.routerName || `/${serveName}` - appRouter[method](routerName, middleware) +export async function initRouter(app) { + const rootRouter = new Router(); + const entries = await glob(path.join(__dirname, './apps/*/index.{ts,js}')); + + for (const entry of entries) { + const module = await import(entry); + const instance = new module.default(); + + const moduleRouter = new Router(); + + const serverConfig: Map = instance[surveyServerKey]; + + for (const [serverName, serverValue] of serverConfig.entries()) { + if (serverValue.routerName) { + const method = serverValue.method || 'get'; + moduleRouter[method](serverValue.routerName, async (ctx: Context, next) => { + const ret = await instance[serverName]({ req: ctx.request, res: ctx.response }, next); + ctx.body = ret; + }); + } } - return appRouter -} + rootRouter.use(module.default[surveyAppKey], moduleRouter.routes()); -export function getRouter() { - const rootRouter = new Router() - const apiAppMap = { - surveyManage: new SurveyManage(), - surveyPublish: new SurveyPublish(), - user: new User(), - } - for (const [apiAppName, apiApp] of Object.entries(apiAppMap)) { - const appRouter = new Router() - loadAppRouter(apiApp, appRouter) - rootRouter.use(`/api/${apiAppName}`, appRouter.routes(), rootRouter.allowedMethods()) - } - loadAppRouter(new Ui(), rootRouter) - return rootRouter + appRegistry.registerApp(instance.constructor.name.toLowerCase(), instance); + + } + // console.log(rootRouter); + app.use(rootRouter.routes()); } \ No newline at end of file diff --git a/server/src/rpc.ts b/server/src/rpc.ts index 26caf494..bd8f4c9c 100644 --- a/server/src/rpc.ts +++ b/server/src/rpc.ts @@ -1,11 +1,12 @@ -export async function rpcInvote(appServerName: string, params: P): Promise { - const appServerNameData = /^(\w+)\.(\w+)$/.exec(appServerName); - if (!appServerNameData) { - throw new Error('rpc调用必须按照app.function名方式填写,app和function名称只支持数字字母下划线') - } - const appName = appServerNameData[1]; - const serverName = appServerNameData[2]; - const App = require(`./apps/${appName}/index`).default - const instance = new App() - return await instance[serverName](params) +import appRegistry from './registry'; + +export function rpcInvote(appServerName: string, params: P): Promise { + const appServerNameData = /^(\w+)\.(\w+)$/.exec(appServerName); + if (!appServerNameData) { + throw new Error('rpc调用必须按照app.function名方式填写,app和function名称只支持数字字母下划线'); + } + const appName = appServerNameData[1]; + const serverName = appServerNameData[2]; + const instance = appRegistry.getApp(appName.toLowerCase()); + return instance[serverName](params); } \ No newline at end of file diff --git a/server/src/types/index.ts b/server/src/types/index.ts index 11eac7a1..fd66361b 100644 --- a/server/src/types/index.ts +++ b/server/src/types/index.ts @@ -1,43 +1,53 @@ export enum DICT_TYPE { - danger = "danger", - secret = "secret" + danger = 'danger', + secret = 'secret' } export enum SURVEY_STATUS { - new = "new", - editing = "editing", - pausing = "pausing", - published = "published", - removed = "removed" + new = 'new', + editing = 'editing', + pausing = 'pausing', + published = 'published', + removed = 'removed' } export enum QUESTION_TYPE { - enps = "enps", - nps = "nps", - question = "question", //通用问卷 - register = "register", //报名 - vote = "vote" //投票 + enps = 'enps', + nps = 'nps', + question = 'question', //通用问卷 + register = 'register', //报名 + vote = 'vote' //投票 } export enum HISTORY_TYPE { - dailyHis = "dailyHis", //保存历史 - publishHis = "publishHis" //发布历史 + dailyHis = 'dailyHis', //保存历史 + publishHis = 'publishHis' //发布历史 +} + +export interface StatusObj { + id: string; + status: string; + date: number; } export interface UserType { _id: string; username: string; password: string; - curStatus: any; + curStatus: StatusObj; createDate: number; } export class CommonError extends Error { - code: number - errmsg: number - constructor(msg, code = 500) { - super(msg) - this.errmsg = msg - this.code = code - } + code: number; + errmsg: number; + constructor(msg, code = 500) { + super(msg); + this.errmsg = msg; + this.code = code; + } +} + +export interface AnyType { + [key: string]: unknown; } diff --git a/server/src/types/keyStore.ts b/server/src/types/keyStore.ts new file mode 100644 index 00000000..14a2c123 --- /dev/null +++ b/server/src/types/keyStore.ts @@ -0,0 +1,8 @@ +export interface KeyStore { + key: string; + surveyPath: string; + type: string; + data: unknown; + createDate: number; + updateDate: number; +} \ No newline at end of file diff --git a/server/src/types/survey.ts b/server/src/types/survey.ts new file mode 100644 index 00000000..a0aa688a --- /dev/null +++ b/server/src/types/survey.ts @@ -0,0 +1,120 @@ +export interface TitleConfig { + mainTitle: string; + subTitle: string; +} + +export interface BannerConfig { + bgImage: string; + videoLink: string; + postImg: string; +} + +export interface BannerConf { + titleConfig: TitleConfig; + bannerConfig: BannerConfig; +} + +export interface TimeStep { + hour: number; + min: number; +} + +export interface NPS { + leftText: string; + rightText: string; +} + +export interface TextRange { + min: { + placeholder: string; + value: number; + }; + max: { + placeholder: string; + value: number; + }; +} + +export interface DataItem { + isRequired: boolean; + showIndex: boolean; + showType: boolean; + showSpliter: boolean; + type: string; + valid: string; + field: string; + title: string; + placeholder: string; + randomSort: boolean; + checked: boolean; + minNum: string; + maxNum: string; + maxPhotos: number; + star: number; + timeStep: TimeStep; + nps: NPS; + placeholderDesc: string; + addressType: number; + isAuto: boolean; + urlKey: string; + textRange: TextRange; + options?: Option[]; + importKey?: string; + importData?: string; + cOption?: string; + cOptions?: string[]; + exclude?: boolean; +} + +export interface Option { + text: string; + imageUrl: string; + others: boolean; + mustOthers: boolean; + othersKey: string; + placeholderDesc: string; + hash: string; +} + +export interface DataConf { + dataList: DataItem[]; +} + +export interface ConfirmAgain { + is_again: boolean; + again_text: string; +} + +export interface MsgContent { + msg_200: string; + msg_9001: string; + msg_9002: string; + msg_9003: string; + msg_9004: string; +} + +export interface SubmitConf { + submitTitle: string; + confirmAgain: ConfirmAgain; + msgContent: MsgContent; +} + +export interface BaseConf { + begTime: string; + endTime: string; + tLimit: string; + language: string; +} + +export interface SkinConf { + skinColor: string; + inputBgColor: string; +} + +export interface ParsedData { + bannerConf: BannerConf; + dataConf: DataConf; + submitConf: SubmitConf; + baseConf: BaseConf; + skinConf: SkinConf; +} diff --git a/server/src/utils/mongoService.ts b/server/src/utils/mongoService.ts index 7de1491e..34bd5b99 100644 --- a/server/src/utils/mongoService.ts +++ b/server/src/utils/mongoService.ts @@ -1,50 +1,55 @@ -import { Collection, MongoClient, ObjectId } from 'mongodb' -import { CommonError } from '../types' +import { Collection, MongoClient, ObjectId } from 'mongodb'; +import { CommonError } from '../types'; -class MongoService { - isInit: boolean - client: MongoClient - dbName: string - constructor({ url, dbName }) { - this.client = new MongoClient(url); - this.dbName = dbName; - } - - async getCollection({ collectionName }): Promise { - try { - // 设置一个6秒的计时器 - const timeoutPromise = new Promise((resolve, reject) => { - setTimeout(() => { - reject(new Error('连接超时')); - }, 6000); // 6秒超时 - }); - await Promise.race([this.client.connect(), timeoutPromise]) - } catch (error) { - throw new CommonError('数据库连接错误:' + error.message) - } - - try { - return this.client.db(this.dbName).collection(collectionName) - } catch (error) { - throw new CommonError(`get collection ${collectionName} error`) - } - } - - convertId2StringByDoc(doc: any): any { - doc._id = doc._id.toString() - return doc - } - - convertId2StringByList(list: Array): Array { - return list.map(e => { - return this.convertId2StringByDoc(e) - }) - } - - getObjectIdByStr(str: string) { - return new ObjectId(str) - } +// 定义一个通用类型,表示具有 _id 字段的对象 +interface ObjectWithId { + _id: ObjectId; + // 其他可能的属性... } -export default MongoService \ No newline at end of file +class MongoService { + isInit: boolean; + client: MongoClient; + dbName: string; + constructor({ url, dbName }) { + this.client = new MongoClient(url); + this.dbName = dbName; + } + + async getCollection({ collectionName }): Promise { + try { + // 设置一个6秒的计时器 + const timeoutPromise = new Promise((resolve, reject) => { + setTimeout(() => { + reject(new Error('连接超时')); + }, 6000); // 6秒超时 + }); + await Promise.race([this.client.connect(), timeoutPromise]); + } catch (error) { + throw new CommonError('数据库连接错误:' + error.message); + } + + try { + return this.client.db(this.dbName).collection(collectionName); + } catch (error) { + throw new CommonError(`get collection ${collectionName} error`); + } + } + + convertId2StringByDoc(doc: T): T { + return { ...doc, _id: doc._id.toString() }; + } + + convertId2StringByList(list: Array): Array { + return list.map(e => { + return this.convertId2StringByDoc(e); + }); + } + + getObjectIdByStr(str: string) { + return new ObjectId(str); + } +} + +export default MongoService; \ No newline at end of file diff --git a/web/src/management/pages/list/config/index.js b/web/src/management/pages/list/config/index.js index 3fb64469..d7eedbfa 100644 --- a/web/src/management/pages/list/config/index.js +++ b/web/src/management/pages/list/config/index.js @@ -59,11 +59,10 @@ export const noListDataConfig = { img: '/imgs/icons/list-empty.png', }; - export const statusMaps = { new: '未发布', editing: '修改中', published: '已发布', removed: '', pausing: '', -}; \ No newline at end of file +}; diff --git a/web/src/management/router/index.js b/web/src/management/router/index.js index ae2f9f1f..00996a6b 100644 --- a/web/src/management/router/index.js +++ b/web/src/management/router/index.js @@ -11,7 +11,8 @@ const routes = [ { path: '/survey', name: 'survey', - component: () => import(/* webpackChunkName: "survey" */'../pages/list/index.vue'), + component: () => + import(/* webpackChunkName: "survey" */ '../pages/list/index.vue'), meta: { needLogin: true, title: '问卷列表', @@ -23,7 +24,8 @@ const routes = [ meta: { needLogin: true, }, - component: () => import(/* webpackChunkName: "editPage" */'../pages/edit/index.vue'), + component: () => + import(/* webpackChunkName: "editPage" */ '../pages/edit/index.vue'), children: [ { path: '', @@ -31,7 +33,10 @@ const routes = [ meta: { needLogin: true, }, - component: () => import(/* webpackChunkName: "QuestionEditIndex" */'../pages/edit/pages/edit.vue'), + component: () => + import( + /* webpackChunkName: "QuestionEditIndex" */ '../pages/edit/pages/edit.vue' + ), }, { path: 'setting', @@ -39,7 +44,10 @@ const routes = [ meta: { needLogin: true, }, - component: () => import(/* webpackChunkName: "QuestionEditSetting" */'../pages/edit/pages/setting.vue'), + component: () => + import( + /* webpackChunkName: "QuestionEditSetting" */ '../pages/edit/pages/setting.vue' + ), }, { path: 'resultConfig', @@ -47,7 +55,10 @@ const routes = [ meta: { needLogin: true, }, - component: () => import(/* webpackChunkName: "QuestionEditResultConfig" */'../pages/edit/pages/resultConfig.vue'), + component: () => + import( + /* webpackChunkName: "QuestionEditResultConfig" */ '../pages/edit/pages/resultConfig.vue' + ), }, ], }, @@ -57,7 +68,10 @@ const routes = [ meta: { needLogin: true, }, - component: () => import(/* webpackChunkName: "analysisPage" */'../pages/analysis/index.vue'), + component: () => + import( + /* webpackChunkName: "analysisPage" */ '../pages/analysis/index.vue' + ), }, { path: '/survey/:id/publishResult', @@ -65,7 +79,10 @@ const routes = [ meta: { needLogin: true, }, - component: () => import(/* webpackChunkName: "publishResultPage" */'../pages/publishResult/index.vue'), + component: () => + import( + /* webpackChunkName: "publishResultPage" */ '../pages/publishResult/index.vue' + ), }, { path: '/create', @@ -74,13 +91,15 @@ const routes = [ needLogin: true, title: '创建问卷', }, - component: () => import(/* webpackChunkName: "create" */'../pages/create/index.vue'), + component: () => + import(/* webpackChunkName: "create" */ '../pages/create/index.vue'), }, { path: '/login', name: 'login', title: '登陆', - component: () => import(/* webpackChunkName: "login" */'../pages/login/index.vue'), + component: () => + import(/* webpackChunkName: "login" */ '../pages/login/index.vue'), }, ]; diff --git a/web/src/materials/questions/common/utils/index.js b/web/src/materials/questions/common/utils/index.js index 542ea0e0..6da25749 100644 --- a/web/src/materials/questions/common/utils/index.js +++ b/web/src/materials/questions/common/utils/index.js @@ -1,4 +1,4 @@ -import { forEach as _forEach, trim as _trim } from 'lodash'; +import { forEach as _forEach, trim as _trim } from 'lodash'; import { escapeFilterXSS } from '@/common/xss'; // 获取选项的hash diff --git a/web/src/render/adapter/rules.js b/web/src/render/adapter/rules.js index aee0f9c4..9f489a21 100644 --- a/web/src/render/adapter/rules.js +++ b/web/src/render/adapter/rules.js @@ -1,4 +1,10 @@ -import { forEach as _forEach, get as _get, isArray as _isArray, keys as _keys, set as _set } from 'lodash'; +import { + forEach as _forEach, + get as _get, + isArray as _isArray, + keys as _keys, + set as _set, +} from 'lodash'; const regexpMap = { nd: /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/, @@ -261,7 +267,7 @@ export default function (questionConfig) { } } else { _forEach(options, (item) => { - const othersKey = `${field}_${item.hash}` + const othersKey = `${field}_${item.hash}`; const { mustOthers } = item; if (mustOthers) { _set(validMap, othersKey, generateValidArr(true, '')); diff --git a/web/src/render/plugins/dialog/index.js b/web/src/render/plugins/dialog/index.js index cfd5849d..519023fe 100644 --- a/web/src/render/plugins/dialog/index.js +++ b/web/src/render/plugins/dialog/index.js @@ -1,7 +1,7 @@ import confirm from '../../components/confirm.vue'; import alert from '../../components/alert.vue'; -import { isFunction as _isFunction} from 'lodash'; +import { isFunction as _isFunction } from 'lodash'; export default { install(Vue) { diff --git a/web/src/render/store/actions.js b/web/src/render/store/actions.js index 69b077b0..6604a80f 100644 --- a/web/src/render/store/actions.js +++ b/web/src/render/store/actions.js @@ -1,6 +1,6 @@ import moment from 'moment'; // 引入中文 -import 'moment/locale/zh-cn' +import 'moment/locale/zh-cn'; // 设置中文 moment.locale('zh-cn'); import adapter from '../adapter'; diff --git a/web/vue.config.js b/web/vue.config.js index 6dd1fbcb..4ed0498b 100644 --- a/web/vue.config.js +++ b/web/vue.config.js @@ -1,8 +1,7 @@ const { defineConfig } = require('@vue/cli-service'); -const Webpack = require('webpack') +const Webpack = require('webpack'); // 分析打包时间 -const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin') - +const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin'); module.exports = defineConfig({ transpileDependencies: true, @@ -31,7 +30,7 @@ module.exports = defineConfig({ devServer: { proxy: { '/api': { - target: 'http://localhost:3000', + target: 'http://127.0.0.1:3000', changeOrigin: true, }, }, @@ -47,19 +46,23 @@ module.exports = defineConfig({ open: true, }, configureWebpack: { - plugins: [new Webpack.IgnorePlugin({resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ })], + plugins: [ + new Webpack.IgnorePlugin({ + resourceRegExp: /^\.\/locale$/, + contextRegExp: /moment$/, + }), + ], }, chainWebpack: (config) => { config.module .rule('js') .test(/\.jsx?$/) - .exclude - .add(/node_modules/) - .end() + .exclude.add(/node_modules/) + .end() .use('babel-loader') .loader('babel-loader') .end(); - + config.optimization.splitChunks({ cacheGroups: { setterWidgets: { @@ -82,41 +85,40 @@ module.exports = defineConfig({ element: { name: 'chunk-element-ui', test: /[\\/]node_modules[\\/]element-ui[\\/]/, - chunks: "all", + chunks: 'all', priority: 3, reuseExistingChunk: true, - enforce: true + enforce: true, }, moment: { name: 'chunk-moment', test: /[\\/]node_modules[\\/]moment[\\/]/, - chunks: "all", + chunks: 'all', priority: 3, reuseExistingChunk: true, - enforce: true + enforce: true, }, '@wangeditor': { name: 'chunk-wangeditor', test: /[\\/]node_modules[\\/]@wangeditor[\\/]/, - chunks: "all", + chunks: 'all', priority: 3, reuseExistingChunk: true, - enforce: true + enforce: true, }, common: { //抽取所有入口页面都需要的公共chunk - name: "chunk-common", - chunks: "initial", + name: 'chunk-common', + chunks: 'initial', minChunks: 2, maxInitialRequests: 5, minSize: 0, priority: 1, reuseExistingChunk: true, - enforce: true - } + enforce: true, + }, }, }); - config.plugin('speed') - .use(SpeedMeasureWebpackPlugin) + config.plugin('speed').use(SpeedMeasureWebpackPlugin); }, });