Commit 3db26da4 by 孙香冬

no message

parents
.idea
/out
/node_modules
/test
/public
/logs
/video
*test*
*.logs
{
// 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
{
"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",
"node-xlsx": "^0.16.1",
"nodemailer": "^6.1.1",
"qs": "^6.11.0",
"request": "^2.88.0",
"svg-captcha": "^1.3.12",
"tencentcloud-sdk-nodejs": "^4.0.562",
"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>7078</port>
<mongodb>
<path>127.0.0.1</path>
<port>27017</port>
<w>1</w>
<dataBase>yfsDB</dataBase>
<wtimeoutMS>30000</wtimeoutMS>
</mongodb>
<!-- 小程序的secret 和 appid -->
<secret>5907d55efdd2f6b3e11e719b8d781111</secret>
<appId>wxbfc5695971b3e395</appId>
<!-- 获取小程序的openId地址 -->
<getOpenIdUrl>https://api.weixin.qq.com/sns/jscode2session</getOpenIdUrl>
</config>
\ No newline at end of file
/**
* 登录
* @param loginId 登录账号
* @param pwd 密码
* @returns
*/
export async function login(loginId:string, pwd:string) {
let resultUserInfo = {};
return resultUserInfo;
}
\ No newline at end of file
/**
* 校验表单参数配置
* 使用场景: 验证客户端请求参数
* 限制: 1.使用端不同不能共用一份配置
* 2.需要搭配 util/verificationParam -> eccFormParam() 方法使用
* 说明: notMustHave = true 时说明该字段是非必填的;不配该字段说明是必填的
*/
/**
* 使用端: 小程序端【孵化器入口】
* 场景: 更新孵化器基础数据表单
* 备注:
*/
export const BaseParamUpdateConfig = {
virtualEnterpriseNum:{type:"Number"},//虚拟企业数量
incubatedAcreage:{type:"Number", notMustHave:true},//在孵面积(㎡)
acreageTotal:{type:"Number", notMustHave:true},//孵化器总面积(㎡)
acreagePersonalUse:{type:"Number", notMustHave:true},//孵化器自用面积(㎡)
hatchingGround:{type:"[Object]", notMustHave:true},//经备案孵化场地
};
\ No newline at end of file
/**更新状态 */
export enum UPDATESTATE {
未填报 = 1,
已填报 = 2
}
/**
* 管理后台导出
*/
export enum OUTPUTTYPE {
当前数据 = 1,
全部数据
}
/**
* 最高学历
*/
export enum DEGREE {
本科 = 1,
硕士,
博士
}
/**
* 性别
*/
export enum SEX {
= 1,
}
/**
* 验证码类型
*/
export enum CODETYPE {
修改密码 = 1,
}
/**
* 短信类型
*/
export enum SMSTYPE {
修改密码 = 1,
信息填报提醒,
创建孵化器提醒
}
\ No newline at end of file
export enum ERRORENUM {
未找到数据,
参数错误,
不能重复提交任务,
表单校验失败,
该企业已存在,
数据无更新,
该孵化器月度填报已存在,
该企业当月数据已存在,
该报表需要填写本月内容后提交,
密码错误,
密码不允许有特殊字符,
不能重复修改密码,
身份验证失败,
非法登录,
身份验证过期,
密码长度不能超过24个字符,
账号不存在,
已入库的数据不能删除,
任务不存在,
该企业不存在,
该孵化器账号信息已存在,
密码不一致,
密码只能由618位字符和数字组成,
统一社会信用代码不合法,
统一社会信用代码重复,
系统错误,
该任务已提交,
无法操作其他孵化器的企业,
请填入其他原因,
账号非绑定关系,
code无效,
频繁操作请稍后再试,
高风险等级用户,
系统繁忙,
绑定失败,
发送验证码次数超限制,
发送验证码频率过快,
没有联系人,
号码与主体不一致,
验证码错误,
验证码失效,
验证码过期,
不能修改过期任务数据,
短信发送失败
}
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
export const FuHuaQiMyDataScoreConfig = {
incubatedAcreage:"Number",//在孵面积(㎡)
acreageTotal:"Number",//孵化器总面积(㎡)
acreagePersonalUse:"Number",//孵化器自用面积(㎡)
hatchingGround:"[Object]",//经备案场地
};
export const FuHuaQiBaseDataScoreConfig = {
name:{type:"String"},// {key:"名称"},
logonTime:{type:"Number"},// {key:"注册时间", changeDate:true},
lv:{type:"Number"},// {key:"孵化器级别"},
identificationTime:{type:"Number"},// {key:"认定时间", changeDate:true},
industry:{type:"[Number]"},// {key:"孵化领域"},
institutionalNature:{type:"Number"},// {key:"机构性质"},
operationModel:{type:"[Number]"},// {key:"运营模式"},//新加
foundingTeam:{type:"[Object]"},// {key:"创始团队"},//新加
liaison:{type:"String"},// {key:"联系人"},
liaisonPhone:{type:"String"},// {key:"联系电话"},
personInCharge:{type:"String"},// {key:"负责人"},
personInChargePhone:{type:"String"},// {key:"负责人联系电话"},
}
export const EnterpriseScoreConfig = {
name: "String",//企业名称
industry:"[Number]",//领域
mainBusiness:"String",//主营业务
logonTime:"Number",//注册时间
firstIncubationTime:"Number",//首次入孵时间
isNaturalPersonHolding:"Boolean",//是否自然人控股企业
logonAdd:"String",//注册地址
operatingAdd:"String",//经营地址
}
\ 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, secret, getOpenIdUrl, appId, sms } = configInfo.config;
systemConfig.port = parseInt(port[0]);
systemConfig.secret = secret[0];
systemConfig.getOpenIdUrl = getOpenIdUrl[0];
systemConfig.appId = appId[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);
}
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 const FuHuaQiBaseListConfig = {
name:{key:"名称"},
operationName:{key:"运营机构名称 不可修改"},
uscc:{key:"统一信用代码 也是登录账号 不可修改"},
virtualEnterpriseNum:{key:"虚拟企业数量"},
logonTime:{key:"注册时间", changeDate:true},
incubatedAcreage:{key:"在孵面积(㎡)"},
acreageTotal:{key:"孵化器总面积(㎡)"},
acreagePersonalUse:{key:"孵化器自用面积(㎡)"},
lv:{key:"孵化器级别"},
identificationTime:{key:"认定时间", changeDate:true},
industry:{key:"领域[]"},
institutionalNature:{key:"机构性质"},
liaison:{key:"联系人"},
liaisonPhone:{key:"联系电话"},
personInCharge:{key:"负责人"},
personInChargePhone:{key:"负责人联系电话"},
hatchingGround:{key:"经备案孵化场地"},
foundingTeam:{key:"创业团队"},
operationModel:{key:"运营模式"},
foundingTeamType:{key:"创业团队类型"}
};
/**
* 使用端: 小程序端【孵化器入口】
* 场景: 添加新注册企业信息
* 备注: 回显
*/
export const EnterpriseInfoConfig = {
draftId:{key:"草稿箱id"},
name:{key:"企业名称"}, //
uscc:{key:"统一信用代码"}, //
industry:{key:"领域"},//
logonTime:{key:"注册时间", changeDate:true},//
firstIncubationTime:{key:"首次入孵时间", changeDate:true},//
isNaturalPersonHolding:{key:"是否自然人控股企业"},//
logonAdd:{key:"注册地址"},//
operatingAdd:{key:"经营地址"},//
leasedArea:{key:"租赁面积(平方米)"},
mainBusiness:{key:"主营业务"},//主营业务
};
/**
* 使用端: 小程序端【孵化器入口】
* 场景: 添加迁入企业信息
* 备注: 回显
*/
export const EnterpriseMoveInInfoConfig = {
draftId:{key:"草稿箱id"},
name:{key:"企业名称"}, //
uscc:{key:"统一信用代码"}, //
industry:{key:"领域"},//
logonTime:{key:"注册时间", changeDate:true},//
firstIncubationTime:{key:"首次入孵时间", changeDate:true},//
isNaturalPersonHolding:{key:"是否自然人控股企业"},//
logonAdd:{key:"注册地址"},//
operatingAdd:{key:"经营地址"},//
leasedArea:{key:"租赁面积(平方米)"},
timeOfImmigration:{key:"迁入时间", changeDate:true},//
oldLogonAdd:{key:"迁入前注册地址"},//
mainBusiness:{key:"主营业务"},//主营业务
};
/**
* 使用端: 小程序端【孵化器入口】
* 场景: 企业融资信息
* 备注: 回显
*/
export const EnterpriseFinancingInfoConfig = {
uscc:{key:"统一信用代码"},//
name:{key:"企业名称"},//
logonAdd:{key:"注册地址"},//
operatingAdd:{key:"经营地址"},//
financingAmount:{key:"融资金额(万元)"},//
investmentInstitutionsName:{key:"投资机构名称"},//
timeToObtainInvestment:{key:"获得投资时间", changeDate:true},//
fuHuaQiInvestment:{key:"孵化器是否投资"},
fuHuaQiInvestmentAmount:{key:"孵化器投资金额(万元)"},//
fuHuaQiInvestmentStyle:{key:"孵化器投资方式"},//
financingRounds:{key:"融资轮次"}
};
/**
* 使用端: 管理后台
* 场景: 在孵企业列表
* 备注: 导出和列表共用一份配置
*/
export const EnterpriseListConfig = {
name:{key:"企业名称"},
createTime:{key:"入库时间 不可修改", changeDate:true},
fuhuaqiUscc:{key:"孵化器统一信用代码 不可修改 这里显示运营机构的名称"},
uscc:{key:"统一信用代码 也是登录账号 不可修改"},
industry:{key:"行业领域[] 最多 选择三个"},
logonTime:{key:"注册时间", changeDate:true},
firstIncubationTime:{key:"首次入孵时间", changeDate:true},
timeOfImmigration:{key:"迁入时间", changeDate:true},
isNaturalPersonHolding:{key:"是否自然人控股"},
oldLogonAdd:{key:"迁入前注册地址"},
logonAdd:{key:"注册地址"},
operatingAdd:{key:"经营地址"},
leasedArea:{key:"租赁面积(平方米)"},
isCreate:{key:"新注册/新迁入"},
mainBusiness:{key:"主营业务"},//主营业务
state:{key:"孵化状态"},
virtualCause:{key:"虚拟孵化模式"}
};
/**
* 使用端: 管理后台
* 场景: 迁出企业列表
* 备注: 导出和列表共用一份配置
*/
export const EnterpriseMoveOutListConfig = {
name:{key:"企业名称"},
moveOutTime:{key:"迁出时间", changeDate:true},
moveOutType:{key:"迁出类型"},
moveOutCause:{key:"迁出原因"},
fuHuaQiUscc:{key:"前所属孵化器"},
industry:{key:"行业领域[] 最多 选择三个"},
createTime:{key:"入库时间 不可修改", changeDate:true},
uscc:{key:"统一信用代码 也是登录账号 不可修改"},
mainBusiness:{key:"主营业务"},//主营业务
logonTime:{key:"注册时间", changeDate:true},
timeOfImmigration:{key:"迁入时间", changeDate:true},
oldLogonAdd:{key:"迁入前注册地址"},
firstIncubationTime:{key:"首次入孵时间", changeDate:true},
isNaturalPersonHolding:{key:"是否自然人控股"},
logonAdd:{key:"注册地址"},
operatingAdd:{key:"经营地址"},
leasedArea:{key:"租赁面积(平方米)"},
};
/**
* 使用端: 管理后台
* 场景: 企业融资信息列表
* 备注: 导出和列表共用一份配置
*/
export const FinancingListConfig = {
uscc:{key:"企业统一信用代码"},
name:{key:"企业名称"},
logonAdd:{key:"注册地址"},
operatingAdd:{key:"经营地址"},
financingAmount:{key:"融资金额(万元)"},
investmentInstitutionsName:{key:"投资机构名称"},
timeToObtainInvestment:{key:"获得投资时间", changeDate:true},
fuHuaQiInvestment:{key:"孵化器是否投资"},
fuHuaQiInvestmentAmount:{key:"孵化器投资金额(万元)"},
fuHuaQiInvestmentStyle:{key:"孵化器投资方式"},
createTime:{key:"录入时间 不可修改", changeDate:true},
industry:{key:"行业领域[] 最多 选择三个"},
logonTime:{key:"注册时间", changeDate:true},
financingRounds:{key:"融资轮次"}
}
/**
* 使用端: 管理后台
* 场景: 账号信息列表
* 备注:
*/
export const FuHuaQiListConfig = {
operationName:{key:"运营机构名称 不可修改"},
uscc:{key:"营业执照"},
liaison:{key:"联系人"},
liaisonPhone:{key:"联系人电话"},
personInChargePhone:{key:"负责人联系电话"},
userState:{key:"账号状态"}
}
/**
* 使用端: 小程序端【孵化器入口】
* 场景: 孵化器月度报表
* 备注: 回显
*/
export const MonthConfig = {
name:{key:"任务名称"},
occupancyRate:{key:"出租率"},
}
/**
* 使用端: 小程序端【孵化器入口】
* 场景: 主界面基础数据
* 备注:
*/
export const FuHuaQiHomeDataConfig = {
incubatedAcreage:{key:"在孵面积"},
acreageTotal:{key:"孵化器总面积"},
acreagePersonalUse:{key:"孵化器自用面积"},
name:{key:"名称"},
lv:{key:"孵化器级别"},
institutionalNature:{key:"机构性质"}
}
/**
* 使用端: 小程序端【孵化器入口】
* 场景: 孵化器详细数据
* 备注: 回显
*/
export const FuHuaQiBaseDataConfig = {
virtualEnterpriseNum:{key:"虚拟企业数量"},
incubatedAcreage:{key:"在孵面积"},
acreageTotal:{key:"孵化器总面积"},
acreagePersonalUse:{key:"孵化器自用面积"},
hatchingGround:{key:"经备案孵化场地"}
}
/**
* 使用端: 小程序端【孵化器入口】
* 场景: 机构信息数据
* 备注: 回显
*/
export const OrganizationBaseDataConfig = {
name:{key:"名称"},
operationName:{key:"运营机构名称"},
uscc:{key:"统一信用代码"},
logonTime:{key:"注册时间", changeDate:true},
lv:{key:"孵化器级别"},
identificationTime:{key:"认定时间", changeDate:true},
industry:{key:"孵化领域"},
institutionalNature:{key:"机构性质"},
operationModel:{key:"运营模式"},//新加
foundingTeam:{key:"创始团队"},//新加
foundingTeamType:{key:"创始团队类型"},//新加
liaison:{key:"联系人"},
liaisonPhone:{key:"联系电话"},
// personInCharge:{key:"负责人"}, 2.0去掉了
// personInChargePhone:{key:"负责人联系电话"}, 2.0去掉了
operationModelDes:{key:"运营模式描述"}
// hatchingGround:{key:"经备案孵化场地"}
}
/**
* 使用端: 小程序端【孵化器入口】
* 场景: 我的企业列表(实体 虚拟)
* 备注:
*/
export const MyEnterpriseDataConfig = {
name:{key:"名称"},
uscc:{key:"统一信用代码"},
state:{key:"孵化器状态"},
leasedArea:{key:"租赁面积"},
}
/**
* 使用端: 小程序端【孵化器入口】
* 场景: 我的企业列表中的企业详情
* 备注: 回显
*/
export const MyEnterpriseBaseDataConfig = {
name: {key:"企业名称"},//
uscc:{key:"统一信用代码" },//
industry:{key:"领域"},//
mainBusiness:{key:"主营业务"},//
logonTime:{key:"注册时间"},//
firstIncubationTime:{key:"首次入孵时间"},//
isNaturalPersonHolding:{key:"是否自然人控股企业"},//
logonAdd:{key:"注册地址"},//
operatingAdd:{key:"经营地址"},//
}
/**
* 系统配置类
*
*/
export class ServerConfig {
/**系统配置 */
port:number;
mongodbStr:string;
secret:string;
/**小程序相关配置 */
getOpenIdUrl:string;
appId:string;
/**短信相关配置 */
smsSDKId:number;
smsAppKey:string;
smsSign:string;
smsModelChangePwd:number;
smsModelPointOut:number;
smsModelInitPointOut:number;
}
\ No newline at end of file
import mongoose = require('mongoose');
let defaultOptions = {
useNewUrlParser:true,
auto_reconnect:true,
// reconnectTries:1000,
// reconnectInterval:3000,
keepAlive: 1,
connectTimeoutMS: 3000,
useCreateIndex: true,
useUnifiedTopology: true
};
export async function createDbConnect(connectUrl:string, options?:object) {
if (!options) options = defaultOptions;
return await mongoose.createConnection(connectUrl, options).catch(
(err)=>{
throw err
});
}
import { systemConfig } from "../../config/serverConfig";
import { BizError } from "../../util/bizError";
import { createDbConnect } from "./dbConnect";
import { initTable } from "./tableInit";
var baseDB;
export async function initDB() {
//如果配置了mongoServerConstVal 才会连接mongo
if (systemConfig.mongodbStr) {
console.log(systemConfig.mongodbStr, ' 连接成功')
baseDB = await createDbConnect(systemConfig.mongodbStr).catch(err => {
throw err
});
await initTable();
console.log('mongodb init success');
} else {
throw new BizError("xml中未配置mongo连接字符串 无法连接到mongodb");
}
}
export { baseDB };
// import * as taskinModel from "../../data/fuHuaQi/task";
export async function initTable() {
// taskinModel.initModel();
}
\ No newline at end of file
import { initConfig, systemConfig} from "./config/serverConfig";
import { initDB } from "./db/mongo/dbInit";
import { httpServer } from "./net/http_server";
async function lanuch() {
/**初始化配置解析 */
await initConfig();
/**初始化数据库 */
await initDB();
/**创建http服务 */
httpServer.createServer(systemConfig.port);
console.log('This indicates that the server is started successfully.');
}
lanuch();
\ No newline at end of file
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;
next();
}
})
}
\ No newline at end of file
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
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(express.static("./static") );
const root = path.join(__dirname, "../../public");
httpServer.use(express.static(root));
httpServer.use(fallback('index.html', { root }));
httpServer.use(bodyParser.json({limit:"1000kb"}));
httpServer.use(compression());
httpServer.use(watch);
routers.setRouter(httpServer);
httpServer.use(httpErrorHandler);
httpServer.listen(port);
console.log('server listen on port:'+port);
}
}
\ No newline at end of file
/**
* 管理后台端 管委会相关
*/
import * as adminBiz from '../../biz/admin/user';
import * as asyncHandler from 'express-async-handler';
import { eccReqParamater } from '../../util/verificationParam';
export function setRouter(httpServer) {
httpServer.post('/admin/login', asyncHandler(login));
}
/**
* 管理后台登录
* @param req
* @param res
*/
async function login(req, res) {
let reqConf = {loginId:'String', pwd:'String'};
let {loginId, pwd} = eccReqParamater(reqConf, req.body);
let userInfo = await adminBiz.login(loginId, pwd);
res.success(userInfo);
}
\ No newline at end of file
/**
* 总路由入口
*/
export function setRouter(httpServer){
}
\ No newline at end of file
/**
* 系统中使用的工具
* 包括 任务生成规则
* 包括 key生成规则
* 包括 草稿箱id生成规则
* 包括 密码加密规则
*/
import moment = require("moment");
const md5 = require("md5");
/**
* 生成任务id
* @param uscc 企业标识
* @returns
*/
export function getTaskId(uscc:string) {
return `${uscc}${getTimeKey()}`;
}
/**
* 根据时间生成任务id
* @param uscc 企业标识
* @param timeMs 时间戳
* @returns
*/
export function getTaskIdByTime(uscc:string, timeMs:number) {
return `${uscc}${new Date(timeMs).getFullYear()}${new Date(timeMs).getMonth() + 1 }`;
}
/**
* 获取当前日期的key
* @param timeMs 指定时间,如果不传
* @returns
*/
export function getTimeKey(timeMs?) {
if (timeMs) return parseInt(`${new Date(timeMs).getFullYear()}${new Date(timeMs).getMonth() + 1 }`);
return parseInt(`${new Date().getFullYear()}${new Date().getMonth() + 1 }`);
}
/**
* 获取上一个月日期的key
* @param timeMs 指定时间,如果不传
* @returns
*/
export function getLastMonthTimeKey() {
let time = moment().subtract(1, 'months').valueOf();
return parseInt(`${new Date(time).getFullYear()}${new Date(time).getMonth() + 1 }`);
}
/**
* 获取上一月的日期的key
* @returns
*/
export function getLastTimeKey() {
return moment().subtract(1,'months').format('YYYYM');
}
/**
* 生成草稿箱Id
* @param uscc
* @returns
*/
export function getDraftId(uscc:string) {
return md5(`${uscc}${new Date().valueOf()}${Math.ceil(Math.random()*1000)}`);
}
/**
* 密码加密
* @param uscc 信用代码
* @param pwd 密码
* @returns md5后的密码
*/
export function getPwdMd5(uscc:string, pwd:string) {
return md5(uscc+pwd);
}
/**
* md5加密
* @param pwd
* @returns pwd 加密后密码
*/
export function md5PwdStr(pwd:string) {
return md5(pwd);
}
/**
* 获取token
* @param uscc 统一信用代码
*/
export function getToken(uscc:string) {
return md5(`${uscc}${new Date().valueOf()}${Math.ceil(Math.random() *100)}`);
}
/**
* 校验uscc是否合法
* @param uscc
* @returns true/false
*/
export function eccUscc(uscc:string) {
let isSuccess = false;
if (uscc.search(/^[A-Za-z0-9]{16}$/) > -1) isSuccess = true;
else if (uscc.search(/^[A-Za-z0-9]{18}$/) > -1) isSuccess = true;
return isSuccess;
}
/**
* 获取绑定id
* @param uscc 孵化器统一信用代码
* @param bindUscc 被绑定的孵化器统一信用代码
* @returns
*/
export function getBindId(uscc:string, bindUscc:string) {
return md5(`${uscc}${bindUscc}${Math.ceil(Math.random() *100)}`);
}
/**
* 获取今天开始时刻的时间戳 0时0分
* @returns
*/
export function getTodayMs() {
let t =`${ moment().format("YYYY-MM-DD")} 00:00:00`;
return new Date(t).valueOf();
}
/**
* 获取这个月的开始时刻的时间戳 0时0分
* @returns
*/
export function getThisMonthMs() {
let t =`${ moment().format("YYYY-MM")}-01 00:00:00`;
return new Date(t).valueOf();
}
/**
* 获取code的id
* @param uscc 发送人的uscc
* @param todaySendCount 今日发送次数
* @returns ''
*/
export function getSMSCodeId(uscc:string, todaySendCount:number) {
return md5(`${uscc}${todaySendCount}${new Date().valueOf()}`);
}
/**
* 获取一个随机6位数的验证码
* @returns
*/
export function getSMSCode() {
let code = ``;
for (let i =0; i < 6; i++) {
code += Math.floor(Math.random() * 10)
}
return code;
}
\ 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/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 {
result[key] = data[key];
if (typeof result[key] == 'string' && !result[key]) result[key] = '';
}
}
return result;
}
/**
* 请求工具
*/
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
}, function(error, response, res) {
if (!error) {
resolve(res);
}
else {
reject(error)
}
});
})
}
/**
* 校验枚举工具
*
*/
import { ERRORENUM } from "../config/errorEnum";
import { BizError } from "./bizError";
/**
* 校验value是否符合传入的枚举
* @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("_",",");
}
return str
}
let str = "";
value.forEach((item, index) => {
let subStr = enumConf[item];
/** 特化处理 中文引号在枚举中不适用*/
if (subStr == "_投资__孵化_类型") {
subStr = subStr.replace("__","+");
subStr = subStr.replace("_","“");
subStr = subStr.replace("_","”");
}
if (str == "经营成本过高_场地成本或人员成本_" || str == "办公空间拓展_无合适办公空间_") {
str = str.replace("_","(");
str = str.replace("_",")");
}
if (str == "迁出孵化器_仍在张江" || str == "迁出张江_仍在浦东" || str == "迁出浦东_仍在上海") {
str = str.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]
* 参数是必填
* 方法会校验表单中存在的多余字段
* todo 后续优化配置
* @param name 被调用的方法名
* @param config 校验配置
* @param param 需要校验的参数
* @returns true 无需关注返回
*/
export function eccFormParam(name:string, keyTypeConf:object, param:object) {
for (let key in keyTypeConf ) {
let {type, notMustHave} = keyTypeConf[key];
let isError = false; //校验是否异常
let errorStr = "";//异常说明
if ( (typeof param[key] != 'boolean' && !param[key] ) ) {
if (!notMustHave) {
isError = true;
errorStr = `缺失${key}字段`;
}
} else if (param[key]) {
let paramType = typeof param[key];
let confType = keyTypeConf[key].type;
switch(confType) {
case 'Number':
if ( paramType != 'number' ) {
isError = true;
} else {
if ((""+param[key]).indexOf('.') > -1) {
param[key] = parseInt(`${param[key] *100}`)/100;
}
}
break;
case 'String':
if ( paramType != 'string' ) isError = true;
break;
case 'Boolean':
if ( paramType != 'boolean' ) 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;
}
errorStr = isError && errorStr == "" ? `${key}应该是${type}型 而不是${paramType}`: errorStr;
}
if ( isError ) throw new BizError(ERRORENUM.表单校验失败, name, errorStr);
}
/**判断多余的参数 */
for (let key in param) {
if (!keyTypeConf[key]) throw new BizError(ERRORENUM.表单校验失败, name, `多余${key}字段`);
}
return true;
}
/**
* 根据conf配置校验请求参数
* @param conf 配置
* @param param 表单
* @param skipKeys []不必填的字段
*/
export function eccReqParamater(conf:object, param, skipKeys?) {
skipKeys = skipKeys || [];
for (let key in conf) {
let type = conf[key];
let value = param[key];
let isError = false; //校验是否异常
let errorStr = "";//异常说明
if ( (typeof value != 'boolean') && !value ) {
if (skipKeys.indexOf(key) < 0 ) {
isError = true;
errorStr = `缺少 ${key} 字段`;
}
} else if(param[key]) {
let paramType = typeof param[key];
switch(conf[key]) {
case 'Number':
if ( paramType != 'number' ) {
isError = true;
}
break;
case 'String':
if ( paramType != 'string' ) isError = true;
break;
case 'Boolean':
if ( paramType != 'boolean' ) 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;
}
errorStr = isError && errorStr == "" ? `${key}应该是${type}型 而不是${paramType}`: errorStr;
}
if (isError) throw new BizError(ERRORENUM.参数错误, errorStr);
}
for (let key in param) {
if (!conf[key]) throw new BizError(ERRORENUM.参数错误, `多余${key}字段`);
}
return param;
}
{
"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