Commit 725aa859 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
img/1.jpg

160 KB

img/2.jpg

74.5 KB

img/3.jpg

154 KB

img/4.jpg

82.1 KB

img/5.jpeg

7.96 KB

This source diff could not be displayed because it is too large. You can view the blob instead.
#
# Wavefront material file
# Converted by Meshlab Group
#
newmtl material_0
Ka 0.200000 0.200000 0.200000
Kd 1.000000 1.000000 1.000000
Ks 1.000000 1.000000 1.000000
Tr 0.000000
illum 2
Ns 0.000000
map_Kd model.jpg
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
server_tokens off;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_set_header X-Forwarder-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:30001;
proxy_redirect http:// $scheme://;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
{
"name": "screen",
"version": "1.0.0",
"description": "",
"main": "main.ts",
"dependencies": {
"@alicloud/sms-sdk": "^1.1.6",
"@types/node": "^10.12.18",
"bson": "^6.1.0",
"compression": "^1.7.4",
"crypto-js": "^4.2.0",
"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.29.4",
"mongoose": "^7.6.0",
"mysql": "^2.18.1",
"mysql2": "^3.6.0",
"node-xlsx": "^0.16.1",
"nodemailer": "^6.1.1",
"qs": "^6.11.0",
"request": "^2.88.0",
"sequelize": "^6.35.1",
"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>30001</port>
<sign>xxx90909082fsdahfjosadjfpoiwausjorip2hjklrhn1ioud0u124rx0qwejfokasjfolksaujfoas</sign>
<appKey>1384855435661541376</appKey>
<appSecret>lRPbWFMckxc5tth6ZQnJtsBwCYIH0CXjcf0rvFgSOD8=</appSecret>
</config>
import moment = require("moment");
import { APIENUM } from "../config/interficeEnum";
import { getQueueData, getReqApiData } from "../data/queueData";
import { DATAQUEUEENUM, GRADEENUM } from "../config/enum";
import { changeEnumValue } from "../util/piecemeal";
export async function getTeacherInfo(teacherId:string) {
let base = {
name:"张三",
sex:"女",
title:"副教授",
age:"38岁",
discipline:"语文",
mainPeriod:"",
imgUrl:""
};
let introduction = "";
let reqTeacherSubjectData:any = await getReqApiData(APIENUM.获取教师列表, {teacherId});
if (Array.isArray(reqTeacherSubjectData.list) && reqTeacherSubjectData.list.length > 0) {
let {subjectNames } = reqTeacherSubjectData.list[0];
base.discipline = subjectNames;
}
let reqTeacherInfoData:any = await getReqApiData(APIENUM.教师基本信息, { teacherId});
if (Array.isArray(reqTeacherInfoData.list) && reqTeacherInfoData.list.length > 0) {
let {name, sexName, title, birthDate, remark } = reqTeacherInfoData.list[0];
base.name = name;
base.sex = sexName;
base.title = title;
introduction = remark || '';
if (birthDate) {
let birtList = birthDate.split("-");
if (birtList.length == 3) {
base.age = `${parseInt( moment(birtList).fromNow(true) )}岁`;
}
}
}
// let test:any = await getReqApiData(APIENUM.获取本校培训信息, { app_key:"", type:1});
return {base, introduction};
}
export async function getTeacherList(inGrade:number, discipline:string, sex:number, teacherName:string) {
let selectParam:any = {};
if (teacherName) selectParam.teacherName = teacherName;
if (sex==0 || sex == 1) selectParam.sex = sex;
if (inGrade) selectParam.grade = inGrade;
if (discipline) selectParam.subjectName = discipline;
let dataList = [];
let reqTeacherInfoData:any = await getReqApiData(APIENUM.获取教师列表, selectParam);
if (reqTeacherInfoData.list && Array.isArray(reqTeacherInfoData.list) && reqTeacherInfoData.list.length > 0) {
reqTeacherInfoData.list.forEach(info => {
let {teacherName, grade, genderName, teacherUserId, subjectNames } = info;
dataList.push({
teacherName:teacherName,
grade:changeEnumValue(GRADEENUM, parseInt(grade)),
sex:genderName,
discipline:subjectNames,
teacherId:teacherUserId
});
})
}
return {dataList};
}
\ No newline at end of file
import { DATAQUEUEENUM } from "../config/enum";
import { getQueueData } from "../data/queueData";
export async function getWholeInternal() {
let xueLiFenBu = getQueueData(DATAQUEUEENUM.教师对内_教师资源_学历分布) || [];
let jiaoLingFenBu = getQueueData(DATAQUEUEENUM.教师对内_教师资源_教龄分布) || [];
let nianLinFenBu = getQueueData(DATAQUEUEENUM.教师对内_教师资源_年龄分布) || [];
let zhiChengFenBu = getQueueData(DATAQUEUEENUM.教师对内_教师资源_职称分布) || [];
return {xueLiFenBu, jiaoLingFenBu, nianLinFenBu, zhiChengFenBu};
}
\ No newline at end of file
export enum DATAQUEUEENUM {
班级列表 =1,
年级列表,
九个一年级平均,
九个一学校平均,
九个一学校平均完成率,
九个一年级平均完成情况,
学生年级_九个一班级平均情况,
学生年级_年级社会实践活动类型统计,
学生年级_体质监测合格率,
学生年级_视力不良率,
学生年级_年级人数,
学生年级_过敏人数,
教师对内_教师资源_学历分布,
教师对内_教师资源_年龄分布,
教师对内_教师资源_教龄分布,
教师对内_教师资源_政治面貌分布,
教师对内_教师资源_职称分布,
九个一预警,
优秀学生
}
export enum GRADEENUM {
一年级 = 1,
二年级,
三年级,
四年级,
五年级,
六年级,
七年级,
八年级,
九年级,
高一,
高二,
高三
}
\ No newline at end of file
export enum ERRORENUM {
不存在表 = 1,
身份验证失败,
非法登录,
TOKEN获取失败,
TOKEN更新失败,
参数错误
}
/**
* 只用做code码定义
*/
export enum ERRORCODEENUM {
身份验证失败 = 401,
非法登录 = 402,
身份验证过期 = 403
}
let bizErrorMsgMap = {};
for (let key in ERRORENUM) {
bizErrorMsgMap[ERRORENUM[key]] = key;
}
export function getBizMsg(param) {
return bizErrorMsgMap[param];
}
\ No newline at end of file
export enum APIENUM {
获取班级列表信息 = 'queryClassList',
获取学生列表 = 'getStudentList',
获取学生个人特长 = 'getStuPersonality',
获取学生成绩信息 = 'getStuScore',
获取学生体质健康 = 'getTzjkOne',
获取学生获奖列表 = 'getStuAwards',
获取学生活动列表 = 'getStuActivity',
学生BMI趋势 = 'getBmiLine',
学生过敏情况 ='getAllergy',
获取年级平均九个一工程 = 'getCountStuTenComplete',
获取学生个人九个一工程 = 'getCountStuTenComplete',
修业课程_获取学生综合成绩 = 'getStuScore',
学生日常行为规范 = 'studentDimensionRadar',
获取学生综合成绩 = 'getStuScore',
获取学生综素质 = 'getStuQuality',
获取学生学习方法= 'getStuMethodStudy',
教师基本信息 = 'getTeacherInfoList',
获取学生特异体质 = 'getAtopy',
获取学生视力 = 'getVision',
获取学生各类活动统计 = 'getCountStuActivity',
获取教师列表 ='getGradeSubTeacherList',
获取本校培训信息 = 'api/train/schools',
获取教师统计 = 'getTeacherStatistics',
获取年级体质检测 = 'getCountTzjk',
获取年级视力不良率 = 'getGradeVisionDefect',
获取各年级学生数量 = 'getYearStuGradeCountEvent',
学生成绩预警 = 'getStuStudyScoreWarning',
学生体质预警 = 'getStuBMIWarning',
九个一预警 = 'queryEarlyWarning',
获取学生模型='queryStuModel'
}
\ No newline at end of file
const Sequelize = require('sequelize');
export const TablesConfig = [
{
tableNameCn:'用户表',
tableName:'users',
schema:{
userId: {
type:Sequelize.INTEGER(20), //表示属性的数据类型
allowNull:false, //表示当前列是否允许为空, false表示该列不能为空
primaryKey:true, //表示主键
unique:true //表示该列的值必须唯一
},
name: {type:Sequelize.STRING(255), allowNull:false}, //名称
loginId: {type:Sequelize.STRING(255), allowNull:false}, //账号
pwd: {type:Sequelize.STRING(255), allowNull:false}, //密码
roleId: {type:Sequelize.INTEGER(20), allowNull:false}, //角色id
exchangeTime: {type:Sequelize.INTEGER(20), allowNull:false}, //调休剩余
annualLeave: {type:Sequelize.INTEGER(20), allowNull:false}, //年假剩余
departmentId: {type:Sequelize.INTEGER(20), allowNull:false}, //部门id
token: {type:Sequelize.STRING(255)},
tokenDate: {type:Sequelize.DATE},
ed: {type:Sequelize.DATE}//入职时间
},
association: [
{type: "hasMany", check: "overtime", foreignKey:"userId"},//外键
{type: "hasMany", check: "askforleave", foreignKey:"userId"},//外键
{type: "hasMany", check: "workinglog", foreignKey:"userId"},//外键
]
},
{
tableNameCn:'角色表',
tableName:'role',
schema:{
roleId:{
type:Sequelize.INTEGER(20), //表示属性的数据类型
allowNull:false, //表示当前列是否允许为空, false表示该列不能为空
primaryKey:true, //表示主键
unique:true //表示该列的值必须唯一
},
roleName:{type:Sequelize.STRING(255), allowNull:false}, //登录账号
},
association: [
{type: "hasMany", check: "users", foreignKey:"roleId"},//外键
]
},
{
tableNameCn:'项目表',
tableName:'project',
schema:{
projectId:{
type:Sequelize.STRING(255), //表示属性的数据类型
allowNull:false, //表示当前列是否允许为空, false表示该列不能为空
primaryKey:true, //表示主键
unique:true //表示该列的值必须唯一
},
name:{type:Sequelize.STRING(255)}, //项目名称
contractId:{type:Sequelize.STRING(255)}, //合同编号
controller:{type:Sequelize.STRING(255)}, //项目经理
createTime:{type:Sequelize.DATE}, //创建时间
},
association: [
{type: "hasMany", check: "overtime", foreignKey:"projectId"},//外键
{type: "hasMany", check: "workinglog", foreignKey:"projectId"},//外键
]
},
{
tableNameCn:'部门表',
tableName:'department',
schema:{
departmentId:{
type:Sequelize.INTEGER(20), //表示属性的数据类型
allowNull:false, //表示当前列是否允许为空, false表示该列不能为空
primaryKey:true, //表示主键
unique:true //表示该列的值必须唯一
},
name:{type:Sequelize.STRING(255), allowNull:false}, //部门名称
},
association: [
{type: "hasMany", check: "users", foreignKey:"departmentId"},//外键
]
},
{
tableNameCn:'加班',
tableName:'overtime',
schema:{
id:{
type:Sequelize.STRING(244), //表示属性的数据类型
allowNull:false, //表示当前列是否允许为空, false表示该列不能为空
primaryKey:true, //表示主键
unique:true //表示该列的值必须唯一
},
projectId:{type:Sequelize.STRING(255)}, //
userId:{type:Sequelize.INTEGER(20)}, //
dateKey:{type:Sequelize.DATE}, //
time:{type:Sequelize.INTEGER(20), allowNull:false}, //
state:{type:Sequelize.INTEGER(20), allowNull:false}, //
approver:{type:Sequelize.INTEGER(20), allowNull:false}, //
workLog:{type:Sequelize.STRING(255), allowNull:true},
notPassing:{type:Sequelize.STRING(255), allowNull:true}//不通过理由
},
association: []
},
{
tableNameCn:'请假',
tableName:'askforleave',
schema:{
id:{
type:Sequelize.STRING(255), //表示属性的数据类型
allowNull:false, //表示当前列是否允许为空, false表示该列不能为空
primaryKey:true, //表示主键
unique:true //表示该列的值必须唯一
},
des:{type:Sequelize.STRING(255)}, //描述
startTime:{type:Sequelize.DATE}, //
endTime:{type:Sequelize.DATE}, //
userId:{type:Sequelize.INTEGER(20)}, //
approver:{type:Sequelize.INTEGER(20), allowNull:false}, //
time:{type:Sequelize.INTEGER(20), allowNull:false}, //
type:{type:Sequelize.INTEGER(20), allowNull:false}, //
day:{type:Sequelize.INTEGER(20), allowNull:false}, //
state:{type:Sequelize.INTEGER(20), allowNull:false}, //
notPassing:{type:Sequelize.STRING(255), allowNull:true},//不通过理由
dateKey:{type:Sequelize.DATE} //
},
association: [
]
},
{
tableNameCn:'工时表',
tableName:'workinglog',
schema:{
id:{
type:Sequelize.STRING(255), //表示属性的数据类型
allowNull:false, //表示当前列是否允许为空, false表示该列不能为空
primaryKey:true, //表示主键
unique:true //表示该列的值必须唯一
},
projectId:{type:Sequelize.STRING(255)}, //
userId:{type:Sequelize.INTEGER(20)}, //
time:{type:Sequelize.INTEGER(20), allowNull:false}, //
dateKey:{type:Sequelize.DATE}, //
isOutside:{type:Sequelize.INTEGER(20)}, //
workLog:{type:Sequelize.STRING(255)}, //描述
},
association: [
]
}
];
\ No newline at end of file
const path = require('path');
import * as fs from "fs";
import { BizError } from "../util/bizError";
import { analysisXml } from "../util/myXML";
import { ServerConfig } from "../config/systemClass";
export let systemConfig = new ServerConfig;
const ConfigName = "serverConfig.xml";
export async function initConfig() {
try {
let buff = fs.readFileSync(path.join(__dirname.substring(0,__dirname.indexOf("out")), ConfigName));
let configStr = buff.toString();
let configInfo:any = await analysisXml(configStr);
if (!configInfo || !configInfo.config) throw new BizError('xml中无配置');
else {
let {port, sign, appKey, appSecret } = configInfo.config;
systemConfig.port = parseInt(port[0]);
systemConfig.sign = sign[0];
systemConfig.appKey = appKey[0];
systemConfig.appSecret = appSecret[0];
}
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 class ServerConfig {
/**系统配置 */
port:number;
sign:string;
appSecret:string;
appKey:string;
}
\ No newline at end of file
import { selectStudentList, studentStatsCenter, studentStatsLeft, studentStatsRight } from "../biz/studentInfo";
import { getTeacherInfo } from "../biz/teacherInfo";
import { getToken, initStudentQueueData, initTeacherQueueData } from "./queueData";
export async function initData() {
//先初始化token
await getToken();
await initStudentQueueData();
await initTeacherQueueData();
//测试
// await selectStudentList(1, 1, '');
// await studentStatsRight('738c2ef8425b11ee98a202031519086a');
// await getTeacherInfo('0be2c9fab1bb11edb278020315b00957');
}
import { initConfig, systemConfig} from "./config/serverConfig";
import { initData } from "./data/dataInit";
import { httpServer } from "./net/http_server";
async function lanuch() {
/**初始化配置解析 */
await initConfig();
// await smsTask();
await initData();
/**创建http服务 */
httpServer.createServer(systemConfig.port);
console.log('This indicates that the server is started successfully.');
}
lanuch();
\ No newline at end of file
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 { TABLENAMEENUM } from "../config/enum";
import { ERRORENUM } from "../config/errorEnum";
import { BizError } from "../util/bizError";
/**
* 中间件 校验token
* @param req
* @param res
* @param next
* @returns
*/
export async function checkFuHuaQiToken(req, res, next) {
next();
}
export function watch(req, res, next) {
res.success = success.bind({res:res, req:req});
return next();
}
/**
* 中间件正确返回方法
* @param data
*/
function success(data) {
let resultPack;
if (data ) {
if ( data.success === undefined || data.success === true ) {
resultPack = {data, success:true, code:200};
}
else {
resultPack = data;
}
}else {
resultPack = {code:500, success:false, msg:'result is null'};
}
this.res.send(resultPack);
}
import express = require('express');
import bodyParser = require('body-parser');
import routers = require('../routers/router');
import compression = require('compression');
import { watch } from '../middleware/watch';
import { httpErrorHandler } from '../middleware/httpErrorHandler';
import * as path from "path";
import * as fallback from 'express-history-api-fallback';
export class httpServer {
static createServer(port:number) {
var httpServer = express();
httpServer.all('*', (req, res, next) => {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header('Access-Control-Allow-Headers', 'Content-Type,request-origin,userid,token');
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header('Access-Control-Allow-Credentials', true);
res.header("X-Powered-By", ' 3.2.1');
next();
});
httpServer.use(express.static("./img") );
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 studentRouter from './student';
import * as teacherRouter from './teacher';
import * as wholeRouter from './whole';
export function setRouter(httpServer) {
studentRouter.setRouter(httpServer);
teacherRouter.setRouter(httpServer);
wholeRouter.setRouter(httpServer);
}
import * as asyncHandler from 'express-async-handler'
import { eccReqParamater } from '../tools/eccParam';
import { studentStatsRight, studentStatsLeft, studentStatsCenter, getClassListByGrade, selectStudentList } from '../biz/studentInfo';
import { GRADEENUM } from '../config/enum';
import { getStudentStatsGradeCenter, getStudentStatsGradeLeft, getStudentStatsGradeRight, getStudentStatsSchoolCenter, getStudentStatsSchoolLeft, getStudentStatsSchoolRight } from '../biz/student';
export function setRouter(httpServer) {
httpServer.post('/data/student/select/gradelist', asyncHandler(gradeList));
httpServer.post('/data/student/select/classlist', asyncHandler(classList));
httpServer.post('/data/student/select/studentlist', asyncHandler(studentList));
httpServer.post('/data/student/portrait/left', asyncHandler(studentLeft));
httpServer.post('/data/student/portrait/center', asyncHandler(studentCenter));
httpServer.post('/data/student/portrait/right', asyncHandler(studentRight));
httpServer.post('/data/student/stats/school/left', asyncHandler(studentStatsSchoolLeft));
httpServer.post('/data/student/stats/school/center', asyncHandler(studentStatsSchoolCenter));
httpServer.post('/data/student/stats/school/right', asyncHandler(studentStatsSchoolRight));
/**年级 */
httpServer.post('/data/student/stats/grade/left', asyncHandler(studentStatsGradeLeft));
httpServer.post('/data/student/stats/grade/center', asyncHandler(studentStatsGradeCenter));
httpServer.post('/data/student/stats/grade/right', asyncHandler(studentStatsGradeRight));
}
/**搜索页 */
async function gradeList(req, res) {
let dataList = [];
for (let key in GRADEENUM) {
let anyKey:any = key;
if (isNaN(anyKey)) {
let keyStr = key;
dataList.push({key:keyStr, value:GRADEENUM[key]});
}
}
res.success({dataList});
}
async function classList(req, res) {
let reqConf = {grade: 'Number' };
let { grade } = eccReqParamater(reqConf, req.body);
let result = getClassListByGrade(grade);
res.success(result);
}
async function studentList(req, res) {
let reqConf = {grade: 'Number', classNum:'Number', name:'String' };
let { grade, classNum, name } = eccReqParamater(reqConf, req.body, ["name", "grade", "classNum"]);
let result = await selectStudentList(grade, classNum, name );
res.success(result);
}
/**个人页 */
async function studentLeft(req, res) {
let reqConf = {studentId: 'String' };
let { studentId } = eccReqParamater(reqConf, req.body, []);
let result = await studentStatsLeft(studentId);
res.success(result);
}
async function studentCenter(req, res) {
let reqConf = {studentId: 'String' };
let { studentId } = eccReqParamater(reqConf, req.body, []);
let result = await studentStatsCenter(studentId);
res.success(result);
}
async function studentRight(req, res) {
let reqConf = {studentId: 'String' };
let { studentId } = eccReqParamater(reqConf, req.body, []);
let result = await studentStatsRight(studentId);
res.success(result);
}
/**学校页 */
async function studentStatsSchoolLeft(req, res) {
let result = await getStudentStatsSchoolLeft();
res.success(result);
}
async function studentStatsSchoolRight(req, res) {
let result = await getStudentStatsSchoolRight();
res.success(result);
}
async function studentStatsSchoolCenter(req, res) {
let result = await getStudentStatsSchoolCenter();
res.success(result);
}
/**年级页 */
async function studentStatsGradeLeft(req, res) {
let reqConf = {gradeId: 'String' };
let { gradeId } = eccReqParamater(reqConf, req.body, []);
let result = await getStudentStatsGradeLeft(gradeId);
res.success(result);
}
async function studentStatsGradeRight(req, res) {
let reqConf = {gradeId: 'String' };
let { gradeId } = eccReqParamater(reqConf, req.body, []);
let result = await getStudentStatsGradeRight(gradeId);
res.success(result);
}
async function studentStatsGradeCenter(req, res) {
let reqConf = {gradeId: 'String' };
let { gradeId } = eccReqParamater(reqConf, req.body, []);
let result = await getStudentStatsGradeCenter(gradeId);
res.success(result);
}
import * as asyncHandler from 'express-async-handler';
import { eccReqParamater } from '../tools/eccParam';
import { getTeacherExternal, getTeacherInternal } from '../biz/teacher';
import { getTeacherInfo, getTeacherList } from '../biz/teacherInfo';
import { GRADEENUM } from '../config/enum';
export function setRouter(httpServer) {
httpServer.post('/data/teacher/select/gradelist', asyncHandler(gradeList));
httpServer.post('/data/teacher/select/disciplinelist', asyncHandler(disciplineList));
httpServer.post('/data/teacher/select/sexlist', asyncHandler(sexList));
httpServer.post('/data/teacher/select/teacherlist', asyncHandler(teacherList));
httpServer.post('/data/teacher/select/teacherinfo', asyncHandler(teacherInfo));
httpServer.post('/data/teacher/stats/internal', asyncHandler(teacherInternal));
httpServer.post('/data/teacher/stats/external', asyncHandler(teacherExternal));
}
/**教师查询页 */
async function gradeList(req, res) {
let dataList = [];
for (let key in GRADEENUM) {
let anyKey:any = key;
if (isNaN(anyKey)) {
let keyStr = key;
dataList.push({key:keyStr, value:GRADEENUM[key]});
}
}
res.success({dataList});
}
async function disciplineList(req, res) {
let dataList = [];
let disciplineTitleList = ["语文", "数学", "英语"];
disciplineTitleList.forEach((str, index) => {
dataList.push({key:str, value:`${index+1}`});
});
res.success({dataList});
}
async function sexList(req, res) {
let dataList = [];
let sexTitleList = [ "女", "男"];
sexTitleList.forEach((str, index) => {
dataList.push({key:str, value:index});
});
res.success({dataList});
}
async function teacherList(req, res) {
let reqConf = {grade: 'Number', discipline:'String', sex:'Number', teacherName:'String' };
let { grade, discipline, sex, teacherName } = eccReqParamater(reqConf, req.body, ["grade", "discipline", "sex", "teacherName"]);
let result = await getTeacherList(grade, discipline, sex, teacherName);
res.success(result);
}
/**教师个人 */
async function teacherInfo(req, res) {
let reqConf = {teacherId:'String' };
let { teacherId } = eccReqParamater(reqConf, req.body);
let result = await getTeacherInfo(teacherId);
res.success(result);
}
async function teacherInternal(req, res) {
let result = await getTeacherInternal();
res.success(result);
}
async function teacherExternal(req, res) {
let result = await getTeacherExternal();
res.success(result);
}
import { getWholeInternal } from "../biz/whole";
import * as asyncHandler from 'express-async-handler';
export function setRouter(httpServer) {
httpServer.post('/data/whole/internal', asyncHandler(gradeList));
}
/**教师查询页 */
async function gradeList(req, res) {
let result = await getWholeInternal();
res.success(result);
}
\ No newline at end of file
import { ERRORENUM } from "../config/errorEnum";
import { BizError } from "../util/bizError";
/**
* 根据conf配置校验请求参数
* @param conf 配置
* @param param 表单
* @param skipKeys []不必填的字段
*/
export function eccReqParamater(conf:object, param, skipKeys?) {
skipKeys = skipKeys || [];
let skipMap = {};
skipKeys.forEach(keyName => {
skipMap[keyName] = 1;
});
/**校验多余字段 */
for (let key in param) {
if (!conf[key]) throw new BizError(ERRORENUM.参数错误, `多余${key}字段`);
}
/**校验必填和缺失字段 */
for (let key in conf) {
let confType = conf[key];
let value = param[key];
let valueType = typeof value;
if ( value == null || value == undefined ) {
if (!skipMap[key]) throw new BizError(ERRORENUM.参数错误, `缺失${key}字段`);
} else {
let isError = false;
let errorStr = "";
switch(confType) {
case 'Number':
if ( confType.toLowerCase() != valueType ) isError = true;
else {
if ((""+param[key]).indexOf('.') > -1) {
param[key] = parseInt(`${param[key] *100}`)/100;
}
}
break;
case 'String':
case 'Boolean':
case 'Object':
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 '[String]':
if ( !Array.isArray(param[key]) ) isError = true;
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}`;
}
}
break;
}
errorStr = isError && errorStr == "" ? `${key}应该是${confType}型 而不是${valueType}`: errorStr;
if (isError) throw new BizError(ERRORENUM.参数错误, errorStr);
}
}
return param;
}
\ 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}`);
}
import moment = require("moment");
/**
* 生成工时填报的dateKey
* @returns
*/
export function generateDateKey(time?) {
if (time) {
return moment(time).format("YYYY-MM-DD")+ ' 18:00:00';
}
return moment().format("YYYY-MM-DD")+ ' 18:00:00'
}
/**
* 生成请假的id
* @param userId
* @returns
*/
export function generateAskForLeaveId(userId:number) {
return `al${userId}${new Date().valueOf()}${Math.ceil(Math.random() *100)}`
}
/**
* 解析xml
*/
var xml2js = require("xml2js");
/**
*
* @param str 需要解析的xml文本
* @returns 解析好的对象
*/
export function analysisXml(str) {
return new Promise( (resolve, reject) => {
xml2js.parseString(str, (err, result) => {
if (err) return reject(err);
return resolve(result);
});
});
}
\ No newline at end of file
/**
* 零碎的通用工具
*/
import moment = require("moment");
/**
* 匹配新旧对象变化
* 将newObj 与 oldObj 比对,将newObj中发生变化的key返回
* 使用前需要校验对象中的内容
* @param newObj 新对象
* @param oldObj 旧对象
* @returns [key] 发生变化的key
*/
export function checkChange(newObj, oldObj) {
let changeKeyList = [];
for (let newKey in newObj) {
if (`${newObj[newKey]}` != `${oldObj[newKey]}`) changeKeyList.push(newKey);
}
return changeKeyList;
}
/**
* 根据conf截取data中的数据
* @param conf
* @param data
* @returns
*/
export function extractData(conf, data, isAdmin) {
let result = {};
for (let key in conf) {
let confInfo = conf[key];
if (confInfo.changeDate) {
if (isAdmin) result[key] = data[key] ? moment(data[key]).format("YYYY-MM-DD") : '-';
else result[key] = data[key] || 0;
} else if (confInfo.isAdd && isAdmin) {
let addStr = "";
data[key].forEach(str => {
addStr += str;
});
result[key] = addStr;
}
else {
result[key] = data[key];
if (typeof result[key] == 'string' && !result[key]) result[key] = '';
}
}
return result;
}
/**
* 校验数据对象是否有空
* @param data
* @param sensitive 敏感校验 true时 0 和 ""会校验失败 false时 校验成功
* @returns true/false true = 有空值 false=无空值
*/
export function checkDataHaveNull(data:object, sensitive:boolean) {
if (Array.isArray(data)) return data.length == 0;
if (Object.keys(data).length == 0) return true;
let success = false;
for (let key in data) {
if (data[key] == null || data[key] == undefined) success = true;
if (sensitive) {
if (data[key] === 0 || data[key] === "" ) success = true;
}
}
return success;
}
/**
* 将枚举值转换成对应的枚举名(key)
* @param enumConf 目标枚举
* @param value 目标值
* @returns string 返回字符串 如果传入多个枚举值,就拼接字符串
*/
export function changeEnumValue(enumConf, value:any) {
if (!value) return '';
if (isNaN(value)) return '';
if ( typeof value == 'number' ) {
let str = enumConf[value];
return str
}
let str = "";
value.forEach((item, index) => {
let subStr = enumConf[item];
str += subStr;
if (index == value.length-1) str+="";
else str += ","
});
return str;
}
\ No newline at end of file
/**
* 请求工具
*/
import * 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, query, reqBody, 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: reqBody,
query:{}
}, function(error, response, body) {
if (!error && response.statusCode == 200) {
resolve(body);
}
else {
// reject(error)
}
});
})
}
export function postForm(url, query, 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
}, function(error, response, res) {
if (!error) {
resolve(res);
}
else {
reject(error)
}
});
})
}
{
"compilerOptions": {
"module": "commonjs",
"target": "es2017",
"sourceMap": true,
"rootDir":"./src",
"outDir":"./out"
},
"exclude": [
"node_modules"
]
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment