Commit a11bcf18 by chenjinjing

项目初始化

parents
.idea
/out
/node_modules
/test
/public
/logs
/video
*test*
*.log
\ No newline at end of file
{
// 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
{
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "gameserver",
"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.7.0",
"lru-cache": "^4.1.5",
"md5": "^2.2.1",
"moment": "^2.24.0",
"mongoose": "^6.2.3",
"node-xlsx": "^0.16.1",
"nodemailer": "^6.1.1",
"pyfl": "^1.1.4",
"request": "^2.88.0",
"svg-captcha": "^1.3.12",
"ws": "^8.13.0",
"xml2js": "^0.4.23"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
<config>
<port>40005</port>
<dataCenterInterface>
<answerText>http://172.21.223.163:18151/studio/api/megaindex/analysis/v1/nl/multi/scene/answer/text</answerText>
</dataCenterInterface>
</config>
\ No newline at end of file
import moment = require("moment");
import { getAIAnswerInterface } from "../data/dataCenterInterface/aiAnswerData";
import { getCarVideo, getInterfaceByInterfaceName } from "../data/cronJob";
import { BizError } from "../util/bizError";
import { ERRORENUM } from "../config/errorEnum";
//ai智能问答
export async function getAIAnswer(req, res) {
let ret:any = {};
let {aiAnswerData} = await getAIAnswerInterface();
res.send(ret);
}
export enum INTERFACEREQUESTTYPEENUM {
即时更新 = 1,
定时更新
}
export enum ERRORENUM {
未找到数据,
参数错误
}
export enum SYSTEMERRORENUM {
初始化配置失败 = 1,
获取第三方接口数据失败,
未按接口协议返回,
请求未鉴权 = 401,
请求路径不存在 = 404,
请求频率过高 = 503
}
let bizErrorMsgMap = {};
for (let key in ERRORENUM) {
bizErrorMsgMap[ERRORENUM[key]] = key;
}
let systemErrorMsgMap = {};
for (let key in SYSTEMERRORENUM) {
systemErrorMsgMap[SYSTEMERRORENUM[key]] = key;
}
export function getBizMsg(param) {
return bizErrorMsgMap[param];
}
export function getSysMsg(param) {
return systemErrorMsgMap[param];
}
\ No newline at end of file
const path = require('path');
import * as fs from "fs";
import { BizError, SysError } from "../util/bizError";
import { analysisXml } from "../util/myXML";
import { SYSTEMERRORENUM } from "./errorEnum";
const os = require('os');
export let systemConfig = {
port:9999,
};
//数据中心接口
export let dataCenterInterfaceConfig = {
answerText:"",//获取问数结果信息
};
let serverIp = "";
const ConfigName = "serverConfig.xml";
export async function initConfig() {
try {
let buff = fs.readFileSync(path.join('./', ConfigName));
// 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) console.log("xml中无配置加载");
else {
//必要配置
let integralConfig = [
"port",
{
"dataCenterInterface":[ "answerText" ]
}
];
checkConfig(integralConfig, configInfo.config);
let {port, dataCenterInterface} = configInfo.config;
systemConfig.port = parseInt(port[0]);
//数据中心接口
dataCenterInterfaceConfig.answerText = dataCenterInterface[0].answerText[0];
}
console.log("config init success");
} catch(err) {
throw new BizError("服务器配置解析错误 请检查根目录下 serverConfig.xml 文件是否正确");
}
}
function checkConfig(config, configData) {
config.forEach(item => {
if (typeof item == "object") {
for (let key in item) {
if (!configData[key] || !configData[key][0]) {
throw new SysError(SYSTEMERRORENUM.初始化配置失败, `serverConfig.xml中 缺少 ${key}`);
}
item[key].forEach( subItem => {
if (!configData[key][0][subItem] || !configData[key][0][subItem][0]) {
throw new SysError(SYSTEMERRORENUM.初始化配置失败, `serverConfig.xml中 ${key}缺少 ${subItem}`);
}
});
}
} else {
if (!configData[item] || !configData[item][0]) {
throw new SysError(SYSTEMERRORENUM.初始化配置失败, `serverConfig.xml中 缺少 ${item}`);
}
}
});
}
//获取内网地址
export function getImageIp() {
return serverIp;
}
//接口任务 定期更新
import moment = require('moment');
import * as request from 'request';
import { SYSTEMERRORENUM } from '../config/errorEnum';
import { BizError, SysError } from "../util/bizError";
let accToken = "";
export async function getInterfaceByInterfaceName(url, body) {
let reqResult = await get(url, body, {});
let {err, res, reqData}:any = reqResult;
let reqErrorMsg = "";
if (err) reqErrorMsg = err.msg || err.message;
else if (!reqData.code) reqErrorMsg = reqData.error_msg;
else {
switch (reqData.code) {
case 401: throw new SysError(SYSTEMERRORENUM.获取第三方接口数据失败, url, ` 请求未鉴权`);
case 404: throw new SysError(SYSTEMERRORENUM.获取第三方接口数据失败, url, ` 请求路径不存在`);
case 503: throw new SysError(SYSTEMERRORENUM.获取第三方接口数据失败, url, ` 请求频率过高`);
case 500: throw new SysError(SYSTEMERRORENUM.获取第三方接口数据失败, url, reqData.msg);
}
}
if (reqErrorMsg) throw new SysError(SYSTEMERRORENUM.获取第三方接口数据失败, url, reqErrorMsg);
let {msg, data, resultData} = reqData;
if (msg) return //小车心跳
if (!data && !resultData) {
throw new SysError(SYSTEMERRORENUM.获取第三方接口数据失败, url, `缺少返回参数 data`);
}
return data || resultData;
}
//接口方会返回500错误,但是这说明没有监控视频
export async function getCarVideo(url, body) {
let {err, res, reqData}:any = await get(url, body, {});
if (reqData.code == 500) {
return false;
}
if (reqData.data || reqData.resultData) return reqData.data || reqData.resultData;
// return reqData.data;
return false;
}
function get(url:string, query?, headers?, timeOut?) {
timeOut = timeOut || 10000;
if (!url || (url.search(/http:/) && url.search(/https:/)) ) throw new BizError(!url ? "请求地址为空" : "请求地址错误");
return new Promise((resolve, reject)=>{
let paramater:any = { url, json:true, timeout:timeOut };
if (query) paramater.qs = query;
if (headers) paramater.headers = headers;
request.get(paramater, function (err, res, reqData) {
resolve({err, res, reqData});
})
})
}
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(err, res, data) {
const success = !err && res && res.statusCode == 200;
let message = err || res.statusCode || "";
resolve({success, message, data});
});
})
}
function postForm(url, body) {
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(err, res, data) {
const success = !err && res && res.statusCode == 200;
let message = err || res.statusCode || "";
resolve({success, message, data});
});
})
}
import moment = require("moment");
import { SYSTEMERRORENUM } from "../../config/errorEnum";
import { dataCenterInterfaceConfig } from "../../config/serverConfig";
import { SysError } from "../../util/bizError";
import { getInterfaceByInterfaceName } from "../cronJob";
//ai智能问答
export async function getAIAnswerInterface() {
const interfaceName = "获取问数结果信息";
let data = await getInterfaceByInterfaceName( dataCenterInterfaceConfig.answerText, {} );
let { questionId, content, params } = data;
if ( !Array.isArray(params) ) throw new SysError(SYSTEMERRORENUM.未按接口协议返回, interfaceName, "params 不是数组", params);
let aiAnswerData = [];
return { aiAnswerData };
}
import { INTERFACEREQUESTTYPEENUM } from "../config/enum";
import { dataCenterInterfaceConfig } from "../config/serverConfig";
//配置
// "接口名称":{
// type:"1是即时更新 2是即时更新 使用 INTERFACErEQUESTTYPEENUM",
// time:"更新频率毫秒 例如1小时这里就是 3600000",
// url:"url地址",
// reqType:"get还是post get = get post = post",
// header:{},
// body:{}
// }
let Authorization = "38a96559-8f70-4df8-87f9-af3eb58fcc27";
export const Config = {
"获取问数结果信息":{
url:dataCenterInterfaceConfig.answerText, reqType:"get", header:{Authorization}, body:{}
},
};
\ No newline at end of file
import { initConfig, systemConfig} from "./config/serverConfig";
import { httpServer } from "./net/http_server";
async function lanuch() {
await initConfig();//初始化配置解析
httpServer.createServer(systemConfig.port);
console.log('This indicates that the server is started successfully.');
}
lanuch();
export async function encryptionReturn(req, res, next) {
res.on('end', function(){
console.log(res.body);
});
let resSend = res.send;
res.send = (obj)=>{
changeNumber(obj);
//递归修改number型
resSend.call(res, obj);
};
next();
}
function changeNumber(obj) {
if (Array.isArray(obj)) {
for (let i = 0; i < obj.length; i++) {
let arrItem = obj[i];
if (typeof arrItem == "number") {
obj[i] = getSameLenNumber(arrItem);
}
else if (typeof arrItem == "object") {
changeNumber(arrItem);
}
}
}
else {
for (let key in obj) {
let objItem = obj[key];
if (typeof objItem == "number") {
if (key == "x" || key == "y") continue;
obj[key] = getSameLenNumber(objItem);
}
else if (typeof objItem == "object") {
changeNumber(objItem);
}
}
}
}
function getSameLenNumber(num) {
let numStr = String(num);
//疑似年份的不做加密
if (numStr.length == 4 && (numStr.indexOf("19") == 0 || numStr.indexOf("20") == 0)) return num;
let str = "";
for (let i = 0; i < numStr.length; i++) {
if (numStr[i] == '.') str += numStr[i];
else str += "6";
}
return Number(str);
}
\ No newline at end of file
var formidable = require("formidable");
export async function parseFormParam(req, res, next) {
    var form = new formidable.IncomingForm();
    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 { BizError } from "../util/bizError";
const LRU = require("lru-cache")
, cacheOptions = { max: 500000
, maxAge: 1000 * 60 * 10 }
, cache = LRU(cacheOptions);
export async function checkSign(req, res, next) {
let signKey = "12345678asd!@#%DFFGa";
let userId = req.headers.userid;
let playerId = req.headers.playerid;
let token = req.headers.token;
let timeStamp = req.headers.timestamp;
let platform = req.headers.platform;
if (req.path != '/api/system/servertime' && req.path.indexOf('admin') < 0 && req.headers.sign != 'xxakdfwosaddf!@3sadfhDAse') {
let now = Date.now();
if (Math.abs(now - timeStamp) > 120000) {
console.log(req.path, new Date(now), "timeStamp", timeStamp);
return next(new BizError('timeStamp error time difference error'))
}
let sign = getSign([signKey, userId, playerId, token, timeStamp, platform, req.path, signKey]);
let cacheSign = cache.get(sign);
if (cacheSign) {
if (cacheSign > 5) return next(new BizError("sign error repetitive sign"));
else {
cacheSign++;
cache.set(sign,cacheSign);
}
}
else {
cache.set(sign,1);
}
if (sign != req.headers.sign) {
console.log(req.path, JSON.stringify(req.headers));
next(new BizError("sign error"))
}
}
next();
}
function getSign(...params) {
let s = "";
for (let i = 0; i < params.length; i++) {
if (!params[i]) continue;
s += params[i];
}
return new m().hex_md5(s);
}
export class m {
public constructor() {
}
private hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
private b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
/*
* These are the privates you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
public hex_md5(s) { return this.rstr2hex(this.rstr_md5(this.str2rstr_utf8(s))); }//这个函数就行了,
public b64_md5(s) { return this.rstr2b64(this.rstr_md5(this.str2rstr_utf8(s))); }
public any_md5(s,e) { return this.rstr2any(this.rstr_md5(this.str2rstr_utf8(s)),e); }
public hex_hmac_md5(k,d)
{ return this.rstr2hex(this.rstr_hmac_md5(this.str2rstr_utf8(k),this.str2rstr_utf8(d))); }
private b64_hmac_md5(k,d)
{ return this.rstr2b64(this.rstr_hmac_md5(this.str2rstr_utf8(k),this.str2rstr_utf8(d))); }
private any_hmac_md5(k,d,e)
{ return this.rstr2any(this.rstr_hmac_md5(this.str2rstr_utf8(k),this.str2rstr_utf8(d)),e); }
/*
* Perform a simple self-test to see if the VM is working
*/
public md5_vm_test() {
return this.hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
}
/*
* Calculate the MD5 of a raw string
*/
public rstr_md5(s) {
return this.binl2rstr(this.binl_md5(this.rstr2binl(s),s.length * 8));
}
/*
* Calculate the HMAC-MD5, of a key and some data (raw strings)
*/
public rstr_hmac_md5(key,data) {
var bkey = this.rstr2binl(key);
if(bkey.length > 16) bkey = this.binl_md5(bkey,key.length * 8);
var ipad = Array(16),opad = Array(16);
for(var i = 0;i < 16;i++) {
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = this.binl_md5(ipad.concat(this.rstr2binl(data)),512 + data.length * 8);
return this.binl2rstr(this.binl_md5(opad.concat(hash),512 + 128));
}
/*
* Convert a raw string to a hex string
*/
public rstr2hex(input) {
try { this.hexcase } catch(e) { this.hexcase = 0; }
var hex_tab = this.hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var output = "";
var x;
for(var i = 0;i < input.length;i++) {
x = input.charCodeAt(i);
output += hex_tab.charAt((x >>> 4) & 0x0F)
+ hex_tab.charAt(x & 0x0F);
}
return output;
}
/*
* Convert a raw string to a base-64 string
*/
public rstr2b64(input) {
try { this.b64pad } catch(e) { this.b64pad = ''; }
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var output = "";
var len = input.length;
for(var i = 0;i < len;i += 3) {
var triplet = (input.charCodeAt(i) << 16)
| (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0)
| (i + 2 < len ? input.charCodeAt(i + 2) : 0);
for(var j = 0;j < 4;j++) {
if(i * 8 + j * 6 > input.length * 8) output += this.b64pad;
else output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
}
}
return output;
}
/*
* Convert a raw string to an arbitrary string encoding
*/
public rstr2any(input,encoding) {
var divisor = encoding.length;
var i,j,q,x,quotient;
/* Convert to an array of 16-bit big-endian values, forming the dividend */
var dividend = Array(Math.ceil(input.length / 2));
for(i = 0;i < dividend.length;i++) {
dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
}
/*
* Repeatedly perform a long division. The binary array forms the dividend,
* the length of the encoding is the divisor. Once computed, the quotient
* forms the dividend for the next step. All remainders are stored for later
* use.
*/
var full_length = Math.ceil(input.length * 8 /
(Math.log(encoding.length) / Math.log(2)));
var remainders = Array(full_length);
for(j = 0;j < full_length;j++) {
quotient = Array();
x = 0;
for(i = 0;i < dividend.length;i++) {
x = (x << 16) + dividend[i];
q = Math.floor(x / divisor);
x -= q * divisor;
if(quotient.length > 0 || q > 0)
quotient[quotient.length] = q;
}
remainders[j] = x;
dividend = quotient;
}
/* Convert the remainders to the output string */
var output = "";
for(i = remainders.length - 1;i >= 0;i--)
output += encoding.charAt(remainders[i]);
return output;
}
/*
* Encode a string as utf-8.
* For efficiency, this assumes the input is valid utf-16.
*/
public str2rstr_utf8(input) {
var output = "";
var i = -1;
var x,y;
while(++i < input.length) {
/* Decode utf-16 surrogate pairs */
x = input.charCodeAt(i);
y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
i++;
}
/* Encode output as utf-8 */
if(x <= 0x7F)
output += String.fromCharCode(x);
else if(x <= 0x7FF)
output += String.fromCharCode(0xC0 | ((x >>> 6) & 0x1F),
0x80 | (x & 0x3F));
else if(x <= 0xFFFF)
output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
0x80 | ((x >>> 6) & 0x3F),
0x80 | (x & 0x3F));
else if(x <= 0x1FFFFF)
output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
0x80 | ((x >>> 12) & 0x3F),
0x80 | ((x >>> 6) & 0x3F),
0x80 | (x & 0x3F));
}
return output;
}
/*
* Encode a string as utf-16
*/
public str2rstr_utf16le(input) {
var output = "";
for(var i = 0;i < input.length;i++)
output += String.fromCharCode(input.charCodeAt(i) & 0xFF,
(input.charCodeAt(i) >>> 8) & 0xFF);
return output;
}
public str2rstr_utf16be(input) {
var output = "";
for(var i = 0;i < input.length;i++)
output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
input.charCodeAt(i) & 0xFF);
return output;
}
/*
* Convert a raw string to an array of little-endian words
* Characters >255 have their high-byte silently ignored.
*/
public rstr2binl(input) {
var output = Array(input.length >> 2);
for(var i = 0;i < output.length;i++)
output[i] = 0;
for(var i = 0;i < input.length * 8;i += 8)
output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
return output;
}
/*
* Convert an array of little-endian words to a string
*/
public binl2rstr(input) {
var output = "";
for(var i = 0;i < input.length * 32;i += 8)
output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
return output;
}
/*
* Calculate the MD5 of an array of little-endian words, and a bit length.
*/
public binl_md5(x,len) {
/* append padding */
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for(var i = 0;i < x.length;i += 16) {
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = this.md5_ff(a,b,c,d,x[i + 0],7,-680876936);
d = this.md5_ff(d,a,b,c,x[i + 1],12,-389564586);
c = this.md5_ff(c,d,a,b,x[i + 2],17,606105819);
b = this.md5_ff(b,c,d,a,x[i + 3],22,-1044525330);
a = this.md5_ff(a,b,c,d,x[i + 4],7,-176418897);
d = this.md5_ff(d,a,b,c,x[i + 5],12,1200080426);
c = this.md5_ff(c,d,a,b,x[i + 6],17,-1473231341);
b = this.md5_ff(b,c,d,a,x[i + 7],22,-45705983);
a = this.md5_ff(a,b,c,d,x[i + 8],7,1770035416);
d = this.md5_ff(d,a,b,c,x[i + 9],12,-1958414417);
c = this.md5_ff(c,d,a,b,x[i + 10],17,-42063);
b = this.md5_ff(b,c,d,a,x[i + 11],22,-1990404162);
a = this.md5_ff(a,b,c,d,x[i + 12],7,1804603682);
d = this.md5_ff(d,a,b,c,x[i + 13],12,-40341101);
c = this.md5_ff(c,d,a,b,x[i + 14],17,-1502002290);
b = this.md5_ff(b,c,d,a,x[i + 15],22,1236535329);
a = this.md5_gg(a,b,c,d,x[i + 1],5,-165796510);
d = this.md5_gg(d,a,b,c,x[i + 6],9,-1069501632);
c = this.md5_gg(c,d,a,b,x[i + 11],14,643717713);
b = this.md5_gg(b,c,d,a,x[i + 0],20,-373897302);
a = this.md5_gg(a,b,c,d,x[i + 5],5,-701558691);
d = this.md5_gg(d,a,b,c,x[i + 10],9,38016083);
c = this.md5_gg(c,d,a,b,x[i + 15],14,-660478335);
b = this.md5_gg(b,c,d,a,x[i + 4],20,-405537848);
a = this.md5_gg(a,b,c,d,x[i + 9],5,568446438);
d = this.md5_gg(d,a,b,c,x[i + 14],9,-1019803690);
c = this.md5_gg(c,d,a,b,x[i + 3],14,-187363961);
b = this.md5_gg(b,c,d,a,x[i + 8],20,1163531501);
a = this.md5_gg(a,b,c,d,x[i + 13],5,-1444681467);
d = this.md5_gg(d,a,b,c,x[i + 2],9,-51403784);
c = this.md5_gg(c,d,a,b,x[i + 7],14,1735328473);
b = this.md5_gg(b,c,d,a,x[i + 12],20,-1926607734);
a = this.md5_hh(a,b,c,d,x[i + 5],4,-378558);
d = this.md5_hh(d,a,b,c,x[i + 8],11,-2022574463);
c = this.md5_hh(c,d,a,b,x[i + 11],16,1839030562);
b = this.md5_hh(b,c,d,a,x[i + 14],23,-35309556);
a = this.md5_hh(a,b,c,d,x[i + 1],4,-1530992060);
d = this.md5_hh(d,a,b,c,x[i + 4],11,1272893353);
c = this.md5_hh(c,d,a,b,x[i + 7],16,-155497632);
b = this.md5_hh(b,c,d,a,x[i + 10],23,-1094730640);
a = this.md5_hh(a,b,c,d,x[i + 13],4,681279174);
d = this.md5_hh(d,a,b,c,x[i + 0],11,-358537222);
c = this.md5_hh(c,d,a,b,x[i + 3],16,-722521979);
b = this.md5_hh(b,c,d,a,x[i + 6],23,76029189);
a = this.md5_hh(a,b,c,d,x[i + 9],4,-640364487);
d = this.md5_hh(d,a,b,c,x[i + 12],11,-421815835);
c = this.md5_hh(c,d,a,b,x[i + 15],16,530742520);
b = this.md5_hh(b,c,d,a,x[i + 2],23,-995338651);
a = this.md5_ii(a,b,c,d,x[i + 0],6,-198630844);
d = this.md5_ii(d,a,b,c,x[i + 7],10,1126891415);
c = this.md5_ii(c,d,a,b,x[i + 14],15,-1416354905);
b = this.md5_ii(b,c,d,a,x[i + 5],21,-57434055);
a = this.md5_ii(a,b,c,d,x[i + 12],6,1700485571);
d = this.md5_ii(d,a,b,c,x[i + 3],10,-1894986606);
c = this.md5_ii(c,d,a,b,x[i + 10],15,-1051523);
b = this.md5_ii(b,c,d,a,x[i + 1],21,-2054922799);
a = this.md5_ii(a,b,c,d,x[i + 8],6,1873313359);
d = this.md5_ii(d,a,b,c,x[i + 15],10,-30611744);
c = this.md5_ii(c,d,a,b,x[i + 6],15,-1560198380);
b = this.md5_ii(b,c,d,a,x[i + 13],21,1309151649);
a = this.md5_ii(a,b,c,d,x[i + 4],6,-145523070);
d = this.md5_ii(d,a,b,c,x[i + 11],10,-1120210379);
c = this.md5_ii(c,d,a,b,x[i + 2],15,718787259);
b = this.md5_ii(b,c,d,a,x[i + 9],21,-343485551);
a = this.safe_add(a,olda);
b = this.safe_add(b,oldb);
c = this.safe_add(c,oldc);
d = this.safe_add(d,oldd);
}
return [a,b,c,d];
}
/*
* These privates implement the four basic operations the algorithm uses.
*/
public md5_cmn(q,a,b,x,s,t) {
return this.safe_add(this.bit_rol(this.safe_add(this.safe_add(a,q),this.safe_add(x,t)),s),b);
}
public md5_ff(a,b,c,d,x,s,t) {
return this.md5_cmn((b & c) | ((~b) & d),a,b,x,s,t);
}
public md5_gg(a,b,c,d,x,s,t) {
return this.md5_cmn((b & d) | (c & (~d)),a,b,x,s,t);
}
public md5_hh(a,b,c,d,x,s,t) {
return this.md5_cmn(b ^ c ^ d,a,b,x,s,t);
}
public md5_ii(a,b,c,d,x,s,t) {
return this.md5_cmn(c ^ (b | (~d)),a,b,x,s,t);
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
public safe_add(x,y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
public bit_rol(num,cnt) {
return (num << cnt) | (num >>> (32 - cnt));
}
}
import express = require('express');
import bodyParser = require('body-parser');
import sign = require('../middleware/sign');
import routers = require('../routers/router');
import compression = require('compression');
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('*',function (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');
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');
if(req.method === 'OPTIONS'){
res.statusCode = 200;
res.end();
}else{
next();
}
});
httpServer.use(express.static("./images") );
// httpServer.use(express.static(path.join(__dirname, "../../video")) );
httpServer.use(express.static("./video" ) );
httpServer.use(bodyParser.json({limit:"10kb"}));
httpServer.use(compression())
routers.setRouter(httpServer);
const root = path.join(__dirname, "../../public");
httpServer.use(express.static(root));
httpServer.use(fallback('index.html', { root }));
httpServer.listen(port);
console.log('server listen on port:'+port);
return httpServer;
}
}
import * as WebSocket from 'ws';
export class Socket {
static createServer(port, callback) {
const wss = new WebSocket.Server({
port,
threshold:1024, // 大小(以字节为单位),低于此大小的消息不压缩
maxPayload:9999,
});
callback(wss);
console.log("socketServer listen on port:"+port);
}
}
\ No newline at end of file
import * as asyncHandler from 'express-async-handler'
import * as aidataBiz from '../biz/aidata';
export function setRouter(httpServer){
httpServer.get('/aianswer', asyncHandler(aidataBiz.getAIAnswer));
}
\ No newline at end of file
//新的解析
const fs = require('fs');
const xlsx = require('node-xlsx');
const path = require('path');
const moment = require('moment');
/**
* getExcelDataBySheetName 将excel文件解析成数据块数据
* @param fileName 文件名称
* @param sheetName 表名称
* @returns thisBlockData 返回数据块集合 格式:blockList = [ {blockData:数据块(二维数组), blockTitle:"数据标题"}]
*/
export function getExcelDataBySheetName(fileName, sheetName) {
//todo 这里使用win10的打包方式 要写成根目录
let {sheetMap, sheetList} = getExcel(`./res/${fileName}` );
// let {sheetMap, sheetList} = getExcel( path.join(__dirname.substring(0,__dirname.indexOf("out")), "res", fileName ));
let thisBlockData = getBlockData(sheetMap[sheetName]);
return thisBlockData;
}
/**
* getBlockDataByData 将excel解析出来的二维数组解析成数据块模式
* @param dataList excel解出来的数据
* @returns thisBlockData 返回数据块集合 格式:blockList = [ {blockData:数据块(二维数组), blockTitle:"数据标题"}]
*/
export function getBlockDataByData(dataList) {
let thisBlockData = getBlockData(dataList);
return thisBlockData;
}
/**
* analysisExcelDataOfObject 将excel解出来的数据块按需求解析成可用数据
* @param dataList excel解出来的数据
* @param isJumpTitle 是否跳过解析表头
* @param keyInX key是否横向排列
* @returns 返回 {"数据标题":数据对象 }
*/
export function analysisExcelDataOfObject(dataList, isJumpTitle?, keyInX?) {
let result = {};
if (keyInX) {
let keyList = dataList[0];
let valueList = dataList[1];
let i = isJumpTitle ? 1:0;
for (; i < keyList.length; i++) {
let key = keyList[i];
let value = valueList[i] || null;
result[key] = value;
}
} else {
let y = isJumpTitle ? 1: 0;
for (; y < dataList.length; y++) {
let childList = dataList[y];
let key = childList[0];
let value = childList[1] || null;
result[key] = value;
}
}
return result;
}
export function analysisExcelDataTime(dataList, isJumpTitle?, keyInX?) {
const HOURS = new Date().getHours() + 1;//获取当前时间
let result = {};
if (keyInX) {
let keyList = dataList[0];
let valueList = dataList[1];
let i = isJumpTitle ? 1:0;
for (; i < keyList.length; i++) {
let key = keyList[i];
let value = valueList[i] || null;
result[key] = value;
}
} else {
let y = isJumpTitle ? 1: 0;
for (; y <= HOURS; y++) {
let childList = dataList[y];
let key = childList[0];
let value = childList[1] || null;
result[key] = value;
}
}
return result;
}
/**
* analysisExcelDataOfMoreObject 将excel解出来的数据块按需求解析成可用数据
* @param dataList excel解出来的数据
* @param isJumpTitle 是否跳过解析表头
* @param headerInx 第一个表头数据是否横向排列
* @returns 返回 {"第一个表头数据":{"表头数据":值...} }
*/
export function analysisExcelDataOfMoreObject(dataList, headerInx?) {
let result = {};
let titleList = dataList[0];
if (!headerInx) {
for (let y =1; y < dataList.length; y++) {
let dataTitle = dataList[y][0];
let thisData = {};
for (let x = 1; x < dataList[y].length; x++) {
let key = titleList[x];
thisData[key] = dataList[y][x];
}
result[dataTitle] = thisData;
}
} else {
let indexKeyMap = {};
titleList.forEach((thisTitle, index) => {
if (!index) return;
indexKeyMap[index] = thisTitle;
result[thisTitle] = {};
});
for (let y =1; y < dataList.length; y++) {
let thisKey = dataList[y][0];
for (let x = 1; x < dataList[y].length; x++) {
let thisTitle = indexKeyMap[x];
result[thisTitle][thisKey] = dataList[y][x];
}
}
}
return result;
}
/**
* analysisExcelDataOfList 将excel解出来的数据块按需求解析成可用数据
* @param dataList excel解出来的数据
* @param keyObject 对应关系 {dataList表头名称: 英文}
* @param headerInx 第一个表头数据是否横向排列
* @returns 返回 {"第一个表头数据":{"表头数据":值...} }
*/
export function analysisExcelDataOfList(dataList, keyObject, headerInx?) {
let result = [];
if (!headerInx) {//在y轴上排列
let titleList = dataList[0];
let indexKeyNameMap = {};
titleList.forEach( (info, index) => {
indexKeyNameMap[index + 1] = info;
});
for (let i = 1; i < dataList.length; i++) {
let onceInfo = {};
let subList = dataList[i];
subList.forEach( (info, index) => {
let key = indexKeyNameMap[index + 1];
let checkKey = keyObject[key];
onceInfo[checkKey] = info;
});
result.push(onceInfo);
}
} else {//在x轴上排列
let indexKeyNameMap = {};
dataList.forEach( (info, index) => {
indexKeyNameMap[index + 1] = info[0];
});
let dataMap = {};
for(let y = 0; y < dataList.length; y++) {
let xList = dataList[y];
for (let x = 1; x < xList.length; x++) {
if (!dataMap[x]) dataMap[x] = {};
let key = indexKeyNameMap[y + 1];
let checkKey = keyObject[key];
dataMap[x][checkKey] = xList[x];
}
}
result = Object.values(dataMap);
}
return result;
}
export function analysisExcelDataOfStringList(dataList) {
let result = [];
for (let i = 0; i < dataList.length; i++) {
if (!i) continue;
let subList = dataList[i];
result.push(subList[1]);
}
return result;
}
export function testmain() {
let {sheetMap, sheetList} = getExcel(`${__dirname.substring(0,__dirname.indexOf("out"))}res\\数据模板.xlsx`);
//根据配置表解析成对应数据
let resultMap = {};
for (let sheetName in sheetMap) {
let thisSheetBlockList = getBlockData(sheetMap[sheetName]);
resultMap[sheetName] = thisSheetBlockList;
}
console.log(resultMap);
return resultMap;
}
/**
* 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
import { getBizMsg, getSysMsg } 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);
}
}
export class SysError extends Error {
constructor(...msgs) {
let reqErrorMsg = '';
let logErrorMsg = '';
for (let i = 0; i <msgs.length; i++) {
if (!i) {
let msg= getSysMsg(msgs[i]);
reqErrorMsg = msg;
logErrorMsg = msg;
} else {
if (typeof msgs[i] == 'object') logErrorMsg += ` | ${JSON.stringify(msgs[i])} `;
else logErrorMsg += ` | ${msgs[i]} `;
}
}
logError(logErrorMsg);
super(reqErrorMsg);
}
}
\ No newline at end of file
const fs = require('fs');
const xlsx = require('node-xlsx');
const path = require('path');
//获取单个目录下的单个excel文件数据 只能有一个文件
export function getExcelDataByPath (dir) {
console.log(path.join(__dirname,dir))
let files = fs.readdirSync( path.join(__dirname,dir));
for (let i = 0; i < files.length; i++) {
if (files[i].indexOf('~') == 0 || files[i].indexOf('.') == 0) continue;
const workSheetsFromFile = xlsx.parse(dir+'/'+files[i]);
let sheetMap = {};
let sheetList = [];
for (let i = 0; i < workSheetsFromFile.length; i++) {
let sheetInfo = workSheetsFromFile[i];
sheetMap[sheetInfo.name] = sheetInfo.data;
sheetList.push(sheetInfo.data)
}
return {sheetMap, sheetList}
}
}
export function updateExcel(data, fileName) {
try{
fs.writeFileSync('output.xlsx', xlsx.build(data), "binary");
console.log(`写入 ${fileName} 成功`);
}catch(err) {
console.log(err);
}
}
//获取单个excel文件的数据
export function getExcelDataByFile(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}
}
export function arrayToObject(dataArr, keyNameArr) {
let obj = {};
for (let i = 0; i < dataArr.length; i++) {
obj[keyNameArr[i]] = dataArr[i];
}
return obj;
}
\ No newline at end of file
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}`);
}
/**
*
* @param keyList 要生成的键名称集合 例如: ["键1", "键2"]
* @param valLen 要生成的值的长度 例如 十位数就传1 百位数就传2 例如: 1 则会生成 键1或键2 的数据是1-10的随机数
* @param haveUnit 单位信息: 如果传 % 号则会把生成的随机数再求百分比 传false 则不生成单位 传 数组 例如:["家","个"] 则 键1的单位是 家, 键2的单位是个
* @param title 数据标题
* @param subTitle 数据副标题
* @param total 是否要求和
* @returns
*/
export function mock键值数据模板(keyList, valLen, haveUnit, title, subTitle, total) {
let data = {
"title": "",
"subTitle": "",
"total": 0,
"list": []
};
if (title) data.title = title;
if (subTitle) data.subTitle = subTitle || title;
if ( haveUnit && haveUnit == "%" ) {
let random = Math.ceil( Math.random() * 20 );
let avg = Math.ceil((100 - random) / keyList.length);
keyList.forEach((key, index) => {
let valut = index == 0 ? avg + random : avg;
let onceInfo:any = {
"key":key,
"value": valut,
unit:"%"
};
data.list.push(onceInfo);
});
} else {
let unitIndex = 0;
for (let i = 0; i < keyList.length; i++) {
let key = keyList[i];
let onceInfo:any = {
"key":key,
"value": getValueByLength(valLen)
};
if (haveUnit) {
if (typeof haveUnit == "string") onceInfo.unit = haveUnit;
else onceInfo.unit = haveUnit[unitIndex];
}
data.list.push(onceInfo);
unitIndex += 1;
}
if (total) {
data.list.forEach(keyValue=>{
data.total += keyValue.value;
})
}
}
return data;
}
//键值数据 值为字符串
export function mock键值数据字符串模板(title, subTitle, obj) {
let data = { title: "", subTitle: "", total: 0, list: [] };
if (title) data.title = title;
if (subTitle) data.subTitle = subTitle || title;
for (let key in obj) {
data.list.push({
key,
value:obj[key]
});
}
return data;
}
//列表数据 obj:{ "表格1":{title1:1, title2:2, title3:3... } }
export function mock列表模板( obj, number ) {
let tableNumber = Object.keys(obj).length;
if (tableNumber > 1) {
let data = [];
for (let key in obj) {
let onceTable:any = {title:key, total:number, subTitle:key, titleList:[], valueList:[] };
onceTable.titleList = Object.keys(obj[key]);
for (let i = 0; i < number; i++) {
onceTable.valueList.push(Object.values(obj[key]) );
}
data.push(onceTable);
}
return data;
} else {
let onceTable:any = {};
for (let key in obj) {
onceTable = {title:key, total:number, subTitle:key, titleList:[], valueList:[] };
onceTable.titleList = Object.keys(obj[key]);
for (let i = 0; i < number; i++) {
onceTable.valueList.push(Object.values(obj[key]) );
}
}
return onceTable;
}
}
export function mock图形数据模板(keyList, title, number?, subTitleList?) {
if (!number) number = 1;
if (number == 1) {
let data = {
"title": title ? title : "测试标题",
"yMaxValue": 100,
"yMinValue": 0,
"yStepValue": 10,
"unit": "个",
"data": {
"title": "测试数据标题",
"subTitle": "测试数据副标题",
"total": 1,
"list": []
}
}
for (let i = 0; i < keyList.length; i++) {
let key = keyList[i];
let onceInfo:any = {
key,
"value": Math.floor(Math.random()*99+1),
"unit": "个"
};
data.data.list.push(onceInfo)
}
data.data.list.forEach(keyValue=>{
data.data.total += keyValue.value;
});
return data;
} else {
let data = {
"title": title ? title : "测试标题",
"yMaxValue": 100,
"yMinValue": 0,
"yStepValue": 10,
"unit": "个",
"data": []
};
for (let y = 0; y < number; y++) {
let onceData = {
"title": subTitleList[y],
"subTitle": subTitleList[y],
"total": 1,
"list": []
}
for (let i = 0; i < keyList.length; i++) {
let key = keyList[i];
let onceInfo:any = {
key,
"value": Math.floor(Math.random()*99+1),
"unit": "个"
};
onceData.list.push(onceInfo)
}
onceData.list.forEach(keyValue=>{
onceData.total += keyValue.value;
});
data.data.push(onceData);
}
return data;
}
}
// 柱状图数据模板 模拟数据
export function mock柱状图数据模板(len, title?) {
let data = {
"title": title ? title : "测试标题",
"yMaxValue": 100,
"yMinValue": 0,
"yStepValue": 10,
"unit": "个",
"data": {
"title": "测试数据标题",
"subTitle": "测试数据副标题",
"total": 1,
"list": [
]
}
}
for (let i = 0; i < len; i++) {
let onceInfo:any = {
"key": 2010 + i,
"value": Math.floor(Math.random()*99+1),
"unit": "个"
};
data.data.list.push(onceInfo)
}
data.data.list.forEach(keyValue=>{
data.data.total += keyValue.value;
})
return data;
}
export function mock多柱柱状数据模板(len, 数组长度, title?) {
let data = {
"title": title ? title : "测试标题",
"yMaxValue": 100,
"yMinValue": 0,
"yStepValue": 10,
"unit": "个",
"data": []
}
for (let arrLen = 0; arrLen < 数组长度; arrLen++) {
let obj = {
"title": "测试数据标题",
"subTitle": "测试数据副标题",
"total": 0,
"list": [
]
}
for (let i = 0; i < len; i++) {
let onceInfo:any = {
"key": 2010 + i,
"value": Math.floor(Math.random()*99+1),
"unit": "个"
};
obj.list.push(onceInfo)
}
obj.list.forEach(keyValue=>{
obj.total += keyValue.value;
});
data.data.push(obj);
}
return data;
}
//获取特定长度的测试文字
export function getTestStrByLength(strLen, strType) {
let testStr = ``;
if (strType == 'c') {//中文
if (strLen < 5) {
testStr += `测试文本`.substring(0, strLen);
} else {
testStr += `测试`;
getPlaByLength((strLen - 4), () => {
testStr += '-';
});
testStr += `文本`
}
} else {//英文
testStr += `te`;
getPlaByLength((strLen - 4), () => {
testStr += '-';
});
testStr += `st`
}
return testStr;
}
function getValueByLength(length) {
let i = 1;
getPlaByLength(length, () => {
i= i * 10;
});
return Math.floor(Math.random() * i);
}
//获取特定长度的 占位符号
function getPlaByLength(num, callback) {
for (let i =0; i < num; i++) {
callback();
}
}
// 地图数据模板 模拟数据
export function mock地图数据模板(len) {
let data = {
"typeNameList": [
"type1","type2","type3"
],
"list": [
]
}
for (let i = 0; i < len; i++) {
data.list.push({
"x": Math.floor(Math.random()*500),
"y": Math.floor(Math.random()*500),
"typeName": "type"+(i%3+1),
"title": "测试标题",
"address": "测试地址",
"data": "测试数据<b>加粗</b></br>等等"
})
}
return data;
}
export function mock表数据模板(表头长度, 数据长度) {
let data = {
title:"",
titleList:[],
valueList:[]
}
for (let i = 0; i < 表头长度; i++) {
data.titleList.push("表头"+i);
}
for(let j = 0; j < 数据长度; j++) {
for (let i = 0; i < 表头长度; i++) {
data.titleList.push("数据"+i);
}
}
}
export function randomNumber(max, min=0) {
return Math.floor(Math.random()*(max-min))+min;
}
\ No newline at end of file
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 * as request from 'request';
import { BizError } from './bizError';
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)
}
});
})
}
export function limitEnteNameString(name, number?) {
number = number ? number : 13;
if (name.length > number) return `${name.substring(0,number - 2)}...`;
return name;
}
const moneyStrConfig = {
"万亿": 13,
"萬億": 13,
"千亿": 12,
"千億": 12,
"百亿": 11,
"佰億": 11,
"十亿": 10,
"拾億": 10,
"亿": 9,
"億": 9,
"千万": 8,
"千萬": 8,
"百万": 7,
"佰萬": 7,
"十万": 6,
"拾萬": 6,
"万": 5,
"萬": 5,
"千":4,
"百":3,
"十":2,
"美元":1,
"人名币":1,
"元":1,
};
// 汇率
let dollarRate = 6.4731;
//解析金额
export function analysisMoneyStr(mnyStr:string) {
let zeroNum = 1;
let moneyNumber = 0;
for (let key in moneyStrConfig) {
let checkNum = mnyStr.indexOf(key);
if (checkNum > -1) {
zeroNum = moneyStrConfig[key];
moneyNumber = parseFloat(mnyStr.slice(0, checkNum));
break;
}
}
if (mnyStr.replace(/[^0-9]/ig,"") == "") return 0;
if (zeroNum > 1) {
let count = 1;
for (let i = 1; i < zeroNum; i++) {
count = count * 10;
}
zeroNum = count;
}
let money = parseInt(`${zeroNum * moneyNumber}`);
if (mnyStr.indexOf('美元')) money = parseInt(`${money * dollarRate}`);
return money;
}
//缩略金额
export function simplifyMoney(mny:number, str:string) {
let num = moneyStrConfig[str];
let count = 1;
for (let i = 1; i < num; i++) {
count = count * 10;
}
return mny / count;
}
//分离 带单位的数据
function separateDataAndUint(str) {
if (!str) return {data:0, unit:""};
let data = str.replace(/[\u4E00-\u9FA5a-zA-Z]+/,"");
let unit = str.replace(/^(-)?\d+(\.\d+)?/, "");
return {data, unit};
}
//object key替换 带单位
export function objKeyReplace(object, keyInfo = {}, isString = true) {
if (isString) {
//校验字符
for (let key in object) {
if (!object[key]) object[key] = '';
}
} else {
//校验数字
for (let key in object) {
if (!object[key]) object[key] = '0';
}
}
let unitMap = {};
let dataMap = {};
for(let key in object) {
let newKey = keyInfo[key] || key;
let {data, unit} = separateDataAndUint(`${object[key]}` || "");
unitMap[newKey] = unit;
dataMap[newKey] = parseFloat(data);
}
return {dataMap, unitMap};
}
//返回特定key和value的obj
export function objKeyAndValue(dataMap, ...keyList) {
let result = {};
for (let key in dataMap) {
if ( keyList.indexOf(key) > -1 ) result[key] = dataMap[key];
}
return result;
}
//获取键值数据 percent =>为数字的时候 保留几位小数
export function getKeyValue(title, dataMap, unit, total, percent ) {
let data = {
title,
subTitle : title,
total : 0,
list : []
};
let count = 0;
for (let key in dataMap) {
let value = parseFloat(dataMap[key]);
count += value;
if (total) data.total += value;
}
for (let key in dataMap) {
let thisUnit = "";
if (unit) {
if (typeof unit == "string") thisUnit = unit;
else thisUnit = unit[key];
}
let value = parseFloat(dataMap[key]);
if (percent) {
thisUnit = '%';
value = getDecimalForN( value/count, percent);
}
let onceInfo:any = { key, value, unit:thisUnit };
data.list.push(onceInfo);
}
return data;
}
export function getKeyStringValue(title, dataMap) {
let data = {
title,
subTitle : title,
total : 0,
list : []
};
for (let key in dataMap) {
if (dataMap[key]) {
data.list.push({
key,
value:dataMap[key]
});
} else {
data.list.push({
key,
value:""
});
}
}
return data;
}
function getChartMin(num) {
if (num > 0) return 0;
return Math.floor(num);
}
export function getChartData(title, dataMap, unit, percent ) {
unit = unit || "";
let data = {
title, yMaxValue:0, yMinValue:new Date().valueOf(), yStepValue:0, unit : percent ? "%" : unit ,
data: { title: title , total : 0, list : [ ] }
}
let count = 0;
for (let key in dataMap) {
let value = parseFloat(dataMap[key] || 0);
data.yMaxValue = Math.max(data.yMaxValue, value);
data.yMinValue = Math.min(data.yMinValue, value);
count += 1;
data.data.total += value;
}
for (let key in dataMap) {
let value = parseFloat(dataMap[key]);
let thisUnit = unit;
if (percent) {
thisUnit = '%';
value = getDecimalForN( value/count, percent);
}
let onceInfo = { key, unit:thisUnit, value };
data.data.list.push(onceInfo)
}
data.yMinValue = getChartMin(data.yMinValue);
data.yStepValue = getChartStepNumber(Math.ceil((data.yMaxValue - data.yMinValue) / count));
let maxVal = Math.ceil(data.yMaxValue);
data.yMaxValue = maxVal+(data.yStepValue - (maxVal%data.yStepValue));
return data;
}
export function getListData( title, dataList, titleList, titleValueObj ) {
let data = { title, subTitle:title, total:dataList.length, titleList, valueList:[] };
dataList.forEach(info => {
let onceList = [];
titleList.forEach(titleName => {
onceList.push(info[ titleValueObj[titleName] ]);
});
data.valueList.push(onceList);
});
return data;
}
//多个y轴的条柱状图 dataMap => {"name":{"key1":1111,"key2":232, "key3":dsfs, ... }, ... }
export function getMoreYChartData(title, dataMap, percent, unit ) {
let data = { title, dataList: [] };
for (let subDataName in dataMap) {
let onceData = { title:subDataName, yMaxValue:0, yMinValue:new Date().valueOf(), yStepValue:0, unit:"", total : 0, list : [ ] };
let thisDataInfo = dataMap[subDataName];
let thisCount = 0;
for (let key in thisDataInfo) {
let value = parseFloat(thisDataInfo[key]);
onceData.yMaxValue = Math.max(onceData.yMaxValue, value);
onceData.yMinValue = Math.min(onceData.yMinValue, value);
onceData.total += value;
thisCount += 1;
}
onceData.yStepValue = getChartStepNumber(Math.ceil( (onceData.yMaxValue - onceData.yMinValue) / thisCount) );
let thisUnit;
if (percent) {
thisUnit = "%";
onceData.yMaxValue = 100;
onceData.yStepValue = Math.ceil( (100 - onceData.yMinValue) / onceData.total ) ;
}
else if (typeof unit == 'object') {
thisUnit = unit[subDataName] || "";
} else thisUnit = unit || "";
for (let key in thisDataInfo) {
let value;
if (percent) value = getDecimalForN( value/onceData.total, percent);
else value = parseFloat(thisDataInfo[key]);
let onceInfo = { key, unit:thisUnit, value };
onceData.list.push(onceInfo)
}
onceData.total = getDecimalForN( onceData.total, 1);
let maxVal = Math.ceil(onceData.yMaxValue);
onceData.yMinValue = getChartMin(onceData.yMinValue);
onceData.yMaxValue = maxVal+(onceData.yStepValue - (maxVal%onceData.yStepValue));
data.dataList.push(onceData);
}
return data;
}
//一个y轴的多个数据的柱状图
export function getSingleYAndMoreData(title, dataMap, percent, unit) {
let data = { title, dataList:[], yMaxValue:0, yMinValue:new Date().valueOf(), yStepValue:0, unit:"", total : 0 };
let maxCount = 0;
for (let subDataName in dataMap) {
let onceData = { title:subDataName, list:[] };
let thisDataCount = 0;
let analysisMap = objKeyReplace(dataMap[subDataName])
let thisData = analysisMap.dataMap;
let thisMax = 0;
for (let key in thisData) {
let value = parseFloat(dataMap[key]);
thisDataCount += value;
thisMax += 1;
}
maxCount = Math.max(maxCount, thisMax);
let thisUnit;
if (percent) thisUnit = "%";
else if (typeof unit == 'object') {
thisUnit = unit[subDataName] || "";
} else thisUnit = unit || "";
for (let key in thisData) {
let value;
if (percent) value = getDecimalForN( value/thisDataCount, percent);
else value = parseFloat(thisData[key]);
data.yMaxValue = Math.max(data.yMaxValue, value);
data.yMinValue = Math.min(data.yMinValue, value);
data.total += value;
let onceInfo = { key, unit:thisUnit, value };
onceData.list.push(onceInfo)
}
data.dataList.push(onceData);
}
data.yMinValue = getChartMin(data.yMinValue);
data.yMaxValue = Math.ceil(data.yMaxValue);
data.yStepValue = getChartStepNumber( Math.ceil((data.yMaxValue - data.yMinValue) / maxCount));
return data;
}
function getChartStepNumber(number) {
let lenth = `${number}`.length;
let count = 1;
for (let i = 1; i < lenth; i++) {
count = count * 10;
}
return number + ( count - (number % count) );
}
//字符模板
export function getStringMoreData(title, valueList) {
let result = { title, data:{} };
valueList.forEach( (info, index) => {
let key = index + 1
result.data[`${key}`] = info;
});
return result;
}
//撒点图 cutApartXAndY:[分割的x坐标,分割的y坐标]
export function getDropMoreData(dataList, title, subTitle, cutApartXAndY?) {
let data:any = {title, subTitle, dataList:[], xMax:0, xMin:new Date().valueOf(), yMax:0, yMin:new Date().valueOf() };
dataList.forEach(info => {
let {x, y} = info;
let thisDropXInfo = separateDataAndUint(`${x}`);
let thisDropX = parseFloat(thisDropXInfo.data);
let thisDropYInfo = separateDataAndUint(`${y}`);
let thisDropY = parseFloat(thisDropYInfo.data);
data.xMax = Math.max(thisDropX, data.xMax);
data.xMin = Math.min(thisDropX, data.xMin);
data.yMax = Math.max(thisDropY, data.yMax);
data.yMin = Math.min(thisDropY, data.yMin);
let value = [thisDropX, thisDropY];
let type = 1;
if (cutApartXAndY) {
let cutX = cutApartXAndY[0];
let cutY = cutApartXAndY[1];
if ( thisDropX < cutX && thisDropY > cutY) type = 1;
else if ( thisDropX > cutX && thisDropY > cutY ) type = 2;
else if ( thisDropX < cutX && thisDropY < cutY ) type = 3;
else type = 4;
}
data.dataList.push({value, name:info.name||"", type});
});
if (cutApartXAndY) {
data.cutApartX = cutApartXAndY[0];
data.cutApartY = cutApartXAndY[1];
}
let count = dataList.length;
let xAvg = Math.ceil((data.xMax - data.xMin) / count);
data.xMax = Math.floor( data.xMax + xAvg);
data.xMin = Math.floor( data.xMin - xAvg);
let yAvg = Math.ceil((data.yMax - data.yMin) / count);
data.yMax = Math.floor( data.yMax + yAvg);
data.yMin = Math.floor( data.yMin - yAvg);
return data;
}
//按需取保留小数长度 tenNumber保留小数位 1位就填1
export function getDecimalForN(number, n) {
let ten = 1;
for (let i = 0; i < n; i ++) {
ten = ten * 10;
}
return Math.ceil(number * ten) / ten
}
//生日获取时间段
export function getAgeByBirthday(birthday:string) {
let b = new Date(birthday).valueOf();
let d = new Date().valueOf();
let onceYear = 365 * 24 * 3600 * 1000;
let age = Math.floor( (d - b) / onceYear );
if (age >= 21 && age <= 30 ) return "21-30";
else if (age >= 31 && age <= 40 ) return "35-45";
else if (age >= 41 && age <= 50 ) return "46-55";
else if (age > 50) return "50岁以上";
else return '其他';
}
export function analysisAddOrRMData(str) {
str = `${str}`;
let checkStr = str.replace(/增加/, "");
let result = checkStr.replace(/减少/, "-");
return result;
}
export function changeDataName(str) {
let result = str.replace(/[()""“”/()-]/, "_");
for (let i =0; i < 10; i++) {
result = result.replace(/[()""“”/()-]/, "_");
}
return result;
}
//数据保留两位小数
export function getDataMapDecimalForN(dataMap, number?) {
let tenCount = number ? number : 2;
let result = {};
for (let key in dataMap) {
let value = dataMap[key];
if (typeof value == 'string') {
let {data } = separateDataAndUint(value);
value = parseFloat(data);
}
result[key] = getDecimalForN(value, tenCount);
}
return result;
}
\ 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