Commit c7fcde06 by lixinming

初始化项目+党员列表功能

parents
.idea
/out
/node_modules
/test
/public
/logs
/video
*.logs
*.zip
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动程序",
"program": "${workspaceFolder}/src/main.ts",
"outFiles": [
"${workspaceFolder}/**/*.js"
]
}
]
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "screen",
"version": "1.0.0",
"description": "",
"main": "main.ts",
"dependencies": {
"@alicloud/sms-sdk": "^1.1.6",
"@types/node": "^10.12.18",
"compression": "^1.7.4",
"express": "^4.17.1",
"express-async-handler": "^1.1.4",
"express-history-api-fallback": "^2.2.1",
"log4js": "^6.6.1",
"lru-cache": "^4.1.5",
"md5": "^2.2.1",
"moment": "^2.24.0",
"node-xlsx": "^0.16.1",
"qs": "^6.11.0",
"request": "^2.88.0",
"svg-captcha": "^1.3.12",
"ws": "^5.2.2",
"xml2js": "^0.4.23"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "cjj",
"license": "ISC",
"bin": "./out/main.js",
"pkg": {
"scripts": "out/**/*.js",
"assets": [
"public/**/*",
"res/**/*",
"images/**/*",
"video/**/*"
],
"outputPath": "dist"
}
}
<config>
<port>40005</port>
<dbPort>40002</dbPort>
<dbHost>localhost</dbHost>
<sign>xxx90909082fsdahfjosadjfpoiwausjorip2hjklrhn1ioud0u124rx0qwejfokasjfolksaujfoas</sign>
</config>
/**
* 用户相关主要逻辑
*/
import { OPERATIONALDATATYPE, TABLENAME } from "../config/enum/enum";
import { ERRORENUM } from "../config/enum/errorEnum";
import { operationalData, selectData } from "../data/operationalData";
import { getMySqlMs, getUserToken } from "../tools/systemTools";
import { BizError } from "../util/bizError";
export async function loginAdminSys(loginId:string, pwd:string) {
let resultInfo = {branch:-1, token:'', userId:''};
if (loginId == "admin") { /**超级管理员 */
let userInfo = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.后台用户表, {loginId}, null);
if (!userInfo || !userInfo.uId) throw new BizError(ERRORENUM.用户不存在, `不存在loginId=${loginId}的用户`);
if (userInfo.pwd != pwd) throw new BizError(ERRORENUM.密码错误);
let token = getUserToken(loginId);
let tokenMs = getMySqlMs();
await operationalData(OPERATIONALDATATYPE.修改, TABLENAME.后台用户表, {token, tokenMs}, {loginId});
resultInfo.branch = 0;
resultInfo.token = token;
resultInfo.userId = userInfo.uId;
} else {
let userInfo = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.党员基础信息表, {loginId}, null);
if (!userInfo || !userInfo.pmId) throw new BizError(ERRORENUM.用户不存在, `不存在loginId=${loginId}的用户`);
if (!userInfo.isAdmin) throw new BizError(ERRORENUM.该用户不是管理员);
if (userInfo.pwd != pwd) throw new BizError(ERRORENUM.密码错误);
let token = getUserToken(loginId);
let tokenMs = getMySqlMs();
await operationalData(OPERATIONALDATATYPE.修改, TABLENAME.党员基础信息表, {adminToken:token, adminTokenMs:tokenMs}, {loginId});
resultInfo.branch = userInfo.bId;
resultInfo.token = token;
resultInfo.userId = userInfo.pmId;
}
return resultInfo;
}
export async function logout(userId:string, isAdmin:boolean) {
if (isAdmin) {
await operationalData(OPERATIONALDATATYPE.修改, TABLENAME.后台用户表, {token:''}, {uId:userId});
} else {
await operationalData(OPERATIONALDATATYPE.修改, TABLENAME.党员基础信息表, {adminToken:''}, {pmId:userId});
}
return {isSuccess:true};
}
\ No newline at end of file
/**
* 修改积极分子信息
*/
export const UpdatePartyActivistsMemberConfig = {
name:{type:"String" },//姓名
sex:{type:"Number" },//性别
birthDate:{type:"Number" },//出生年月
phone:{type:"String" },//电话
levelOfEducation: {type:"Number" },//文化程度
bId:{type:"Number" },//支部
askForTime:{type:"Number" },//入党申请时间
listedAsActivistsTime:{type:"Number" },//列为积极分子时间
departmentName:{type:"[Number]" },//所属科室表id
administrativePositionName:{type:"Number" },//行政职务id
liaison:{type:"String"}//联系人
}
/**
* 修改正式党员信息
*/
export const UpdatePartyFormalMemberConfig = {
// pmId:{type:"String" },//
name:{type:"String" },//姓名
sex:{type:"Number" },//性别
birthDate:{type:"Number" },//出生年月
phone:{type:"String" },//电话
levelOfEducation: {type:"Number" },//文化程度
bId:{type:"Number" },//支部
partyJoiningTime:{type:"Number" },//入党时间
administrativePositionName:{type:"Number" },//行政职务id
partyPositionsName:{type:"[Number]" },//党内职务id
departmentName:{type:"[Number]" },//所属科室表id
}
/**
* 预备党员信息
*/
export const UpdatePartyCandidateMemberConfig = {
name:{type:"String" },//姓名
sex:{type:"Number" },//性别
birthDate:{type:"Number" },//出生年月
phone:{type:"String" },//电话
levelOfEducation: {type:"Number" },//文化程度
bId:{type:"Number" },//支部
askForTime:{type:"Number" },//入党申请时间
talkTime:{type:"Number" },//谈话时间
administrativePositionName:{type:"Number" },//行政职务id
departmentName:{type:"[Number]" },//所属科室表id
}
/**
* 预备党员信息
*/
export const CreatePartyCandidateMemberConfig = {
name:{type:"String" },//姓名
sex:{type:"Number" },//性别
birthDate:{type:"Number" },//出生年月
phone:{type:"String" },//电话
levelOfEducation: {type:"Number" },//文化程度
bId:{type:"Number" },//支部
askForTime:{type:"Number" },//入党申请时间
talkTime:{type:"Number" },//谈话时间
administrativePositionName:{type:"Number" },//行政职务id
departmentName:{type:"[Number]" },//所属科室表id
}
\ No newline at end of file
/**
* 请求数据中心类型
*/
export enum OPERATIONALDATATYPE {
增加='/yfs/dataserver/mysql/table/add',
修改='/yfs/dataserver/mysql/table/update',
删除='/yfs/dataserver/mysql/table/delete',
查询单个='/yfs/dataserver/mysql/table/find/one',
查询多个='/yfs/dataserver/mysql/table/find/many',
分页查询='/yfs/dataserver/mysql/table/find/manytopage',
查询数据量='/yfs/dataserver/mysql/table/find/count',
多表联查='/yfs/dataserver/mysql/table/find/aggragate',
多表分页='/yfs/dataserver/mysql/table/find/aggragatetopage'
}
/**
* 表名
*/
export enum TABLENAME {
支部表='branch',
后台用户表='adminUser',
党员基础信息表='partyMember',
行政职务表='administrativePosition',
党内职务表='partyPositions',
所属科室表='department',
支部制度表='branchSystem',
组织生活表='organizationalLife',
专题活动表='thematicActivities',
党建动态表='partyBuildingDynamic',
党费管理表='partyExpenses',
党建先锋表='partyVanguard',
党员学习表='memberLearning',
学习进度表='rateLearning',
课程类型='courseType',
学习强国='learningPower',
党建质量='partyQuality'
}
/**
* 文件------------------------
*/
/**上传文件类型 */
export enum FILETYPE {
word = 1,
pdf,
图片,
视频,
多类型
}
/**
* 党员基础信息表---------------------------
*/
/**名册录入类型 */
export enum ENTRYTYPE {
正式党员 = 1,
入党积极分子,
预备党员
}
/**性别 */
export enum SEX {
= 1,
}
/**文化程度 */
export enum DEGREE {
初中 = 1,
高中,
大专,
本科,
硕士,
博士
}
/**所属支部 */
export enum BRANCHNAME {
党总支 = 1,
牙防所第一支部,
牙防所第二支部,
牙防所第三支部,
牙防所第四支部
}
/**行政职务 */
export enum ADMINISTRATIVEPOSITION {
职员 = 1,
办公室主任,
办公室副主任,
财务科副科长,
副所长,
口腔种植科主任,
副主任护师,
副主任医师,
工会主席,
口腔技术室主任,
护理部主任,
护师,
护士,
技师,
技士,
康健分所主任,
口腔颌面外科副主任,
口腔修复科副主任,
口腔正畸科主任,
口腔综合科副主任,
人事科科长,
项目管理工程师,
牙体牙髓科副主任,
牙周科主任,
医师,
医务科副科长,
预防口腔,
儿童口腔科主任,
执行所长,
主管护师,
主管技师,
主治医师,
}
/**党内职务 */
export enum PARTYPOSITIONS {
党总支书记 = 4,
党总支副书记,
党总支宣传委员,
党总支统战委员,
党总支纪检委员,
支部书记,
支部副书记,
纪检委员,
统战委员,
组织委员,
宣传委员,
}
/**所属科室 */
export enum DEDPARTMENT {
办公室 = 1,
财务科,
放射科,
工会,
技术室,
颌面外科,
护理,
护理部,
检验科,
康健分所,
科教科,
口腔颌面外科,
口腔科,
口腔修复科,
口腔正畸科,
口腔综合科,
人事科,
特需,
信息科,
修复科,
牙体牙髓科,
牙周科,
药房,
医务科,
预防科,
预防口腔,
儿童口腔科,
院部,
种植科,
正畸科,
综合科,
}
/**党员状态 */
export enum PARTYSTATE {
在党 = 1,
退党
}
/**
* 组织生活---------------------------
*/
/**主题类型 */
export enum THEMETYPE {
理论学习 = 1,
}
/**
* 党费管理---------------------------
*/
/**缴纳状态 */
export enum PAYTYPE {
已缴纳 = 1,
未缴纳
}
/**
* 党建先锋---------------------------
*/
/**一级指标 */
export enum PRIMARYINDICATORS {
班子队伍健全 = 1,
教育管理党员规范,
党员先锋模范作用有力,
党风廉政行风建设有效,
医院文化建设到位,
特色亮点显著,
}
/**荣誉类型 */
export enum HONORTYPE {
区级 = 1,
市级,
院级,
国家级,
}
/**授予范围 */
export enum GRANTINGRANGE {
团体 = 1,
单位,
个人
}
/**
* 党员学习---------------------------
*/
/**课程类型 */
export enum COURSETYPE {
学习二十大 = 1,
党课,
四个意识,
四个自信,
}
\ No newline at end of file
export enum ERRORENUM {
身份验证失败 = 1,
非法登录,
身份验证过期,
参数错误,
地址数据不完整,
请完善信息,
该方法仅可进行数据操作,
数据操作失败,
该方法仅可进行查询操作,
该方法仅可进行联合查询操作,
分页请设置当前页数,
密码错误,
用户不存在,
该用户不是管理员
}
export enum ERRORCODEENUM {
身份验证失败 = 401,
非法登录 = 402,
身份验证过期 = 403
}
let bizErrorMsgMap = {};
for (let key in ERRORENUM) {
bizErrorMsgMap[ERRORENUM[key]] = key;
}
export function getBizMsg(param) {
return bizErrorMsgMap[param];
}
\ No newline at end of file
const path = require('path');
import * as fs from "fs";
import { BizError } from "../util/bizError";
import { analysisXml } from "../util/myXML";
import { ServerConfig } from "../config/systemClass";
export let systemConfig = new ServerConfig;
const ConfigName = "serverConfig.xml";
export async function initConfig() {
try {
let buff = fs.readFileSync(path.join(__dirname.substring(0,__dirname.indexOf("out")), ConfigName));
let configStr = buff.toString();
let configInfo:any = await analysisXml(configStr);
if (!configInfo || !configInfo.config) throw new BizError('xml中无配置');
else {
let {port, dbHost, dbPort, sign } = configInfo.config;
systemConfig.port = parseInt(port[0]);
systemConfig.dbPath = analysisDBPathStr(dbHost[0], dbPort[0]);
systemConfig.sign = sign[0];
}
console.log("config init success");
} catch(err) {
console.log('ERROR => 服务器配置解析错误 请检查根目录下 serverConfig.xml 文件是否正确');
console.log(err);
throw new BizError("服务器配置解析错误 请检查根目录下 serverConfig.xml 文件是否正确");
}
}
function analysisDBPathStr(host, port) {
let str = `http://${host}:${port}`;
console.log("请确认,数据中心地址:", str);
return str;
}
/**
* 系统配置类
*
*/
export class ServerConfig {
/**系统配置 */
port:number;
dbPath:string;
sign:string;
}
\ No newline at end of file
import { OPERATIONALDATATYPE, TABLENAME } from "../config/enum/enum";
import { ERRORENUM } from "../config/enum/errorEnum";
import { systemConfig } from "../config/serverConfig";
import { BizError } from "../util/bizError";
import { post } from "../util/request";
/**
* 操作数据库 新增 修改 删除
* @param url url地址 根据枚举获取值
* @param tableName 表名
* @param data 数据
* @param param 条件
*/
export async function operationalData(url:string, tableName:string, data, param) {
let header = {table:tableName, sign:systemConfig.sign};
let queray:any = {};
if (url == OPERATIONALDATATYPE.增加) {
queray.data = data;
} else if (url == OPERATIONALDATATYPE.修改) {
queray.data = data;
queray.param = param;
} else if (url == OPERATIONALDATATYPE.删除) {
queray.param = param;
} else {
throw new BizError(ERRORENUM.该方法仅可进行数据操作, '使用操作数据库的方法进行查询调用');
}
let result:any = await post(`${systemConfig.dbPath}${url}`, queray, header );
if (result.code != 200) throw new BizError(ERRORENUM.数据操作失败, result.code);
if (!result.data || !result.data.isSuccess) throw new BizError(ERRORENUM.数据操作失败, JSON.stringify(result.data));
return true;
}
/**
* 查询
* @param url url地址 根据枚举获取值
* @param tableName 表名
* @param param 条件
* @param pageNumber 分页传入的页数 非分页可不传
* @param pageSize 分页传入的单页大小 非分页可不传
*/
export async function selectData(url, tableName, param, column, pageNumber?, pageSize?) {
if (url != OPERATIONALDATATYPE.查询单个 && url != OPERATIONALDATATYPE.查询多个 && url != OPERATIONALDATATYPE.查询数据量 && url != OPERATIONALDATATYPE.分页查询) {
throw new BizError(ERRORENUM.该方法仅可进行查询操作, '该方法仅可进行查询操作');
}
let header = {table:tableName, sign:systemConfig.sign};
let queray:any = {param};
if (column && column.length) {
queray.column = column;
}
if (url == OPERATIONALDATATYPE.分页查询) {
if (!pageNumber) throw new BizError(ERRORENUM.分页请设置当前页数, `pageNumber:${pageNumber};pageSize:${pageSize}`);
queray.pageNumber = pageNumber;
queray.pageSize = pageSize || 10;
}
let result:any = await post(`${systemConfig.dbPath}${url}`, queray, header );
if (result.code != 200) throw new BizError(ERRORENUM.数据操作失败, result.code);
if (!result.data || !result.data.data) throw new BizError(ERRORENUM.数据操作失败, JSON.stringify(result.data));
return result.data.data;
}
export async function selectManyTableData(url, tableName, param, column, includeConf, pageNumber?, pageSize?) {
if (url != OPERATIONALDATATYPE.多表联查 && url != OPERATIONALDATATYPE.多表分页) {
throw new BizError(ERRORENUM.该方法仅可进行联合查询操作, '该方法仅可进行联合查询操作');
}
let header = {table:tableName, sign:systemConfig.sign};
let queray:any = {param, includeConf};
if (column && column.length) {
queray.column = column;
}
if (url == OPERATIONALDATATYPE.分页查询) {
if (!pageNumber) throw new BizError(ERRORENUM.分页请设置当前页数, `pageNumber:${pageNumber};pageSize:${pageSize}`);
queray.pageNumber = pageNumber;
queray.pageSize = pageSize || 10;
}
let result:any = await post(`${systemConfig.dbPath}${url}`, queray, header );
if (result.code != 200) throw new BizError(ERRORENUM.数据操作失败, result.code);
if (!result.data || !result.data.data) throw new BizError(ERRORENUM.数据操作失败, JSON.stringify(result.data));
return result.data.data;
}
\ No newline at end of file
import { initConfig, systemConfig} from "./config/serverConfig";
import { httpServer } from "./net/http_server";
async function lanuch() {
/**初始化配置解析 */
await initConfig();
/**创建http服务 */
httpServer.createServer(systemConfig.port);
// await smsTask();
console.log('This indicates that the server is started successfully.');
}
lanuch();
\ No newline at end of file
import { ERRORCODEENUM } from "../config/enum/errorEnum";
/**
* 中间件 错误返回
* @param err
* @param req
* @param res
* @param next
*/
export function httpErrorHandler(err, req, res, next) {
console.log("in httpErrorHandler");
console.log(err);
//todo 自定义错误编码
if (err) {
if ( ERRORCODEENUM[err.message] ) {
res.success({success:false, msg:err.message, code:ERRORCODEENUM[err.message]});
next();
}
else {
res.success({success:false, msg:err.message, code:500});
next();
}
}
}
\ No newline at end of file
import { OPERATIONALDATATYPE, TABLENAME } from "../config/enum/enum";
import { ERRORENUM } from "../config/enum/errorEnum";
import { selectData } from "../data/operationalData";
import { BizError } from "../util/bizError";
/**
* 中间件 校验孵化器token
* @param req
* @param res
* @param next
* @returns
*/
export async function checkToken(req, res, next) {
if (!req.headers) req.headers = {};
let userId = req.headers.userid;
let token = req.headers.token;
if (!userId || !token) return next(new BizError(ERRORENUM.非法登录));
if (userId == "admin") {
let userInfo = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.后台用户表, {uId:userId}, null);
if (!userInfo || !userInfo.uId) return next(new BizError(ERRORENUM.身份验证失败));
if (!userInfo.token || userInfo.token != token) return next(new BizError(ERRORENUM.身份验证过期));
req.userInfo = {
branch:0,
isAdmin:true,
userId,
};
}
else {
let userInfo = await selectData(OPERATIONALDATATYPE.查询单个, TABLENAME.党员基础信息表, {pmId:userId}, null);
if (!userInfo || !userInfo.pmId) return next(new BizError(ERRORENUM.身份验证失败));
if (!userInfo.adminToken || userInfo.adminToken != token) return next(new BizError(ERRORENUM.身份验证过期));
req.userInfo = {
branch:userInfo.bId,
isAdmin:false,
userId,
};
}
next();
}
export function watch(req, res, next) {
res.success = success.bind({res:res, req:req});
return next();
}
/**
* 中间件正确返回方法
* @param data
*/
function success(data) {
let resultPack;
if (data ) {
if ( data.success === undefined || data.success === true ) {
resultPack = {data, success:true, code:200};
}
else {
resultPack = data;
}
}else {
resultPack = {code:500, success:false, msg:'result is null'};
}
this.res.send(resultPack);
}
import express = require('express');
import bodyParser = require('body-parser');
import routers = require('../routers/router');
import compression = require('compression');
import { watch } from '../middleware/watch';
import { httpErrorHandler } from '../middleware/httpErrorHandler';
import * as path from "path";
import * as fallback from 'express-history-api-fallback';
export class httpServer {
static createServer(port:number) {
var httpServer = express();
httpServer.all('*', (req, res, next) => {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header('Access-Control-Allow-Headers', 'Content-Type,request-origin,userid,token');
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header('Access-Control-Allow-Credentials', true);
res.header("X-Powered-By", ' 3.2.1');
next();
// if(req.method === 'OPTIONS'){
// res.statusCode = 200;
// res.end();
// }else{
// next();
// }
});
// httpServer.use(bodyParser.json({limit:'5mb'}));
// httpServer.use(bodyParser.urlencoded({limit:'5mb', extends:true}));
const root = path.join(__dirname, "../../public");
httpServer.use(express.static(root));
httpServer.use(fallback('index.html', { root }));
httpServer.use(compression());
httpServer.use(watch);
httpServer.use(bodyParser.json({limit:"5000kb"}));
routers.setRouter(httpServer);
httpServer.use(httpErrorHandler);
httpServer.listen(port);
console.log('server listen on port:'+port);
}
}
\ No newline at end of file
/***
* 党员路由
*/
import * as asyncHandler from 'express-async-handler'
import { eccReqParamater } from '../tools/eccParam';
import * as partyMemberBiz from '../biz/partyMember';
import { checkToken } from '../middleware/user';
import { ENTRYTYPE } from '../config/enum/enum';
export function setRouter(httpServer) {
httpServer.post('/yfs/admin/partymember/formal/list', checkToken, asyncHandler(formalPartyList));
httpServer.post('/yfs/admin/partymember/formal/info', checkToken, asyncHandler(formalPartyInfo));
httpServer.post('/yfs/admin/partymember/formal/update', checkToken, asyncHandler(updateFormalPartyInfo));
httpServer.post('/yfs/admin/partymember/activists/list', checkToken, asyncHandler(activistsPartyList));
httpServer.post('/yfs/admin/partymember/activists/info', checkToken, asyncHandler(activistsPartyInfo));
httpServer.post('/yfs/admin/partymember/activists/update', checkToken, asyncHandler(updateActivistsInfo));
httpServer.post('/yfs/admin/partymember/candidate/list', checkToken, asyncHandler(candidatePartyList));
httpServer.post('/yfs/admin/partymember/candidate/info', checkToken, asyncHandler(candidatePartyInfo));
httpServer.post('/yfs/admin/partymember/candidate/update', checkToken, asyncHandler(updateCandidateInfo));
}
/**
* 正式党员列表
* @param req
* @param res
*/
async function formalPartyList(req, res) {
let userInfo = req.userInfo;
let reqConf = {branch:'Number', name:'String', pageNumber:'Number'};
let {branch, name, pageNumber} = eccReqParamater(reqConf, req.body);
let result = await partyMemberBiz.formalList(branch, name, pageNumber);
res.success(result);
}
/**
* 回显正式党员信息
* @param req
* @param res
*/
async function formalPartyInfo(req, res) {
let userInfo = req.userInfo;
let reqConf = {pmId:'String'};
let {pmId} = eccReqParamater(reqConf, req.body);
let result = await partyMemberBiz.partyFormalMemberInfomation(pmId);
res.success(result);
}
/**
* 修改正式党员信息
* @param req
* @param res
*/
async function updateFormalPartyInfo(req, res) {
let userInfo = req.userInfo;
let reqConf = {pmId:'String', form:'Object'};
let { pmId, form } = eccReqParamater(reqConf, req.body);
let result = await partyMemberBiz.updatePartyFormalMemberData(pmId, form);
res.success(result);
}
/**
* 积极分子列表
* @param req
* @param res
*/
async function activistsPartyList(req, res) {
let userInfo = req.userInfo;
let reqConf = {branch:'Number', name:'String', pageNumber:'Number'};
let {branch, name, pageNumber} = eccReqParamater(reqConf, req.body);
let result = await partyMemberBiz.activistsList(branch, name, pageNumber);
res.success(result);
}
/**
* 回显积极分子信息
* @param req
* @param res
*/
async function activistsPartyInfo(req, res) {
let userInfo = req.userInfo;
let reqConf = {pmId:'String'};
let {pmId} = eccReqParamater(reqConf, req.body);
let result = await partyMemberBiz.partyActivistsMemberInfomation(pmId);
res.success(result);
}
async function updateActivistsInfo(req, res) {
let userInfo = req.userInfo;
let reqConf = {pmId:'String', form:'Object'};
let { pmId, form } = eccReqParamater(reqConf, req.body);
let result = await partyMemberBiz.updatePartyActivistsMemberData(pmId, form);
res.success(result);
}
/**
* 预备党员列表
* @param req
* @param res
*/
async function candidatePartyList(req, res) {
let userInfo = req.userInfo;
let reqConf = {branch:'Number', name:'String', pageNumber:'Number'};
let {branch, name, pageNumber} = eccReqParamater(reqConf, req.body);
let result = await partyMemberBiz.candidateList(branch, name, pageNumber);
res.success(result);
}
async function candidatePartyInfo(req, res) {
let userInfo = req.userInfo;
let reqConf = {pmId:'String'};
let {pmId} = eccReqParamater(reqConf, req.body);
let result = await partyMemberBiz.partyCandidateMemberInfomation(pmId);
res.success(result);
}
/**
* 修改预备党员信息
* @param req
* @param res
*/
async function updateCandidateInfo(req, res) {
let userInfo = req.userInfo;
let reqConf = {pmId:'String', form:'Object'};
let { pmId, form } = eccReqParamater(reqConf, req.body);
let result = await partyMemberBiz.updatePartyCandidateMemberData(pmId, form);
res.success(result);
}
\ No newline at end of file
import * as userRouter from "./user";
export function setRouter(httpServer) {
userRouter.setRouter(httpServer);
}
\ No newline at end of file
/***
* 用户路由
*/
import * as asyncHandler from 'express-async-handler'
import { eccReqParamater } from '../tools/eccParam';
import * as userBIz from '../biz/user';
import { checkToken } from '../middleware/user';
export function setRouter(httpServer) {
httpServer.post('/yfs/admin/user/login', asyncHandler(login));
httpServer.post('/yfs/admin/user/logout', checkToken, asyncHandler(logout));
}
async function login(req, res) {
let reqConf = {loginId:'String', pwd:'String'};
let {loginId, pwd} = eccReqParamater(reqConf, req.body);
let userInfo = await userBIz.loginAdminSys(loginId, pwd);
res.success(userInfo);
}
async function logout(req, res) {
let userInfo = req.userInfo;
let result = await userBIz.logout(userInfo.userId, userInfo.isAdmin);
res.success(result);
}
import { ERRORENUM } from "../config/enum/errorEnum";
import { BizError } from "../util/bizError";
/**
* 校验value是否符合传入的枚举
* @param name 被掉用名称 用于输出异常日志
* @param key 目标字段 用于输出异常日志
* @param enumConf 目标枚举
* @param value 目标值
* 无返回 有异常直接报错
*/
export function eccEnumValue(name:string, key:string, enumConf, value:any) {
let eccSuccess = true;
if ( typeof value == 'number' ) {
if (!enumConf[value] ) eccSuccess = false;
} else if (Array.isArray(value)) {
value.forEach(item => {
if ( !enumConf[item] ) eccSuccess = false;
});
}
if (!eccSuccess) throw new BizError(ERRORENUM.请完善信息, `${name} 下的 ${key} 字段值为 ${value} 不满足枚举范围`);
}
/**
* 将枚举值转换成对应的枚举名(key)
* @param enumConf 目标枚举
* @param value 目标值
* @returns string 返回字符串 如果传入多个枚举值,就拼接字符串
*/
export function changeEnumValue(enumConf, value:any) {
if (!value) return '';
if ( typeof value == 'number' ) {
let str = enumConf[value];
return str
} else if (typeof value == 'string') {
try {
value = JSON.parse(value);
}catch(err) {
return enumConf[parseInt(value)];
}
}
let str = "";
value.forEach((item, index) => {
let subStr = enumConf[item];
str += subStr;
if (index == value.length-1) str+="";
else str += ","
});
return str;
}
\ No newline at end of file
/**
* 校验参数工具
*
*/
import { ERRORENUM } from "../config/enum/errorEnum";
import { BizError } from "../util/bizError";
/**
* 通过config校验表单参数param
* 包括类型 String, Number, Boolean, [Number], [Object]
* 参数是必填
* 方法会校验表单中存在的多余字段
* @param name 被调用的方法名
* @param config 校验配置
* @param param 需要校验的参数
* @returns true 无需关注返回
*/
export function eccFormParam(name:string, keyTypeConf:object, param:object) {
/**校验多余字段 */
for (let key in param) {
if (!keyTypeConf[key]) throw new BizError(ERRORENUM.参数错误, name, `多余${key}字段`);
}
/**校验已填参数 */
for (let key in keyTypeConf ) {
let {type, notMustHave} = keyTypeConf[key];
let isError = false; //校验是否异常
let errorStr = "";//异常说明
let value = param[key];
let valueType = typeof value;
if ( value == null || value == undefined ) {
if (!notMustHave) throw new BizError(ERRORENUM.参数错误, name, `缺失${key}字段`);
} else {
switch(type) {
case 'Number':
if ( type.toLowerCase() != valueType ) {
isError = true;
} else {
if ((""+param[key]).indexOf('.') > -1) {
param[key] = parseInt(`${param[key] *1000}`)/1000;
}
}
break;
case 'String':
case 'Boolean':
if ( type.toLowerCase() != valueType ) isError = true;
break;
case '[Number]':
if ( !Array.isArray(param[key]) ) isError = true;
for (let i =0; i < param[key].length; i++) {
let item = param[key][i];
if ( typeof item != 'number' ) {
isError = true;
errorStr = `${key}应是number型数组其中下标${i}${typeof item}`;
}
}
break;
case '[Object]':
if ( !Array.isArray(param[key]) ) isError = true;
for (let i =0; i < param[key].length; i++) {
let item = param[key][i];
if ( typeof item != 'object' ) {
isError = true;
errorStr = `${key}应是object型数组其中下标${i}${typeof item}`;
}
}
break;
case 'Address':
/**地址类型 基本数据类型为数组字符串但是要判断层级关系 */
if ( !Array.isArray(param[key]) ) {
isError = true;
errorStr = `${key}应是数组形`;
}
if ( param[key].length != 4) {
isError = true;
errorStr = `${key}超过特定长度4 目前长度 ${param[key].length}`;
}
for (let i =0; i < param[key].length; i++) {
let item = param[key][i];
if ( typeof item != 'string' ) {
isError = true;
errorStr = `${key}应是string型数组其中下标${i}${typeof item}`;
}
}
/** 不符合规则的 */
let nullIndex = -1;
for (let i = 0; i < param[key].length; i++) {
if (nullIndex != -1) {//出现过空 第一次出现后的位置 都不能有值
if (param[key]) {
//做一个特化
throw new BizError(ERRORENUM.地址数据不完整, name, `${key} 下标 ${nullIndex} 为空 `);
}
}
if (nullIndex == -1 && !param[key][i]) {
/**按顺序第一次赋值 */
nullIndex = i;
}
}
break;
}
errorStr = isError && errorStr == "" ? `${key}应该是${type}型 而不是${valueType}`: errorStr;
if ( isError ) throw new BizError(ERRORENUM.请完善信息, name, errorStr);
}
}
return true;
}
/**
* 根据conf配置校验请求参数
* @param conf 配置
* @param param 表单
* @param skipKeys []不必填的字段
*/
export function eccReqParamater(conf:object, param, skipKeys?) {
skipKeys = skipKeys || [];
let skipMap = {};
skipKeys.forEach(keyName => {
skipMap[keyName] = 1;
});
/**校验多余字段 */
for (let key in param) {
if (!conf[key]) throw new BizError(ERRORENUM.参数错误, `多余${key}字段`);
}
/**校验必填和缺失字段 */
for (let key in conf) {
let confType = conf[key];
let value = param[key];
let valueType = typeof value;
if ( value == null || value == undefined ) {
if (!skipMap[key]) throw new BizError(ERRORENUM.参数错误, `缺失${key}字段`);
} else {
let isError = false;
let errorStr = "";
switch(confType) {
case 'Number':
if ( confType.toLowerCase() != valueType ) isError = true;
else {
if ((""+param[key]).indexOf('.') > -1) {
param[key] = parseInt(`${param[key] *100}`)/100;
}
}
break;
case 'String':
case 'Boolean':
if ( confType.toLowerCase() != valueType ) isError = true;
break;
case '[Number]':
if ( !Array.isArray(param[key]) ) isError = true;
for (let i =0; i < param[key].length; i++) {
let item = param[key][i];
if ( typeof item != 'number' ) {
isError = true;
errorStr = `${key}应是number型数组其中下标${i}${typeof item}`;
}
}
break;
case '[Object]':
if ( !Array.isArray(param[key]) ) isError = true;
for (let i =0; i < param[key].length; i++) {
let item = param[key][i];
if ( typeof item != 'object' ) {
isError = true;
errorStr = `${key}应是object型数组其中下标${i}${typeof item}`;
}
}
break;
case 'Address':
/**地址类型 基本数据类型为数组字符串但是要判断层级关系 */
if ( !Array.isArray(param[key]) ) {
isError = true;
errorStr = `${key}应是数组形`;
}
if ( param[key].length != 4) {
isError = true;
errorStr = `${key}超过特定长度4 目前长度 ${param[key].length}`;
}
for (let i =0; i < param[key].length; i++) {
let item = param[key][i];
if ( typeof item != 'string' ) {
isError = true;
errorStr = `${key}应是string型数组其中下标${i}${typeof item}`;
}
}
/** 不符合规则的 */
let nullIndex = -1;
for (let i = 0; i < param[key].length; i++) {
if (nullIndex != -1) {//出现过空 第一次出现后的位置 都不能有值
if (param[key]) {
//做一个特化
throw new BizError(ERRORENUM.地址数据不完整, `${key} 下标 ${nullIndex} 为空 `);
}
}
if (nullIndex == -1 && !param[key][i]) {
/**按顺序第一次赋值 */
nullIndex = i;
}
}
break;
}
errorStr = isError && errorStr == "" ? `${key}应该是${confType}型 而不是${valueType}`: errorStr;
if (isError) throw new BizError(ERRORENUM.参数错误, errorStr);
}
}
return param;
}
\ No newline at end of file
import moment = require("moment");
const md5 = require("md5");
export function getUserToken(loginId:string) {
return md5(`${loginId}_${Math.ceil(Math.random()*1000)}${new Date().valueOf()}`);
}
export function getMySqlMs(time?) {
time = time || new Date().valueOf();
return moment(time).format("YYYY-MM-DD HH:mm:ss");
}
export function getPartyMemberId(param) {
return md5(`${param}-${new Date().valueOf()}-${Math.ceil(Math.random() * 10000)}`);
}
\ No newline at end of file
const xlsx = require('node-xlsx');
const path = require('path');
/**
* onceSheetBecomeOfblockData 将excel文件的指定sheet解析成数据块数据
* @param fileName 文件名称
* @param sheetName 表名称
* @returns [ {blockData:数据块(二维数组), blockTitle:"数据标题"}]
*/
export function onceSheetBecomeOfblockData(fileName, sheetName) {
let {sheetMap} = getExcel( path.join(__dirname.substring(0,__dirname.indexOf("out")), "res", fileName ));
// return sheetMap;
let thisBlockData = getBlockData(sheetMap[sheetName]);
return thisBlockData;
}
/**
* excelBecomeOfBlockData 将excel所有的sheet解析成数据块
* @param fileName 文件名称
* @returns {"sheetName1":[ {blockData:数据块(二维数组), blockTitle:"数据标题"}], ...}
*/
export function excelBecomeOfBlockData(fileName) {
let {sheetMap} = getExcel( path.join(__dirname.substring(0,__dirname.indexOf("out")), "res", fileName ));
let result = {};
for (let sheetName in sheetMap) {
result[sheetName] = getBlockData(sheetMap[sheetName]);
}
return result;
}
/**
* planaryArrayBecomeOfBlockData 将符合excel规则的sheet二维数组转为 数据块
* @param dataList excel解出来的数据
* @returns thisBlockData 返回数据块集合 格式:blockList = [ {blockData:数据块(二维数组), blockTitle:"数据标题"}]
*/
export function planaryArrayBecomeOfBlockData(planaryArray) {
return getBlockData(planaryArray);;
}
//===
/**
* getBlockData 数据分块
* @param dataList 解析出来的excel二维数组
* @returns 返回数据块集合 格式:blockList = [ {blockData:数据块(二维数组), blockTitle:"数据标题"}]
*/
function getBlockData(dataList) {
let blockList = [];
for (let i = 0; i < 999; i++) {
let {blockData, blockTitle, notItem, delDataList} = checkBlock(dataList);
if (notItem) break;
dataList = delDataList;
if (blockTitle) blockList.push({blockData, blockTitle});
}
return blockList;
}
function getListFristNotNullItemIndex(list) { //获取起始坐标
if (!list.length) return null;
for (let i = 0; i < list.length; i++) {
if (list[i]) return i;
}
}
function getListFirstNullItemIndex(startX, list) { //获取第一个为空的坐标
if (!list.length) return null;
let checkItem = false;
let firstItemIndex = 0;
for (let i = startX; i <= list.length; i++) {
let item = list[i];
if (!checkItem && item) checkItem = true;
if (checkItem && !item) {
firstItemIndex = i;
break;
}
}
return firstItemIndex;
}
function listRegionIsNull(list, startX, endX) { //指定区间内数据是否未空
let isNull = true;
if ( !list.length ) return isNull;
for (let i = startX; i < endX; i++) {
let item = list[i];
if (item) {
isNull = false;
break;
}
}
return isNull;
}
function thisListNotItem(list) {
for (let i = 0; i < list.length; i++) {
if (list[i]) return false;
}
return true
}
function checkBlock(dataList) {
//纵向有效起始点
let startY = 0;
let startX = 0;
let isNotBlockTitle = false; //没有块标题
let isLook = false;
let endX = 0;//x轴最长结束下标 【包括下标】
let blockTitle = ''; //标题块名称
let notItem = true;
for (let i = 0; i < dataList.length; i++) {
let childList = dataList[i] || [];
if (!thisListNotItem(childList)) {
if ( !isLook ) {
let thisRoowStartX = getListFristNotNullItemIndex(childList);
let thisRoowLastItem = childList[thisRoowStartX + 1];
let LastList = dataList[i+1] || [];
// let lastRoowStartX = getListFristNotNullItemIndex(LastList);
let lastRoowHaveItem = LastList[thisRoowStartX];
if ( thisRoowLastItem || (LastList.length && lastRoowHaveItem) ) {
if (lastRoowHaveItem && thisRoowLastItem ) {
isNotBlockTitle = true; //不存在标题块
blockTitle = `${thisRoowStartX}_${i}`;
startY = i;
startX = thisRoowStartX;
}
else {
blockTitle = dataList[i][thisRoowStartX];
dataList[i][thisRoowStartX] = null;
if ( thisRoowLastItem ) { // 同行存在元素 标题在y轴上
startY = i;
startX = thisRoowStartX + 1;
} else { // 同行存在元素 标题在x轴上
startY = i + 1;
startX = thisRoowStartX;
}
}
isLook = true;
} else { //只有标题 无内容
console.log(dataList[i][thisRoowStartX]);
dataList[i][thisRoowStartX] = null;
}
} else {
//测量最大连续长度
let firstNullX = getListFirstNullItemIndex(startX, childList);
if (firstNullX) endX = Math.max(endX, firstNullX-1);
break;
}
notItem = false;
}
}
let endY = 0;//y轴连续下标 【包括下标】
let yInfoStart = false;
let yInfoEnd = false;
for (let y = startY; y < dataList.length; y++) {
//纵向找连续性
let thisRoow = dataList[y];
let regionIsNull = listRegionIsNull(thisRoow, startX, endX);
if (!regionIsNull) {
endY = y;
if (!yInfoStart) yInfoStart = true;
}
if (yInfoStart && regionIsNull) yInfoEnd = true;
if (yInfoEnd) break;
}
let blockData = [];
for (let y = startY; y <= endY; y++) {
let onceList = [];
for (let x = startX; x <= endX; x++) {
onceList.push(dataList[y][x]);
dataList[y][x] = null;
}
blockData.push(onceList);
}
return {blockData, blockTitle, delDataList:dataList,notItem};
}
//获取单个excel文件的数据
function getExcel(filePath) {
const workSheetsFromFile = xlsx.parse(filePath);
let sheetMap = {};
let sheetList = [];
for (let i = 0; i < workSheetsFromFile.length; i++) {
let sheetInfo = workSheetsFromFile[i];
sheetMap[sheetInfo.name] = sheetInfo.data;
sheetList.push(sheetInfo);
}
return {sheetMap, sheetList}
}
\ No newline at end of file
/**
* 异常类
* 需要和log4js共同使用
*/
import { getBizMsg } from "../config/enum/errorEnum";
import { logError } from "./log";
export class BizError extends Error {
constructor(...msgs) {
let reqErrorMsg = '';
let logErrorMsg = '';
for (let i = 0; i <msgs.length; i++) {
if (!i) {
let msg = getBizMsg(msgs[i]);
reqErrorMsg = msg;
logErrorMsg = msg;
} else {
logErrorMsg += ` | ${msgs[i]} `;
}
}
logError(logErrorMsg);
super(reqErrorMsg);
}
}
/**
* 日志类
* 包括错误日志 普通日志
* 日志存放在根目录的logs内
*/
let log4js = require('log4js');
let path = require('path');
//log路径
export const systemLogPath = {
errorLogFile:"error",
errorLogDir:"error",
handleLogFile:"handle",
handleLogDir:"handle"
}
//日志根目录
// let baseLogPath = path.resolve(__dirname.substring(0, __dirname.indexOf("out")), 'logs');
let baseLogPath = path.resolve('./', 'logs');
let errFile = path.resolve(baseLogPath, systemLogPath.errorLogDir, systemLogPath.errorLogFile);
let handFile =path.resolve(baseLogPath, systemLogPath.handleLogDir, systemLogPath.handleLogFile);
let config = {
appenders:
{
"rule-console": {"type": "console"},
"errorLogger": {
"type": "dateFile", // 日志类型
"filename": errFile, // 输出文件名
"pattern": "yyyy-MM-dd.log", // 后缀
"alwaysIncludePattern": true, // 上面两个参数是否合并
"encoding": "utf-8", // 编码格式
"maxLogSize": 1000, // 最大存储内容
"numBackups": 3, // 当文件内容超过文件存储空间时,备份文件的数量
"path": `/${systemLogPath.errorLogDir}`
},
"handleLogger": {
"type": "dateFile",
"filename": handFile,
"pattern": "yyyy-MM-dd.log",
"alwaysIncludePattern": true,
"encoding": "utf-8",
"maxLogSize": 1000,
"numBackups": 3,
"path": `/${systemLogPath.handleLogDir}`
}
},
categories: {
"default": {"appenders": ["rule-console"], "level": "all"}, //这个配置一定要有
"errorLogger": {"appenders": ["errorLogger"], "level": "error"},
"handleLogger": {"appenders": ["handleLogger"], "level": "all"}
},
"baseLogPath": path.resolve(baseLogPath, systemLogPath.handleLogDir, systemLogPath.handleLogFile)
};
log4js.configure(config); //加载配置文件
//调用预先定义的日志名称
let errorLogger = log4js.getLogger("errorLogger");
let handleLogger = log4js.getLogger("handleLogger");
let consoleLogger = log4js.getLogger("rule-console");
//错误日志
export function logError(...errStrs) {
let str = "";
errStrs.forEach(item => {
str += item + " | ";
});
errorLogger.error(`errorInfo => ${str}`);
}
//普通日志
export function logHandle(msgStr:string) {
handleLogger.info(`logInfo => ${msgStr}`);
}
//输出日志
export function logConsole(logStr:string) {
consoleLogger.info(`logInfo => ${logStr}`);
}
/**
* 解析xml
*/
var xml2js = require("xml2js");
/**
*
* @param str 需要解析的xml文本
* @returns 解析好的对象
*/
export function analysisXml(str) {
return new Promise( (resolve, reject) => {
xml2js.parseString(str, (err, result) => {
if (err) return reject(err);
return resolve(result);
});
});
}
\ No newline at end of file
/**
* 零碎的通用工具
*/
import moment = require("moment");
/**
* 匹配新旧对象变化
* 将newObj 与 oldObj 比对,将newObj中发生变化的key返回
* 使用前需要校验对象中的内容
* @param newObj 新对象
* @param oldObj 旧对象
* @returns [key] 发生变化的key
*/
export function checkChange(newObj, oldObj) {
let changeKeyList = [];
for (let newKey in newObj) {
if (`${newObj[newKey]}` != `${oldObj[newKey]}`) changeKeyList.push(newKey);
}
return changeKeyList;
}
/**
* 根据conf截取data中的数据
* @param conf
* @param data
* @returns
*/
export function extractData(conf, data, isAdmin) {
let result = {};
for (let key in conf) {
let confInfo = conf[key];
if (confInfo.changeDate) {
if (isAdmin) result[key] = data[key] ? moment(data[key]).format("YYYY-MM-DD") : '-';
else result[key] = data[key] || 0;
} else if (confInfo.isAdd && isAdmin) {
let addStr = "";
data[key].forEach(str => {
addStr += str;
});
result[key] = addStr;
}
else {
result[key] = data[key];
if (typeof result[key] == 'string' && !result[key]) result[key] = '';
}
}
return result;
}
/**
* 校验数据对象是否有空
* @param data
* @param sensitive 敏感校验 true时 0 和 ""会校验失败 false时 校验成功
* @returns true/false true = 有空值 false=无空值
*/
export function checkDataHaveNull(data:object, sensitive:boolean) {
if (Array.isArray(data)) return data.length == 0;
if (Object.keys(data).length == 0) return true;
let success = false;
for (let key in data) {
if (data[key] == null || data[key] == undefined) success = true;
if (sensitive) {
if (data[key] === 0 || data[key] === "" ) success = true;
}
}
return success;
}
export function dateMschangeToStr(timeMs:number) {
return moment(timeMs).format("YYYY-MM-DD HH:mm:SS")
}
export function datechangeToStr(timeMs) {
return moment(timeMs).format("YYYY-MM-DD")
}
\ No newline at end of file
/**
* 请求工具
*/
import * as request from 'request';
import { BizError } from './bizError';
/**
* 请求接口(get)
* @param url 路由
* @param query 请求参数
* @param headers 请求头
* @returns
*/
export function get(url:string, query?, headers?) {
if (!url || (url.search(/http:/) && url.search(/https:/)) ) throw new BizError(!url ? "请求地址为空" : "请求地址错误");
return new Promise((resolve, reject)=>{
let paramater:any = { url, json:true };
if (query) paramater.qs = query;
if (headers) paramater.headers = headers;
request.get(paramater, function (err, r, body) {
if (err) return reject(err);
if (r && r.statusCode != 200) return reject(new Error('httpError:'+r.statusCode));
resolve(body);
});
})
}
export function post(url, body, headers) {
if (!url || (url.search(/http:/) && url.search(/https:/)) ) throw new BizError(!url ? "请求地址为空" : "请求地址错误");
let header = {"content-type": "application/json"};
return new Promise((resolve, reject)=>{
request({
url: url,
method: "POST",
json: true,
headers: Object.assign(header, headers),
body: body
}, function(error, response, body) {
if (!error && response.statusCode == 200) {
resolve(body);
}
else {
resolve(body);
}
});
})
}
export function postForm(url, body, headers) {
if (!url || (url.search(/http:/) && url.search(/https:/)) ) throw new BizError(!url ? "请求地址为空" : "请求地址错误");
return new Promise((resolve, reject)=>{
request({
url: url,
method: "POST",
json: true,
form:body
}, function(error, response, res) {
if (!error) {
resolve(res);
}
else {
reject(error)
}
});
})
}
{
"compilerOptions": {
"module": "commonjs",
"target": "es2017",
"sourceMap": true,
"rootDir":"./src",
"outDir":"./out"
},
"exclude": [
"node_modules"
]
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment