北斗应用技术培训报名系统

This commit is contained in:
2026-03-27 17:53:28 +08:00
commit e8e23fb003
58 changed files with 2091 additions and 0 deletions

182
app/controller/Exam.js Normal file
View File

@@ -0,0 +1,182 @@
const Controller = require('../core/base_controller');
const fileName = "Exam";
class ExamController extends Controller {
// 用户报名接口
async application() {
const { ctx } = this;
try {
let rdmcode = await this.checkUid(ctx);
if (!rdmcode) {
this.setResponse(ctx, 401, 'token过期或错误', "none");
return;
}
const uid = JSON.parse(rdmcode).uid;
const body = ctx.request.body;
const form = {
user_uid: uid,
exam_uid: this.decryptRequest(body.uid),
exam_name: this.decryptRequest(body.exam_name),
source: "个人",
status: 0,
pay_status: 0,
result: "用户个人报名",
created_at: new Date()
};
const result = await ctx.service.exam.application(uid, form);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (result) {
this.setResponse(ctx, 200, '操作成功', "none");
} else {
this.setResponse(ctx, 404, '操作失败', "none");
}
} catch (error) {
const blockName = fileName + "--" + "application";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
// 用户取消报名接口
async cancelApplication() {
const { ctx } = this;
try {
let rdmcode = await this.checkUid(ctx);
if (!rdmcode) {
this.setResponse(ctx, 401, 'token过期或错误', "none");
return;
}
const uid = JSON.parse(rdmcode).uid;
const body = ctx.request.body;
const exam_uid = this.decryptRequest(body.uid);
const result = await ctx.service.exam.cancelApplication(uid, exam_uid);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (result) {
this.setResponse(ctx, 200, '操作成功', "none");
} else {
this.setResponse(ctx, 404, '操作失败', "none");
}
} catch (error) {
const blockName = fileName + "--" + "cancelApplication";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
// 用户查看所有考试接口
async examList() {
const { ctx } = this;
try {
let rdmcode = await this.checkUid(ctx);
if (!rdmcode) {
this.setResponse(ctx, 401, 'token过期或错误', "none");
return;
}
const uid = JSON.parse(rdmcode).uid;
const body = ctx.request.body;
const result = await ctx.service.exam.examList(uid, body);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (result) {
let examMsg = [];
result.rows.forEach(element => {
examMsg.push(element.dataValues);
});
const data = {
examMsg,
count: result.count
};
this.setResponse(ctx, 200, '操作成功', "deconstruction", data);
} else {
this.setResponse(ctx, 404, '操作失败', "none");
}
} catch (error) {
const blockName = fileName + "--" + "examList";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
// 用户查看考试结果接口
async gradesList() {
const { ctx } = this;
try {
let rdmcode = await this.checkUid(ctx);
if (!rdmcode) {
this.setResponse(ctx, 401, 'token过期或错误', "none");
return;
}
const uid = JSON.parse(rdmcode).uid;
const body = ctx.request.body;
const result = await ctx.service.exam.gradesList(uid, body);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (result) {
let gradesMsg = [];
result.rows.forEach(element => {
gradesMsg.push(element.dataValues);
});
const data = {
gradesMsg,
count: result.count
};
this.setResponse(ctx, 200, '操作成功', "deconstruction", data);
} else {
this.setResponse(ctx, 404, '操作失败', "none");
}
} catch (error) {
const blockName = fileName + "--" + "gradesList";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
// 用户查看报名历史接口
async applicationList() {
const { ctx } = this;
try {
let rdmcode = await this.checkUid(ctx);
if (!rdmcode) {
this.setResponse(ctx, 401, 'token过期或错误', "none");
return;
}
const uid = JSON.parse(rdmcode).uid;
const body = ctx.request.body;
const result = await ctx.service.exam.applicationList(uid, body);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (result) {
let applicationMsg = [];
result.rows.forEach(element => {
applicationMsg.push(element.dataValues);
});
const data = {
applicationMsg,
count: result.count
};
this.setResponse(ctx, 200, '操作成功', "deconstruction", data);
} else {
this.setResponse(ctx, 404, '操作失败', "none");
}
} catch (error) {
const blockName = fileName + "--" + "applicationList";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
}
module.exports = ExamController;

161
app/controller/System.js Normal file
View File

@@ -0,0 +1,161 @@
const Controller = require('../core/base_controller');
const fileName = "System";
class SystemController extends Controller {
// 系统获取考试信息接口
async examMsg() {
const { ctx } = this;
try {
const result = await ctx.service.system.examMsg();
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (result) {
this.setResponse(ctx, 200, '操作成功', "deconstruction", result);
} else {
this.setResponse(ctx, 404, '操作失败', "none");
}
} catch (error) {
const blockName = fileName + "--" + "examMsg";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
// 比较身份证号
async diffIdentityCard() {
const { ctx } = this;
try {
const body = ctx.request.body;
const identity_card = this.decryptRequest(body.identity_card);
const type = this.decryptRequest(body.type);
const data = this.decryptRequest(body.data);
const uid = data == 'null' ? null : data.split('?')[0];
const result = await ctx.service.system.diffIdentityCard(identity_card, type, uid);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (!result) {
this.setResponse(ctx, 404, '该身份证号已注册', "none");
} else {
this.setResponse(ctx, 200, '验证通过', "none");
}
} catch (error) {
const blockName = fileName + "--" + "diffIdentityCard";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
// 比较邮箱
async diffEmail() {
const { ctx } = this;
try {
const body = ctx.request.body;
const email = this.decryptRequest(body.email);
const type = this.decryptRequest(body.type);
const data = this.decryptRequest(body.data);
const uid = data == 'null' ? null : data.split('?')[0];
const result = await ctx.service.system.diffEmail(email, type, uid);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (!result) {
this.setResponse(ctx, 404, '该邮箱已经注册', "none");
} else {
this.setResponse(ctx, 200, '验证通过', "none");
}
} catch (error) {
const blockName = fileName + "--" + "diffEmail";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
// 比较电话号码
async diffPhone() {
const { ctx } = this;
try {
const body = ctx.request.body;
const phone = this.decryptRequest(body.phone);
const type = this.decryptRequest(body.type);
const data = this.decryptRequest(body.data);
const uid = data == 'null' ? null : data.split('?')[0];
const result = await ctx.service.system.diffPhone(phone, type, uid);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (!result) {
this.setResponse(ctx, 404, '该手机号已注册', "none");
} else {
this.setResponse(ctx, 200, '验证通过', "none");
}
} catch (error) {
const blockName = fileName + "--" + "diffPhone";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
// 用户注册接口
async registered() {
const { ctx } = this;
try {
const body = ctx.request.body;
const phone = this.decryptRequest(body.phone);
// redis 存放短信验证码,过期时间为 10 分钟
const redis = ctx.app.redis;
const codeResult = await redis.get('db3').get(phone);
if(!codeResult || JSON.parse(codeResult).status != '1') {
this.setResponse(ctx, 333, '短信验证码错误', "none");
return;
}
const salt = this.generateRandomString();
const form = {
uid: this.generateNumberString('E'),
salt: this.encryptRequest(salt),
password: this.shaForm(this.decryptRequest(body.password), salt),
user_name: this.decryptRequest(body.user_name),
identity_card: this.decryptRequest(body.identity_card),
real_check: 0,
workplace: this.decryptRequest(body.workplace),
address: this.decryptRequest(body.address),
phone: phone,
email: this.decryptRequest(body.email),
referrers: body.referrers ? this.decryptRequest(body.referrers) : null,
status: 1,
created_at: new Date(),
updated_at: new Date(),
login_status: 0,
};
const auditForm = {
user_uid: form.uid,
user_name: form.user_name,
identity_card: form.identity_card,
status: 0,
created_at: new Date(),
};
const result = await ctx.service.system.registered(form, auditForm);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (result) {
this.setResponse(ctx, 200, '操作成功', "none");
} else {
this.setResponse(ctx, 404, '操作失败', "none");
}
} catch (error) {
const blockName = fileName + "--" + "registered";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
}
module.exports = SystemController;

180
app/controller/User.js Normal file
View File

@@ -0,0 +1,180 @@
const Controller = require('../core/base_controller');
const fileName = "User";
const fs = require('fs');
const path = require('path');
class UserController extends Controller {
// 信息完整性,合法性校验
async checkInfo() {
const { ctx } = this;
try {
let rdmcode = await this.checkUid(ctx);
if (!rdmcode) {
this.setResponse(ctx, 401, 'token过期或错误', "none");
return;
}
const uid = JSON.parse(rdmcode).uid;
const result = await ctx.service.user.checkInfo(uid);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (result == 'OK') {
this.setResponse(ctx, 200, '信息校验完成', "none");
} else if (result == 'CNTEV') {
this.setResponse(ctx, 303, '信息校验中', "none");
} else {
this.setResponse(ctx, 404, '信息校验失败', "none");
}
} catch (error) {
const blockName = fileName + "--" + "checkInfo";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
// 用户照片是否存在判断
async checkPhoto() {
const { ctx } = this;
try {
let rdmcode = await this.checkUid(ctx);
if (!rdmcode) {
this.setResponse(ctx, 401, 'token过期或错误', "none");
return;
}
const uid = JSON.parse(rdmcode).uid;
const result = await ctx.service.user.checkPhoto(uid);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (result.exist) {
ctx.set('Cache-Control', 'no-cache, no-store, must-revalidate');
ctx.set("Pragma", "no-cache");
ctx.set("Expires", "0");
this.setResponse(ctx, 200, '照片校验成功', "deconstruction", result);
} else {
this.setResponse(ctx, 404, '照片校验失败', "none");
}
} catch (error) {
const blockName = fileName + "--" + "checkPhoto";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
// 身份证二要素核验
async CNTEV() {
const { ctx } = this;
try {
let rdmcode = await this.checkUid(ctx);
if (!rdmcode) {
this.setResponse(ctx, 401, 'token过期或错误', "none");
return;
}
const { user_name, identity_card } = ctx.request.body;
const result = await ctx.service.user.CNTEV(user_name, identity_card);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (result == "1") {
this.setResponse(ctx, 200, '身份证二要素核验成功', "none");
} else if (result == "0") {
const check = await ctx.app.redis.get('db3').get(identity_card);
if (check == null) {
ctx.curl('http://127.0.0.1:' + 8011 + '/CNTEV', {
dataType: 'json',
contentType: 'application/x-www-form-urlencoded',
method: 'POST',
timeout: 3000,
data: {
user_name,
identity_card,
},
});
} else {
await ctx.service.user.updateCNTEV(user_name, identity_card, JSON.parse(check).real_check);
await ctx.app.redis.get('db3').del(identity_card);
}
this.setResponse(ctx, 303, '正在核验中', "none");
} else {
this.setResponse(ctx, 404, '身份证二要素核验失败,请修改正确后等待管理员审核', "none");
}
} catch (error) {
const blockName = fileName + "--" + "CNTEV";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
// 用户上传照片
async uploadPhoto() {
const { ctx } = this;
try {
let rdmcode = await this.checkUid(ctx);
if (!rdmcode) {
this.setResponse(ctx, 401, 'token过期或错误', "none");
return;
}
const uid = JSON.parse(rdmcode).uid;
const { files } = ctx.request;
const result = await ctx.service.user.uploadPhoto(uid, files);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (result) {
this.setResponse(ctx, 200, '操作成功', "none");
} else {
this.setResponse(ctx, 404, '操作失败', "none");
}
} catch (error) {
const blockName = fileName + "--" + "uploadPhoto";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
} finally {
// 需要删除临时文件
await ctx.cleanupRequestFiles();
}
}
// 用户找回密码
async resetPassword() {
const { ctx } = this;
try {
const body = ctx.request.body;
// redis 存放短信验证码,过期时间为 10 分钟
const phone = this.decryptRequest(body.phone);
const redis = ctx.app.redis;
const codeResult = await redis.get('db3').get(phone);
if(!codeResult || JSON.parse(codeResult).status != '1') {
this.setResponse(ctx, 333, '短信验证码错误', "none");
return;
}
const salt = this.generateRandomString();
const updateForm = {
salt: this.encryptRequest(salt),
password: this.shaForm(this.decryptRequest(body.password), salt)
}
const result = await ctx.service.user.resetPassword(updateForm, phone);
if (result == "error") {
this.setResponse(ctx, 500, '服务器错误', "none");
return;
}
if (result) {
this.setResponse(ctx, 200, '修改密码成功', "none");
} else {
this.setResponse(ctx, 404, '修改密码失败', "none");
}
} catch (error) {
const blockName = fileName + "--" + "resetPassword";
ctx.app.middleware.log('../../controllerLog', blockName + ">>>>" + error);
this.setResponse(ctx, 500, '服务器错误', "none");
}
}
}
module.exports = UserController;

133
app/core/base_controller.js Normal file
View File

@@ -0,0 +1,133 @@
const { Controller } = require('egg');
const sha256 = require("crypto-js/sha256");
const CryptoJS = require("crypto-js");
const KEY = CryptoJS.enc.Utf8.parse('BDQH');
class BaseController extends Controller {
shaForm = (body, salt) => {
return sha256(sha256(body).toString() + salt).toString();
}
encryptRequest = (body) => {
return CryptoJS.AES.encrypt(body, KEY, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}).toString();
}
decryptRequest = (body) => {
return CryptoJS.AES.decrypt(body, KEY, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8);
}
// 用户uid生成函数
generateNumberString = (side) => {
// 获取当前日期(年月日)
const now = new Date();
const year = String(now.getFullYear()).padStart(4, '0');
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,所以加1
const date = String(now.getDate()).padStart(2, '0');
const dateString = year + month + date;
// 获取当前时间戳的后三位
const timestamp = String(Date.now()).slice(-3);
// 生成三位随机数字
const randomDigits = Math.floor(Math.random() * 100).toString().padStart(3, '0');
// 组合成最终的15位字符串
const fullNumberString = dateString + timestamp + randomDigits + side;
return fullNumberString;
}
// 随机盐生成函数
generateRandomString = () => {
const lowerCaseLetters = 'abcdefghijklmnopqrstuvwxyz';
const upperCaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const numbers = '0123456789';
let result = '';
// 生成5位随机小写字母
for (let i = 0; i < 5; i++) {
const randomIndex = Math.floor(Math.random() * lowerCaseLetters.length);
result += lowerCaseLetters[randomIndex];
}
// 生成5位随机大写字母
for (let i = 0; i < 5; i++) {
const randomIndex = Math.floor(Math.random() * upperCaseLetters.length);
result += upperCaseLetters[randomIndex];
}
// 生成2位随机数字
for (let i = 0; i < 2; i++) {
const randomIndex = Math.floor(Math.random() * numbers.length);
result += numbers[randomIndex];
}
// 打乱整个字符串
const characters = result.split('');
for (let i = characters.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[characters[i], characters[j]] = [characters[j], characters[i]];
}
return characters.join('');
}
// 随机生成12位客户端id
generateClientId = () => {
const numbers = '0123456789';
let result = '';
// 生成4位随机数字
for (let i = 0; i < 4; i++) {
const randomIndex = Math.floor(Math.random() * numbers.length);
result += numbers[randomIndex];
}
// 打乱整个字符串
const characters = result.split('');
for (let i = characters.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[characters[i], characters[j]] = [characters[j], characters[i]];
}
// 获取当前日期(年月日)
const now = new Date();
const year = String(now.getFullYear()).padStart(4, '0');
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,所以加1
const date = String(now.getDate()).padStart(2, '0');
const dateString = year + month + date;
const fullNumberString = dateString + characters.join('');
return fullNumberString;
}
checkUid = async (ctx) => {
const token = ctx.request.header.authorization;
const redis = ctx.app.redis;
const exam = await redis.get('db6').get(token);
return exam ? exam : false;
};
setResponse = (ctx, code, msg, model, data = {}) => {
const modelType = {
"none": { code, msg },
"deconstruction": { code, msg, ...data },
"polymerization": { code, msg, data }
}
ctx.body = modelType[model];
}
}
module.exports = BaseController;

88
app/core/base_service.js Normal file
View File

@@ -0,0 +1,88 @@
const { Service } = require('egg');
const { Op } = require('sequelize');
const sha256 = require("crypto-js/sha256");
const CryptoJS = require("crypto-js");
const KEY = CryptoJS.enc.Utf8.parse('BDQH');
class BaseService extends Service {
shaForm = (body, salt) => {
return sha256(sha256(body).toString() + salt).toString();
}
encryptRequest = (body) => {
return CryptoJS.AES.encrypt(body, KEY, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}).toString();
}
decryptRequest = (body) => {
return CryptoJS.AES.decrypt(body, KEY, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8);
}
// uid生成函数
generateNumberString = () => {
// 获取当前日期(年月日)
const now = new Date();
const year = String(now.getFullYear()).padStart(4, '0');
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,所以加1
const date = String(now.getDate()).padStart(2, '0');
const dateString = year + month + date;
// 获取当前时间戳的后四位
const timestamp = String(Date.now()).slice(-4);
// 生成四位随机数字
const randomDigits = Math.floor(Math.random() * 10000).toString().padStart(4, '0');
// 组合成最终的16位数字字符串
const fullNumberString = dateString + timestamp + randomDigits;
return fullNumberString;
}
// 随机盐生成函数
generateRandomString = () => {
const lowerCaseLetters = 'abcdefghijklmnopqrstuvwxyz';
const upperCaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const numbers = '0123456789';
let result = '';
// 生成5位随机小写字母
for (let i = 0; i < 5; i++) {
const randomIndex = Math.floor(Math.random() * lowerCaseLetters.length);
result += lowerCaseLetters[randomIndex];
}
// 生成5位随机大写字母
for (let i = 0; i < 5; i++) {
const randomIndex = Math.floor(Math.random() * upperCaseLetters.length);
result += upperCaseLetters[randomIndex];
}
// 生成2位随机数字
for (let i = 0; i < 2; i++) {
const randomIndex = Math.floor(Math.random() * numbers.length);
result += numbers[randomIndex];
}
// 打乱整个字符串
const characters = result.split('');
for (let i = characters.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[characters[i], characters[j]] = [characters[j], characters[i]];
}
return characters.join('');
}
}
module.exports = BaseService;

72
app/middleware/log.js Normal file
View File

@@ -0,0 +1,72 @@
// 错误日志
const fs = require('fs');
const os = require('os');
const path = require('path');
const dirCheck = (dirPath) => {
// 检查文件夹是否存在
fs.access(dirPath, fs.constants.F_OK, (err) => {
if (err) {
// 文件夹不存在
console.log('文件夹不存在,正在创建...');
fs.mkdir(dirPath, { recursive: true }, (err) => {
if (err) throw err;
console.log('文件夹已创建');
});
} else {
// 文件夹存在
console.log('文件夹已存在');
}
});
}
module.exports = (filePath, msg) => {
// 获取时间
let now = new Date(),
times = {
year: now.getFullYear(),
month: now.getMonth() + 1,
day: now.getDate(),
hour: now.getHours(),
minute: now.getMinutes(),
second: now.getSeconds()
};
// 获取操作系统类型
const type = os.type();
console.log(`操作系统类型: ${type}`);
filePath = path.join(__dirname, filePath);
dirCheck(filePath);
const yearPath = filePath + '/' + times.year;
dirCheck(yearPath);
const monthPath = yearPath + '/' + times.month;
dirCheck(monthPath);
const dayPath = monthPath + '/' + times.day + '.txt';
const logTime = '[' + times.year + '-' + times.month + '-' + times.day + '>>>' + times.hour + ':' + times.minute + ':' + times.second + ']' + '>>>';
let crlf;
// 判断操作系统类型,设置换行符
if (type === 'Windows_NT') {
crlf = '\n';
} else {
crlf = '\r\n';
}
// 读取文件内容
fs.readFile(dayPath, 'utf8', (err, data) => {
if (err) {
if (err.code === 'ENOENT') {
// 文件不存在,直接写入新内容(这里实际上还是使用了覆盖的方式)
fs.writeFile(dayPath, logTime + msg + crlf, (err) => {
if (err) throw err;
console.log('文件已创建并写入新内容');
});
} else {
throw err;
}
} else {
// 文件存在,追加新内容
fs.appendFile(dayPath, logTime + msg + crlf, (err) => {
if (err) throw err;
console.log('新内容已追加到文件');
});
}
});
};

23
app/model/Application.js Normal file
View File

@@ -0,0 +1,23 @@
'use strict';
module.exports = (app) => {
const { INTEGER, CHAR, STRING, DATE } = app.Sequelize;
const Application = app.model.define('application', {
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
user_uid: CHAR(15),
exam_uid: CHAR(10),
source: STRING(24),
status: INTEGER(3),
pay_status: INTEGER(3),
result: STRING(24),
created_at: DATE,
},{
freezeTableName: true,
timestamp: true,
createdAt: true,
updatedAt: false,
});
return Application;
};

21
app/model/Audit.js Normal file
View File

@@ -0,0 +1,21 @@
'use strict';
module.exports = (app) => {
const { INTEGER, CHAR, STRING, DATE } = app.Sequelize;
const Audit = app.model.define('audit', {
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
user_uid: CHAR(15),
identity_card: CHAR(18),
user_name: STRING(6),
status: INTEGER(3),
created_at: DATE,
},{
freezeTableName: true,
timestamp: true,
createdAt: true,
updatedAt: false,
});
return Audit;
};

23
app/model/Examination.js Normal file
View File

@@ -0,0 +1,23 @@
'use strict';
module.exports = (app) => {
const { INTEGER, CHAR, STRING, DATE } = app.Sequelize;
const Examination = app.model.define('examination', {
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
uid: CHAR(10),
exam_name: STRING(60),
status: INTEGER(3),
application_start: DATE,
application_end: DATE,
exam_start: DATE,
exam_end: DATE,
},{
freezeTableName: true,
timestamp: true,
createdAt: false,
updatedAt: false,
});
return Examination;
};

31
app/model/Examinee.js Normal file
View File

@@ -0,0 +1,31 @@
'use strict';
module.exports = (app) => {
const { INTEGER, CHAR, STRING, DATE } = app.Sequelize;
const Examinee = app.model.define('examinee', {
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
uid: CHAR(15),
salt: CHAR(24),
password: CHAR(64),
user_name: STRING(10),
identity_card: CHAR(18),
real_check: INTEGER(3),
workplace: STRING(60),
address: STRING(120),
phone: CHAR(11),
email: STRING(60),
referrers: STRING(60),
status: INTEGER(3),
created_at: DATE,
updated_at: DATE,
login_status: INTEGER(3),
},{
freezeTableName: true,
timestamp: true,
createdAt: true,
updatedAt: true,
});
return Examinee;
};

21
app/model/Grades.js Normal file
View File

@@ -0,0 +1,21 @@
'use strict';
module.exports = (app) => {
const { INTEGER, CHAR, STRING } = app.Sequelize;
const Grades = app.model.define('grades', {
id: { type: INTEGER(8), primaryKey: true, autoIncrement: true },
user_uid: CHAR(15),
exam_uid: CHAR(10),
status: INTEGER(3),
grades: STRING(5),
pass_type: INTEGER(3),
},{
freezeTableName: true,
timestamp: false,
createdAt: false,
updatedAt: false,
});
return Grades;
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

37
app/router.js Normal file
View File

@@ -0,0 +1,37 @@
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
// 系统获取考试信息接口
router.post("/examMsg", controller.system.examMsg);
// 比较身份证号
router.post("/diffIdentityCard", controller.system.diffIdentityCard);
// 比较邮箱
router.post("/diffEmail", controller.system.diffEmail);
// 比较电话号码
router.post("/diffPhone", controller.system.diffPhone);
// 用户注册接口
router.post("/registered", controller.system.registered);
// 信息完整性,合法性校验
router.post("/checkInfo", controller.user.checkInfo);
// 用户照片是否存在判断
router.post("/checkPhoto", controller.user.checkPhoto);
// 身份证二要素核验
router.post("/CNTEV", controller.user.CNTEV);
// 用户上传照片接口
router.post("/uploadPhoto", controller.user.uploadPhoto);
// 用户找回密码接口
router.post("/resetPassword", controller.user.resetPassword);
// 用户报名接口
router.post("/application", controller.exam.application);
// 用户取消报名接口
router.post("/cancelApplication", controller.exam.cancelApplication);
// 用户查看所有考试接口
router.post("/examList", controller.exam.examList);
// 用户查看考试结果接口
router.post("/gradesList", controller.exam.gradesList);
// 用户查看报名历史接口
router.post("/applicationList", controller.exam.applicationList);
};

30
app/schedule/auditTask.js Normal file
View File

@@ -0,0 +1,30 @@
module.exports = {
schedule: {
interval: '1h', // 1 小时间隔
type: 'all', // 指定所有的 worker 都需要执行
},
async task(ctx) {
const AuditResult = await ctx.model.Audit.findAll({ where: { status: 0 } });
if (AuditResult.length != 0) {
AuditResult.forEach(async element => {
const { identity_card, user_name } = element.dataValues;
const check = await ctx.app.redis.get('db3').get(identity_card);
if (check == null) {
await ctx.curl('http://127.0.0.1:' + 8011 + '/CNTEV', {
dataType: 'json',
contentType: 'application/x-www-form-urlencoded',
method: 'POST',
timeout: 3000,
data: {
idCard: identity_card,
name: user_name
},
});
} else {
await ctx.service.user.updateCNTEV(identity_card, user_name, JSON.parse(check).real_check);
await ctx.app.redis.get('db3').del(identity_card);
}
});
};
},
};

279
app/service/Exam.js Normal file
View File

@@ -0,0 +1,279 @@
'use strict';
const Service = require('../core/base_service');
const { Op } = require('sequelize');
const fileName = "Exam";
class ExamService extends Service {
// 用户报名接口
async application(uid, form) {
const { ctx } = this;
try {
let where = { uid }
const user = await ctx.model.Examinee.findOne({ where });
if (!user) return false;
where = { user_uid: uid, exam_uid: form.exam_uid }
const application = await ctx.model.Application.findOne({ where });
let result;
if (!application) {
result = await ctx.model.Application.create(form);
return result ? true : false;
} else {
result = await ctx.model.Application.update(form, { where });
return result[0] != 0;
};
} catch (error) {
const blockName = fileName + "--" + "application";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 用户取消报名接口
async cancelApplication(uid, exam_uid) {
const { ctx } = this;
try {
const result = await ctx.model.Application.update({ status: 3, result: "用户已取消报名" }, { where: { user_uid: uid, exam_uid } });
return result[0] != 0;
} catch (error) {
const blockName = fileName + "--" + "cancelApplication";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 用户查看所有考试接口
async examList(uid, body) {
const { ctx } = this;
try {
let { offset, limit, searchOptions, sortOptions } = body;
offset = (offset - 1) * limit;
let attributes = ['uid', 'exam_name', 'status', 'application_end', 'exam_start', 'exam_end'],
where = {}, order = [], dbOptions, joinSubstring = [],
substring = ['uid', 'exam_name'], key = ['status'], between = ['application_end', 'exam_start', 'exam_end'];
attributes.forEach(element => {
if (searchOptions[element]) {
if (searchOptions[element] == '*空') {
if (joinSubstring.includes(element)) {
where[element] = null;
} else {
where[element] = [null, ''];
}
} else if (substring.includes(element)) {
where[element] = { [Op.substring]: searchOptions[element] };
} else if (key.includes(element)) {
where[element] = searchOptions[element];
} else if (between.includes(element)) {
where[element] = { [Op.between]: [searchOptions[element][0], searchOptions[element][1]] };
}
}
if (sortOptions[element] == true) {
order.push([element, 'ASC']);
} else if (sortOptions[element] == false) {
order.push([element, 'DESC']);
}
});
dbOptions = { attributes, offset, limit, where, order };
const result = await ctx.model.Examination.findAndCountAll(dbOptions);
if (result.rows.length == 0) return false;
const examUids = result.rows.map(exam => exam.dataValues.uid);
const applicationStatus = await ctx.model.Application.findAll({ where: { user_uid: uid, exam_uid: { [Op.in]: examUids } } });
const statusMap = new Map();
applicationStatus.forEach(item => {
statusMap.set(item.dataValues.exam_uid, item.dataValues.status);
});
result.rows.forEach(exam => {
statusMap.get(exam.dataValues.uid) == undefined ?
exam.dataValues.applicationStatus = 4 :
exam.dataValues.applicationStatus = statusMap.get(exam.dataValues.uid);
});
let passExamArr = result.rows.map(exam => exam.dataValues.status == 0 ? exam.dataValues.uid : '').filter(item => item !== '')
const applicationCheck = await ctx.model.Application.findAll({ attributes: ['exam_uid', 'status'], where: { user_uid: uid, exam_uid: passExamArr, status: { [Op.in]: [0, 1] } } });
let applicationCheckSwitch = false;
result.rows.forEach((item) => {
item.dataValues.applicationCheck = 0;
item.dataValues.applicationCheckSwitch = false;
applicationCheck.forEach(element => {
if (element.dataValues.exam_uid == item.dataValues.uid) {
if (element.dataValues.status == 0 || element.dataValues.status == 1) {
item.dataValues.applicationCheck = 1;
applicationCheckSwitch = true;
}
}
})
});
if (applicationCheckSwitch) {
result.rows.forEach((items) => {
items.dataValues.applicationCheckSwitch = true;
});
}
return result;
} catch (error) {
const blockName = fileName + "--" + "examList";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 用户查看考试结果接口
async gradesList(user_uid, body) {
const { ctx } = this;
try {
let { offset, limit, searchOptions, sortOptions } = body;
offset = (offset - 1) * limit;
let attributes = ['exam_uid', 'status', 'grades', 'pass_type'],
where = { user_uid }, order = [], dbOptions, joinSubstring = [],
substring = ['exam_uid'], key = ['status', 'grades', 'pass_type'], between = [];
attributes.forEach(element => {
if (searchOptions[element]) {
if (searchOptions[element] == '*空') {
if (joinSubstring.includes(element)) {
where[element] = null;
} else {
where[element] = [null, ''];
}
} else if (substring.includes(element)) {
where[element] = { [Op.substring]: searchOptions[element] };
} else if (key.includes(element)) {
where[element] = searchOptions[element];
} else if (between.includes(element)) {
where[element] = { [Op.between]: [searchOptions[element][0], searchOptions[element][1]] };
}
}
if (sortOptions[element] == true) {
order.push([element, 'ASC']);
} else if (sortOptions[element] == false) {
order.push([element, 'DESC']);
}
});
let examination = ['exam_name'],
examinationWhere = {},
examinationOrder = [],
examinationJoinSubstring = [],
examinationSubstring = ['exam_name'],
examinationKey = [],
examinationBetween = [];
examination.forEach(item => {
if (searchOptions[item]) {
if (searchOptions[item] == '*空') {
if (examinationJoinSubstring.includes(item)) {
examinationWhere[item] = null;
} else {
examinationWhere[item] = [null, ''];
}
} else if (examinationSubstring.includes(item)) {
examinationWhere[item] = { [Op.substring]: searchOptions[item] };
} else if (examinationKey.includes(item)) {
examinationWhere[item] = searchOptions[item];
} else if (examinationBetween.includes(item)) {
examinationWhere[item] = { [Op.between]: [searchOptions[item][0], searchOptions[item][1]] };
}
}
if (sortOptions[item] == true) {
examinationOrder.push([item, 'ASC']);
} else if (sortOptions[item] == false) {
examinationOrder.push([item, 'DESC']);
}
});
let include = [
{
model: ctx.model.Examination,
attributes: ['exam_name', 'status'],
where: examinationWhere,
order: examinationOrder
}
];
ctx.model.Grades.belongsTo(ctx.model.Examination, { foreignKey: 'exam_uid', targetKey: 'uid' });
dbOptions = { attributes, offset, limit, where, order, include };
const result = await ctx.model.Grades.findAndCountAll(dbOptions);
return result.rows.length == 0 ? false : result;
} catch (error) {
const blockName = fileName + "--" + "gradesList";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 用户查看报名历史接口
async applicationList(user_uid, body) {
const { ctx } = this;
try {
let { offset, limit, searchOptions, sortOptions } = body;
offset = (offset - 1) * limit;
let attributes = ['exam_uid', 'source', 'status', 'pay_status', 'result', 'created_at'],
where = { user_uid }, order = [], dbOptions, joinSubstring = [],
substring = ['exam_uid', 'source', 'result'], key = ['status', 'pay_status'], between = ['created_at', 'application_end', 'exam_start', 'exam_end'];
attributes.forEach(element => {
if (searchOptions[element]) {
if (searchOptions[element] == '*空') {
if (joinSubstring.includes(element)) {
where[element] = null;
} else {
where[element] = [null, ''];
}
} else if (substring.includes(element)) {
where[element] = { [Op.substring]: searchOptions[element] };
} else if (key.includes(element)) {
where[element] = searchOptions[element];
} else if (between.includes(element)) {
where[element] = { [Op.between]: [searchOptions[element][0], searchOptions[element][1]] };
}
}
if (sortOptions[element] == true) {
order.push([element, 'ASC']);
} else if (sortOptions[element] == false) {
order.push([element, 'DESC']);
}
});
let examination = ['exam_name', 'application_end', 'exam_start', 'exam_end'],
examinationWhere = {},
examinationOrder = [],
examinationJoinSubstring = [],
examinationSubstring = ['exam_name'],
examinationKey = [],
examinationBetween = ['application_end', 'exam_start', 'exam_end'];
examination.forEach(item => {
if (searchOptions[item]) {
if (searchOptions[item] == '*空') {
if (examinationJoinSubstring.includes(item)) {
examinationWhere[item] = null;
} else {
examinationWhere[item] = [null, ''];
}
} else if (examinationSubstring.includes(item)) {
examinationWhere[item] = { [Op.substring]: searchOptions[item] };
} else if (examinationKey.includes(item)) {
examinationWhere[item] = searchOptions[item];
} else if (examinationBetween.includes(item)) {
examinationWhere[item] = { [Op.between]: [searchOptions[item][0], searchOptions[item][1]] };
}
}
if (sortOptions[item] == true) {
examinationOrder.push([item, 'ASC']);
} else if (sortOptions[item] == false) {
examinationOrder.push([item, 'DESC']);
}
});
let include = [
{
model: ctx.model.Examination,
attributes: ['exam_name', 'status', 'application_end', 'exam_start', 'exam_end'],
where: examinationWhere,
order: examinationOrder
}
];
ctx.model.Application.belongsTo(ctx.model.Examination, { foreignKey: 'exam_uid', targetKey: 'uid' });
dbOptions = { attributes, offset, limit, where, order, include };
const result = await ctx.model.Application.findAndCountAll(dbOptions);
return result.rows.length == 0 ? false : result;
} catch (error) {
const blockName = fileName + "--" + "applicationList";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
}
module.exports = ExamService;

109
app/service/System.js Normal file
View File

@@ -0,0 +1,109 @@
'use strict';
const Service = require('../core/base_service');
const { Op } = require('sequelize');
const fileName = "System";
class SystemService extends Service {
// 系统获取考试信息接口
async examMsg() {
const { ctx } = this;
try {
// 该接口只返回可报名的考试信息,即 status 为 0 的考试信息
const where = { status: 0 };
const result = await ctx.model.Examination.findAll({ where });
return result.length == 0 ? false : result;
} catch (error) {
const blockName = fileName + "--" + "examMsg";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 比较身份证号
async diffIdentityCard(identity_card, type, uid) {
const { ctx } = this;
try {
let attributes = ['identity_card'],
where = { identity_card },
dbOptions = { attributes, where };
const search = await ctx.model.Examinee.findAll(dbOptions);
if (type == 'register') {
return search.length == 0;
} else if (type == 'edit') {
where = { uid };
dbOptions = { attributes, where };
const result = await ctx.model.Examinee.findOne(dbOptions);
return result.dataValues.identity_card == identity_card ? true : search.length == 0;
}
} catch (error) {
const blockName = fileName + "--" + "diffIdentityCard";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 比较邮箱
async diffEmail(email, type, uid) {
const { ctx } = this;
try {
let attributes = ['email'],
where = { email },
dbOptions = { attributes, where };
const search = await ctx.model.Examinee.findAll(dbOptions);
if (type == 'register') {
return search.length == 0;
} else if (type == 'edit') {
where = { uid };
dbOptions = { attributes, where };
const result = await ctx.model.Examinee.findOne(dbOptions);
return result.dataValues.email == email ? true : search.length == 0;
}
} catch (error) {
const blockName = fileName + "--" + "diffEmail";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 比较电话号码
async diffPhone(phone, type, uid) {
const { ctx } = this;
try {
let attributes = ['phone'],
where = { phone },
dbOptions = { attributes, where };
const search = await ctx.model.Examinee.findAll(dbOptions);
if (type == 'register') {
return search.length == 0;
} else if (type == 'edit') {
where = { uid };
dbOptions = { attributes, where };
const result = await ctx.model.Examinee.findOne(dbOptions);
return result.dataValues.phone == phone ? true : search.length == 0;
}
} catch (error) {
const blockName = fileName + "--" + "diffPhone";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 用户注册接口
async registered(form, auditForm) {
const { ctx } = this;
try {
const result = await ctx.model.Examinee.create(form);
await ctx.model.Audit.create(auditForm);
return result ? true : false;
} catch (error) {
const blockName = fileName + "--" + "registered";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
}
module.exports = SystemService;

183
app/service/User.js Normal file
View File

@@ -0,0 +1,183 @@
'use strict';
const Service = require('../core/base_service');
const { Op } = require('sequelize');
const fs = require('fs');
const path = require('path');
const fileName = "User";
class UserService extends Service {
// 信息完整性,合法性校验
async checkInfo(uid) {
const { ctx } = this;
try {
let attributes = ['user_name', 'identity_card', 'real_check', 'status'],
where = { uid },
dbOptions = { attributes, where };
const result = await ctx.model.Examinee.findOne(dbOptions);
if (result == null || result.dataValues.status == 2 || result.dataValues.real_check == 2) return false;
let type = 'OK';
const { user_name, identity_card, real_check } = result.dataValues;
if (real_check == 0) {
type = 'CNTEV';
const check = await ctx.app.redis.get('db3').get(identity_card);
if (check == null) {
ctx.curl('http://127.0.0.1:' + 8011 + '/CNTEV', {
dataType: 'json',
contentType: 'application/x-www-form-urlencoded',
method: 'POST',
timeout: 3000,
data: {
user_name,
identity_card,
},
});
} else {
await ctx.service.user.updateCNTEV(user_name, identity_card, JSON.parse(check).real_check);
await ctx.app.redis.get('db3').del(identity_card);
}
}
return type;
} catch (error) {
const blockName = fileName + "--" + "checkInfo";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 用户照片是否存在判断
async checkPhoto(uid) {
const { ctx } = this;
try {
let attributes = ['identity_card'],
where = { uid },
dbOptions = { attributes, where };
const result = await ctx.model.Examinee.findOne(dbOptions);
if (result == null) return false;
const filePath = path.join(__dirname, `../public/userPhoto/${ result.dataValues.identity_card }.jpg`);
// const filePath = `/disk/a/userPhoto/${ result.dataValues.identity_card }.jpg`;
const fileExists = fs.existsSync(filePath);
let exist = false;
if (fileExists) {
// 文件存在
exist = true;
} else {
// 文件不存在
let attributes = ['identity_card'],
where = { user_uid: uid },
order = [['created_at', 'DESC']],
limit = 1,
offset = 1,
dbOptions = { attributes, where, order, limit, offset };
const oldIdentityCard = await ctx.model.Audit.findOne(dbOptions);
if(!oldIdentityCard) {
exist = false;
} else {
const oldFilePath = path.join(__dirname, `../public/userPhoto/${ oldIdentityCard.dataValues.identity_card }.jpg`);
// const oldFilePath = `/disk/a/userPhoto/${ oldIdentityCard.dataValues.identity_card }.jpg`;
const fileExists = fs.existsSync(oldFilePath);
if (fileExists) {
// 文件存在
fs.renameSync(oldFilePath, filePath);
// 文件改名
exist = true;
} else {
// 文件不存在
exist = false;
}
}
}
// 本机服务器地址
// 'http://127.0.0.1:8019'
// 'http://192.168.31.28:8019'
// 公司服务器地址
// 'http://123.57.205.46:8019'
// 'http://certlogin.hwasmart.com//bdTrainingExam'
return { exist, photoUrl: exist ? 'http://127.0.0.1:8019' + `/public/userPhoto/${ result.dataValues.identity_card }.jpg?time=${ new Date().getTime() }` : '#' };
} catch (error) {
const blockName = fileName + "--" + "checkPhoto";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 身份证二要素核验
async CNTEV(user_name, identity_card) {
const { ctx } = this;
try {
let attributes = ['real_check'],
where = { user_name, identity_card },
dbOptions = { attributes, where };
const result = await ctx.model.Examinee.findOne(dbOptions);
if (result == null) return false;
return result.dataValues.real_check;
} catch (error) {
const blockName = fileName + "--" + "CNTEV";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 身份证二要素核验状态更新
async updateCNTEV(user_name, identity_card, real_check) {
const { ctx } = this;
try {
const where = { user_name, identity_card };
await ctx.model.Examinee.update({ real_check }, { where });
await ctx.model.Audit.update({ status: real_check }, { where });
} catch (error) {
const blockName = fileName + "--" + "CNTEV";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 用户上传照片接口
async uploadPhoto(uid, files) {
const { ctx } = this;
try {
let attributes = ['identity_card'],
where = { uid },
dbOptions = { attributes, where };
const result = await ctx.model.Examinee.findOne(dbOptions);
if (result == null) return false;
// 重命名用户上传的文件并保存到证件照文件夹中
files[0].filename = result.dataValues.identity_card + '.jpg';
const { filename, filepath } = files[0];
const uploadDir = path.join(__dirname, '../public/userPhoto'); // 设置文件保存目录
// const uploadDir = '/disk/a/userPhoto'; // 设置服务器文件保存目录
const newPath = path.join(uploadDir, filename); // 构造新文件路径
// 确保上传目录存在
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
// 使用 copyFileSync 复制文件,而不是 renameSync
fs.copyFileSync(filepath, newPath);
// 删除临时文件
fs.unlinkSync(filepath);
return true;
} catch (error) {
const blockName = fileName + "--" + "uploadPhoto";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
// 用户找回密码接口
async resetPassword(updateForm, phone) {
const { ctx } = this;
try {
const result = await ctx.model.Examinee.update(updateForm, { where: { phone } });
return result[0] == 0 ? false : result;
} catch (error) {
const blockName = fileName + "--" + "resetPassword";
ctx.app.middleware.log('../../serviceLog', blockName + ">>>>" + error);
return 'error';
}
}
}
module.exports = UserService;