Commit 8e9c9039 by lixinming

no message

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
-----BEGIN CERTIFICATE-----
MIIEITCCAwmgAwIBAgIUQTINc5JIuHOdpopiqhhUmTXBha0wDQYJKoZIhvcNAQEL
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
Q0EwHhcNMjQwMzE0MDc0OTI5WhcNMjkwMzEzMDc0OTI5WjB7MRMwEQYDVQQDDAox
NjE0NjA1ODU5MRswGQYDVQQKDBLlvq7kv6HllYbmiLfns7vnu58xJzAlBgNVBAsM
HuS4reWbveiJuuacr+iBjOS4muaVmeiCsuWtpuS8mjELMAkGA1UEBhMCQ04xETAP
BgNVBAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
lufaAAotUkNB+ZQ8v3FfhSuERqZ621pOAfPOx/QAttaBlNRQDbX+Pt0T+HTAnIqP
ZFBMjnYyoKNr6wybSikrd1UzV72A413jBGIkvvBVgXko7/0+qdY76YlGJZ0RQMf7
IgAUeq/KI3LIa9YdTunvo2LjcPYlhpF4YnaqKIGHq4V6Se4uZQPsE2zJ3aN9suhA
dkhQRCV0/lueceEUSpQW4tACF45sq6wDCR0IiV/Gxiz4uD8ahqt1xx7VjnsjDYIl
PhgdOAZHJ1yq6iPeMFjNeJvxhcoEfe+KeeVN270BJ05zxBbaVDlkwv4rydQw8XcM
GZ2gdch+MvFXSpLb2ghbKQIDAQABo4G5MIG2MAkGA1UdEwQCMAAwCwYDVR0PBAQD
AgP4MIGbBgNVHR8EgZMwgZAwgY2ggYqggYeGgYRodHRwOi8vZXZjYS5pdHJ1cy5j
b20uY24vcHVibGljL2l0cnVzY3JsP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3
NTQ5ODQ2QzAxQzNFOEVCRDImc2c9SEFDQzQ3MUI2NTQyMkUxMkIyN0E5RDMzQTg3
QUQxQ0RGNTkyNkUxNDAzNzEwDQYJKoZIhvcNAQELBQADggEBAKehyvRFvzyBaHXX
Md16BdVNuhicPxaQi1hZjqb9nVzy1ragqcv2rKLuh+JA6HUFL2hXykHuF5Ajw/vx
/YGFE8vnRjRFAHuuJnogKoJXbaVWCJPcwkV3u6xAB0QHNeQHVSTgDvweKhxa/PPv
bPxqHnc+U+RPKHdpoNqj+T3zq9p05CD9DEnnKo3qYzkX270UD0N8A+fVpX366vYL
s+DOop9ZrOgvHPRFIAiMuTZO7Ut7XMuqGAOzKjMcswFmIFJZ4TsU5yBwjMkPC7TW
nkYCXu91H6ma19bFC66m/YUhGwC0r0ZqsNf2q4Gotww78NzvpGQoxrXWTLSvkF9x
eFoddhM=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCW59oACi1SQ0H5
lDy/cV+FK4RGpnrbWk4B887H9AC21oGU1FANtf4+3RP4dMCcio9kUEyOdjKgo2vr
DJtKKSt3VTNXvYDjXeMEYiS+8FWBeSjv/T6p1jvpiUYlnRFAx/siABR6r8ojcshr
1h1O6e+jYuNw9iWGkXhidqoogYerhXpJ7i5lA+wTbMndo32y6EB2SFBEJXT+W55x
4RRKlBbi0AIXjmyrrAMJHQiJX8bGLPi4PxqGq3XHHtWOeyMNgiU+GB04BkcnXKrq
I94wWM14m/GFygR974p55U3bvQEnTnPEFtpUOWTC/ivJ1DDxdwwZnaB1yH4y8VdK
ktvaCFspAgMBAAECggEAZ7t0tXZJdTTaky99GrRaTvZ89PvXlBVdbiYkTHrESurl
JGNVrDcgUCI0aiQHixQMQY6ZMYy6fIYZ1vdRgAcQ4/TjWDrh8GlHdmnojIA0ps2c
gGv6uVCU2pIMcCqqA3f0f4jCixtvvjJW5xnGB8rzecKuSaZKYVh6AmVDzphLpHEM
R61AqQXHkGTightXh0I7VJ/7Kw+tUdX5oS0jBepMgPFjHspRPPrMo19oHjAyuR8S
uu9GWC0AMPtfsUA0+nCBEIXLaJCb5woBnpCj8MFLV9kbJPq1ic59ZN4HCqneicv6
eOF9t6JHS11snxiumR8f0+ElT7WsdFY0oW4lI78/CQKBgQDFjWTQCvN6896eAyG+
G+nSFmuwS1biBeytZ78S9FMJ4bVz45AiJX6EMjQ2ECBRj8l3F8AU6AmidagFPfVe
fR6nIqX69J6yohLlGBRYeyKbNPtrFfHXXpUdx9L+jIZXdbguJ6pgzMBPciqY55Cu
Ukl/qENVcPKnq+fKrFaKcDRfrwKBgQDDjXErlQYtAsyJwhV/VtbGWOM03F3UZBl0
uJViEjQUrhrLNdCgMtklPz3Ep+lQ8zux8K1ibjtPShRJENJJv6AJnrVb7ZMsmYev
s2J2WHn3Vzq4y55tT1YziFSjKFbr9FTi/aFL6hmK4+YWcaCu+D+IxCGEcS9fKMVg
KOLTWg0QpwKBgGE9hwkMyuqTjdnTitFsJfz+gkWF4B9jcSut7JSk5RbxHgMMWY8l
S5BAsgiGiZH8J9vSOf9QdCWeqnTiGZxIFEWKvY64yED/nDNeVe1ztwYU30jHxYIQ
kW/WQ1p+y0XTsTQu3CPHxUWV2bfoDARyhrEqnvI4pYi5CmBt0i9UqcMLAoGBAIJg
VOmHq9xql0/pNEf3763CKYleurgWHNqzDfWayVpYUcjWEkgcXqX0qgvpHyc3Y79Z
BWAwuh4895VXP7yno92GEMg/dvYvTkWYRbc9eeOsJpx6NSAP2xr0c+lrxbf+6HGG
Q/nHFEyDcS3ZiBXfsQxQJ0CT7c918VIRMFlVGozVAoGAfQMC7naplwJU/W49FTOj
zUyWj++i7IaJ3fbAWwTHYCMvMSr8LHfRkEpMytkX9Jdg1q53Geh7NE0Lstcf7RX3
CfbbcBaLL2w8wp4L2RIcT131wgjmowxT/J8dZalyHA/c6q55aPMCf9LgeyYroH8j
0E4SxgffcgJi7vfvqpw0OEc=
-----END PRIVATE KEY-----
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",
"formidable": "^1.2.1",
"log4js": "^6.6.1",
"lru-cache": "^4.1.5",
"md5": "^2.2.1",
"moment": "^2.24.0",
"mongoose": "^5.4.0",
"mysql": "^2.18.1",
"mysql2": "^3.7.0",
"node-xlsx": "^0.16.1",
"nodemailer": "^6.1.1",
"officegen": "^0.6.5",
"qs": "^6.11.0",
"request": "^2.88.0",
"sequelize": "^6.35.2",
"svg-captcha": "^1.3.12",
"tencentcloud-sdk-nodejs": "^4.0.562",
"wechatpay-node-v3": "^2.2.0",
"ws": "^5.2.2",
"xml2js": "^0.4.23"
},
"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>40012</port>
<!-- 默认null mysql填入mysql mongodb填入mongo 都有填all 如果没有数据库填null -->
<specifyDB>all</specifyDB>
<mongodb>
<path>127.0.0.1</path>
<port>27017</port>
<w>1</w>
<!-- <dataBase>baseDB</dataBase> -->
<dataBase>xuehui</dataBase>
<wtimeoutMS>30000</wtimeoutMS>
</mongodb>
<mysqldb>
<!-- 本地mysql配置 -->
<mysqlHost>192.168.0.105</mysqlHost>
<mysqlPort>3306</mysqlPort>
<mysqlUser>root</mysqlUser>
<mysqlPwd>123456</mysqlPwd>
<dataBase>xuehui</dataBase>
</mysqldb>
<!-- 短信相关配置 -->
<sms>
<sdkAppId>1400799515</sdkAppId>
<appKey>a36634bd106ee72eeea4a4bb4e62a03b</appKey>
<smsSign>会员注册</smsSign>
<!-- 填报提示 -->
<pointOut>1729286</pointOut>
<!-- 单位会员注册 -->
<unitMemberRegister>1729288</unitMemberRegister>
</sms>
</config>
import { ARTICLEPOSITION, DONGTAIZIXUNSUBTYPE, PARTYBUILDSUBTYPEENUM, PARTYBUILDTYPEENUM } from "../config/enum";
import { TABLEENUM } from "../data/models/model";
import { find } from "../data/select";
export function setEnumInterface({defaultParam}) {
let dataList = [];
for (let key in defaultParam) {
let anyKey:any = key;
if (isNaN(anyKey)) {
let keyStr = key;
let value = defaultParam[key];
if(/_dou/.test(keyStr)) keyStr = keyStr.replace(/_dou/, ",");
if(/_zyh/.test(keyStr)) keyStr = keyStr.replace(/_zyh/, "“");
if(/_yyh/.test(keyStr)) keyStr = keyStr.replace(/_yyh/, "”");
if(/_dun/.test(keyStr)) keyStr = keyStr.replace(/_dun/, "、");
if(/_ju/.test(keyStr)) keyStr = keyStr.replace(/_ju/, "。");
if(/_hgh/.test(keyStr)) keyStr = keyStr.replace(/_hgh/, "-");
if(/_kbh/.test(keyStr)) keyStr = keyStr.replace(/_kbh/, "");
dataList.push({key:keyStr, value});
}
}
return {dataList};
}
export function zhengCeZiXunLeiXing() {
let conf = {};
conf[DONGTAIZIXUNSUBTYPE.政策动向] = "Policy Tendence";
conf[DONGTAIZIXUNSUBTYPE.学会动态] = "Assoclation dynamics";
conf[DONGTAIZIXUNSUBTYPE.行业风采] = "Industry style";
let dataList = [];
for (let key in DONGTAIZIXUNSUBTYPE) {
let anyKey:any = key;
if (isNaN(anyKey)) {
let keyStr = key;
let value = DONGTAIZIXUNSUBTYPE[key];
dataList.push({key:keyStr, value, keyEng:conf[value]});
}
}
return {dataList}
}
export async function filePosition() {
let dataList = [];
for (let key in ARTICLEPOSITION) {
let anyKey:any = key;
if (isNaN(anyKey)) {
let keyStr = key;
let value = ARTICLEPOSITION[key];
dataList.push({key:keyStr, value});
}
}
let wenZiDBList = await find(TABLEENUM.党建, {type:PARTYBUILDTYPEENUM.学习园地, subType:PARTYBUILDSUBTYPEENUM.文字资料});
wenZiDBList.forEach(info => {
let {id, name} = info;
dataList.push({key:name, value:id});
});
return { dataList};
}
\ No newline at end of file
/**
* 图片编辑表中的type
*/
export enum IMGEDITFUNENUM {
学术研究 = 1,
}
/**
* 党建栏目类型
*/
export enum PARTYBUILDTYPEENUM {
主题教育 = 1,
学习园地,
}
/**
* 党建子栏目
*/
export enum PARTYBUILDSUBTYPEENUM {
视频资料 = 1,
文字资料
}
/**
* 动态资讯子栏目
*/
export enum DONGTAIZIXUNSUBTYPE {
政策动向 = 1,
学会动态,
行业风采
}
/**
* 资料类型
*/
export enum INFORMATIONTYPEENUM {
文件类型 = 1,
视频类型
}
/**
* 通知公告
*/
export enum TONGZHIGONGGAO {
会议通知 = 1,
活动通知,
项目公告
}
/**
* 会员类型
*/
export enum MEMBERTYPE {
个人会员 = 1,
单位会员
}
/**
* 性别
*/
export enum SEX {
= 1,
,
}
/**
* 专业类别
*/
export enum PROFCATEGORY {
教育理论 = 1,
教学管理,
舞蹈,
音乐,
美术设计,
戏剧影视,
戏曲,
曲艺杂技,
舞台技术,
群众艺术,
旅游相关,
文化产业,
文化管理,
文化科技,
其他
}
/**
* 作品类型
*/
export enum TYPEOFWORKS {
作品类型1 = 1,
作品类型2,
作品类型3,
作品类型4,
作品类型5,
作品类型6
}
/**
* 内容管理banner位置
*/
export enum BANNERPOSITION {
首页_hghbanner01 = 1,
首页_hghbanner02,
首页_hghbanner03,
学会概况_hghbanner01,
学会概况_hghbanner02,
学会概况_hghbanner03,
动态资讯,
品牌项目_hghbanner01,
品牌项目_hghbanner02,
品牌项目_hghbanner03,
}
/**
* 内容管理文章位置
*/
export enum ARTICLEPOSITION {
动态资讯_hgh政策动向 = 1,
动态资讯_hgh学会动态,
动态资讯_hgh行业风采,
学会概况_hgh学会规章,
品牌项目_hgh乡村振兴,
品牌项目_hgh学术研究,
品牌项目_hgh芳华杯,
// 党建工作_hgh主题教育
}
/**
* 内容管理视频位置
*/
export enum VIDEOPOSITION {
首页_hgh热点视频 = 1,
党建工作_hgh主题教育,
党建工作_hgh工作动态,
党建工作_hgh学习交流
}
export enum DANGJIANVIDEO {
主题教育 = 2,
工作动态,
学习交流
}
export enum YEARENUM {
_kbh2024 = 2024,
_kbh2023 = 2023,
_kbh2022 = 2022,
_kbh2021 = 2021,
_kbh2020 = 2020,
_kbh2019 = 2019,
_kbh2018 = 2018,
_kbh2017 = 2017,
_kbh2016 = 2016,
_kbh2015 = 2015,
_kbh2014 = 2014,
_kbh2013 = 2013,
_kbh2012 = 2012,
_kbh2011 = 2011,
_kbh2010 = 2010,
}
/**
* 证件类型
*/
export enum DOCUMENTTYPE {
身份证 = 1,
}
/**
* 民族
*/
export enum NATION {
汉族 = 1,
壮族,
满族,
回族,
苗族,
维吾尔族,
土家族,
彝族,
蒙古族,
藏族,
布依族,
侗族,
瑶族,
朝鲜族,
白族,
哈尼族,
哈萨克族,
黎族,
傣族,
畲族,
傈僳族,
仡佬族,
东乡族,
高山族,
拉祜族,
水族,
佤族,
纳西族,
羌族,
土族,
仫佬族,
锡伯族,
柯尔克孜族,
达斡尔族,
景颇族,
毛南族,
撒拉族,
布朗族,
塔吉克族,
阿昌族,
普米族,
鄂温克族,
怒族,
京族,
基诺族,
德昂族,
保安族,
俄罗斯族,
裕固族,
乌孜别克族,
门巴族,
鄂伦春族,
独龙族,
塔塔尔族,
赫哲族,
珞巴族
}
/**
* 参加会议成员 participant
*/
export enum CODPARTICIPANT {
会议成员1 = 1,
会议成员2,
会议成员3,
会议成员4,
会议成员5,
会议成员6,
会议成员7,
会议成员8,
会议成员9
}
/**
* 委员名单
*/
export enum COMMITTEEMEMBER {
委员1 = 1,
委员2,
委员3
}
/**
* 分会职务
*/
export enum BRANCHPOSITION {
主任 = 1,
副主任,
秘书长,
副秘书长,
委员
}
/**
* 状态
*/
export enum STATE {
= 0,
= 1
}
/**
* 下载专区分类
*/
export enum DWTYPE {
分类1 = 1,
分类2,
分类3,
分类4,
分类5,
分类6,
分类7
}
/**
* 会员状态
*/
export enum MEMBERSTATE {
正常 = 1,
异常,
冻结,
冻结管理员
}
/**
* 单位会员类型
*/
export enum UNITMEMBERTYPE {
单位会员院校 = 9,
单位会员机构,
单位会员其他
}
/**
* 个人会员类型 Individual
*/
export enum INDIVIDUALMEMBERTYPE {
个人会员 = 1,
个人会员专家,
}
/**
* 会员类型 校验用
*/
export enum MEMBERTYPEECCENUM {
个人会员 = 1,
个人会员专家,
单位会员院校 = 9,
单位会员机构,
单位会员其他
}
/**
* 会员等级 会员职务
*/
export enum MEMBERLEVEL {
普通会员 = 1,
专家会员,
理事,
常务理事,
}
/**
* 用户注册状态
*/
export enum USERREGISTERSTATE {
待审核 = 1,
重新提交,
驳回修改,
通过
}
/**
* 证书类型
*/
export enum CERTIFICATETYPE {
普通会员证书 = 1,
专家证书,
理事证书,
常务理事证书
}
/**
* 订单状态
*/
export enum ORDERSTATE {
未支付 = 1,
已支付
}
/*
* 验证码类型
*/
export enum CODETYPE {
用户注册 = 1
}
/**
* 会费类别
*/
export enum COSTTYPE {
首次 = 1,
续费
}
export enum ISPAYENUM {
全部 = 0,
已支付 = 1,
未支付
}
/**
* 发票状态
*/
export enum INVOICESTATUS{
不具备开票条件 = 1,
已开发票 = 2,
未开发票,
退回
}
/**
* 发票状态 前端用
*/
export enum INVOICESTATUSCLIENT{
全部 = 0,
已开发票 = 2,
未开发票,
}
/**
* 审核状态 前端用
*/
export enum AUDITINGCLIENT {
已申请 = 0,
审核通过 = 2,
后台审批中 = 3,
审核失败 = 4
}
/*
* 短信类型
*/
export enum SMSTYPE {
单位会员注册 = 1,
信息填报提醒,
}
/**
* 会员注册流程
*/
export enum REGISTERFLOW {
未注册 = 0,
完成第一步,
完成第二步,
完成第三步
}
/**
* 收款确认
*/
export enum RECEIPTCONFIRMATION {
待确认 = 1,
收款确认 = 2,
退回
}
/**
* 支付方式
*/
export enum PAYMENTTYPE {
微信支付 = 1,
银行转账,
线下支付
}
/**
* 院校办学类型 yuanXiaoBanXueLeiXing
*/
export enum BANXUELEIXING {
中职 = 1,
高职,
本科,
社会培训,
非教学
}
/**
* 审批历史操作行为
*/
export enum OPERATIONREHAVIOR {
待审核 = 1,
重新提交,
驳回修改,
通过,
用户提交
}
/**
* 支付状态
*/
export enum PAYMENTSTATUS {
已支付 = 1,
未支付,
银行转账,
线下付款
}
/**
* 管理员类别
*/
export enum ADMINTYPE {
管理员 = 1,
行政,
财务
}
/**
* 管理后台一级目录
*/
export enum ADMINFIRSTDIR {
网站管理 = 1,
会员管理 = 2
}
/**
* 管理员等级
*/
export enum ADMINLV {
学会概况 = 101,
动态资讯 = 102,
品牌项目,
党建工作,
分支机构,
通知公告,
内容管理= 107,
会员库 = 201,
审批管理,
会费管理,
发票管理,
会员管理,
管理设置 = 206
}
/**
* 微信支付状态
*/
export enum WEICHARTPAYSTATE{
未提交=0,
未支付,
已支付
}
/**
* 学历
*/
export enum EDUCATION {
大专 = 1,
本科,
}
/**
* 前端使用
*/
export enum MYORDERLISTSTATE {
申请发票 = 1,
申请进度,
下载发票
}
/**
* 前端使用
*/
export enum MYORDERLISTPAYSTATE {
待缴费 = 1,
已缴费,
财务查账中,
缴费失败
}
\ No newline at end of file
export enum ERRORENUM {
身份验证失败,
非法登录,
身份验证过期,
code无效,
频繁操作请稍后再试,
高风险等级用户,
系统繁忙,
请完善信息,
参数错误,
地址数据不完整,
文件上传失败,
只能上传pngjpg图片,
系统错误,
目标数据不存在,
账号或密码错误,
用户名重复,
联系人手机号重复,
邮箱重复,
两次密码不一致,
密码只能由618位字符和数字组成,
发送验证码次数超限制,
发送验证码频率过快,
验证码错误,
验证码失效,
验证码过期,
重复提交,
无法获取未来届次,
微信支付无法被退回,
订单状态无法开具发票,
微信支付无法退回发票请求,
流程3不支持会员身份非单位会员,
数据状态错误,
用户已注册成功,
不具备审批条件,
该用户已在宽限期内,
该订单已支付,
调起微信支付失败,
查看微信支付状态失败,
订单不存在,
发票已开具不可重复提交,
请求已被退回请重新申请,
不满足重新请求条件,
该订单正在支付,
}
export enum ERRORCODEENUM {
身份验证失败 = 401,
非法登录 = 402,
身份验证过期 = 403,
code无效 = 40029,
频繁操作请稍后再试 = 45011,
高风险等级用户 = 40226,
系统繁忙 = 40227
}
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";
const os = require('os');
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, mongodb, mysqldb, specifyDB } = configInfo.config;
systemConfig.port = parseInt(port[0]);
const MongoPath = mongodb[0].path[0];
const MongoPort = mongodb[0].port[0];
const MongoW = mongodb[0].w[0];
const MongoDataBase = mongodb[0].dataBase[0];
const MongoWtimeoutMS = mongodb[0].wtimeoutMS[0];
systemConfig.mongodbStr = analysisMongoConnectStr( MongoPath, MongoPort, MongoDataBase, MongoW, MongoWtimeoutMS);
if (mysqldb) {
let dbConfigInfo = mysqldb[0];
systemConfig.mysqldb = {host:'', port:0, user:'', pwd:'', dataBase:''};
if (dbConfigInfo.mysqlHost && dbConfigInfo.mysqlPort && dbConfigInfo.mysqlUser && dbConfigInfo.dataBase) {
systemConfig.mysqldb.host=dbConfigInfo.mysqlHost[0];
systemConfig.mysqldb.port=parseInt(dbConfigInfo.mysqlPort[0]);
systemConfig.mysqldb.user=dbConfigInfo.mysqlUser[0];
systemConfig.mysqldb.pwd=dbConfigInfo.mysqlPwd[0] || "";
systemConfig.mysqldb.dataBase=dbConfigInfo.dataBase[0];
}
}
if (specifyDB) {
systemConfig.specifyDB = specifyDB[0];
} else systemConfig.specifyDB = null;
}
console.log("config init success");
} catch(err) {
console.log('ERROR => 服务器配置解析错误 请检查根目录下 serverConfig.xml 文件是否正确');
console.log(err);
throw new BizError("服务器配置解析错误 请检查根目录下 serverConfig.xml 文件是否正确");
}
}
function analysisMongoConnectStr(path, port, dataBase, w, timeOutMs) {
return `mongodb://${path}:${port}/${dataBase}?w=${w}&wtimeoutMS=${timeOutMs}`
}
export function getEnum() {
}
\ No newline at end of file
/**
* 系统配置类
*
*/
export class ServerConfig {
/**系统配置 */
port:number;
mongodbStr:string;
specifyDB:string;//指定使用哪种数据库 mongo mysql all
mysqldb:{
host:string,
port:number,
user:string,
pwd:string,
dataBase:string
};
/**短信相关配置 */
smsSDKId:number;
smsAppKey:string;
smsSign:string;
smsUnitMemberRegister:number;
}
\ No newline at end of file
/**
* 添加数据相关操作
*/
import { dataModels } from "./models/modelInit";
export async function addOneData(tableEnumValue:string, data:object) {
await dataModels[tableEnumValue].addOneData(data);
return { isSuccess:true };
}
export async function addManyData(tableEnumValue:string, dataArray:object) {
await dataModels[tableEnumValue].addManyData(dataArray);
return { isSuccess:true };
}
\ No newline at end of file
import mongoose = require('mongoose');
import { initMongoModel, initMysqlModel } from '../models/modelInit';
import { ERRORENUM } from '../../config/errorEnum';
import { systemConfig } from '../../config/serverConfig';
import { BizError } from '../../util/bizError';
const Sequelize = require('sequelize');
/**
* 初始化数据库
*/
export async function initDataBaseModel() {
if (systemConfig.specifyDB == 'mongo') {
await toMongo();
} else if (systemConfig.specifyDB == 'mysql') {
await toMysql();
} else if (systemConfig.specifyDB == 'all') {
await toMongo();
await toMysql();
} else {
console.log(`this service does not use a database`);
}
}
async function toMysql() {
let {dataBase, user, pwd, host, port} = systemConfig.mysqldb;
let mysqlDB = new Sequelize(dataBase, user, pwd,{
host:host,
port:port,
dialect:'mysql', //数据库类型
pool:{ //数据库连接池
max:20, //最大连接对象的个数
min:5, //最小连接对象的个数
idle:1000 //最长等待时间,单位为毫秒
},
timezone: '+08:00', //东八时区
dialectOptions: {
dateStrings: true,
typeCast: true
},
});
await initMysqlModel(mysqlDB);
console.log(`mysql connection success, connection config:${host}:${port}/${dataBase}`);
}
async function toMongo() {
const DefaultOptions = {
useNewUrlParser:true,
auto_reconnect:true,
// reconnectTries:1000,
// reconnectInterval:3000,
keepAlive: true,
connectTimeoutMS: 3000,
useCreateIndex: true,
useUnifiedTopology: true
};
//如果配置了mongoServerConstVal 才会连接mongo
if (systemConfig.mongodbStr) {
console.log(systemConfig.mongodbStr);
let dataBase = await mongoose.createConnection(systemConfig.mongodbStr, DefaultOptions).catch(
(err)=>{
throw err
});
await initMongoModel(dataBase);
console.log(`mongodb connection success, connection config:${systemConfig.mongodbStr}`);
} else {
throw new BizError(ERRORENUM.系统错误, "xml中未配置mongo连接字符串 无法连接到mongodb");
}
}
\ No newline at end of file
/**
* 删除
*/
import { dataModels } from "./models/modelInit";
export async function deleteManyData(tableEnumValue:string, param:object) {
await dataModels[tableEnumValue].deleteManyData(param);
return {isSuccess:true};
}
export async function deleteOneData(tableEnumValue:string, param:object) {
await dataModels[tableEnumValue].deleteOneData(param);
return {isSuccess:true};
}
\ No newline at end of file
import { INVOICESTATUS, MEMBERSTATE, REGISTERFLOW, STATE, USERREGISTERSTATE, WEICHARTPAYSTATE } from "../../config/enum";
enum TABLESOURCEENUM {
mysql = 1,
mongo = 2
}
enum TABLEENUM {
学会概括 = 'xueHuiGaiKuo',
学会领导 = 'xueHuiLingDao',
学会架构 = 'xueHuiJiaGou',
图片编辑 = 'tuPianBianJi',
芳华杯 = 'fangHuaBei',
党建 = 'dangJian',
下载专区 = 'xiaZaiZhuanQu',
会议通知 = 'huiYiTongZhi',
文章管理 = 'wenZhangGuanLi',
banner管理 = 'bannerGuanLi',
视频管理 = 'shiPinGuanLi',
专题系列 = 'zhuanTiXiLie',
机构管理 = 'jiGouGuanLi',
活动通知 = 'huoDongTongZhi',
项目公告 = 'xiangMuGongGao',
工作动态 = 'gongZuoDongTai',
委员名单 = 'weiYuanMingDan',
文字资料 = 'wenZiZiLiao',
}
const ModelArray = [
{
tableName:TABLEENUM.学会概括,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
title:{ type:'String', default:'' },//标题
desc:{ type:'String', default:'' },//简介
imgList:{ type:'[String]', default:[] },//图片地址
ut:{ type:'Number'}//最后一次修改时间
}
},
{
tableName:TABLEENUM.学会领导,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
rank:{ type:'Number' },//排序
name:{ type:'String', default:'' },//名称
position:{ type:'String', default:'' },//职位
imgUrl:{ type:'String', default:''},//大图地址
miniImgUrl:{ type:'String', default:'' },//小图片地址
desc:{ type:'String', default:'' },//描述
ct:{ type:'Number'}//创建 时间
}
},
{
tableName:TABLEENUM.学会架构,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
departmentName:{ type:'String', default:'' },//部门名称
desc:{ type:'String', default:'' },//部门介绍
display:{ type:'Number', default:0},//是否显示
ct:{ type:'Number'}//创建 时间
}
},
{
tableName:TABLEENUM.图片编辑,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
type:'Number',//枚举 IMGEDITFUNENUM
index:'Number',
imgUrl:{type:'String', default:''},
desc:{type:'String', default:''}
}
},
{
tableName:TABLEENUM.芳华杯,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
name:'String',
works:'String',
worksType:'Number',//作品类型枚举
awardTime:'Number',//获奖时间
desc:{type:'String', default:''}
}
},
{
tableName:TABLEENUM.党建,//党建类型
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'Number', index:true },
type:'Number',//选项中的二级名称 枚举 PARTYBUILDTYPEENUM
subType:'Number',//区分学习园地的视频资源和文章资源
display:'Number',//是否在官网显示
name:'String'
}
},
{
tableName:TABLEENUM.文字资料,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
title:'String',//展示标题
rank:'Number',//排序
imgUrl:'String',//图片地址
position:'Number',//位置
articleTitle:'String',//文章标题
articleUrl:'String',//链接 前端生成
type:'Number',//分类 参考党建表>学习园地>文字资料
updateTime:'Number',//更新时间
}
},
{
tableName:TABLEENUM.文章管理,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
title:'String',//文章大标题
articleType:'[Number]',//文章类型
imgUrl:'[String]',//图片地址
articleTime:'Number',//文章时间
desc:'String',//内容
display:{type:'Number', default:0},//是否显示 使用是否的枚举
ct:'Number'
}
},
{
tableName:TABLEENUM.banner管理,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
location:'Number',//所属位置枚举 24.3.1改成单选
position:'Number',//位置
articleTitle:'String',//文章标题
imgUrl:'String',//图片地址
articleUrl:'String',//文章链接
desc:'String',//副标题
display:{type:'Number', default:0},//是否显示 使用是否的枚举
ct:'Number'
}
},
{
tableName:TABLEENUM.视频管理,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
title:'String',//大标题
videoType:'Number',//分类
videoUrl:'String',//视频地址
videoTime:'Number',//video时间
desc:'String',//说明
display:{type:'Number', default:0},//是否显示 使用是否的枚举
ct:'Number',
coverUrl:'String',//封面图片
}
},
{
tableName:TABLEENUM.专题系列,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
rank:'Number',//排序 不可被修改
title:'String',//标题
position:'Number',//位置
articleTitle:'String',//文章标题
articleUrl:'String',//链接 前端生成
imgUrl:'String',
ct:'Number'
}
},
{
tableName:TABLEENUM.机构管理,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
name:'String',//机构名称
desc:'String',//内容
createTime:'Number',//成立时间
rank:'Number',
logoUrl:'String',
ct:'Number',
}
},
{
tableName:TABLEENUM.会议通知,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
name:'String',//会议名称
st:'Number',
addrest:'String',
members:{type:'[Number]', default:[]},//参会会员id,用中文逗号隔开
push:'Number',//是否开启推送
desc:'String',//参会说明
ct:'Number'
}
},
{
tableName:TABLEENUM.活动通知,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
name:'String',//活动名称
st:'Number',//开始时间
addrest:'String',
members:{type:'[Number]', default:[]},//参会会员id,用中文逗号隔开
push:'Number',//是否开启推送
desc:'String',//参会说明
ct:'Number'
}
},
{
tableName:TABLEENUM.项目公告,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
name:'String',//项目名称
st:'Number',
addrest:'String',
members:{type:'[Number]', default:[]},//参会会员id,用中文逗号隔开
push:'Number',//是否开启推送
desc:'String',//项目说明
ct:'Number'
}
},
{
tableName:TABLEENUM.工作动态,
source:TABLESOURCEENUM.mongo,
schema:{
id:{type:'String', index:true },
agencyId:{type:'String', index:true},//机构id
title:'String',//标题
activityTime:'Number',//创建时间
imgUrl:'String',//图片地址
desc:'String',//内容
isUse:{type:'Number', default:0},//是否上架0表示不上架1表示上架
ct:'Number'
}
},
{
tableName:TABLEENUM.委员名单,
source:TABLESOURCEENUM.mongo,
schema:{
id:{type:'String', index:true },
agencyId:{type:'String', index:true},//机构id
name:'String',//姓名
branchDuties:'Number',//分会职务
unit:'String',//单位
unitDuties:'String',//单位职务
ct:'Number'
}
},
{
tableName:TABLEENUM.下载专区,
source:TABLESOURCEENUM.mongo,
schema:{
id:{ type:'String', index:true },
agencyId:{type:'String', index:true},//机构id
name:'String',
type:'Number',
fileUrl:'String',
ct:'Number',//创建时间
}
}
];
export {ModelArray, TABLEENUM, TABLESOURCEENUM};
/**
* 模型控制器 根据配置初始化模型
*/
import mongoose = require('mongoose');
import { ModelArray, TABLESOURCEENUM } from './model';
import { ERRORENUM } from '../../config/errorEnum';
import { BizError } from '../../util/bizError';
/**
* 匹配mongo数据类型
* @param typeInfo
* @returns
*/
function checkTypeIsMongoDBType(typeInfo:any) {
const TypeList = ['String', '[String]', 'Number', '[Number]', 'Boolean'];
if (typeof typeInfo == 'string') {
return TypeList.indexOf(typeInfo) > -1;
} else if (typeof typeInfo == 'object') {
return TypeList.indexOf(typeInfo.type) > -1;
}
else throw new BizError(ERRORENUM.系统错误, `初始化 mongodb 的 model 时 ${typeInfo} 不可被系统识别`)
}
/**
* 校验mongo类型
* @param fileKey
* @param fileValue
* @returns
*/
function eccMongoFile(fileKey, fileValue:any) {
if (typeof fileValue == 'string') {
switch(fileValue) {
case 'String': return String;
case '[String]': return [String];
case 'Number': return Number;
case '[Number]': return [Number];
case 'Boolean': return Boolean;
// default: throw new BizError(ERRORENUM.系统错误, `${fileKey}字段类型为${fileValue} 解析失败`);
}
} else {
let fileInfo:any = {type:null};
if (fileValue.type) {
switch(fileValue.type) {
case 'String': fileInfo.type = String; break;
case '[String]': fileInfo.type = [String]; break;
case 'Number': fileInfo.type = Number; break;
case '[Number]': fileInfo.type = [Number]; break;
case 'Boolean': fileInfo.type = Boolean; break;
}
} else throw new BizError(ERRORENUM.系统错误, `${fileKey}字段缺失类型 解析失败`);
if (fileValue.index) fileInfo.index = true;
if (fileValue.default != null || fileValue.default != undefined) {
fileInfo.default = fileValue.default;
}
return fileInfo;
}
}
let dataModels = {};
/**
* 初始化mongodb数据库模型
* @param dataBase
*/
async function initMongoModel(myMongoDB:any) {
/**得到文档树 */
let modelListData = [];
let modelMapData = {};
ModelArray.forEach(info => {
let {tableName, source} = info;
if (source == TABLESOURCEENUM.mongo) {
modelMapData[tableName] = info;
modelListData.push(info);
}
});
let distinctMap = {};
function arrayToObject(array, parentKey) {
let modelSchema = {};
for (let i = 0; i < array.length; i++) {
let item = typeof array[i] == 'string' ? modelMapData[array[i]]: array[i];
let {tableName, schema} = item;
if (!parentKey) {
modelSchema[tableName] = {};
for (let key in schema) {
/**解析字段 */
let fileKey = key;
let fileValue = schema[fileKey];
if ( !checkTypeIsMongoDBType(fileValue) ) {//非基础数据类型
modelSchema[tableName][key] = arrayToObject([ modelMapData[fileValue] ], tableName);
distinctMap[fileValue] = 1;
} else {
modelSchema[tableName][key] = eccMongoFile(fileKey, fileValue);
}
}
} else {
for (let key in schema) {
/**解析子文档字段 */
let fileKey = key;
let fileValue = schema[fileKey];
if ( !checkTypeIsMongoDBType(fileValue) ) {//非基础数据类型
modelSchema[key] = arrayToObject([ modelMapData[fileValue] ], tableName);
distinctMap[fileValue] = 1;
} else {
modelSchema[key] = eccMongoFile(fileKey, fileValue);
}
}
}
}
return parentKey ? new mongoose.Schema(modelSchema) : modelSchema;
}
let tree = arrayToObject(modelListData, '');
for (let tableName in tree) {
if (distinctMap[tableName]) continue;
dataModels[tableName] = myMongoDB.model(tableName, tree[tableName]);
dataModels[tableName].addOneData = async function(data) {
return await dataModels[tableName].create(data);
}
dataModels[tableName].addManyData = async function(dataList) {
return await dataModels[tableName].insertMany(dataList);
}
dataModels[tableName].findCount = async function(param) {
return await dataModels[tableName].find(param).countDocuments();
}
dataModels[tableName].updateManyData = async function(param, updateInfo) {
return await dataModels[tableName].updateMany(param, {$set:updateInfo});
}
dataModels[tableName].updateOneData = async function(param, updateInfo) {
return await dataModels[tableName].updateOne(param, {$set:updateInfo});
}
dataModels[tableName].deleteManyData = async function(param) {
return await dataModels[tableName].deleteMany(param);
}
dataModels[tableName].deleteOneData = async function(param) {
return await dataModels[tableName].deleteOne(param);
}
}
console.log(`mongo database model init success`);
}
async function initMysqlModel(mysqlDB:any) {
/**初始化表 */
for (let i =0; i < ModelArray.length; i++) {
let { tableName, schema, source } = ModelArray[i];
if (source == TABLESOURCEENUM.mysql) {
let schemaConf = {
freezeTableName:true, //true表示使用给定的表名,false表示模型名后加s作为表名
timestamps:false //true表示给模型加上时间戳属性(createAt、updateAt),false表示不带时间戳属性
};
let model = mysqlDB.define( tableName, schema, schemaConf);
dataModels[tableName] = await model.sync({}).then();
}
}
/**初始化表关联 */
for (let i =0; i < ModelArray.length; i++) {
let { tableName, association }:any = ModelArray[i];
association = association || [];
association.forEach( (item:any) => {
if (item) {
let {type, check, foreignKey} = item;
if (type == "hasOne") {
dataModels[check].hasOne(dataModels[tableName]);
} else if (type == "hasMany") {
dataModels[tableName].hasMany(dataModels[check], {foreignKey});
}
dataModels[check].belongsTo(dataModels[tableName], {foreignKey});
}
});
}
console.log(`mysql database model init success`);
}
export {initMongoModel, initMysqlModel, dataModels};
\ No newline at end of file
import { dataModels } from "./models/modelInit";
export async function findToPage(tableEnumValue:string, param:object, files:object, pageNumber:number, pageSize?) {
pageSize = pageSize || 10;//默认每页10个
let data = await dataModels[tableEnumValue].find(param, files).skip((pageNumber - 1) *pageSize).limit(pageSize);
return data;
}
export async function findToSortToPage(tableEnumValue:string, param:object, files:object, sortParam, pageNumber:number, pageSize?) {
let data = await dataModels[tableEnumValue].find(param, files).sort(sortParam).skip((pageNumber - 1) *pageSize).limit(pageSize);
return data;
}
export async function findCount(tableEnumValue:string, param:object) {
let data = await dataModels[tableEnumValue].findCount(param);
return data;
}
export async function findOnce(tableEnumValue:string, param:object, files?) {
let data = await dataModels[tableEnumValue].findOne(param, files);
return data;
}
export async function findOnceToSort(tableEnumValue:string, param:object, sortParam, files?) {
let data = await dataModels[tableEnumValue].findOne(param, files).sort(sortParam);
return data;
}
export async function find(tableEnumValue:string, param, files?) {
files = files || [];
let data = await dataModels[tableEnumValue].find(param, files);
return data;
}
export async function findToSort(tableEnumValue:string, param, sortParam, files?) {
files = files || [];
let data = await dataModels[tableEnumValue].find(param, files).sort(sortParam);
return data;
}
\ No newline at end of file
/**
* 修改
*/
import { dataModels } from "./models/modelInit";
export async function updateManyData(tableEnumValue:string, param:object, data:object) {
await dataModels[tableEnumValue].updateManyData(param, data);
return {isSuccess:true};
}
export async function updateOneData(tableEnumValue:string, param:object, data:object) {
await dataModels[tableEnumValue].updateOneData(param, data);
return {isSuccess:true};
}
\ No newline at end of file
import { initConfig, systemConfig} from "./config/serverConfig";
import { initDataBaseModel } from "./data/db/db";
import { httpServer } from "./net/http_server";
async function lanuch() {
/**初始化配置解析 */
await initConfig();
/**初始化数据库 */
await initDataBaseModel();
/**创建http服务 */
httpServer.createServer(systemConfig.port);
// await smsTask();
console.log('This indicates that the server is started successfully.');
}
lanuch();
import { ERRORENUM } from "../config/errorEnum";
import { BizError } from "../util/bizError";
var formidable = require("formidable");
const path = require('path');
export async function parseFormParam(req, res, next) {
var form = new formidable.IncomingForm();
form.uploadDir = path.join(__dirname.substring(0,__dirname.indexOf("out")), 'files');
form.parse(req, (err, fields, files)=>{
if (err) {
next(err)
}
else {
req.fields = fields;
req.files = files;
if (!files.file) {
return next(new BizError(ERRORENUM.文件上传失败) )
}
if ( files.file.type == 'image/png') {
req.fileType = '.png';
next();
} else if (files.file.type == 'image/jpg' || files.file.type == 'image/jpeg') {
req.fileType = '.jpg';
next();
} else {
return next(new BizError(ERRORENUM.只能上传pngjpg图片) )
}
}
})
}
import { bizlive } from "tencentcloud-sdk-nodejs";
import { ERRORCODEENUM } from "../config/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 { ERRORENUM } from "../config/errorEnum";
import { BizError } from "../util/bizError";
/**
* 中间件
* @param req
* @param res
* @param next
* @returns
*/
export async function checkUser(req, res, next) {
if (!req.headers) req.headers = {};
const reqToken = req.headers.token;
const userId = req.headers.userid || "";
// if (!reqToken || !userId ) return next(new BizError(ERRORENUM.身份验证失败, `userId:${userId} token:${reqToken}`));
// let userInfo = await findOnce(TABLEENUM.用户表, {userId});
// if (!userInfo || !userInfo.userId) return next(new BizError(ERRORENUM.身份验证失败));
// if (userInfo.token != reqToken) return next(new BizError(ERRORENUM.身份验证过期));
// let checkToken = '';
// //30分钟更新token
// if ( (userInfo.tokenMs - new Date().valueOf()) >= (30 * 60 * 1000) ) {
// return next(new BizError(ERRORENUM.身份验证过期));
// } else {
// checkToken = reqToken;
// await updateOneData(TABLEENUM.用户表, {userId:userInfo.userId}, { tokenMs:new Date().valueOf()});
// }
req.headers.userId = userId;
req.headers.userInfo = {
userId,
// isAdmin:userInfo.isAdmin
}
next();
}
export async function notCheck(req, res, next) {
next();
}
/**
* 中间件 数据维护接口
* @param req
* @param res
* @param next
* @returns
*/
export async function checkInterior(req, res, next) {
if (!req.headers) req.headers = {};
const Sign = req.headers.sign;
let sysSign = 'sadfjslakdfjlksadjffujisdaiofjsajl09092302'
if (!Sign || Sign != sysSign) return next(new BizError(ERRORENUM.非法登录, `内部接口非法调用 ${Sign}`));
next();
}
\ No newline at end of file
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}));
httpServer.use(express.static("./static") );
httpServer.use(express.static("./files") );
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 officialWebsiteBiz from "../../biz/officialWebsite";
export const FirstName = '官网路由';
export const FirstRouter = '/officialwebsite';
export const Config = {
"首页":[
{
apiName:"banner图",
subUrl:'/banner',
param:[],
bindBiz:officialWebsiteBiz.banner
},
{
apiName:"内容",
subUrl:'/homepage',
param:[],
bindBiz:officialWebsiteBiz.homePage
},
],
"学会概况":[
{
apiName:"学会概况",
subUrl:'/xuehuigaikuang',
param:[],
bindBiz:officialWebsiteBiz.xueHuiGaiKuang
},
{
apiName:"学会概况详情",
subUrl:'/xuehuigaikuangxiangqing',
param:[],
bindBiz:officialWebsiteBiz.xueHuiGaiKuangXiangQing
},
{
apiName:"学会规章列表(更多按钮触发)",
subUrl:'/xuehuiguizhang',
param:[
{key:"pageNumber", type:"Number", desc:"当前页"},
],
bindBiz:officialWebsiteBiz.guiZhangLieBiaoFenYe
},
{
apiName:"学会规则详情",
subUrl:'/xuehuiguizhangxiangqing',
param:[
{key:"id", type:"String", desc:"规章列表下发的标识"},
],
bindBiz:officialWebsiteBiz.guiZhangZhiDuXiangQing
},
],
"动态资讯":[
{
apiName:"动态资讯列表",
subUrl:'/dongtaizixun',
param:[
{key:"type", type:"Number", desc:"政策动向学会动态行业风采,参考公用接口"},
{key:"pageNumber", type:"Number", desc:"当前页"},
],
bindBiz:officialWebsiteBiz.dongTaiZiXun
},
{
apiName:"文章详情",
subUrl:'/wenzhangxiangqing',
param:[
{key:"id", type:"String", desc:"动态资讯列表中的标识"},
],
bindBiz:officialWebsiteBiz.wenZhangXiangQing
},
{
apiName:"热门排行",
subUrl:'/remenpaihang',
param:[
{key:"type", type:"Number", desc:"类型"}
],
bindBiz:officialWebsiteBiz.reMenPaiHang
}
],
"品牌项目":[
{
apiName:"品牌项目banner",
subUrl:'/pinpaixiangmubanner',
param:[],
bindBiz:officialWebsiteBiz.pinPaiXiangMuBanner
},
{
apiName:"品牌项目信息",
subUrl:'/pinpaixiangmu',
param:[],
bindBiz:officialWebsiteBiz.pinPaiXiangMu
},
{
apiName:"学术研究列表",
subUrl:'/xueshuyanjiu',
param:[
{key:"pageNumber", type:"Number", desc:"单前页"}
],
bindBiz:officialWebsiteBiz.xueshuyanjiu
},
{
apiName:"乡村振兴列表",
subUrl:'/xiangcunzhenxing',
param:[
{key:"pageNumber", type:"Number", desc:"单前页"}
],
bindBiz:officialWebsiteBiz.xiangCunZhenXing
},
],
"党建工作":[
{
apiName:"主题教育",
subUrl:'/zhutijiaoyu',
param:[],
bindBiz:officialWebsiteBiz.zhuTiJiaoYu
},
{
apiName:"学习园地-视频资料",
subUrl:'/xuexiyuandishipin',
param:[
{key:"type", type:"Number", desc:"类型"}
],
bindBiz:officialWebsiteBiz.xueXiYuanDiShiPin
},
{
apiName:"学习园地-文字资料",
subUrl:'/xuexiyuandiwenzi',
param:[
{key:"type", type:"Number", desc:"类型"}
],
bindBiz:officialWebsiteBiz.xueXiYuanDiWenZi
},
{
apiName:"党建资源列表",
subUrl:'/dangjianziyuan',
param:[
{key:"first", type:"Number", desc:"一级目录 参考公用接口"},
{key:"secondary", type:"Number", desc:"二级目录 参考公用接口"},
{key:"three", type:"Number", desc:"三级目录", isNull:true},
{key:"pageNumber", type:"Number", desc:"单前页"}
],
bindBiz:officialWebsiteBiz.dangJianZiYuan
},
{
apiName:"党建资源目录列表",
subUrl:'/dangjianziyuanmulu',
param:[],
bindBiz:officialWebsiteBiz.dangJianZiYuanMuLu
},
{
apiName:"学习园地-文字资料类型",
subUrl:'/xuexiyuandiwenzitype',
param:[],
bindBiz:officialWebsiteBiz.xueXiYuanDiWenZiType
},
{
apiName:"学习园地-视频资料类型",
subUrl:'/xuexiyuandishipintype',
param:[],
bindBiz:officialWebsiteBiz.xueXiYuanDiShiPinType
}
],
"通知公告":[
{
apiName:"主题教育",
subUrl:'/tongzhigonggao',
param:[
{key:"type", type:"Number", desc:"类型 参考公用组件"},
{key:"pageNumber", type:"Number", desc:"单前页"}
],
bindBiz:officialWebsiteBiz.tongZhiGongGao
},
{
apiName:"通知公告详情",
subUrl:'/tongzhigonggaoinfo',
param:[
{key:"type", type:"Number", desc:"类型 参考公用组件"},
{key:"id", type:"String", desc:"标识"}
],
bindBiz:officialWebsiteBiz.tongZhiGongGaoInfo
},
],
"分支机构":[
{
apiName:"机构列表",
subUrl:'/fenzhijigoulist',
param:[],
bindBiz:officialWebsiteBiz.fenZhiJiGou
},
{
apiName:"分会动态",
subUrl:'/fenhuidongtai',
param:[
{key:"pageNumber", type:"Number", desc:"当前页数"},
{key:"agencyId", type:"String", desc:"分会id 不填就是全部", isNull:true}
],
bindBiz:officialWebsiteBiz.fenHuiDongTai
},
{
apiName:"分会详情",
subUrl:'/fenhuixiangqing',
param:[
{key:"id", type:"String", desc:"分会id"}
],
bindBiz:officialWebsiteBiz.fenHuiDongTaiInfo
},
{
apiName:"委员名单",
subUrl:'/weiyuanmingdan',
param:[
{key:"name", type:"String", desc:"成员名称"},
{key:"agencyId", type:"Number", desc:"分会id"},
{key:"pageNumber", type:"Number", desc:"分页-页数"}
],
bindBiz:officialWebsiteBiz.weiYuanMingDanList
}
],
}
\ No newline at end of file
import * as publicBiz from '../../biz/public';
import * as enumConfig from '../../config/enum';
export const FirstName = '公共接口';
export const FirstRouter = '/public';
export const Config = {
"下拉框数据":[
{
apiName:"性别",
subUrl:'/sex',
param:[],
defaultParam:enumConfig.SEX,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"会员类型",
subUrl:'/membertype',
param:[],
defaultParam:enumConfig.MEMBERTYPE,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"专业类别",
subUrl:'/profcategory',
param:[],
defaultParam:enumConfig.PROFCATEGORY,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"内容管理banner位置",
subUrl:'/position',
param:[],
defaultParam:enumConfig.BANNERPOSITION,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"内容管理文章位置",
subUrl:'/articleposition',
param:[],
bindBiz:publicBiz.filePosition
},
{
apiName:"内容管理视频位置",
subUrl:'/videoposition',
param:[],
defaultParam:enumConfig.VIDEOPOSITION,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"年筛选",
subUrl:'/years',
param:[],
defaultParam:enumConfig.YEARENUM,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"作品类型",
subUrl:'/typeofworks',
param:[],
defaultParam:enumConfig.TYPEOFWORKS,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"参会人员",
subUrl:'/codparticipant',
param:[],
defaultParam:enumConfig.CODPARTICIPANT,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"分委会职务",
subUrl:'/branchposition',
param:[],
defaultParam:enumConfig.BRANCHPOSITION,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"下载专区分类",
subUrl:'/dwtype',
param:[],
defaultParam:enumConfig.DWTYPE,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"民族",
subUrl:'/nation',
param:[],
defaultParam:enumConfig.NATION,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"证件类型",
subUrl:'/documenttype',
param:[],
defaultParam:enumConfig.DOCUMENTTYPE,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"动态资讯类型列表",
subUrl:'/dongtaizixuntype',
param:[],
bindBiz:publicBiz.zhengCeZiXunLeiXing
},
{
apiName:"通知公告类型",
subUrl:'/tongzhigonggaotype',
param:[],
defaultParam:enumConfig.TONGZHIGONGGAO,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"验证码类型",
subUrl:'/codetype',
param:[],
defaultParam:enumConfig.CODETYPE,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"会员缴费列表类型",
subUrl:'/ispay',
param:[],
defaultParam:enumConfig.ISPAYENUM,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"支付方式",
subUrl:'/paytype',
param:[],
defaultParam:enumConfig.PAYMENTTYPE,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"发票状态",
subUrl:'/invoicestate',
param:[],
defaultParam:enumConfig.INVOICESTATUSCLIENT,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"会费类别",
subUrl:'/costtype',
param:[],
defaultParam:enumConfig.COSTTYPE,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"订单状态",
subUrl:'/orderstate',
param:[],
defaultParam:enumConfig.ORDERSTATE,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"单位会员类别",
subUrl:'/unitmembertype',
param:[],
defaultParam:enumConfig.UNITMEMBERTYPE,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"个人会员类别",
subUrl:'/individualnembertype',
param:[],
defaultParam:enumConfig.INDIVIDUALMEMBERTYPE,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"会员职务",
subUrl:'/memberlevel',
param:[],
defaultParam:enumConfig.MEMBERLEVEL,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"会员类别", //前端用
subUrl:'/membertypeecc',
param:[],
defaultParam:enumConfig.MEMBERTYPEECCENUM,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"管理员类别",
subUrl:'/admintype',
param:[],
defaultParam:enumConfig.ADMINTYPE,
bindBiz:publicBiz.setEnumInterface
},
{
apiName:"学历",
subUrl:'/education',
param:[],
defaultParam:enumConfig.EDUCATION,
bindBiz:publicBiz.setEnumInterface
},
],
}
/**
* 总路由入口
*
*
* */
import { ERRORENUM } from "../config/errorEnum";
import { BizError } from "../util/bizError";
import { eccFormParam, eccReqParamater } from "../util/verificationParam";
import * as officalWebsiteRouter from "./officalWebsite/router";
import * as publicRouter from "./public/router";
import { checkUser, notCheck } from "../middleware/user";
export async function setRouter(httpServer){
await analysisRouter(httpServer, officalWebsiteRouter.Config, officalWebsiteRouter.FirstRouter, false);//官网路由
await analysisRouter(httpServer, publicRouter.Config, publicRouter.FirstRouter, false);//公用组件
}
async function analysisRouter(httpServer, config, firstRouter, haveMiddleware) {
for (let modelKey in config) {
config[modelKey].forEach(info => {
let {apiName, defaultParam, subUrl, param, bindBiz, notMiddleware} = info;
httpServer.post(firstRouter+subUrl , haveMiddleware? checkUser : notCheck, async function (req, res) {
let chackObjectList = [];
let checkStringMap = {};
let stringNotMustHaveKeys = [];
let funcParam:any = {};
funcParam.userId = req.headers.userId;
for (let i = 0; i < param.length; i++) {
let info:any = param[i];
let {key, type} = param[i];
if (info.isNull) stringNotMustHaveKeys.push(key);
if (type == 'Object') {
chackObjectList.push(param[i]);
checkStringMap[key] = type;
}
else checkStringMap[key] = type;
}
/**校验参数 */
if (chackObjectList.length) {
chackObjectList.forEach(item => {
if (!req.body[item.key]) throw new BizError(ERRORENUM.参数错误, `缺少参数${item.key}`);
eccFormParam(apiName, item.sub, req.body[item.key]);
funcParam[item.key] = req.body[item.key];
});
}
if (Object.keys(checkStringMap).length) {
let eccResult = eccReqParamater(apiName, checkStringMap, req.body, stringNotMustHaveKeys);
for (let key in eccResult) {
funcParam[key] = eccResult[key];
}
}
if (defaultParam) funcParam["defaultParam"] = defaultParam;
let result = await bindBiz(funcParam);
res.success(result);
});
});
}
}
import { systemConfig } from "../config/serverConfig";
import { postForm } from "../util/request";
const Cookie = [
'sidebar_collapsed=false',
'cookie_token=6a28392e71084032f8076d24e32fc15e6dc8532d0717f8183529ce0d9a7e0df5',
'_gitlab_session=a8de022ccd772cd40a82f6e9cc11b061',
'PHPSESSID=62mlp67e45ijp450hs9f5tt9h5',
'think_language=zh-CN'
];
let headers = {
Cookie,
Accept:"application/json, text/plain, */*",
"Accept-Encoding":"gzip, deflate",
"Content-Type":['application/x-www-form-urlencoded', 'charset=UTF-8'],
"Connection":"keep-alive",
"Accept-Language":['zh-CN,zh', 'q=0.9'],
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
Host:"123.207.147.179:2222",
Origin:"http://123.207.147.179:2222",
Referer:"http://123.207.147.179:2222/showdoc/web/"
};
const ItemId = 81;//项目id
let distinctMap = {};
export async function getDoc() {
let body = {
item_id:ItemId,
page_id: 1642
};
let result:any = await postForm('http://123.207.147.179:2222/showdoc/server/index.php?s=/api/item/info', body, headers);
result.data.menu.catalogs.forEach(info => {
let {cat_name, catalogs, cat_id} = info;//一级目录
if (!distinctMap[cat_name]) distinctMap[cat_name] = {firstId:cat_id, secondMap:{} };
catalogs.forEach(item => {
let {pages} = item;
if (!distinctMap[cat_name].secondMap[item.cat_name]) {
distinctMap[cat_name].secondMap[item.cat_name] = {secondId:item.cat_id, apiMap:{} };
}
pages.forEach(apiItem => {
let {page_title, page_id } = apiItem;
distinctMap[cat_name].secondMap[item.cat_name].apiMap[page_title] = page_id;
});
});
});
}
export async function initDoc(firstName, apiConfig, apiFirstRouter) {
let itemHeaders = Object.assign({ Accept:"application/json, text/plain, */*", "Cache-Control":"no-store, no-cache, must-revalidate, post-check=0, pre-check=0"}, headers);
/**创建一级目录 */
if (!distinctMap[firstName]) {
let addFirstParam = {
item_id:ItemId,
cat_name:firstName
};
let addFirstResult:any = await postForm('http://123.207.147.179:2222/showdoc/server/index.php?s=/api/catalog/save', addFirstParam , itemHeaders);
distinctMap[firstName] = {firstId:addFirstResult.data.cat_id, secondMap:{} };
}
for (let pKey in apiConfig) {
if (!distinctMap[firstName].secondMap[pKey]) {
/**创建二级目录 */
let addSecondParam = {
item_id:ItemId,
cat_name:pKey,
parent_cat_id:distinctMap[firstName].firstId
};
let addSecondResult:any = await postForm('http://123.207.147.179:2222/showdoc/server/index.php?s=/api/catalog/save', addSecondParam , itemHeaders);
distinctMap[firstName].secondMap[pKey] = {secondId:addSecondResult.data.cat_id, apiMap:{} };
}
let subAPIList = apiConfig[pKey];
for (let i = 0; i < subAPIList.length; i++) {
let info = subAPIList[i];
const ApiIsExistent = distinctMap[firstName].secondMap[pKey].apiMap[info.apiName];
let itemStr = `**<h4>接口描述</h4>**\n`;
itemStr += `- ${info.apiName}\n\n------\n`;
itemStr += `**<h4>接口说明</h4>**\n\n`;
itemStr += `|方式|ip|端口|URL地址|\n`;
itemStr += `|:----- |:----- |----- |-------------- |\n`;
itemStr += `|post|192.168.0.105|${systemConfig.port} |${apiFirstRouter}${info.subUrl}|\n`;
itemStr += `**<h4>接口地址</h4>**\n\n`;
itemStr += `\`http://192.168.0.105:${systemConfig.port}${apiFirstRouter}${info.subUrl}\`\n\n------\n`;
itemStr += `**<h4>请求头(headers)</h4>**\n\n`;
itemStr += `|参数名|类型|说明|\n`;
itemStr += `|:---- |:----- |----- |\n`;
itemStr += `|userid |string |用户id |\n`;
itemStr += `|token |string |登录下发的token |\n\n ------\n`;
if (!info.param || !info.param.length) {
itemStr += `**<h4>请求参数参数(body)</h4>**\n\n`;
itemStr += `· 无 \n\n ------\n`;
} else {
itemStr += `**<h4>请求参数参数(body)</h4>**\n\n`;
itemStr += `|参数名|必选|类型|说明|\n`;
itemStr += `|:----|:---|:-----|-----|\n`;
let subMap = {};
info.param.forEach(subInfo => {
let {key, type, sub, desc, isNull} = subInfo;
if (sub) {
itemStr += `|${key}|是|object| 参考 ${key}参数 |\n`;
subMap[key] = sub;
} else {
itemStr += `|${key}|${isNull == true?"否":"是"}|${type}| ${desc||''} |\n`;
}
});
itemStr += `\n------\n\n`;
for (let subMapKey in subMap) {
itemStr+=`**<h5>${subMapKey}参数</h5>**\n\n`;
itemStr += `|参数名|必选|类型|说明|\n`;
itemStr += `|:----|:---|:-----|-----|\n`;
for (let subMapItemKey in subMap[subMapKey]) {
let subMapItemValue = subMap[subMapKey][subMapItemKey];
itemStr += `|${subMapItemKey}|${subMapItemValue.notMustHave==false? '否' : '是'}|${subMapItemValue.type}| ${subMapItemValue.desc||''} |\n`;
}
itemStr += `\n\n----------------\n`;
}
}
itemStr += `**<h4>返回示例</h4>**\n`;
if (ApiIsExistent) {
let oldItemData:any = await postForm('http://123.207.147.179:2222/showdoc/server/index.php?s=/api/page/info', {page_id:ApiIsExistent} , itemHeaders);
let oldItemDataStrList = oldItemData.data.page_content.split('```');
itemStr += `\`\`\``;
let checkItemStr = oldItemDataStrList[1].replace(/&amp;/g, "");
checkItemStr = checkItemStr.replace(/&quot;/g, "");
checkItemStr = checkItemStr.replace(/&amp;/g, "");
itemStr += checkItemStr;
itemStr += `\`\`\` \n\n`;
} else {
itemStr += `\`\`\` \n`;
itemStr += ` {\n`;
itemStr += ` "code":200,//接口状态码\n`;
itemStr += ` "success":true,//响应状态\n`;
itemStr += ` "data":{//数据主体\n`;
itemStr += ` "success":true\n`;
itemStr += ` }\n`;
itemStr += ` }\n`;
itemStr += `\`\`\` \n\n`;
}
itemStr += `------\n\n`;
itemStr += `**<h4>错误码</h4>**\n\n`;
itemStr += `|code码|说明|错误原因|后续操作|\n`;
itemStr += `|:---- |:----- |:----- |----- |\n`;
itemStr += `|401 |身份验证失败 |headers中的userid错误 |强制跳转到登陆页面 |\n`;
itemStr += `|402 |非法登录 |headers中没有token或者userid |强制跳转到登陆页面 |\n`;
itemStr += `|403 |身份验证过期 |token过期 |+强制跳转到登陆页面 |\n`;
itemStr += ``;
let body = {
page_id:ApiIsExistent || 0,
item_id:ItemId,
page_title:info.apiName,
cat_id: distinctMap[firstName].secondMap[pKey].secondId,
page_content:itemStr
};
let result = await postForm('http://123.207.147.179:2222/showdoc/server/index.php?s=/api/page/save', body , itemHeaders);
console.log(`${info.apiName}文档${ApiIsExistent ? "修改 ":"创建 "}成功`);
}
}
console.log("所有接口文档已更新完毕");
}
/**
* 系统中使用的工具
* 包括 草稿箱id生成规则
* 包括 密码加密规则
*/
import moment = require("moment");
const md5 = require("md5");
/**
* 返回编辑正确的结果
* @returns
*/
export function successResult() {
return {success:true}
}
/**
* 生成系统id
* @param tableName
* @param userId
* @returns
*/
export function generateSystemId(tableName:string, userId:string) {
return md5(`${tableName}${Math.floor(Math.random() * 10000)}${userId}${new Date().valueOf()}${Math.floor(Math.random() * 100)}`);
}
/**
* 生成token
* @param userId
* @returns
*/
export function generateToken(userId:string) {
return md5(`${userId}${Math.floor(Math.random() * 10000)}${new Date().valueOf()}${Math.floor(Math.random() * 100)}`);
}
/**
* 生成userid
*/
export function generateUserId() {
return md5(`${Math.random() * 100}${new Date().valueOf()}${Math.floor(Math.random() * 10000)}`);
}
/**
* 获取code的id
* @param loginId 用户Id
* @param todaySendCount 今日发送次数
* @returns ''
*/
export function getSMSCodeId(loginId:string, todaySendCount:number) {
return md5(`${loginId}${todaySendCount}${new Date().valueOf()}`);
}
/**
* 获取一个随机6位数的验证码
* @returns
*/
export function generateSMSCode() {
let code = ``;
for (let i =0; i < 6; i++) {
code += Math.floor(Math.random() * 10);
}
return code;
}
/**
* 生成唯一订单id
*/
export function generateOrderId(userId:string) {
return md5(`${userId}${Math.random() * 100}${new Date().valueOf()}${Math.floor(Math.random() * 1000)}`);
}
/*
* 获取今天开始时刻的时间戳 0时0分
* @returns
*/
export function getTodayMs() {
return new Date(`${ moment().format("YYYY-MM-DD")} 00:00:00`).valueOf();
}
export function generateWXOrderId(memberType, userId) {
let thisDate = new Date();
return `${md5(`${memberType}${userId}${Math.random() * 100}${thisDate.valueOf()}${Math.floor(Math.random() * 1000)}`)}`
}
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/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 data
* @param conf
* @returns
*/
export function extractData(data, conf) {
if (!conf.length) conf = Object.keys(data);
let result = {};
conf.forEach(key => {
result[key] = data[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;
}
\ 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 {
// reject(error)
}
});
})
}
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,
headers
}, function(error, response, res) {
if (!error) {
resolve(res);
}
else {
reject(error)
}
});
})
}
/**
* 校验枚举工具
*
*/
import { ERRORENUM } from "../config/errorEnum";
import { BizError } from "./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];
/** 特化处理 中文引号在枚举中不适用*/
if (str == "_投资__孵化_类型") {
str = str.replace("__","+");
str = str.replace("_","“");
str = str.replace("_","”");
}
if (str == "经营成本过高_场地成本或人员成本_" || str == "办公空间拓展_无合适办公空间_") {
str = str.replace("_","(");
str = str.replace("_",")");
}
if (str == "迁出孵化器_仍在张江" || str == "迁出张江_仍在浦东" || str == "迁出浦东_仍在上海") {
str = str.replace("_",",");
}
if (str == "科技金融_风险投资_" || str == "科技金融_其他_" || str == "技术专家_法律专家_") {
str = str.replace("_","(");
str = str.replace("_",")");
}
return str
}
let str = "";
value.forEach((item, index) => {
let subStr = enumConf[item];
/** 特化处理 中文引号在枚举中不适用*/
if (subStr == "_投资__孵化_类型") {
subStr = subStr.replace("__","+");
subStr = subStr.replace("_","“");
subStr = subStr.replace("_","”");
}
if (subStr == "经营成本过高_场地成本或人员成本_" || subStr == "办公空间拓展_无合适办公空间_") {
subStr = subStr.replace("_","(");
subStr = subStr.replace("_",")");
}
if (subStr == "迁出孵化器_仍在张江" || subStr == "迁出张江_仍在浦东" || subStr == "迁出浦东_仍在上海") {
subStr = subStr.replace("_",",");
}
if (subStr == "科技金融_风险投资_" || subStr == "科技金融_其他_" || subStr == "技术专家_法律专家_") {
subStr = subStr.replace("_","(");
subStr = subStr.replace("_",")");
}
str += subStr;
if (index == value.length-1) str+="";
else str += ","
});
return str;
}
\ No newline at end of file
/**
* 校验参数工具
*
*/
import { ERRORENUM } from "../config/errorEnum";
import { BizError } from "./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(apiName:string, 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.参数错误, apiName,`多余${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.参数错误, apiName,`缺失${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.地址数据不完整,apiName, `${key} 下标 ${nullIndex} 为空 `);
}
}
if (nullIndex == -1 && !param[key][i]) {
/**按顺序第一次赋值 */
nullIndex = i;
}
}
break;
}
errorStr = isError && errorStr == "" ? `${key}应该是${confType}型 而不是${valueType}`: errorStr;
if (isError) throw new BizError(ERRORENUM.参数错误, apiName, errorStr);
}
}
return param;
}
\ No newline at end of file
{
"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