Commit 263ea354 by chenjinjing

no message

parent 5e1bae8d
......@@ -4,6 +4,8 @@
/test
/public
/logs
/files
/img
/video
*.logs
*.zip
......@@ -2,6 +2,7 @@
<port>13275</port>
<sign></sign>
<dbServer>http://127.0.0.1:13275</dbServer>
<imgUrl>http://127.0.0.1:13275</imgUrl>
<mysqldb>
<!-- 本地mysql配置 -->
<mysqlHost>192.168.0.71</mysqlHost>
......
......@@ -195,6 +195,7 @@ async function getHuoLanDe(infoid) {
let findCareer = await selectDataListByParam(TABLENAME.职业对照表, selectParam, []);
let testReport = {
infoid: findUserData.data.infoid,
name:findUserData.data.name,
card:findUserData.data.card,
phone:findUserData.data.phone,
......
/**
* 导入相关数据
*/
import moment from "moment";
import { TABLENAME } from "../config/dbEnum";
import { selectDataCountByParam } from "../data/findData";
import { CERTIFICATETYPE, COURSELEVEL, EDUCATION, JOBSTATUS, PRIORITYTYPE } from "../config/enum";
import { addData } from "../data/addData";
let xlsx = require('node-xlsx');
let path = require('path');
/**
* 获取单个excel文件数据
* @param filePath
* @returns
*/
function getExcel(filePath) {
let 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}
}
/**
* 导入岗位信息数据
* @returns
*/
export async function addJobData() {
try {
//检查是否已有数据
let dataCount = await selectDataCountByParam(TABLENAME.岗位信息表, {});
if (dataCount.data > 10) {
console.log("*** 岗位数据 无需初始化");
return;
}
// 读取Excel文件
let {sheetMap} = getExcel(path.join(__dirname.substring(0,__dirname.indexOf("out")), "res", '招聘岗位信息.xlsx' ));
// 获取工作表数据(根据Excel中的工作表名称)
let sheetName = '岗位发布';
let dataList = sheetMap[sheetName];
if (!dataList || dataList.length === 0) {
console.log(`工作表 ${sheetName} 无数据`);
return;
}
console.log(`读取到 ${dataList.length} 行数据`);
// 表头映射
let titleMap = {
"0": "gsmc", //公司名称
"1": "gwmc", //岗位名称
"2": "zprs", //招聘人数
"3": "fbsj", //发布时间
"4": "xzdy", //薪资待遇
"5": "gzsj", //工作时间
"6": "gzdd", //工作地点
"7": "gwzz", //岗位职责
"8": "lggw", //零工岗位
"9": "tyjryx", //退役军人优先
"10": "syyhgw", //生育友好岗
"11": "lgg", //临公岗
}
let titleIndexList = Object.keys(titleMap);
let currentTime = new Date().valueOf();
let addList = [];
// 提取表头行(第0行)
let headerRow = dataList[0] || [];
// 处理每一行数据(从第1行开始)
for (let rowIndex = 1; rowIndex < dataList.length; rowIndex++) {
let subList = dataList[rowIndex];
// 构建行数据对象(用于标签解析)
let rowData:any = {};
titleIndexList.forEach((colIndex, idx) => {
let key = titleMap[colIndex];
let value = subList[parseInt(colIndex)];
rowData[key] = value;
});
let time_at = moment(new Date()).format("YYYY-MM-DD HH:mm:ss");
//处理特殊身份
let priority_type = 0;
if (rowData.lggw) {
priority_type = PRIORITYTYPE.零工岗位;
} else if (rowData.tyjryx) {
priority_type = PRIORITYTYPE.退役军人优先;
} else if (rowData.syyhgw) {
priority_type = PRIORITYTYPE.生育友好岗;
} else if (rowData.lgg) {
priority_type = PRIORITYTYPE.临公岗;
}
let publish_date = moment(new Date(rowData.fbsj)).format("YYYY-MM-DD") + " 00:00:00";
// 创建企业数据对象
let addDataInfo:any = {
company_name: rowData.gsmc,
job_title: rowData.gwmc,
recruitment_count: rowData.zprs,
publish_date,
salary_range: rowData.xzdy,
working_hours: rowData.gzsj,
work_location: rowData.gzdd,
job_responsibilities: rowData.gwzz,
priority_type: priority_type,
job_status: JOBSTATUS.招聘中,
education_requirement: EDUCATION.,
experience_requirement: "无",
contact_info: "",
created_at: time_at, //创建时间
updated_at: time_at, //更新时间
is_deleted: false, //软删除标记
};
addList.push(addDataInfo);
}
console.log(`准备导入 ${addList.length} 条岗位数据`);
await addData(TABLENAME.岗位信息表, addList);
} catch (error) {
console.error("初始化岗位数据失败:", error);
throw error;
}
}
/**
* 导入培训信息数据
*/
export async function addTrainingCourseData() {
try {
//检查是否已有数据
let dataCount = await selectDataCountByParam(TABLENAME.培训课程表, {});
if (dataCount.data > 10) {
console.log("*** 培训数据 无需初始化");
return;
}
// 读取Excel文件
let {sheetMap} = getExcel(path.join(__dirname.substring(0,__dirname.indexOf("out")), "res", '凯达职业技能等级认定项目资料2026年.xlsx' ));
// 获取工作表数据(根据Excel中的工作表名称)
let sheetName = '职业技能认定';
let dataList = sheetMap[sheetName];
if (!dataList || dataList.length === 0) {
console.log(`工作表 ${sheetName} 无数据`);
return;
}
console.log(`读取到 ${dataList.length} 行数据`);
// 表头映射
let titleMap = {
"0": "xh", //序号
"1": "xm", //项目
"2": "jb", //级别
"3": "kcnr", //课程内容
"4": "xxkcpxf", //线下课程培训费
"5": "xxkcclf", //线下课程材料费
"6": "bfzsmc", //颁发证书名称
"7": "bfzsdj", //颁发证书等级
"8": "bz", //备注(报考条件)
"9": "pxzxdh", //培训咨询电话
}
let titleIndexList = Object.keys(titleMap);
let addList = [];
// 提取表头行(第0行)
let headerRow = dataList[0] || [];
// 处理每一行数据(从第1行开始)
for (let rowIndex = 1; rowIndex < dataList.length; rowIndex++) {
let subList = dataList[rowIndex];
// 构建行数据对象(用于标签解析)
let rowData:any = {};
titleIndexList.forEach((colIndex, idx) => {
let key = titleMap[colIndex];
let value = subList[parseInt(colIndex)];
rowData[key] = value;
});
let time_at = moment(new Date()).format("YYYY-MM-DD HH:mm:ss");
let course_level = COURSELEVEL[rowData.jb];
let certificate_type = CERTIFICATETYPE[rowData.bfzsdj];
// 创建企业数据对象
let addDataInfo:any = {
course_name: rowData.xm,
course_type: 1,
course_level,
course_content: rowData.kcnr,
offline_training_fee: rowData.xxkcpxf,
offline_material_fee: rowData.xxkcclf,
certificate_name: rowData.bfzsmc,
certificate_type,
apply_conditions: rowData.bz,
contact_phone: rowData.pxzxdh,
created_at: time_at,
updated_at: time_at,
is_deleted: false,
};
addList.push(addDataInfo);
}
console.log(`准备导入 ${addList.length} 条培训课程数据`);
await addData(TABLENAME.培训课程表, addList);
} catch (error) {
console.error("初始化培训课程数据失败:", error);
throw error;
}
}
......@@ -8,7 +8,7 @@ import { CHAPTER, HLDTYPE, HUOLANDE, QUESTION, QUESTIONTITLE, TESTTYPE } from ".
import { ERRORENUM } from "../config/errorEnum";
import { addData } from "../data/addData";
import { selectDataListByParam, selectDataToTableAssociation, selectDataToTableAssociationToPage, selectOneDataByParam } from "../data/findData";
import { changeEnumValue, eccEnumValue } from "../tools/eccEnum";
import { changeEnumNameByCode, changeEnumValue, eccEnumValue } from "../tools/eccEnum";
import { BizError } from "../util/bizError";
import { updateManyData } from "../data/updateData";
......@@ -22,7 +22,7 @@ import { updateManyData } from "../data/updateData";
* @param area
* @param email 非必填,没有传null
* @returns
*/
*/
export async function addUsers(testType, name, phone, card?) {
let findCardData = await selectOneDataByParam(TABLENAME.测试信息表, {test_type:testType, name, phone}, []);
// if (findCardData.data.core) throw new BizError(ERRORENUM.该身份证号码重复);
......@@ -239,7 +239,7 @@ export async function getFinalScore(infoid, isTest) {
for (let enumkey in HLDTYPE) {
let anyKey: any = enumkey;
let keyNum = 0;
let keyName = changeEnumValue(QUESTION, HLDTYPE[enumkey]);
let keyName = changeEnumNameByCode(QUESTION, HLDTYPE[enumkey]);
if (isNaN(anyKey)) {
if (countInfo[enumkey]) keyNum = countInfo[enumkey];
countData.push({key:keyName, value:keyNum});
......@@ -263,12 +263,13 @@ export async function getFinalScore(infoid, isTest) {
let findCareer = await selectDataListByParam(TABLENAME.职业对照表, selectParam, []);
let time = moment(new Date()).format("YYYY年MM月DD日HH时mm分");
let testReport = {
name:findUserData.data.name,
infoid: findUserData.data.infoid,
name: findUserData.data.name,
time,
report1:optionData,
report2:countData,
statistics:topThreeStr,
recommend:""
report1: optionData,
report2: countData,
statistics: topThreeStr,
recommend: ""
}
findCareer.data.forEach( info => {
......
......@@ -28,6 +28,11 @@ export enum TABLENAME {
演示版测试信息记录表 = 'inforecord_test',
职业对照表 = 'career_contrast',
超级管理员表 = 'sys_user',
政策文件表 = 'policy_info',
岗位信息表 = 'job_info',
培训课程表 = 'training_course',
求职信息表 = 'job_seekers',
AI推荐记录表 = "ai_recommendation_record",
}
......
......@@ -129,6 +129,94 @@ export enum HUOLANDE {
}
/**
* 岗位类型
*/
export enum PRIORITYTYPE {
普通岗位 = 0,
零工岗位,
退役军人优先,
生育友好岗,
临公岗
}
/**
* 岗位状态
*/
export enum JOBSTATUS {
招聘中 = 0,
已结束,
}
/**
* 课程类型
*/
export enum COURSETYPE {
就业服务站 = 0,
第三方
}
/**
* 课程级别
*/
export enum COURSELEVEL {
初级 = 1,
中级,
高级,
}
/**
* 颁发证书等级
*/
export enum CERTIFICATETYPE {
一级证书 = 1,
二级证书,
三级证书,
四级证书,
五级证书,
}
/**
* 学历
*/
export enum EDUCATION {
= 0,
小学 = 1,
初中,
高中,
中专,
大专,
本科,
硕士,
博士,
其他,
}
/**
* 性别
*/
export enum GENDER {
= 1,
,
}
/**
* 特殊身份
*/
export enum SPECIALIDENTITY {
= 0,
退役军人 = 1,
残疾人 = 2,
应届毕业生 = 3,
}
......@@ -18,7 +18,14 @@ export enum ERRORENUM {
INTERNAL_SERVER_ERROR,
文件不存在,
该身份证号码重复,
账号或密码错误
账号或密码错误,
数据不存在,
地址数据不完整,
请完善信息,
删除失败,
空文件失败,
文件上传失败,
只能上传docdocxexcelpngjpg图片
}
/**
......
......@@ -14,11 +14,11 @@ export async function initConfig() {
if (!configInfo || !configInfo.config) throw new BizError('xml中无配置');
else {
let {port, sign, dbServer, mysqldb } = configInfo.config;
let {port, sign, dbServer, imgUrl, mysqldb } = configInfo.config;
systemConfig.port = parseInt(port[0]);
systemConfig.sign = sign[0]
systemConfig.dbPath = dbServer[0]
systemConfig.sign = sign[0];
systemConfig.dbPath = dbServer[0];
systemConfig.imgUrl = imgUrl[0];
if (mysqldb) {
let dbConfigInfo = mysqldb[0];
......
/**
* 拆分返回结果配置
* 使用场景:逻辑层中需要返回数据给客户端的地方
* 限制:使用端不同不能共用一份配置
*/
/**政策文件列表 */
export const policyListConfig = {
id:{key:"标识"},
file_name:{key:"政策文件名称"},
subsidy_scope:{key:"补贴范围对象"},
full_text:{key:"政策内容"},
policy_file_url:{key:"政策文件地址"},
policy_file_img:{key:"政策文件图片文件夹"},
policy_imgname:{key:"政策文件图片地址"},
policy_start_time:{key:"政策开始时间", changeDate:true},
policy_end_time:{key:"政策结束时间", changeDate:true},
}
/**岗位信息列表 */
export const jobListConfig = {
id:{key:"标识"},
company_name:{key:"公司名称"},
job_title:{key:"岗位名称"},
recruitment_count:{key:"招聘人数"},
publish_date:{key:"发布时间", changeDate:true},
salary_range:{key:"薪资待遇"},
working_hours:{key:"工作时间"},
work_location:{key:"工作地点"},
job_responsibilities:{key:"岗位职责"},
priority_type:{key:"岗位类型"},
job_status:{key:"岗位状态"},
education_requirement:{key:"学历要求"},
experience_requirement:{key:"工作经验要求"},
contact_info:{key:"联系方式"},
}
/**培训课程列表 */
export const trainingCourseListConfig = {
id:{key:"标识"},
course_name:{key:"课程名称"},
course_type:{key:"课程类型"},
course_level:{key:"课程级别"},
course_content:{key:"课程内容"},
offline_training_fee:{key:"线下课程培训费(元)"},
offline_material_fee:{key:"线下课程材料费(元)"},
certificate_name:{key:"颁发证书名称"},
certificate_type:{key:"颁发证书等级"},
apply_conditions:{key:"备注(报考条件)"},
contact_phone:{key:"培训咨询电话"},
}
/**求职信息列表 */
export const jobSeekersListConfig = {
id:{key:"标识"},
/** 基本信息 */
name:{key:"姓名"},
gender:{key:"性别"},
age:{key:"年龄"},
phone:{key:"手机号码"},
id_card:{key:"身份证号码"},
address:{key:"居住地址"},
education:{key:"学历"},
household:{key:"户籍"},
/**求职意向 */
applied_position:{key:"应聘岗位"},
expected_salary_min:{key:"期望最低薪资(元/月)"},
expected_salary_max:{key:"期望最高薪资(元/月)"},
expected_area:{key:"期望工作区域"},
/** 特殊身份 */
special_identity:{key:"特殊身份"},
}
......@@ -8,7 +8,7 @@ export class ServerConfig {
port:number;
sign:string;
dbPath:string;
imgUrl:string;
mysqldb:{
host:string,
port:number,
......
import { addJobData, addTrainingCourseData } from "./biz/dataInit";
import { initConfig, systemConfig} from "./config/serverConfig";
import * as mysqlDB from "./db/mysqlInit";
import { initMysqlModel } from "./model/sqlModelBind";
import { httpServer } from "./net/http_server";
async function lanuch() {
/**初始化配置解析 */
await initConfig();
......@@ -20,8 +19,21 @@ async function lanuch() {
// await smsTask();
console.log('This indicates that the server is started successfully.');
console.log("开始岗位信息同步");
await addJobData();
console.log("岗位信息同步成功");
console.log("开始培训课程同步");
await addTrainingCourseData();
console.log("培训课程信息同步成功");
}
lanuch();
lanuch();
\ No newline at end of file
import { ERRORENUM } from "../config/errorEnum";
import { BizError } from "../util/bizError";
var formidable = require("formidable");
const path = require('path');
const fs = require('fs');
export async function parseFormParam(req, res, next) {
// 临时上传目录
const tempUploadDir = path.join(__dirname.substring(0, __dirname.indexOf("out")), 'files', 'temp');
// 确保临时目录存在
if (!fs.existsSync(tempUploadDir)) {
fs.mkdirSync(tempUploadDir, { recursive: true });
}
var form = new formidable.IncomingForm({
uploadDir: tempUploadDir,
maxFileSize: 50 * 1024 * 1024, // 增大到 50MB,支持多文件
keepExtensions: true,
multiples: true // 启用多文件支持
});
form.parse(req, (err, fields, files) => {
if (err) {
return next(err);
} else if (!files || Object.keys(files).length === 0) {
return next(new BizError(ERRORENUM.空文件失败));
}
else {
req.fields = fields;
req.body = fields;
req.files = {};
// 处理多文件上传:files.formData 可能是数组
if (files.formData) {
req.files.formData = files.formData;
} else if (files.file) {
req.files.formData = files.file;
} else if (files.files) {
req.files.formData = files.files;
}
// 检查是否有文件
let hasFile = false;
let fileList = Array.isArray(req.files.formData) ? req.files.formData : [req.files.formData];
for (let file of fileList) {
if (file && file.name) {
hasFile = true;
break;
}
}
if (!hasFile) {
return next(new BizError(ERRORENUM.文件上传失败));
}
// 获取 targetDir
req.targetDir = fields.targetDir || req.query?.targetDir;
console.log("目标目录:", req.targetDir);
console.log("文件数量:", fileList.length);
// 只验证第一个文件的类型(或者你可以遍历验证)
let firstFile = fileList[0];
if (firstFile && firstFile.name) {
const fileExtension = firstFile.name.split('.').pop().toLowerCase();
if (firstFile.type == 'image/png') {
req.fileType = '.png';
} else if (firstFile.type == 'image/jpg' || firstFile.type == 'image/jpeg') {
req.fileType = '.jpg';
} else if (firstFile.type == "application/pdf") {
req.fileType = '.pdf';
} else if (firstFile.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document" || fileExtension == 'docx') {
req.fileType = '.docx';
} else if (firstFile.type == "application/msword") {
req.fileType = '.doc';
} else if (firstFile.type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {
req.fileType = '.xlsx';
} else if (firstFile.type == "application/vnd.ms-excel") {
req.fileType = '.xls';
} else {
return next(new BizError(ERRORENUM.只能上传docdocxexcelpngjpg图片));
}
}
return next();
}
});
}
/**
* 文件管理 路由
*/
import asyncHandler = require('express-async-handler');
import { parseFormParam } from '../middleware/fromParam';
import moment from 'moment';
const fs = require('fs');
const path = require('path');
export function setRouter(httpServer) {
httpServer.post('/aiposition/files/up', parseFormParam, asyncHandler(upFiles));
// 新增:支持指定目录的上传接口(单文件)
httpServer.post('/aiposition/files/upwithdir', parseFormParam, asyncHandler(upFilesWithDir));
// 新增:支持多文件上传到指定目录
httpServer.post('/aiposition/files/upwithdir/multiple', parseFormParam, asyncHandler(upMultipleFilesWithDir));
}
/**
* 上传文件(原有逻辑,保持兼容)
*/
async function upFiles(req, res) {
let fileType = req.fileType;
let { name } = req.files.formData;
let docPath = req.files.formData.path;
let fileDir = path.resolve(docPath, '..');
let fileName = `${getFilesId(fileType, name)}${fileType}`;
let newPath = path.join(fileDir, fileName);
fs.renameSync(docPath, newPath);
console.log("上传文件", fileName, "成功");
res.success({ isSuccess: true, url: `/${fileName}`, fileName });
}
/**
* 单文件上传到指定目录
*/
async function upFilesWithDir(req, res) {
let fileType = req.fileType;
let { name } = req.files.formData;
let docPath = req.files.formData.path;
let targetDir = req.body.targetDir || req.query.targetDir;
// 获取项目根目录下的 files 目录路径
const baseDir = path.join(__dirname.substring(0, __dirname.indexOf("out")), 'files');
// 构建完整的目标目录路径
let fileDir = targetDir ? path.join(baseDir, targetDir) : baseDir;
// 确保目录存在
if (!fs.existsSync(fileDir)) {
fs.mkdirSync(fileDir, { recursive: true });
}
// 保留原始文件名
let fileName = name;
let newPath = path.join(fileDir, fileName);
// 如果文件名已存在,添加时间戳避免覆盖
if (fs.existsSync(newPath)) {
let ext = path.extname(fileName);
let baseName = path.basename(fileName, ext);
fileName = `${baseName}_${moment().format("YYYYMMDD_HHmmSS")}${ext}`;
newPath = path.join(fileDir, fileName);
}
fs.renameSync(docPath, newPath);
console.log("上传文件到目录", targetDir, ",文件名", fileName, "成功");
// 返回相对路径(相对于 files 目录)
let relativeUrl = targetDir ? `/${targetDir}/${fileName}` : `/${fileName}`;
res.success({ isSuccess: true, url: relativeUrl, fileName, targetDir });
}
/**
* 多文件上传到指定目录
* 支持同时上传多个文件到同一个目标目录
*/
async function upMultipleFilesWithDir(req, res) {
const baseDir = path.join(__dirname.substring(0, __dirname.indexOf("out")), 'files');
let targetDir = req.body.targetDir || req.query.targetDir;
// 获取所有上传的文件(支持 formData 数组或单个文件)
let uploadedFiles = [];
let filesList = [];
// formidable 中多个同名文件会被处理为数组
if (req.files.formData) {
filesList = Array.isArray(req.files.formData) ? req.files.formData : [req.files.formData];
} else if (req.files.files) {
filesList = Array.isArray(req.files.files) ? req.files.files : [req.files.files];
}
if (filesList.length === 0) {
return res.error({ isSuccess: false, message: "没有找到上传的文件" });
}
// 构建完整的目标目录路径
let fileDir = targetDir ? path.join(baseDir, targetDir) : path.join(baseDir, 'uploads');
// 确保目录存在
if (!fs.existsSync(fileDir)) {
fs.mkdirSync(fileDir, { recursive: true });
}
// 处理每个文件
for (let file of filesList) {
let docPath = file.path;
let originalName = file.name;
let fileName = originalName;
let newPath = path.join(fileDir, fileName);
// 如果文件名已存在,添加时间戳避免覆盖
if (fs.existsSync(newPath)) {
let ext = path.extname(fileName);
let baseName = path.basename(fileName, ext);
fileName = `${baseName}_${moment().format("YYYYMMDD_HHmmSS")}${ext}`;
newPath = path.join(fileDir, fileName);
}
fs.renameSync(docPath, newPath);
console.log("上传文件到目录", targetDir, ",文件名", fileName, "成功");
// 记录上传成功的文件信息
uploadedFiles.push({
originalName: originalName,
fileName: fileName,
url: targetDir ? `/${targetDir}/${fileName}` : `/${fileName}`,
size: file.size
});
}
res.success({
isSuccess: true,
targetDir: targetDir,
fileCount: uploadedFiles.length,
files: uploadedFiles
});
}
export function getFilesId(type: string, fileName: string) {
return `${fileName.replace(type, "")}${moment().format("YYYYMMDD_HHmmSS")}`;
}
/**
* 公共资源路由
*/
import asyncHandler = require('express-async-handler');
import * as enumConfig from '../config/enum';
import { eccReqParamater } from '../util/verificationParam';
const config = {
"/public/prioritytype":enumConfig.PRIORITYTYPE, //岗位类型
"/public/jobstatus":enumConfig.JOBSTATUS, //岗位状态
"/public/coursetype":enumConfig.COURSETYPE, //课程类型
"/public/courselevel":enumConfig.COURSELEVEL, //课程级别
"/public/education":enumConfig.EDUCATION, //学历要求
"/public/certificatetype":enumConfig.CERTIFICATETYPE, //颁发证书类型
"/public/specialidentity":enumConfig.SPECIALIDENTITY, //特殊身份
}
export function setRouter(httpServer) {
for (let modelKey in config) {
httpServer.post(modelKey, asyncHandler(getEnum(config[modelKey])));
}
}
/**
* 获取枚举
* @param enumCof
* @returns
*/
function getEnum(enumCof) {
return async function (req, res) {
let dataList = [];
for (let key in enumCof) {
let anyKey:any = key;
if (isNaN(anyKey)) {
dataList.push({key, value:enumCof[key]});
}
}
res.success({dataList});
}
}
......@@ -4,8 +4,14 @@
import * as huolandeRouter from './huolande';
import * as adminRouter from './admin';
import * as publicRouter from './public';
import * as aiPositionRouter from './aiPosition';
import * as filesRouter from './files';
export function setRouter(httpServer){
huolandeRouter.setRouter(httpServer);
adminRouter.setRouter(httpServer);
publicRouter.setRouter(httpServer);
aiPositionRouter.setRouter(httpServer);
filesRouter.setRouter(httpServer);
}
......@@ -27,41 +27,107 @@ export function eccEnumValue(name:string, key:string, enumConf, value:any) {
/**
* 将枚举值转换成对应的枚举名(key)
* @param enumConf 目标枚举
* @param value 目标值
* @param value 目标值
* @returns string 返回字符串 如果传入多个枚举值,就拼接字符串
*/
export function changeEnumValue(enumConf, value:any) {
if (!value) return '';
if ( typeof value == 'number' ) {
let str = enumConf[value];
/**特化处理 */
if(/_dou/.test(str)) str = str.replace(/_dou/gm, ",");
if(/_zyh/.test(str)) str = str.replace(/_zyh/gm, "“");
if(/_yyh/.test(str)) str = str.replace(/_yyh/gm, "”");
if(/_dun/.test(str)) str = str.replace(/_dun/gm, "、");
if(/_ju/.test(str)) str = str.replace(/_ju/gm, "。");
/** 特化处理 中文引号在枚举中不适用*/
if (str == "_投资__孵化_类型") {
str = str.replace("__","+");
str = str.replace("_","“");
str = str.replace("_","”");
}
if (str == "经营成本过高_场地成本或人员成本_" || str == "办公空间拓展_无合适办公空间_") {
str = str.replace("_","(");
str = str.replace("_",")");
}
if (str == "迁出孵化器_仍在张江" || str == "迁出张江_仍在浦东" || str == "迁出浦东_仍在上海") {
str = str.replace("_",",");
}
if (str == "科技金融_风险投资_" || str == "科技金融_其他_" || str == "技术专家_法律专家_") {
str = str.replace("_","(");
str = str.replace("_",")");
}
return str
} else if (typeof value == 'string') {
try {//兼容数据库 '[1,2,3]'
value = JSON.parse(value);
}catch(err) {
return enumConf[parseInt(value)];
}
}
let str = "";
value.forEach((item, index) => {
let subStr = enumConf[item];
/**特化处理 */
if(/_dou/.test(subStr)) subStr = subStr.replace(/_dou/gm, ",");
if(/_zyh/.test(subStr)) subStr = subStr.replace(/_zyh/gm, "“");
if(/_yyh/.test(subStr)) subStr = subStr.replace(/_yyh/gm, "”");
if(/_dun/.test(subStr)) subStr = subStr.replace(/_dun/gm, "、");
if(/_ju/.test(subStr)) subStr = subStr.replace(/_ju/gm, "。");
/** 特化处理 中文引号在枚举中不适用*/
if (subStr == "_投资__孵化_类型") {
subStr = subStr.replace("__","+");
subStr = subStr.replace("_","“");
subStr = subStr.replace("_","”");
}
if (subStr == "经营成本过高_场地成本或人员成本_" || subStr == "办公空间拓展_无合适办公空间_") {
subStr = subStr.replace("_","(");
subStr = subStr.replace("_",")");
}
if (subStr == "迁出孵化器_仍在张江" || subStr == "迁出张江_仍在浦东" || subStr == "迁出浦东_仍在上海") {
subStr = subStr.replace("_",",");
}
if (subStr == "科技金融_风险投资_" || subStr == "科技金融_其他_" || subStr == "技术专家_法律专家_") {
subStr = subStr.replace("_","(");
subStr = subStr.replace("_",")");
}
str += subStr;
if (index == value.length-1) str+="";
else str += ","
});
return str;
}
\ No newline at end of file
}
export function changeEnumManyValue(enumConf, value:any) {
let list = [];
value.forEach((item, index) => {
let subStr = enumConf[item];
/** 特化处理 中文引号在枚举中不适用*/
if (subStr == "_投资__孵化_类型") {
subStr = subStr.replace("__","+");
subStr = subStr.replace("_","“");
subStr = subStr.replace("_","”");
}
if (subStr == "经营成本过高_场地成本或人员成本_" || subStr == "办公空间拓展_无合适办公空间_") {
subStr = subStr.replace("_","(");
subStr = subStr.replace("_",")");
}
if (subStr == "迁出孵化器_仍在张江" || subStr == "迁出张江_仍在浦东" || subStr == "迁出浦东_仍在上海") {
subStr = subStr.replace("_",",");
}
if (subStr == "科技金融_风险投资_" || subStr == "科技金融_其他_" || subStr == "技术专家_法律专家_") {
subStr = subStr.replace("_","(");
subStr = subStr.replace("_",")");
}
list.push(subStr);
});
return list;
}
/**
* 根据枚举值反向获取名称
* @param enumConf
* @param code
* @returns
*/
export function changeEnumNameByCode(enumConf, code: string) {
for (const [name, value] of Object.entries(enumConf)) {
if (value === code) {
return name;
}
}
return '未知行业';
}
......@@ -2,8 +2,21 @@ import moment = require("moment");
import { ERRORENUM } from "../config/errorEnum";
import { BizError } from "../util/bizError";
import { FILETYPE } from "../config/enum";
import { systemConfig } from "../config/serverConfig";
const md5 = require("md5");
let fs = require("fs");
const path = require('path');
/**
* 获取随机id
* @param uscc
*/
export function randomId(tableName:string) {
let randomStr = `${new Date().valueOf()}_${Math.ceil(Math.random()*100000)}`;
return `${tableName}_${md5(randomStr)}`;
}
export function getUserToken(loginId:string) {
return md5(`${loginId}_${Math.ceil(Math.random()*1000)}${new Date().valueOf()}`);
......@@ -49,3 +62,60 @@ export function getFileType(fileName) {
});
return fileType;
}
/**
* 获取政策文件图片地址
* @param dirPath 政策文件图片目录路径(如:/政策文件图片/上海市毕业生就业补贴政策)
* @param imgNames 图片文件名数组
*/
export function getVerticalPolicy(dirPath, imgNames = []) {
// 如果目录路径为空,返回空数组
if (!dirPath || typeof dirPath !== 'string') {
return [];
}
// 如果没有图片文件名数组,返回空数组
if (!Array.isArray(imgNames) || imgNames.length === 0) {
return [];
}
try {
let fileList = [];
for (let i = 0; i < imgNames.length; i++) {
const fileName = imgNames[i];
// 构建完整的文件系统路径进行验证
const baseDir = 'img'; // 基础目录
const fullPath = path.join(baseDir, dirPath, fileName);
// 检查文件是否存在(可选,根据需求决定是否要验证)
// if (fs.existsSync(fullPath)) {
// 构建图片访问路径
// 例如:/政策文件图片/上海市毕业生就业补贴政策/1.png
const imagePath = `${systemConfig.imgUrl}${dirPath}/${fileName}`;
fileList.push(imagePath);
// } else {
// console.warn(`政策文件图片不存在: ${fullPath}`);
// }
}
return fileList;
} catch (error) {
console.error('构建政策文件图片路径出错:', error);
return [];
}
}
/**
* 校验参数工具
*
*/
import { ERRORENUM } from "../config/errorEnum";
import { BizError } from "./bizError";
/**
* 通过config校验表单参数param
* 包括类型 String, Number, Boolean, [Number], [Object]
* 参数是必填
* 方法会校验表单中存在的多余字段
* @param name 被调用的方法名
* @param config 校验配置
* @param param 需要校验的参数
* @returns true 无需关注返回
*/
export function eccFormParam(name:string, keyTypeConf:object, param:object) {
/**校验多余字段 */
for (let key in param) {
if (!keyTypeConf[key]) throw new BizError(ERRORENUM.参数错误, name, `多余${key}字段`);
}
/**校验已填参数 */
for (let key in keyTypeConf ) {
let {type, notMustHave} = keyTypeConf[key];
let isError = false; //校验是否异常
let errorStr = "";//异常说明
let value = param[key];
let valueType = typeof value;
if ( value == null || value == undefined ) {
if (!notMustHave) throw new BizError(ERRORENUM.参数错误, name, `缺失${key}字段`);
} else {
switch(type) {
case 'Number':
if ( type.toLowerCase() != valueType ) {
isError = true;
} else {
if ((""+param[key]).indexOf('.') > -1) {
param[key] = parseInt(`${param[key] *1000}`)/1000;
}
}
break;
case 'String':
case 'Boolean':
if ( type.toLowerCase() != valueType ) isError = true;
break;
case '[Number]':
if ( !Array.isArray(param[key]) ) isError = true;
for (let i =0; i < param[key].length; i++) {
let item = param[key][i];
if ( typeof item != 'number' ) {
isError = true;
errorStr = `${key}应是number型数组其中下标${i}${typeof item}`;
}
}
break;
case '[Object]':
if ( !Array.isArray(param[key]) ) isError = true;
for (let i =0; i < param[key].length; i++) {
let item = param[key][i];
if ( typeof item != 'object' ) {
isError = true;
errorStr = `${key}应是object型数组其中下标${i}${typeof item}`;
}
}
break;
case 'Address':
/**地址类型 基本数据类型为数组字符串但是要判断层级关系 */
if ( !Array.isArray(param[key]) ) {
isError = true;
errorStr = `${key}应是数组形`;
}
if ( param[key].length != 4) {
isError = true;
errorStr = `${key}超过特定长度4 目前长度 ${param[key].length}`;
}
for (let i =0; i < param[key].length; i++) {
let item = param[key][i];
if ( typeof item != 'string' ) {
isError = true;
errorStr = `${key}应是string型数组其中下标${i}${typeof item}`;
}
}
/** 不符合规则的 */
let nullIndex = -1;
for (let i = 0; i < param[key].length; i++) {
if (nullIndex != -1) {//出现过空 第一次出现后的位置 都不能有值
if (param[key]) {
//做一个特化
throw new BizError(ERRORENUM.地址数据不完整, name, `${key} 下标 ${nullIndex} 为空 `);
}
}
if (nullIndex == -1 && !param[key][i]) {
/**按顺序第一次赋值 */
nullIndex = i;
}
}
break;
}
errorStr = isError && errorStr == "" ? `${key}应该是${type}型 而不是${valueType}`: errorStr;
if ( isError ) throw new BizError(ERRORENUM.请完善信息, name, errorStr);
}
}
return true;
}
/**
* 根据conf配置校验请求参数
* @param conf 配置
* @param param 表单
* @param skipKeys []不必填的字段
*/
export function eccReqParamater(conf:object, param, skipKeys?) {
skipKeys = skipKeys || [];
let skipMap = {};
skipKeys.forEach(keyName => {
skipMap[keyName] = 1;
});
/**校验多余字段 */
for (let key in param) {
if (!conf[key]) throw new BizError(ERRORENUM.参数错误, `多余${key}字段`);
}
/**校验必填和缺失字段 */
for (let key in conf) {
let confType = conf[key];
let value = param[key];
let valueType = typeof value;
if ( value == null || value == undefined ) {
if (!skipMap[key]) throw new BizError(ERRORENUM.参数错误, `缺失${key}字段`);
} else {
let isError = false;
let errorStr = "";
switch(confType) {
case 'Number':
if ( confType.toLowerCase() != valueType ) isError = true;
else {
if ((""+param[key]).indexOf('.') > -1) {
param[key] = parseInt(`${param[key] *100}`)/100;
}
}
break;
case 'String':
case 'Boolean':
if ( confType.toLowerCase() != valueType ) isError = true;
break;
case '[Number]':
if ( !Array.isArray(param[key]) ) isError = true;
for (let i =0; i < param[key].length; i++) {
let item = param[key][i];
if ( typeof item != 'number' ) {
isError = true;
errorStr = `${key}应是number型数组其中下标${i}${typeof item}`;
}
}
break;
case '[Object]':
if ( !Array.isArray(param[key]) ) isError = true;
for (let i =0; i < param[key].length; i++) {
let item = param[key][i];
if ( typeof item != 'object' ) {
isError = true;
errorStr = `${key}应是object型数组其中下标${i}${typeof item}`;
}
}
break;
case 'Address':
/**地址类型 基本数据类型为数组字符串但是要判断层级关系 */
if ( !Array.isArray(param[key]) ) {
isError = true;
errorStr = `${key}应是数组形`;
}
if ( param[key].length != 4) {
isError = true;
errorStr = `${key}超过特定长度4 目前长度 ${param[key].length}`;
}
for (let i =0; i < param[key].length; i++) {
let item = param[key][i];
if ( typeof item != 'string' ) {
isError = true;
errorStr = `${key}应是string型数组其中下标${i}${typeof item}`;
}
}
/** 不符合规则的 */
let nullIndex = -1;
for (let i = 0; i < param[key].length; i++) {
if (nullIndex != -1) {//出现过空 第一次出现后的位置 都不能有值
if (param[key]) {
//做一个特化
throw new BizError(ERRORENUM.地址数据不完整, `${key} 下标 ${nullIndex} 为空 `);
}
}
if (nullIndex == -1 && !param[key][i]) {
/**按顺序第一次赋值 */
nullIndex = i;
}
}
break;
}
errorStr = isError && errorStr == "" ? `${key}应该是${confType}型 而不是${valueType}`: errorStr;
if (isError) throw new BizError(ERRORENUM.参数错误, errorStr);
}
}
return param;
}
\ No newline at end of file
......@@ -6,20 +6,13 @@
"rootDir":"./src",
"outDir":"./out",
"esModuleInterop": true,
// "strict": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"noImplicitAny": false,
"strictNullChecks": false,
"types": ["node"]
},
"exclude": [
"node_modules",
]
}
// {
// "compilerOptions": {
// "target": "ES6",
// "module": "commonjs",
// "esModuleInterop": true,
// "outDir": "./dist",
// "strict": true
// },
// "include": ["src/**/*"]
// }
}
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