Commit 9b343953 by chenjinjing

no message

parents
.idea
/out
/node_modules
/test
/public
/logs
/video
*.logs
*.zip
*.mp4
*.png
/nm_backups
/res
{
// 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
{
"compile-hero.disable-compile-files-on-did-save-code": true
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "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",
"connect-history-api-fallback": "^2.0.0",
"express": "^4.21.2",
"express-async-handler": "^1.1.4",
"express-history-api-fallback": "^2.2.1",
"formidable": "^1.2.1",
"iconv-lite": "^0.7.0",
"log4js": "^6.6.1",
"lru-cache": "^4.1.5",
"md5": "^2.2.1",
"moment": "^2.24.0",
"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.32.1",
"ssh2": "^1.17.0",
"svg-captcha": "^1.3.12",
"tencentcloud-sdk-nodejs": "^4.0.562",
"winston": "^3.17.0",
"ws": "^5.2.2",
"xml2js": "^0.4.23",
"xmlrpc": "^1.3.2"
},
"devDependencies": {
"@types/express": "^5.0.0"
},
"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>13261</port>
<sign></sign>
<img>http://192.168.0.71:13261</img>
<dbServer>http://127.0.0.1:13261</dbServer>
<abilitycomparison>http://192.168.0.71:13276/gzn/throwmethod/abilitycomparison</abilitycomparison>
<mysqldb>
<!-- 本地mysql配置 -->
<mysqlHost>127.0.0.1</mysqlHost>
<mysqlPort>3306</mysqlPort>
<mysqlUser>root</mysqlUser>
<mysqlPwd>123456</mysqlPwd>
<dataBase>nanmoMentorPlatform</dataBase>
<!-- 服务器mysql配置 -->
<!-- <mysqlHost>127.0.0.1</mysqlHost>
<mysqlPort>3306</mysqlPort>
<mysqlUser>root</mysqlUser>
<mysqlPwd>123456</mysqlPwd>
<dataBase>nanmoMentorPlatform</dataBase> -->
</mysqldb>
<!-- XML-RPC服务器配置 -->
<xmlRpcServer>
<enabled>true</enabled>
<port>13277</port>
<host>localhost</host>
<path>/gzn/rpc</path>
<auth>
<username>K12RPC</username>
<password>K12RPCPwd</password>
</auth>
</xmlRpcServer>
</config>
This diff is collapsed. Click to expand it.
/**师生交流 */
import { selectDataListByParam, selectOneDataByParam, selectPaginatedDataWithOrder } from "../../data/findData";
import { markReminderAsHandled, REMINDER_TYPE } from './communicationReminder';
import { updateManyData } from "../../data/updateData";
import { addData } from "../../data/addData";
import { delData } from "../../data/delData";
import { TABLENAME } from "../../config/dbEnum";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
import { getCurrentSemester } from "../common/semesterService";
import { COMMUNICATIONTYPE } from "../../config/enum";
import { hasData } from "../../tools/system";
/**
* 师生交流详情
* @param id 交流记录ID
*/
export async function communicationInfo(id: number) {
let comm = await selectOneDataByParam(TABLENAME.交流记录表, { id: id });
if (!hasData(comm)) {
throw new BizError(ERRORENUM.未找到数据, `交流记录${id}不存在`);
}
if (comm.data.main_type !== COMMUNICATIONTYPE.师生交流) {
throw new BizError(ERRORENUM.参数错误, `记录${id}不是师生交流类型`);
}
let subtype = await selectOneDataByParam(TABLENAME.交流记录子类型表, { id: comm.data.subtype_id });
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: comm.data.student_id });
let studentProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, { user_id: comm.data.student_id });
let classInfo = null;
if (studentProfile.data && studentProfile.data.class_id) {
classInfo = await selectOneDataByParam(TABLENAME.班级表, { id: studentProfile.data.class_id });
}
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: comm.data.teacher_id });
return {
dataInfo: {
id: comm.data.id,
date: comm.data.date,
location: comm.data.location,
subtype_id: comm.data.subtype_id,
subtype_name: subtype.data ? subtype.data.subtype_name : '',
student_id: comm.data.student_id,
student_name: student.data ? student.data.user_name : '',
student_grade_class: classInfo && classInfo.data ? classInfo.data.full_name : '',
teacher_id: comm.data.teacher_id,
teacher_name: teacher.data ? teacher.data.user_name : '',
content: comm.data.content,
semester_id: comm.data.semester_id
}
};
}
/**
* 师生交流-新增
* @param param 交流参数
*/
export async function communicationAdd(param: { student_id:string; teacher_id:string; date:string; location:string; subtype_id:number; content:string; }) {
let semester = await getCurrentSemester();
// 校验子类型是否存在且属于师生交流
let subtype = await selectOneDataByParam(TABLENAME.交流记录子类型表, { id: param.subtype_id });
if (!hasData(subtype)) {
throw new BizError(ERRORENUM.未找到数据, `交流子类型${param.subtype_id}不存在`);
}
if (subtype.data.main_type !== COMMUNICATIONTYPE.师生交流) {
throw new BizError(ERRORENUM.参数错误, `交流子类型${subtype.data.subtype_name}不属于师生交流类别`);
}
// 校验学生是否存在
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: param.student_id });
if (!hasData(student)) {
throw new BizError(ERRORENUM.未找到数据, `学生${param.student_id}不存在`);
}
// 校验导师是否存在
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: param.teacher_id });
if (!hasData(teacher)) {
throw new BizError(ERRORENUM.未找到数据, `导师${param.teacher_id}不存在`);
}
await addData(TABLENAME.交流记录表, {
main_type: COMMUNICATIONTYPE.师生交流,
subtype_id: param.subtype_id,
semester_id: semester.id,
teacher_id: param.teacher_id,
student_id: param.student_id,
date: param.date,
location: param.location || '',
content: param.content
});
// 【新增】标记师生交流提醒为已处理
await markReminderAsHandled(REMINDER_TYPE.师生交流, param.student_id, param.teacher_id);
return { isSuccess: true };
}
/**
* 师生交流-编辑
* @param id 交流记录ID
* @param param 修改参数
*/
export async function communicationUpdate(id: number, param: {
date?: string;
location?: string;
subtype_id?: number;
content?: string;
}) {
let comm = await selectOneDataByParam(TABLENAME.交流记录表, { id: id });
if (!hasData(comm)) {
throw new BizError(ERRORENUM.未找到数据, `交流记录${id}不存在`);
}
// 如果修改子类型,校验新子类型
if (param.subtype_id) {
let subtype = await selectOneDataByParam(TABLENAME.交流记录子类型表, { id: param.subtype_id });
if (!hasData(subtype)) {
throw new BizError(ERRORENUM.未找到数据, `交流子类型${param.subtype_id}不存在`);
}
if (subtype.data.main_type !== COMMUNICATIONTYPE.师生交流) {
throw new BizError(ERRORENUM.参数错误, `交流子类型${subtype.data.subtype_name}不属于师生交流类别`);
}
}
let updateData: any = {};
if (param.date !== undefined) updateData.date = param.date;
if (param.location !== undefined) updateData.location = param.location;
if (param.subtype_id !== undefined) updateData.subtype_id = param.subtype_id;
if (param.content !== undefined) updateData.content = param.content;
if (Object.keys(updateData).length > 0) {
await updateManyData(TABLENAME.交流记录表, { id: id }, updateData);
}
return { isSuccess: true };
}
/**
* 师生交流-删除
* @param id 交流记录ID
*/
export async function communicationDelete(id: number) {
let comm = await selectOneDataByParam(TABLENAME.交流记录表, { id: id });
if (!hasData(comm)) {
throw new BizError(ERRORENUM.未找到数据, `交流记录${id}不存在`);
}
await delData(TABLENAME.交流记录表, { id: id });
return { isSuccess: true };
}
/**交流子类型管理 */
import { selectDataListByParam, selectOneDataByParam, selectPaginatedDataWithOrder } from "../../data/findData";
import { updateManyData } from "../../data/updateData";
import { addData } from "../../data/addData";
import { delData } from "../../data/delData";
import { TABLENAME } from "../../config/dbEnum";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
import { COMMUNICATIONTYPE } from "../../config/enum";
import { hasData } from "../../tools/system";
/**
* 交流子类型列表
*/
export async function communicationSubtypeList( ) {
let result = await selectDataListByParam( TABLENAME.交流记录子类型表, {}, ["id", "main_type", "subtype_name"] );
// 添加主类型名称
let dataList = result.data.map((item: any) => ({
id: item.id,
// main_type_name: item.main_type === COMMUNICATIONTYPE.师生交流 ? '师生交流' : '家校沟通',
subtype_name: item.subtype_name
}));
return {
count: dataList.length,
dataList
};
}
/**
* 获取启用的交流子类型(用于下拉选择)
* @param mainType 主类型(必填,1-师生交流,2-家校沟通)
*/
export async function getActiveCommunicationSubtypes(mainType: number) {
let selectParam: any = {
main_type: mainType,
is_active: true
};
let typeList = await selectDataListByParam(
TABLENAME.交流记录子类型表,
selectParam,
["id", "subtype_name"]
);
return typeList.data;
}
/**
* 交流子类型详情
* @param id 类型ID
*/
export async function communicationSubtypeInfo(id: number) {
let type = await selectOneDataByParam(TABLENAME.交流记录子类型表, { id: id });
if (!hasData(type)) throw new BizError(ERRORENUM.未找到数据, `交流子类型${id}不存在`);
let dataInfo = {
id: type.data.id,
subtype_name: type.data.subtype_name,
}
return { dataInfo };
}
/**
* 交流子类型新增
* @param param 类型参数
*/
export async function communicationSubtypeAdd(param: { subtype_name: string; }) {
// 检查子类型名称是否已存在(同一主类型下不能重复)
let existing = await selectOneDataByParam(TABLENAME.交流记录子类型表, {
main_type: COMMUNICATIONTYPE.师生交流,
subtype_name: param.subtype_name
});
if (hasData(existing)) {
throw new BizError(ERRORENUM.数据已存在, `师生交流下已存在子类型【${param.subtype_name}】`);
}
await addData(TABLENAME.交流记录子类型表, {
main_type: COMMUNICATIONTYPE.师生交流,
subtype_name: param.subtype_name,
is_active: true
});
return { isSuccess: true };
}
/**
* 交流子类型编辑
* @param id 类型ID
* @param param 修改参数
*/
export async function communicationSubtypeUpdate(id:number, subtype_name:string) {
let type = await selectOneDataByParam(TABLENAME.交流记录子类型表, { id: id });
if (!hasData(type)) {
throw new BizError(ERRORENUM.未找到数据, `交流子类型${id}不存在`);
}
// 如果修改子类型名称,检查是否重复
if (subtype_name && subtype_name !== type.data.subtype_name) {
let existing = await selectOneDataByParam(TABLENAME.交流记录子类型表, { main_type: type.data.main_type, subtype_name });
if (hasData(existing) && existing.data.id !== id) {
let mainTypeName = type.data.main_type === COMMUNICATIONTYPE.师生交流 ? '师生交流' : '家校沟通';
throw new BizError(ERRORENUM.数据已存在, `【${mainTypeName}】下已存在子类型【${subtype_name}】`);
}
}
let updateData: any = {};
if (subtype_name !== undefined) updateData.subtype_name = subtype_name;
if (Object.keys(updateData).length > 0) {
await updateManyData(TABLENAME.交流记录子类型表, { id: id }, updateData);
}
return { isSuccess: true };
}
/**
* 交流子类型删除
* @param id 类型ID
*/
export async function communicationSubtypeDelete(id: number) {
// 检查是否有交流记录使用了该子类型
let communicationList = await selectDataListByParam(TABLENAME.交流记录表, { subtype_id: id });
if (communicationList.data.length > 0) {
throw new BizError(ERRORENUM.数据被引用, `该交流子类型已被${communicationList.data.length}条交流记录使用,无法删除`);
}
await delData(TABLENAME.交流记录子类型表, { id });
return { isSuccess: true };
}
/**
* 管理员数据看板
*/
import { selectDataCountByParam, selectDataListByParam, selectOneDataByParam, selectSumValue } from "../../data/findData";
import { TABLENAME } from "../../config/dbEnum";
import { USERROLE, MATCHTYPE } from "../../config/enum";
import { getCurrentSemester } from "../common/semesterService";
import moment from "moment";
/**
* 管理员首页数据看板
* @param adminId 管理员ID(用于获取管理员名称)
*/
export async function dashboard(adminId: string) {
// 获取当前学期
const semester = await getCurrentSemester();
const semesterStart = semester?.start_date ? moment(semester.start_date).startOf('day').valueOf() : null;
const semesterEnd = semester?.end_date ? moment(semester.end_date).endOf('day').valueOf() : null;
// 1. 管理员名称
const adminName = await getAdminName(adminId);
// 2. 统计数据
const statistics = await getStatistics(semester);
// 3. 记录类型统计
const recordTypeStats = await getRecordTypeStats(semester, semesterStart, semesterEnd);
// 4. 导师指导次数(基于当前学期交流记录)
const teacherGuidanceCounts = await getTeacherGuidanceCounts(semester, semesterStart, semesterEnd);
return {
adminName,
statistics,
recordTypeStats,
teacherGuidanceCounts
};
}
/**
* 获取管理员名称
*/
async function getAdminName(adminId: string) {
const admin = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: adminId });
return admin.data?.user_name || '管理员';
}
/**
* 获取统计数据
*/
async function getStatistics(semester: any) {
// 导师总数
const teacherCountRes = await selectDataCountByParam(TABLENAME.用户扩展信息表, {
roles: { "%like%": USERROLE.教师.toString() }
});
const teacherCount = teacherCountRes.data || 0;
// 学生总数
const studentCountRes = await selectDataCountByParam(TABLENAME.用户扩展信息表, {
roles: { "%like%": USERROLE.学生.toString() }
});
const studentCount = studentCountRes.data || 0;
// 已匹配学生数(当前学期)
let matchedCount = 0;
if (semester) {
const matchedRes = await selectDataCountByParam(TABLENAME.师生匹配表, {
semester_id: semester.id,
is_active: true
});
matchedCount = matchedRes.data || 0;
}
const unmatchedCount = studentCount - matchedCount;
// 过程性记录数 = 交流记录 + 成长寄语 + 导师见面会 + 学生作品(个人上传)
const communicationCountRes = await selectDataCountByParam(TABLENAME.交流记录表, {});
const growthCountRes = await selectDataCountByParam(TABLENAME.成长寄语表, {});
const meetingCountRes = await selectDataCountByParam(TABLENAME.导师见面会表, {});
const workCountRes = await selectDataCountByParam(TABLENAME.作品表, { type: '个人上传' });
const processRecordCount = (communicationCountRes.data || 0) +
(growthCountRes.data || 0) +
(meetingCountRes.data || 0) +
(workCountRes.data || 0);
return {
teacherCount,
studentCount,
matchedStudentCount: matchedCount,
unmatchedStudentCount: unmatchedCount,
processRecordCount
};
}
/**
* 获取记录类型统计(基于当前学期,若学期有时间范围则过滤)
*/
async function getRecordTypeStats(semester: any, semesterStart: number | null, semesterEnd: number | null) {
// 构建时间过滤条件(若学期有起止时间)
const dateFilter: any = {};
if (semesterStart && semesterEnd) {
dateFilter.date = { "%gte%": semesterStart, "%lte%": semesterEnd };
}
// 师生交流数量(交流记录表 main_type = 1)
const teacherStudentCommRes = await selectDataCountByParam(TABLENAME.交流记录表, {
...dateFilter,
main_type: 1
});
const teacherStudentCommunication = teacherStudentCommRes.data || 0;
// 成长寄语数量
const growthRes = await selectDataCountByParam(TABLENAME.成长寄语表,
semester ? { semester_id: semester.id } : {}
);
const growthMessageCount = growthRes.data || 0;
// 家校沟通数量(main_type = 2)
const parentTeacherCommRes = await selectDataCountByParam(TABLENAME.交流记录表, {
...dateFilter,
main_type: 2
});
const parentTeacherCommunication = parentTeacherCommRes.data || 0;
// 导师见面会数量(根据学期过滤,见面会表可能有 start_time 字段)
let meetingCount = 0;
if (semesterStart && semesterEnd) {
const meetingRes = await selectDataCountByParam(TABLENAME.导师见面会表, {
start_time: { "%gte%": semesterStart, "%lte%": semesterEnd }
});
meetingCount = meetingRes.data || 0;
} else {
const meetingRes = await selectDataCountByParam(TABLENAME.导师见面会表, {});
meetingCount = meetingRes.data || 0;
}
const mentorMeetingCount = meetingCount;
// 学生作品数量(个人上传)
const workRes = await selectDataCountByParam(TABLENAME.作品表, { type: '个人上传' });
const studentWorkCount = workRes.data || 0;
return {
teacherStudentCommunication,
growthMessageCount,
parentTeacherCommunication,
mentorMeetingCount,
studentWorkCount
};
}
/**
* 获取导师指导次数(当前学期内,每位导师的交流记录总数)
*/
async function getTeacherGuidanceCounts(semester: any, semesterStart: number | null, semesterEnd: number | null) {
// 获取所有导师列表
const teachers = await selectDataListByParam(TABLENAME.用户扩展信息表, {
roles: { "%like%": USERROLE.教师.toString() }
});
if (!teachers.data.length) return [];
// 构建时间过滤条件
const dateFilter: any = {};
if (semesterStart && semesterEnd) {
dateFilter.date = { "%gte%": semesterStart, "%lte%": semesterEnd };
}
// 统计每个导师的交流次数
const guidanceCounts = [];
for (const teacher of teachers.data) {
const teacherId = teacher.user_id;
const countRes = await selectDataCountByParam(TABLENAME.交流记录表, {
teacher_id: teacherId,
...dateFilter
});
const count = countRes.data || 0;
if (count > 0) { // 只返回有交流记录的导师(可选)
// 获取导师姓名
const teacherInfo = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: teacherId });
guidanceCounts.push({
teacherName: teacherInfo.data?.user_name || teacherId,
guidanceCount: count
});
}
}
// 按指导次数降序排列
guidanceCounts.sort((a, b) => b.guidanceCount - a.guidanceCount);
return guidanceCounts;
}
/**成长寄语管理 */
import { selectDataListByParam, selectOneDataByParam, selectPaginatedDataWithOrder } from "../../data/findData";
import { updateManyData } from "../../data/updateData";
import { addData } from "../../data/addData";
import { delData } from "../../data/delData";
import { TABLENAME } from "../../config/dbEnum";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
import { getCurrentSemester } from "../common/semesterService";
import { hasData } from "../../tools/system";
/**
* 成长寄语详情
* @param id 寄语ID
*/
export async function growthMessageInfo(id: number) {
let msg = await selectOneDataByParam(TABLENAME.成长寄语表, { id: id });
if (!hasData(msg)) {
throw new BizError(ERRORENUM.未找到数据, `成长寄语${id}不存在`);
}
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: msg.data.student_id });
let studentProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, { user_id: msg.data.student_id });
let classInfo = null;
if (studentProfile.data && studentProfile.data.class_id) {
classInfo = await selectOneDataByParam(TABLENAME.班级表, { id: studentProfile.data.class_id });
}
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: msg.data.teacher_id });
return {
dataInfo: {
id: msg.data.id,
date: msg.data.date,
student_id: msg.data.student_id,
student_name: student.data ? student.data.user_name : '',
student_grade_class: classInfo && classInfo.data ? classInfo.data.full_name : '',
teacher_id: msg.data.teacher_id,
teacher_name: teacher.data ? teacher.data.user_name : '',
content: msg.data.content,
semester_id: msg.data.semester_id
}
};
}
/**
* 成长寄语-新增
* @param param 寄语参数
*/
export async function growthMessageAdd(param: {
student_id: string;
teacher_id: string;
date: string;
content: string;
}) {
let semester = await getCurrentSemester();
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: param.student_id });
if (!hasData(student)) {
throw new BizError(ERRORENUM.未找到数据, `学生${param.student_id}不存在`);
}
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: param.teacher_id });
if (!hasData(teacher)) {
throw new BizError(ERRORENUM.未找到数据, `导师${param.teacher_id}不存在`);
}
await addData(TABLENAME.成长寄语表, {
semester_id: semester.id,
teacher_id: param.teacher_id,
student_id: param.student_id,
date: param.date,
content: param.content
});
return { isSuccess: true };
}
/**
* 成长寄语-编辑
* @param id 寄语ID
* @param param 修改参数
*/
export async function growthMessageUpdate(id: number, param: {
date?: string;
content?: string;
}) {
let msg = await selectOneDataByParam(TABLENAME.成长寄语表, { id: id });
if (!hasData(msg)) {
throw new BizError(ERRORENUM.未找到数据, `成长寄语${id}不存在`);
}
let updateData: any = {};
if (param.date !== undefined) updateData.date = param.date;
if (param.content !== undefined) updateData.content = param.content;
if (Object.keys(updateData).length > 0) {
await updateManyData(TABLENAME.成长寄语表, { id: id }, updateData);
}
return { isSuccess: true };
}
/**
* 成长寄语-删除
* @param id 寄语ID
*/
export async function growthMessageDelete(id: number) {
let msg = await selectOneDataByParam(TABLENAME.成长寄语表, { id: id });
if (!hasData(msg)) {
throw new BizError(ERRORENUM.未找到数据, `成长寄语${id}不存在`);
}
await delData(TABLENAME.成长寄语表, { id: id });
return { isSuccess: true };
}
/**导师见面会管理 */
import { selectDataListByParam, selectOneDataByParam, selectPaginatedDataWithOrder } from "../../data/findData";
import { updateManyData } from "../../data/updateData";
import { addData } from "../../data/addData";
import { delData } from "../../data/delData";
import { TABLENAME } from "../../config/dbEnum";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
import { getCurrentSemester } from "../common/semesterService";
import { hasData } from "../../tools/system";
import { randomId } from "../../tools/systemTools";
/**
* 导师见面会详情
* @param id 见面会ID
*/
export async function meetingInfo(id: number) {
let meeting = await selectOneDataByParam(TABLENAME.导师见面会表, { id: id });
if (!hasData(meeting)) {
throw new BizError(ERRORENUM.未找到数据, `见面会${id}不存在`);
}
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: meeting.data.teacher_id });
// 获取参与学生列表
let meetingStudents = await selectDataListByParam(TABLENAME.见面会学生表, { meeting_id: meeting.data.id });
let studentIds = meetingStudents.data.map((ms: any) => ms.student_id);
let studentList = [];
for (let studentId of studentIds) {
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: studentId });
let studentProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, { user_id: studentId });
let classInfo = null;
if (studentProfile.data && studentProfile.data.class_id) {
classInfo = await selectOneDataByParam(TABLENAME.班级表, { id: studentProfile.data.class_id });
}
studentList.push({
student_id: studentId,
student_name: student.data ? student.data.user_name : '',
grade_class: classInfo && classInfo.data ? classInfo.data.full_name : ''
});
}
// 解析附件JSON
let studentAttachments = meeting.data.student_attachments ? JSON.parse(meeting.data.student_attachments) : [];
let teacherAttachments = meeting.data.teacher_attachments ? JSON.parse(meeting.data.teacher_attachments) : [];
return {
dataInfo: {
id: meeting.data.id,
title: meeting.data.title,
start_time: meeting.data.start_time,
end_time: meeting.data.end_time,
location: meeting.data.location,
content: meeting.data.content,
teacher_id: meeting.data.teacher_id,
teacher_name: teacher.data ? teacher.data.user_name : '',
student_list: studentList,
student_attachments: studentAttachments,
teacher_attachments: teacherAttachments,
semester_id: meeting.data.semester_id
}
};
}
/**
* 导师见面会-新增
* @param param 见面会参数
*/
export async function meetingAdd(param: {
teacher_id: string;
title: string;
start_time: string;
end_time: string;
location: string;
content?: string;
student_ids?: string[];
student_attachments?: string[];
teacher_attachments?: string[];
}) {
let semester = await getCurrentSemester();
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: param.teacher_id });
if (!hasData(teacher)) {
throw new BizError(ERRORENUM.未找到数据, `导师${param.teacher_id}不存在`);
}
// 新增见面会
let meetingId = await addData(TABLENAME.导师见面会表, {
semester_id: semester.id,
teacher_id: param.teacher_id,
title: param.title,
start_time: param.start_time,
end_time: param.end_time,
location: param.location,
content: param.content || '',
student_attachments: param.student_attachments ? JSON.stringify(param.student_attachments) : null,
teacher_attachments: param.teacher_attachments ? JSON.stringify(param.teacher_attachments) : null
});
// 新增参与学生
if (param.student_ids && param.student_ids.length > 0) {
for (let studentId of param.student_ids) {
await addData(TABLENAME.见面会学生表, {
meeting_id: meetingId,
student_id: studentId
});
}
}
return { isSuccess: true };
}
/**
* 导师见面会-编辑
* @param id 见面会ID
* @param param 修改参数
*/
export async function meetingUpdate(id: number, param: {
title?: string;
start_time?: string;
end_time?: string;
location?: string;
content?: string;
student_ids?: string[];
student_attachments?: string[];
teacher_attachments?: string[];
}) {
let meeting = await selectOneDataByParam(TABLENAME.导师见面会表, { id: id });
if (!hasData(meeting)) {
throw new BizError(ERRORENUM.未找到数据, `见面会${id}不存在`);
}
let updateData: any = {};
if (param.title !== undefined) updateData.title = param.title;
if (param.start_time !== undefined) updateData.start_time = param.start_time;
if (param.end_time !== undefined) updateData.end_time = param.end_time;
if (param.location !== undefined) updateData.location = param.location;
if (param.content !== undefined) updateData.content = param.content;
if (param.student_attachments !== undefined) updateData.student_attachments = JSON.stringify(param.student_attachments);
if (param.teacher_attachments !== undefined) updateData.teacher_attachments = JSON.stringify(param.teacher_attachments);
if (Object.keys(updateData).length > 0) {
await updateManyData(TABLENAME.导师见面会表, { id: id }, updateData);
}
// 更新参与学生
if (param.student_ids !== undefined) {
// 删除原有
await delData(TABLENAME.见面会学生表, { meeting_id: id });
// 批量新增
for (let studentId of param.student_ids) {
await addData(TABLENAME.见面会学生表, {
meeting_id: id,
student_id: studentId
});
}
}
return { isSuccess: true };
}
/**
* 导师见面会-删除
* @param id 见面会ID
*/
export async function meetingDelete(id: number) {
let meeting = await selectOneDataByParam(TABLENAME.导师见面会表, { id: id });
if (!hasData(meeting)) {
throw new BizError(ERRORENUM.未找到数据, `见面会${id}不存在`);
}
// 删除关联的学生记录
await delData(TABLENAME.见面会学生表, { meeting_id: id });
// 删除见面会
await delData(TABLENAME.导师见面会表, { id: id });
return { isSuccess: true };
}
/**家校沟通管理 */
import { selectDataListByParam, selectOneDataByParam, selectPaginatedDataWithOrder } from "../../data/findData";
import { updateManyData } from "../../data/updateData";
import { addData } from "../../data/addData";
import { delData } from "../../data/delData";
import { TABLENAME } from "../../config/dbEnum";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
import { getCurrentSemester } from "../common/semesterService";
import { COMMUNICATIONTYPE } from "../../config/enum";
import { hasData } from "../../tools/system";
/**
* 家校沟通详情
* @param id 交流记录ID
*/
export async function parentCommunicationInfo(id: number) {
let comm = await selectOneDataByParam(TABLENAME.交流记录表, { id: id });
if (!hasData(comm)) {
throw new BizError(ERRORENUM.未找到数据, `交流记录${id}不存在`);
}
if (comm.data.main_type !== COMMUNICATIONTYPE.家校沟通) {
throw new BizError(ERRORENUM.参数错误, `记录${id}不是家校沟通类型`);
}
let subtype = await selectOneDataByParam(TABLENAME.交流记录子类型表, { id: comm.data.subtype_id });
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: comm.data.student_id });
let studentProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, { user_id: comm.data.student_id });
let classInfo = null;
if (studentProfile.data && studentProfile.data.class_id) {
classInfo = await selectOneDataByParam(TABLENAME.班级表, { id: studentProfile.data.class_id });
}
let parent = await selectOneDataByParam(TABLENAME.家长表, { parent_id: comm.data.parent_id });
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: comm.data.teacher_id });
return {
dataInfo: {
id: comm.data.id,
date: comm.data.date,
location: comm.data.location,
subtype_id: comm.data.subtype_id,
subtype_name: subtype.data ? subtype.data.subtype_name : '',
student_id: comm.data.student_id,
student_name: student.data ? student.data.user_name : '',
student_grade_class: classInfo && classInfo.data ? classInfo.data.full_name : '',
parent_id: comm.data.parent_id,
parent_name: parent.data ? parent.data.parent_name : '',
parent_phone: parent.data ? parent.data.phone : '',
teacher_id: comm.data.teacher_id,
teacher_name: teacher.data ? teacher.data.user_name : '',
content: comm.data.content,
semester_id: comm.data.semester_id
}
};
}
/**
* 家校沟通-新增
* @param param 交流参数
*/
export async function parentCommunicationAdd(param: { student_id:string; parent_id:string; teacher_id:string; date:string; location:string; subtype_id:number; content:string; }) {
let semester = await getCurrentSemester();
// 校验子类型是否存在且属于家校沟通
let subtype = await selectOneDataByParam(TABLENAME.交流记录子类型表, { id: param.subtype_id });
if (!hasData(subtype)) {
throw new BizError(ERRORENUM.未找到数据, `交流子类型${param.subtype_id}不存在`);
}
if (subtype.data.main_type !== COMMUNICATIONTYPE.家校沟通) {
throw new BizError(ERRORENUM.参数错误, `交流子类型${subtype.data.subtype_name}不属于家校沟通类别`);
}
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: param.student_id });
if (!hasData(student)) {
throw new BizError(ERRORENUM.未找到数据, `学生${param.student_id}不存在`);
}
let parent = await selectOneDataByParam(TABLENAME.家长表, { parent_id: param.parent_id });
if (!hasData(parent)) {
throw new BizError(ERRORENUM.未找到数据, `家长${param.parent_id}不存在`);
}
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: param.teacher_id });
if (!hasData(teacher)) {
throw new BizError(ERRORENUM.未找到数据, `导师${param.teacher_id}不存在`);
}
await addData(TABLENAME.交流记录表, {
main_type: COMMUNICATIONTYPE.家校沟通,
subtype_id: param.subtype_id,
semester_id: semester.id,
teacher_id: param.teacher_id,
student_id: param.student_id,
parent_id: param.parent_id,
date: param.date,
location: param.location || '',
content: param.content
});
return { isSuccess: true };
}
/**
* 家校沟通-编辑
* @param id 交流记录ID
* @param param 修改参数
*/
export async function parentCommunicationUpdate(id: number, param: {
date?: string;
location?: string;
subtype_id?: number;
content?: string;
}) {
let comm = await selectOneDataByParam(TABLENAME.交流记录表, { id: id });
if (!hasData(comm)) {
throw new BizError(ERRORENUM.未找到数据, `交流记录${id}不存在`);
}
if (param.subtype_id) {
let subtype = await selectOneDataByParam(TABLENAME.交流记录子类型表, { id: param.subtype_id });
if (!hasData(subtype)) {
throw new BizError(ERRORENUM.未找到数据, `交流子类型${param.subtype_id}不存在`);
}
if (subtype.data.main_type !== COMMUNICATIONTYPE.家校沟通) {
throw new BizError(ERRORENUM.参数错误, `交流子类型${subtype.data.subtype_name}不属于家校沟通类别`);
}
}
let updateData: any = {};
if (param.date !== undefined) updateData.date = param.date;
if (param.location !== undefined) updateData.location = param.location;
if (param.subtype_id !== undefined) updateData.subtype_id = param.subtype_id;
if (param.content !== undefined) updateData.content = param.content;
if (Object.keys(updateData).length > 0) {
await updateManyData(TABLENAME.交流记录表, { id: id }, updateData);
}
return { isSuccess: true };
}
/**
* 家校沟通-删除
* @param id 交流记录ID
*/
export async function parentCommunicationDelete(id: number) {
let comm = await selectOneDataByParam(TABLENAME.交流记录表, { id: id });
if (!hasData(comm)) {
throw new BizError(ERRORENUM.未找到数据, `交流记录${id}不存在`);
}
await delData(TABLENAME.交流记录表, { id: id });
return { isSuccess: true };
}
/** 公共下拉管理 */
import { selectDataListByParam, selectDataWithCustomOrder } from "../../data/findData";
import { TABLENAME } from "../../config/dbEnum";
import { getGradeName } from "../../tools/system";
/**
* 获取所有年级列表(去重)
* @returns { dataList: [{ id: number, key: string, value: number }] }
*/
export async function getAllGrades() {
let classList = await selectDataListByParam(
TABLENAME.班级表,
{},
["id", "grade"]
);
let gradeMap = new Map(); // 用于存储年级对应的班级id(取第一个班级的id作为年级id)
for (let item of (classList.data || [])) {
if (!gradeMap.has(item.grade)) {
gradeMap.set(item.grade, item.id);
}
}
let uniqueGrades: any = [...gradeMap.keys()];
// 按年级降序排列(高年级在前)
uniqueGrades.sort((a: number, b: number) => b - a);
let dataList = uniqueGrades.map((grade: number) => ({
id: gradeMap.get(grade), // 年级对应的班级id
key: getGradeName(grade), // 例如:2024 -> 当前年级名称(高一/高二/高三/已毕业)
value: grade
}));
return { dataList };
}
/**
* 根据年级获取班级列表
* @param grade 年级,如 2024
* @returns { dataList: [{ key: "1班", value: 班级ID }] }
*/
export async function getClassesByGrade(grade: number) {
let selectParam = {};
if (grade) { selectParam["grade"] = grade }
let classList = await selectDataWithCustomOrder(
TABLENAME.班级表,
selectParam,
["id", "class_name"],
[["id", "ASC"]] // 按班级名称升序
);
let dataList = (classList.data || []).map((item: any) => ({
key: item.class_name,
value: item.id
}));
return { dataList };
}
/**
* 获取所有科目列表(去重)
* @returns { dataList: [{ key: string, value: string }] }
*/
export async function getAllSubjects() {
let subjectList = await selectDataListByParam(
TABLENAME.教师任教科目表,
{},
["subject"]
);
// 去重
let uniqueSubjects: any = [...new Set((subjectList.data || []).map((item: any) => item.subject))];
// 按科目名称排序
uniqueSubjects.sort((a: string, b: string) => a.localeCompare(b, 'zh-CN'));
let dataList = uniqueSubjects.map((subject: string) => ({
key: subject,
value: subject
}));
return { dataList };
}
/**导师案例管理 */
import { selectDataListByParam, selectOneDataByParam, selectPaginatedDataWithOrder } from "../../data/findData";
import { updateManyData } from "../../data/updateData";
import { addData } from "../../data/addData";
import { delData } from "../../data/delData";
import { TABLENAME } from "../../config/dbEnum";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
import { getCurrentSemester } from "../common/semesterService";
import { hasData } from "../../tools/system";
import { getMySqlMs } from "../../tools/systemTools";
/**
* 导师案例详情
* @param id 案例ID
*/
export async function teacherCaseInfo(id: number) {
let tc = await selectOneDataByParam(TABLENAME.导师案例表, { id: id });
if (!hasData(tc)) {
throw new BizError(ERRORENUM.未找到数据, `导师案例${id}不存在`);
}
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: tc.data.teacher_id });
return {
dataInfo: {
id: tc.data.id,
case_name: tc.data.case_name,
attachment: tc.data.attachment,
upload_time: tc.data.upload_time,
teacher_id: tc.data.teacher_id,
teacher_name: teacher.data ? teacher.data.user_name : '',
semester_id: tc.data.semester_id
}
};
}
/**
* 导师案例-新增
* @param param 案例参数
*/
export async function teacherCaseAdd(param: {
teacher_id: string;
case_name: string;
attachment?: string;
}) {
let semester = await getCurrentSemester();
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: param.teacher_id });
if (!hasData(teacher)) {
throw new BizError(ERRORENUM.未找到数据, `导师${param.teacher_id}不存在`);
}
await addData(TABLENAME.导师案例表, {
semester_id: semester.id,
teacher_id: param.teacher_id,
case_name: param.case_name,
attachment: param.attachment || null,
upload_time: getMySqlMs()
});
return { isSuccess: true };
}
/**
* 导师案例-编辑
* @param id 案例ID
* @param param 修改参数
*/
export async function teacherCaseUpdate(id: number, param: {
case_name?: string;
attachment?: string;
}) {
let tc = await selectOneDataByParam(TABLENAME.导师案例表, { id: id });
if (!hasData(tc)) {
throw new BizError(ERRORENUM.未找到数据, `导师案例${id}不存在`);
}
let updateData: any = {};
if (param.case_name !== undefined) updateData.case_name = param.case_name;
if (param.attachment !== undefined) updateData.attachment = param.attachment;
if (Object.keys(updateData).length > 0) {
await updateManyData(TABLENAME.导师案例表, { id: id }, updateData);
}
return { isSuccess: true };
}
/**
* 导师案例-删除
* @param id 案例ID
*/
export async function teacherCaseDelete(id: number) {
let tc = await selectOneDataByParam(TABLENAME.导师案例表, { id: id });
if (!hasData(tc)) {
throw new BizError(ERRORENUM.未找到数据, `导师案例${id}不存在`);
}
await delData(TABLENAME.导师案例表, { id: id });
return { isSuccess: true };
}
/**
* 获取导师案例列表(不分页,用于下拉选择等)
* @param teacherId 导师ID(可选)
*/
export async function getTeacherCaseOptions(teacherId?: string) {
let semester = await getCurrentSemester();
let selectParam: any = {
semester_id: semester.id
};
if (teacherId) {
selectParam.teacher_id = teacherId;
}
let caseList = await selectDataListByParam(TABLENAME.导师案例表, selectParam, ["id", "case_name"]);
return caseList.data.map((tc: any) => ({
id: tc.id,
case_name: tc.case_name
}));
}
/**班主任首页数据看板 */
import { selectDataListByParam, selectOneDataByParam, selectDataCountByParam } from "../../data/findData";
import { TABLENAME } from "../../config/dbEnum";
import { getCurrentSemester } from "../common/semesterService";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
import { getUnreadNotificationCount } from "./notification";
/**
* 班主任首页数据看板
* @param headteacherId 班主任ID
* @param headteacherName 班主任姓名(由调用方传入)
*/
export async function headteacherDashboard(headteacherId: string, headteacherName: string) {
/**获取班主任所带班级 */
let classInfo = await selectOneDataByParam(TABLENAME.班级表, {
head_teacher_id: headteacherId
});
if (!classInfo.data) {
throw new BizError(ERRORENUM.权限不足, '您不是班主任');
}
let classId = classInfo.data.id;
let semester = await getCurrentSemester();
/**获取本班学生 */
let students = await selectDataListByParam(TABLENAME.用户扩展信息表, {
class_id: classId,
roles: { "%like%": 'student' }
});
let studentIds = students.data.map((s: any) => s.user_id);
/**统计学生总数 */
let studentCount = studentIds.length;
/**统计已匹配学生 */
let matchedCount:any = 0;
if (studentIds.length > 0) {
matchedCount = await selectDataCountByParam(TABLENAME.师生匹配表, {
student_id: { "%in%": studentIds },
semester_id: semester.id,
is_active: true
});
matchedCount = matchedCount.data;
}
/**统计未匹配学生 */
let unmatchedCount = studentCount - matchedCount;
/**统计今日交流 */
let todayStart = new Date();
todayStart.setHours(0, 0, 0, 0);
let todayEnd = new Date();
todayEnd.setHours(23, 59, 59, 999);
let todayCommunication:any = 0;
if (studentIds.length > 0) {
todayCommunication = await selectDataCountByParam(TABLENAME.交流记录表, {
student_id: { "%in%": studentIds },
date: {
"%gte%": todayStart.getTime(),
"%lte%": todayEnd.getTime()
}
});
todayCommunication = todayCommunication.data;
}
/**统计本周交流 */
let weekStart = new Date();
weekStart.setDate(weekStart.getDate() - weekStart.getDay());
weekStart.setHours(0, 0, 0, 0);
let weekEnd = new Date();
weekEnd.setHours(23, 59, 59, 999);
let weekCommunication:any = 0;
if (studentIds.length > 0) {
weekCommunication = await selectDataCountByParam(TABLENAME.交流记录表, {
student_id: { "%in%": studentIds },
date: {
"%gte%": weekStart.getTime(),
"%lte%": weekEnd.getTime()
}
});
weekCommunication = weekCommunication.data;
}
/**统计本月交流 */
let monthStart = new Date();
monthStart.setDate(1);
monthStart.setHours(0, 0, 0, 0);
let monthEnd = new Date();
monthEnd.setHours(23, 59, 59, 999);
let monthCommunication:any = 0;
if (studentIds.length > 0) {
monthCommunication = await selectDataCountByParam(TABLENAME.交流记录表, {
student_id: { "%in%": studentIds },
date: {
"%gte%": monthStart.getTime(),
"%lte%": monthEnd.getTime()
}
});
monthCommunication = monthCommunication.data;
}
/**统计本周成长寄语 */
let weekGrowth:any = 0;
if (studentIds.length > 0) {
weekGrowth = await selectDataCountByParam(TABLENAME.成长寄语表, {
student_id: { "%in%": studentIds },
date: {
"%gte%": weekStart.getTime(),
"%lte%": weekEnd.getTime()
}
});
weekGrowth = weekGrowth.data;
}
/**统计待处理预约(本班学生相关) */
let pendingAppointment = 0;
if (studentIds.length > 0) {
/**获取本班学生家长 */
let parents = await selectDataListByParam(TABLENAME.家长表, {
student_id: { "%in%": studentIds }
});
let parentIds = parents.data.map((p: any) => p.parent_id);
/**统计预约(学生或家长作为发起人或目标人) */
let appointmentCount1 = await selectDataCountByParam(TABLENAME.预约表, {
initiator_id: { "%in%": [...studentIds, ...parentIds] },
status: 1 // 待确认
});
let appointmentCount2 = await selectDataCountByParam(TABLENAME.预约表, {
target_id: { "%in%": [...studentIds, ...parentIds] },
status: 1 // 待确认
});
pendingAppointment = appointmentCount1.data + appointmentCount2.data;
}
/**获取最新消息 */
let latestNotifications = await selectDataListByParam(TABLENAME.消息通知表, {
"%orderDesc%": "time",
"%limit%": 5
});
let notifications = latestNotifications.data.map((item: any) => ({
id: item.id,
type: item.type,
title: item.title,
content: item.content,
related_users: item.related_users ? JSON.parse(item.related_users) : [],
time: item.time
}));
/**获取未读消息数量 */
let unreadCountResult = await getUnreadNotificationCount(headteacherId);
let unreadCount = unreadCountResult.count;
return {
/** 基础信息 */
basic_info: {
headteacher_name: headteacherName, // 班主任姓名
class_full_name: classInfo.data.full_name, // 完整班级名称
unread_message_count: unreadCount // 未读消息数
},
/** 统计数据 */
statistics: {
student_count: studentCount, // 班级学生总数
matched_count: matchedCount, // 已匹配导师学生数
unmatched_count: unmatchedCount, // 未匹配学生数
matched_rate: studentCount ? Math.round((matchedCount / studentCount) * 100) : 0, // 匹配率
week_growth: weekGrowth, // 本周成长寄语数
today_communication: todayCommunication, // 今日交流数
week_communication: weekCommunication, // 本周交流数
month_communication: monthCommunication, // 本月交流数
pending_appointment: pendingAppointment // 待处理预约数
},
/** 最新消息通知(最多5条) */
latest_notifications: notifications
};
}
/**成长寄语汇总 */
import { selectDataListByParam, selectOneDataByParam, selectPaginatedDataWithOrder, selectDataToTableAssociation } from "../../data/findData";
import { TABLENAME } from "../../config/dbEnum";
import { getCurrentSemester } from "../common/semesterService";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
/**
* 获取本班学生成长寄语汇总(支持按学生ID、学期ID筛选,均为可选)
* - 不传 studentId:返回全班学生的寄语
* - 不传 semesterId:返回所有学期的寄语
*/
export async function getClassGrowthMessages(
headteacherId: string,
params: { studentId?: string; semesterId?: number; page?: number; pageSize?: number }
) {
let { studentId, semesterId, page = 1, pageSize = 10 } = params;
// 1. 获取班主任所带班级
let classInfo = await selectOneDataByParam(TABLENAME.班级表, {
head_teacher_id: headteacherId,
});
if (!classInfo.data) {
throw new BizError(ERRORENUM.权限不足, '您不是班主任');
}
const classId = classInfo.data.id;
// 2. 确定学生ID列表
let studentIds: string[] = [];
if (studentId && studentId.trim() !== '') {
// 校验学生是否在本班且为学生角色(角色代码为 3)
let studentProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, {
user_id: studentId,
class_id: classId,
roles: { "%like%": '3' }, // 学生角色代码
});
if (!studentProfile.data) {
throw new BizError(ERRORENUM.权限不足, '该学生不在您管理的班级');
}
studentIds = [studentId];
} else {
// 获取本班所有学生
let students = await selectDataListByParam(TABLENAME.用户扩展信息表, {
class_id: classId,
roles: { "%like%": '3' }, // 学生角色代码
});
studentIds = students.data.map((s: any) => s.user_id);
if (studentIds.length === 0) {
return { count: 0, dataList: [] };
}
}
// 3. 查询条件
let selectParam: any = {
student_id: { "%in%": studentIds },
};
if (semesterId) {
selectParam.semester_id = semesterId;
}
// 4. 分页查询
let result = await selectPaginatedDataWithOrder(
TABLENAME.成长寄语表,
selectParam,
["id", "student_id", "teacher_id", "semester_id", "date", "content"],
page,
pageSize,
[["date", "DESC"]]
);
// 5. 组装返回数据
let dataList = [];
for (let msg of result.data) {
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: msg.student_id });
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: msg.teacher_id });
let semester = await selectOneDataByParam(TABLENAME.学期表, { id: msg.semester_id });
dataList.push({
id: msg.id,
student_id: msg.student_id,
student_name: student.data ? student.data.user_name : '',
student_class: classInfo.data.full_name,
teacher_id: msg.teacher_id,
teacher_name: teacher.data ? teacher.data.user_name : '',
semester_id: msg.semester_id,
semester_name: semester.data ? semester.data.name : '',
date: msg.date,
content: msg.content,
});
}
return {
count: result.pagination.total,
dataList,
};
}
/**
* 导出本班成长寄语
* @param headteacherId 班主任ID
*/
export async function exportClassGrowthMessages(headteacherId: string) {
/**获取班主任所带班级 */
let classInfo = await selectOneDataByParam(TABLENAME.班级表, {
head_teacher_id: headteacherId
});
if (!classInfo.data) {
throw new BizError(ERRORENUM.权限不足, '您不是班主任');
}
/**获取本班学生 */
let students = await selectDataListByParam(TABLENAME.用户扩展信息表, {
class_id: classInfo.data.id,
roles: { "%like%": 'student' }
});
if (students.data.length === 0) {
return [];
}
let studentIds = students.data.map((s: any) => s.user_id);
/**获取所有成长寄语 */
let messages = await selectDataListByParam(TABLENAME.成长寄语表, {
student_id: { "%in%": studentIds }
});
/**构建导出数据 */
let exportData = [];
for (let msg of messages.data) {
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: msg.student_id });
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: msg.teacher_id });
let semester = await selectOneDataByParam(TABLENAME.学期表, { id: msg.semester_id });
exportData.push({
student_name: student.data ? student.data.user_name : '',
student_class: classInfo.data.full_name,
teacher_name: teacher.data ? teacher.data.user_name : '',
semester_name: semester.data ? semester.data.name : '',
date: msg.date,
content: msg.content
});
}
return exportData;
}
import { selectDataListByParam, selectOneDataByParam } from "../../data/findData";
import { updateManyData } from "../../data/updateData";
import { TABLENAME, TABLEID } from "../../config/dbEnum";
import { USERROLE } from "../../config/enum";
import { getMySqlMs, randomId } from "../../tools/systemTools";
import { BizError } from "../../util/bizError";
import { addData } from "../../data/addData";
import { ERRORENUM } from "../../config/errorEnum";
/**
* 初始化学生和教师数据
* 从 uac_user 同步到 user_profile
*/
export async function initUserData() {
console.log('🚀 开始初始化用户数据...');
/**1. 获取所有活跃的UAC用户 */
let uacUsers = await selectDataListByParam(TABLENAME.统一用户表, {
active_flag: 1 // 只同步活跃用户
});
console.log(`📊 从UAC获取到 ${uacUsers.data.length} 个活跃用户`);
let studentCount = 0;
let teacherCount = 0;
let adminCount = 0;
let skipCount = 0;
/**2. 遍历处理每个用户 */
for (let uacUser of uacUsers.data) {
/**解析用户类型 */
let roles = parseUacUserType(uacUser.user_type);
if (roles.length === 0) {
console.log(`用户 ${uacUser.user_id} 无有效角色,跳过`);
skipCount++;
continue;
}
/**检查是否已存在 */
let existing = await selectOneDataByParam(TABLENAME.用户扩展信息表, {
user_id: uacUser.user_id
});
if (existing.data && Object.keys(existing.data).length > 0) {
console.log(`用户 ${uacUser.user_id} 已存在,跳过`);
skipCount++;
continue;
}
/**创建用户扩展信息 - 默认权限为0 */
let profileData: any = {
user_id: uacUser.user_id,
roles: roles.join(','),
permission: 0, // 默认非管理员
created_at: getMySqlMs()
};
/**如果是教师,设置教师特有字段 */
if (roles.includes(USERROLE.教师)) {
let isClassTeacher = await checkIsClassTeacher(uacUser.user_id);
profileData.is_class_teacher = isClassTeacher;
profileData.max_students = 20; // 默认最大带生数
profileData.political_status = ''; // 默认为空
teacherCount++;
}
/**如果是学生,设置学生特有字段 */
if (roles.includes(USERROLE.学生)) {
profileData.is_youth_party_school = false;
profileData.student_no = ''; // 学号需要后续从教务系统同步或手动录入
profileData.middle_school = ''; // 默认为空
studentCount++;
}
/**写入数据库 */
await addData(TABLENAME.用户扩展信息表, profileData);
console.log(`✅ 创建用户: ${uacUser.user_id}, 角色: ${roles.join(',')}, 权限: 普通用户`);
}
console.log(`🎉 用户数据初始化完成!`);
console.log(`📊 统计:总处理 ${uacUsers.data.length} 人,新增学生 ${studentCount} 人,新增教师 ${teacherCount} 人,跳过 ${skipCount} 人`);
console.log(`⚠️ 注意:所有用户初始权限均为普通用户,管理员需手动在后台设置`);
return {
total: uacUsers.data.length,
students: studentCount,
teachers: teacherCount,
skipped: skipCount
};
}
/**
* 同步单个用户(可用于UAC回调)
* @param userId 用户ID
*/
export async function syncSingleUser(userId: string) {
let uacUser = await selectOneDataByParam(TABLENAME.统一用户表, {
user_id: userId,
active_flag: 1
});
if (!uacUser.data || Object.keys(uacUser.data).length === 0) {
console.log(`用户 ${userId} 不存在或不活跃`);
return false;
}
let roles = parseUacUserType(uacUser.data.user_type);
if (roles.length === 0) {
console.log(`用户 ${userId} 无有效角色`);
return false;
}
let existing = await selectOneDataByParam(TABLENAME.用户扩展信息表, {
user_id: userId
});
let profileData: any = {
user_id: userId,
roles: roles.join(','),
permission: 0 // 默认非管理员
};
if (roles.includes(USERROLE.教师)) {
let isClassTeacher = await checkIsClassTeacher(userId);
profileData.is_class_teacher = isClassTeacher;
profileData.max_students = 20;
}
if (roles.includes(USERROLE.学生)) {
profileData.is_youth_party_school = false;
}
if (existing.data && Object.keys(existing.data).length > 0) {
// 更新
await updateManyData(TABLENAME.用户扩展信息表, { user_id: userId }, profileData);
console.log(`✅ 更新用户: ${userId}`);
} else {
// 新增
profileData.created_at = getMySqlMs();
await addData(TABLENAME.用户扩展信息表, profileData);
console.log(`✅ 创建用户: ${userId}`);
}
return true;
}
/**
* 设置管理员权限(单独的方法,供管理员手动调用)
* @param userId 用户ID
*/
export async function setAdminPermission(userId: string) {
let userProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, {
user_id: userId
});
if (!userProfile.data || Object.keys(userProfile.data).length === 0) {
throw new BizError(ERRORENUM.未找到数据, '用户不存在');
}
/**获取当前角色 */
let roles = userProfile.data.roles ? userProfile.data.roles.split(',').map((r: string) => parseInt(r)) : [];
/**如果还没有管理员角色,添加 */
if (!roles.includes(USERROLE.管理员)) {
roles.push(USERROLE.管理员);
}
await updateManyData(TABLENAME.用户扩展信息表, { user_id: userId }, {
roles: roles.join(','),
permission: 1
});
console.log(`✅ 用户 ${userId} 已设置为管理员`);
return true;
}
/**
* 取消管理员权限
* @param userId 用户ID
*/
export async function removeAdminPermission(userId: string) {
let userProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, {
user_id: userId
});
if (!userProfile.data || Object.keys(userProfile.data).length === 0) {
throw new BizError(ERRORENUM.未找到数据, '用户不存在');
}
/**移除管理员角色 */
let roles = userProfile.data.roles ? userProfile.data.roles.split(',').map((r: string) => parseInt(r)) : [];
roles = roles.filter(r => r !== USERROLE.管理员);
await updateManyData(TABLENAME.用户扩展信息表, { user_id: userId }, {
roles: roles.join(','),
permission: 0
});
console.log(`✅ 用户 ${userId} 已取消管理员权限`);
return true;
}
/**
* 解析UAC用户类型为系统角色ID
* UAC user_type: 5位字符串,分别代表一般注册用户、行政管理人员、教职员工、学生、家长
*/
function parseUacUserType(userType: string): number[] {
let roles: number[] = [];
if (!userType || userType.length < 5) {
return roles;
}
// 第4位:学生
if (userType.charAt(3) === '1') {
roles.push(USERROLE.学生); // 3
}
// 第3位:教职员工(包含导师和班主任)
if (userType.charAt(2) === '1') {
roles.push(USERROLE.教师); // 2
}
// 注意:管理员角色不自动添加,需要手动设置
// 行政管理人员(第2位)也不自动转为管理员
return roles;
}
/**
* 检查教师是否是班主任
*/
async function checkIsClassTeacher(teacherId: string): Promise<boolean> {
let classInfo = await selectOneDataByParam(TABLENAME.班级表, {
head_teacher_id: teacherId
});
return classInfo.data && Object.keys(classInfo.data).length > 0;
}
\ No newline at end of file
/**
* 孩子成长寄语
*/
import { selectDataListByParam, selectOneDataByParam, selectPaginatedDataWithOrder } from "../../data/findData";
import { TABLENAME } from "../../config/dbEnum";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
/**
* 获取孩子成长寄语列表
* @param parentId 家长ID
* @param page 页码
* @param pageSize 每页大小
*/
export async function getChildGrowthMessages(parentId:string, semesterId:string, page:number = 1, pageSize:number = 10) {
/**获取家长信息 */
let parent = await selectOneDataByParam(TABLENAME.家长表, { parent_id: parentId });
if (!parent.data) {
throw new BizError(ERRORENUM.未找到数据, '家长不存在');
}
let studentId = parent.data.student_id;
/**获取学生姓名(从统一用户表查询) */
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: studentId });
let studentName = student.data ? student.data.user_name : '';
/**查询成长寄语 */
let selectParam: any = {
student_id: studentId
};
/**如果传入了学期ID,则按学期筛选 */
if (semesterId !== undefined && semesterId !== null) {
selectParam.semester_id = semesterId;
}
let result = await selectPaginatedDataWithOrder(
TABLENAME.成长寄语表,
selectParam,
["id", "teacher_id", "student_id", "semester_id", "date", "content"],
page,
pageSize,
[["date", "DESC"]]
);
/**补充导师信息和学期信息 */
let dataList = [];
for (let msg of result.data) {
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: msg.teacher_id });
let semesterInfo = await selectOneDataByParam(TABLENAME.学期表, { id: msg.semester_id });
dataList.push({
id: msg.id,
studentName: studentName, // 添加学生姓名
teacherName: teacher.data ? teacher.data.user_name : '',
semesterName: semesterInfo.data ? semesterInfo.data.name : '',
date: msg.date,
content: msg.content
});
}
return {
dataList,
pagination: result.pagination.total
};
}
/**
* 获取成长寄语详情
* @param parentId 家长ID
* @param messageId 寄语ID
*/
export async function getChildGrowthMessageDetail(parentId: string, messageId: string) {
/**参数校验 */
if (!messageId) {
throw new BizError(ERRORENUM.参数错误, '寄语ID不能为空');
}
/**获取家长信息 */
let parent = await selectOneDataByParam(TABLENAME.家长表, { parent_id: parentId });
if (!parent.data) {
throw new BizError(ERRORENUM.未找到数据, '家长不存在');
}
let studentId = parent.data.student_id;
/**查询成长寄语 */
let message = await selectOneDataByParam(TABLENAME.成长寄语表, { id: messageId });
if (!message.data) {
throw new BizError(ERRORENUM.未找到数据, '成长寄语不存在');
}
/**验证权限:必须是该学生的寄语 */
if (message.data.student_id !== studentId) {
throw new BizError(ERRORENUM.权限不足, '您无权查看该成长寄语');
}
/**获取导师信息 */
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: message.data.teacher_id });
let teacherProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, {
user_id: message.data.teacher_id
});
/**获取学期信息 */
let semester = await selectOneDataByParam(TABLENAME.学期表, { id: message.data.semester_id });
return {
id: message.data.id,
teacher: {
id: message.data.teacher_id,
name: teacher.data ? teacher.data.user_name : '',
gender: teacher.data ? teacher.data.gender : '',
political_status: teacherProfile.data ? teacherProfile.data.political_status : ''
},
semester: {
id: message.data.semester_id,
name: semester.data ? semester.data.name : ''
},
date: message.data.date,
content: message.data.content
};
}
/**
* 获取当前学期
*/
async function getCurrentSemester() {
let semesterList = await selectDataListByParam(TABLENAME.学期表, { is_current: true });
return semesterList.data && semesterList.data.length > 0 ? semesterList.data[0] : null;
}
/**
* 孩子作品
*/
import { selectDataListByParam, selectOneDataByParam, selectPaginatedDataWithOrder } from "../../data/findData";
import { TABLENAME } from "../../config/dbEnum";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
import { formatAttachmentNameUrl } from "../../tools/system";
/**
* 获取孩子作品列表
* @param parentId 家长ID
* @param uploadTime 上传时间(可选,格式:YYYY-MM-DD)
* @param content 作品内容关键词(可选,模糊搜索)
* @param page 页码
* @param pageSize 每页大小
*/
export async function getChildWorks(parentId: string, uploadTime: string = '', content: string = '', page: number = 1, pageSize: number = 10) {
/**获取家长信息 */
let parent = await selectOneDataByParam(TABLENAME.家长表, { parent_id: parentId });
if (!parent.data) {
throw new BizError(ERRORENUM.未找到数据, '家长不存在');
}
let studentId = parent.data.student_id;
/**获取学生姓名 */
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: studentId });
let studentName = student.data ? student.data.user_name : '';
/**构建时间筛选条件 */
let timeFilter: any = {};
if (uploadTime) {
timeFilter.upload_time = {
"%between%": [`${uploadTime} 00:00:00`, `${uploadTime} 23:59:59`]
};
}
/**构建内容筛选条件 */
let contentFilter: any = {};
if (content) {
contentFilter.content = { "%like%": `%${content}%` };
}
/**获取学生自己上传的作品(type = '个人上传') */
let studentWorks = await selectPaginatedDataWithOrder(
TABLENAME.作品表,
{
uploader_id: studentId,
type: '个人上传',
...timeFilter,
...contentFilter
},
["id", "uploader_id", "content", "attachment", "upload_time", "type", "semester_id"],
page,
pageSize,
[["upload_time", "DESC"]]
);
/**获取导师上传的作品中关联该学生的(type = '导师上传') */
let workRelations = await selectDataListByParam(TABLENAME.作品学生关联表, {
student_id: studentId
});
let teacherWorkIds = workRelations.data.map((r: any) => r.work_id);
let teacherWorks = { data: [], pagination: { total: 0 } };
if (teacherWorkIds.length > 0) {
teacherWorks = await selectPaginatedDataWithOrder(
TABLENAME.作品表,
{
id: { "%in%": teacherWorkIds },
type: '导师上传',
...timeFilter,
...contentFilter
},
["id", "uploader_id", "content", "attachment", "upload_time", "type", "semester_id", "meeting_id"],
page,
pageSize,
[["upload_time", "DESC"]]
);
}
/**合并作品列表 */
let allWorks = [...studentWorks.data, ...teacherWorks.data];
/**按上传时间排序 */
allWorks.sort((a, b) => new Date(b.upload_time).getTime() - new Date(a.upload_time).getTime());
/**格式化返回数据,参考 getTeacherWorkList 的返回字段风格 */
let dataList = [];
for (let work of allWorks) {
let uploaderName = '';
let uploader = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: work.uploader_id });
uploaderName = uploader.data ? uploader.data.user_name : '';
/**如果是导师上传的作品,获取该作品关联的所有学生以及见面会地点 */
let students = [];
let meetingLocation: string | null = null;
if (work.type === '导师上传') {
// 获取关联的学生
let workStudents = await selectDataListByParam(TABLENAME.作品学生关联表, {
work_id: work.id
});
for (let ws of workStudents.data) {
let studentInfo = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: ws.student_id });
if (studentInfo.data) {
students.push({
studentId: ws.student_id,
studentName: studentInfo.data.user_name
});
}
}
// 获取见面会地点(导师作品才有)
if (work.meeting_id) {
let meeting = await selectOneDataByParam(TABLENAME.导师见面会表, { id: work.meeting_id });
meetingLocation = meeting.data ? meeting.data.location : null;
}
} else {
// 学生自己上传的作品,只关联自己
students.push({
studentId: studentId,
studentName: studentName
});
}
/**获取学期信息 */
let semesterInfo = await selectOneDataByParam(TABLENAME.学期表, { id: work.semester_id });
dataList.push({
id: work.id,
time: work.upload_time, // 上传时间
uploader: uploaderName, // 上传人姓名
uploaderId: work.uploader_id, // 上传人ID
content: work.content || '', // 作品内容
attachment: formatAttachmentNameUrl(work.attachment), // 格式化后的附件
semesterName: semesterInfo.data ? semesterInfo.data.name : '', // 学期名称
meetingId: work.meeting_id || null, // 关联的见面会ID(导师作品才有)
location: meetingLocation, // 新增:关联的见面会地点(导师作品才有)
students: students // 作品关联的学生列表
});
}
/**分页处理(注意:临时方案,实际应使用数据库分页) */
let start = (page - 1) * pageSize;
let end = start + pageSize;
let pagedDataList = dataList.slice(start, end);
return {
count: allWorks.length,
dataList: pagedDataList
};
}
/**
* 获取作品详情
* @param parentId 家长ID
* @param workId 作品ID
*/
export async function getChildWorkDetail(parentId: string, workId: string) {
/**参数校验 */
if (!workId) {
throw new BizError(ERRORENUM.参数错误, '作品ID不能为空');
}
/**获取家长信息 */
let parent = await selectOneDataByParam(TABLENAME.家长表, { parent_id: parentId });
if (!parent.data) {
throw new BizError(ERRORENUM.未找到数据, '家长不存在');
}
let studentId = parent.data.student_id;
/**查询作品 */
let work = await selectOneDataByParam(TABLENAME.作品表, { id: workId });
if (!work.data) {
throw new BizError(ERRORENUM.未找到数据, '作品不存在');
}
/**验证权限:作品必须是该学生的,或者是关联到该学生的 */
let hasPermission = false;
if (work.data.uploader_id === studentId) {
// 学生自己上传的
hasPermission = true;
} else {
// 检查是否关联到该学生
let relation = await selectOneDataByParam(TABLENAME.作品学生关联表, {
work_id: workId,
student_id: studentId
});
hasPermission = !!relation.data;
}
if (!hasPermission) {
throw new BizError(ERRORENUM.权限不足, '您无权查看该作品');
}
/**获取上传人信息 */
let uploaderName = '';
if (work.data.uploader_type === 1) {
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: work.data.uploader_id });
uploaderName = student.data ? student.data.user_name : '学生';
} else {
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: work.data.uploader_id });
uploaderName = teacher.data ? teacher.data.user_name : '导师';
}
/**如果作品关联了多个学生,获取所有学生信息 */
let relatedStudents = [];
if (work.data.uploader_type === 2) {
let relations = await selectDataListByParam(TABLENAME.作品学生关联表, {
work_id: workId
});
for (let rel of relations.data) {
if (rel.student_id === studentId) continue; // 当前学生已知道
let stu = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: rel.student_id });
if (stu.data) {
relatedStudents.push(stu.data.user_name);
}
}
}
return {
work: {
id: work.data.id,
title: work.data.title || '',
content: work.data.content || '',
attachment: work.data.attachment,
uploadTime: work.data.upload_time,
uploaderName: uploaderName,
uploaderType: work.data.uploader_type === 1 ? '学生' : '导师'
},
relatedStudents: relatedStudents
};
}
/**
* 学生数据看板
*/
import { selectDataListByParam, selectOneDataByParam } from "../../data/findData";
import { TABLENAME } from "../../config/dbEnum";
import { getCurrentSemester } from "../common/semesterService";
import { post } from "../../util/request";
import { systemConfig } from "../../config/serverConfig";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
export async function studentDashboard(studentId: string) {
let semester = await getCurrentSemester();
let 个人信息 = await getPersonalInfo(studentId);
let 我的导师 = await getMyTeacherInfo(studentId, semester);
let 公智能测评 = await getAbilityAssessment(studentId);
return {
personalInfo: 个人信息,
teacherInfo: 我的导师,
abilityAssessment: 公智能测评
};
}
async function getPersonalInfo(studentId: string) {
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: studentId });
if (!student.data) throw new BizError(ERRORENUM.未找到数据, '学生不存在');
let studentProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, { user_id: studentId });
let profile = studentProfile.data || {};
let className = '';
if (profile.class_id) {
let classInfo = await selectOneDataByParam(TABLENAME.班级表, { id: profile.class_id });
className = classInfo.data?.full_name || '';
}
let parentPhone = '';
let parent = await selectOneDataByParam(TABLENAME.家长表, { student_id: studentId });
if (parent.data) {
// 注意:原代码使用 parent.data?.phone,但家长表可能没有 phone 字段,需要从统一用户表获取
let parentUser = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: parent.data.parent_id });
parentPhone = parentUser.data?.phone || '';
}
return {
studentName: student.data.user_name || '',
gradeClass: className,
juniorSchool: profile.middle_school || '',
youthPartyMember: profile.is_youth_party_school ? '是' : '否',
studentNo: profile.student_no || '',
familyContact: parentPhone
};
}
async function getMyTeacherInfo(studentId: string, semester: any) {
if (!semester) return { hasTeacher: false };
let match = await selectOneDataByParam(TABLENAME.师生匹配表, {
student_id: studentId,
semester_id: semester.id,
is_active: true
});
// 修复:正确判断是否有匹配数据
if (!match.data || Object.keys(match.data).length === 0) {
return { hasTeacher: false };
}
let teacherId = match.data.teacher_id;
if (!teacherId) {
return { hasTeacher: false };
}
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: teacherId });
let teacherProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, { user_id: teacherId });
// 任教学科(有 semester_id 字段)
let teacherSubjects = await selectDataListByParam(TABLENAME.教师任教科目表, {
teacher_id: teacherId,
semester_id: semester.id
});
let subjectSet = new Set(teacherSubjects.data.map((s: any) => s.subject));
let subjects = Array.from(subjectSet).join('、');
// 任教班级(表 teacher_class 无 semester_id 字段,暂不过滤学期)
let teacherClasses = await selectDataListByParam(TABLENAME.导师任教班级表, { teacher_id: teacherId });
let classNames = [];
for (let tc of teacherClasses.data) {
let classInfo = await selectOneDataByParam(TABLENAME.班级表, { id: tc.class_id });
if (classInfo.data) classNames.push(classInfo.data.full_name);
}
let uniqueClassNames = [...new Set(classNames)];
let classes = uniqueClassNames.join('、');
return {
hasTeacher: true,
teacherName: teacher.data?.user_name || '',
teacherSubjects: subjects,
teacherClasses: classes,
teacherGender: teacher.data?.gender || '',
politicalStatus: teacherProfile.data?.political_status || ''
};
}
async function getAbilityAssessment(studentId: string) {
try {
let response: any = await post(systemConfig.abilitycomparison, { student_id: studentId }, {});
const abilityData = response?.data;
if (!abilityData || !abilityData.hasData) {
return {
hasData: false,
message: abilityData?.message || '该学生暂无答题记录',
totalScore: 0,
totalDescription: '',
lionImage: '',
lionInfo: null,
gongDescription: '',
zhiDescription: '',
nengDescription: '',
gongScore: 0,
zhiScore: 0,
nengScore: 0
};
}
const gongScore = abilityData.directionScores?.gong?.currentScore ?? 0;
const zhiScore = abilityData.directionScores?.zhi?.currentScore ?? 0;
const nengScore = abilityData.directionScores?.neng?.currentScore ?? 0;
return {
hasData: true,
totalScore: abilityData.totalScore?.currentScore ?? 0,
totalDescription: abilityData.totalScore?.description ?? '',
lionImage: abilityData.lionImageInfo?.lionImage ?? '',
lionInfo: abilityData.lionImageInfo ?? null,
gongDescription: abilityData.directionScores?.gong?.description ?? '',
zhiDescription: abilityData.directionScores?.zhi?.description ?? '',
nengDescription: abilityData.directionScores?.neng?.description ?? '',
gongScore, zhiScore, nengScore
};
} catch (error) {
console.error('获取公智能测评失败:', error);
return {
hasData: false,
message: '测评服务暂不可用',
totalScore: 0,
totalDescription: '',
lionImage: '',
lionInfo: null,
gongDescription: '',
zhiDescription: '',
nengDescription: '',
gongScore: 0, zhiScore: 0, nengScore: 0
};
}
}
/**
* 学生成长寄语
*/
import { selectDataListByParam, selectDataWithCustomOrder, selectOneDataByParam, selectPaginatedDataWithOrder } from "../../data/findData";
import { TABLENAME } from "../../config/dbEnum";
import { getCurrentSemester } from "../common/semesterService";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
/**
* 获取我的成长寄语列表
* @param studentId 学生ID
* @param semesterId 学期ID(可选,不传则返回全部学期)
*/
export async function getGrowthMessages(studentId: string, semesterId?: number) {
let selectParam: any = {
student_id: studentId
};
/**如果传入了学期ID,则按学期筛选 */
if (semesterId !== undefined && semesterId !== null) {
selectParam.semester_id = semesterId;
}
/**使用自定义排序查询,不分页,按日期倒序 */
let result = await selectDataWithCustomOrder(
TABLENAME.成长寄语表,
selectParam,
["id", "teacher_id", "student_id", "semester_id", "date", "content"],
[["date", "DESC"]]
);
/**补充导师信息和学期信息 */
let dataList = [];
for (let msg of result.data) {
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: msg.teacher_id });
let semesterInfo = await selectOneDataByParam(TABLENAME.学期表, { id: msg.semester_id });
dataList.push({
id: msg.id,
teacherId: msg.teacher_id,
teacherName: teacher.data ? teacher.data.user_name : '',
semesterId: msg.semester_id,
semesterName: semesterInfo.data ? semesterInfo.data.name : '',
date: msg.date,
content: msg.content
});
}
return {
list: dataList,
count: dataList.length
};
}
/**
* 获取成长寄语详情
* @param studentId 学生ID
* @param messageId 寄语ID
*/
export async function getGrowthMessageDetail(studentId: string, messageId: string) {
/**参数校验 */
if (!messageId) {
throw new BizError(ERRORENUM.参数错误, '寄语ID不能为空');
}
/**查询成长寄语 */
let message = await selectOneDataByParam(TABLENAME.成长寄语表, { id: messageId });
if (!message.data) {
throw new BizError(ERRORENUM.未找到数据, '成长寄语不存在');
}
/**验证权限:必须是该学生的寄语 */
if (message.data.student_id !== studentId) {
throw new BizError(ERRORENUM.权限不足, '您无权查看该成长寄语');
}
/**获取导师信息 */
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: message.data.teacher_id });
let teacherProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, {
user_id: message.data.teacher_id
});
/**获取学期信息 */
let semester = await selectOneDataByParam(TABLENAME.学期表, { id: message.data.semester_id });
return {
id: message.data.id,
teacher: {
id: message.data.teacher_id,
name: teacher.data ? teacher.data.user_name : '',
gender: teacher.data ? teacher.data.gender : '',
politicalStatus: teacherProfile.data ? teacherProfile.data.political_status : ''
},
semester: {
id: message.data.semester_id,
name: semester.data ? semester.data.name : ''
},
date: message.data.date,
content: message.data.content
};
}
/**
* 获取所有学期列表(通用)
* @returns 所有学期列表
*/
export async function getAllSemesters() {
let semesters = await selectDataListByParam(TABLENAME.学期表, {}, ["id", "name", "start_date", "end_date", "is_current"]);
if (!semesters.data) {
return {
list: [],
total: 0
};
}
/**按开始日期倒序排列 */
let semesterList = semesters.data.sort((a, b) => {
return new Date(b.start_date).getTime() - new Date(a.start_date).getTime();
});
return {
list: semesterList,
total: semesterList.length
};
}
/**
* 我的导师
*/
import { selectDataListByParam, selectOneDataByParam } from "../../data/findData";
import { updateManyData } from "../../data/updateData";
import { addData } from "../../data/addData";
import { TABLENAME, TABLEID } from "../../config/dbEnum";
import { MATCHTYPE, APPOINTMENTSTATUS } from "../../config/enum";
import { getCurrentSemester } from "../common/semesterService";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
import { getGradeName } from "../../tools/system";
import { getMySqlMs, randomId } from "../../tools/systemTools";
/**
* 将完整班级名称中的年级部分替换为年级名称
* @param fullName 完整班级名称,如 "2026级1班"
* @returns 转换后的名称,如 "高三1班"
*/
function formatClassName(fullName: string): string {
// 匹配 "XXXX级X班" 格式(支持1-3位数字的班号)
const match = fullName.match(/^(\d{4})(\d{1,3})$/);
if (match) {
const grade = parseInt(match[1]);
const className = match[2];
const gradeName = getGradeName(grade);
return `${gradeName}${className}`;
}
return fullName;
}
/**
* 数组去重
* @param arr 需要去重的数组
* @returns 去重后的数组
*/
function uniqueArray<T>(arr: T[]): T[] {
return [...new Set(arr)];
}
/**
* 获取我的导师信息
* @param studentId 学生ID
*/
export async function getMyTeacher(studentId: string) {
/**获取当前学期 */
let semester = await getCurrentSemester();
if (!semester) {
return {
hasTeacher: false,
teacherInfo: null,
matchInfo: null
};
}
/**查询匹配关系 */
let match = await selectOneDataByParam(TABLENAME.师生匹配表, {
student_id: studentId,
semester_id: semester.id,
is_active: true
});
if (!match.data) {
return {
hasTeacher: false,
teacherInfo: null,
matchInfo: null
};
}
/**获取导师基本信息 */
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: match.data.teacher_id });
let teacherProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, {
user_id: match.data.teacher_id
});
/**获取导师任教班级 */
let teacherClasses = await selectDataListByParam(TABLENAME.导师任教班级表, {
teacher_id: match.data.teacher_id
});
let classNames = [];
for (let tc of teacherClasses.data) {
let classInfo = await selectOneDataByParam(TABLENAME.班级表, { id: tc.class_id });
if (classInfo.data) {
// 转换班级名称格式(如:2026级1班 -> 高三1班)
classNames.push(formatClassName(classInfo.data.full_name));
}
}
// 班级去重
classNames = uniqueArray(classNames);
/**获取导师任教科目 */
let teacherSubjects = await selectDataListByParam(TABLENAME.教师任教科目表, {
teacher_id: match.data.teacher_id
});
// 科目去重
let subjectList = teacherSubjects.data.map((s: any) => s.subject);
let uniqueSubjects = uniqueArray(subjectList);
/**获取导师的成长寄语 */
let growthMessages = await selectDataListByParam(TABLENAME.成长寄语表, {
teacher_id: match.data.teacher_id,
student_id: studentId,
semester_id: semester.id,
"%orderDesc%": "date",
"%limit%": 5
});
/**获取最近的预约 */
let appointments = await selectDataListByParam(TABLENAME.预约表, {
target_id: match.data.teacher_id,
initiator_id: studentId,
"%orderDesc%": "start_time",
"%limit%": 3
});
return {
hasTeacher: true,
teacherInfo: {
user_id: match.data.teacher_id,
user_name: teacher.data ? teacher.data.user_name : '',
gender: teacher.data ? teacher.data.gender : '',
phone: teacher.data ? teacher.data.phone : '',
email: teacher.data ? teacher.data.email : '',
political_status: teacherProfile.data ? teacherProfile.data.political_status : '',
classes: classNames.join('、'),
subjects: uniqueSubjects.join('、')
},
matchInfo: {
matchType: match.data.match_type,
matchTime: match.data.match_time
},
recentGrowth: growthMessages.data.map((g: any) => ({
id: g.id,
date: g.date,
content: g.content.length > 50 ? g.content.substring(0, 50) + '...' : g.content
})),
recentAppointments: appointments.data.map((a: any) => ({
id: a.id,
start_time: a.start_time,
location: a.location,
content: a.content,
status: a.status
}))
};
}
/**
* 退选导师
* @param studentId 学生ID
* @param reason 退选原因
*/
export async function withdrawTeacher(studentId: string, reason?: string) {
/**获取当前学期 */
let semester = await getCurrentSemester();
if (!semester) {
throw new BizError(ERRORENUM.操作失败, '当前没有进行中的学期');
}
/**查询匹配关系 */
let match = await selectOneDataByParam(TABLENAME.师生匹配表, {
student_id: studentId,
semester_id: semester.id,
is_active: true
});
if (!match.data) {
throw new BizError(ERRORENUM.未找到数据, '您当前没有导师');
}
/**更新匹配状态为无效 */
await updateManyData(TABLENAME.师生匹配表, { id: match.data.id }, { is_active: false });
/**记录退选日志(可选) */
return { isSuccess: true };
}
/**
* 获取互动动态列表
* @param studentId 学生ID
* @returns 成长寄语和预约信息的合并列表,按时间倒序排列
*/
export async function getInteractionDynamic(studentId: string) {
/**获取当前学期 */
let semester = await getCurrentSemester();
if (!semester) {
return [];
}
/**查询学生是否有导师 */
let match = await selectOneDataByParam(TABLENAME.师生匹配表, {
student_id: studentId,
semester_id: semester.id,
is_active: true
});
if (!match.data) {
return [];
}
let teacherId = match.data.teacher_id;
/**获取导师信息 */
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: teacherId });
let teacherName = teacher.data ? teacher.data.user_name : '';
/**获取学生信息 */
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: studentId });
let studentName = student.data ? student.data.user_name : '';
/**1. 获取成长寄语列表 */
let growthMessages = await selectDataListByParam(TABLENAME.成长寄语表, {
teacher_id: teacherId,
student_id: studentId,
semester_id: semester.id,
"%orderDesc%": "date"
});
let growthList = growthMessages.data.map((g: any) => ({
type: '成长寄语',
teacher_name: teacherName,
time: g.date,
display_content: g.content,
// display_content: `导师${teacherName}给你写下了成长寄语:${g.content}`,
detail_id: g.id
}));
/**2. 获取所有预约(使用 %or% 查询) */
let appointments = await selectDataListByParam(TABLENAME.预约表, {
"%or%": [
{ initiator_id: studentId, target_id: teacherId },
{ initiator_id: teacherId, target_id: studentId }
],
"%orderDesc%": "start_time"
});
let appointmentList = appointments.data.map((a: any) => {
// 判断发起方
let isStudentInitiator = a.initiator_id === studentId;
let initiatorName = isStudentInitiator ? studentName : teacherName;
let targetName = isStudentInitiator ? teacherName : studentName;
// 格式化时间(只显示日期部分)
let formattedTime = a.start_time ? a.start_time.split(' ')[0] : '';
// 构建显示内容
let displayContent = '';
if (isStudentInitiator) {
// 学生发起的预约:你预约导师王星星[时间:2025-12-01,地点:XXX,内容:XXX]
displayContent = `你预约导师${targetName}[时间:${a.start_time},地点:${a.location || '未填写'},内容:${a.content || '无'}]`;
} else {
// 导师发起的预约:导师王星星预约你[时间:2025-12-01,地点:XXX,内容:XXX]
displayContent = `导师${initiatorName}预约你[时间:${a.start_time},地点:${a.location || '未填写'},内容:${a.content || '无'}]`;
}
return {
type: '预约信息',
teacher_name: teacherName,
time: formattedTime,
end_time: a.end_time,
location: a.location,
content: a.content,
status: a.status,
display_content: displayContent,
detail_id: a.id
};
});
/**3. 合并列表并按时间倒序排序 */
let dynamicList = [...growthList, ...appointmentList];
dynamicList.sort((a, b) => {
let timeA = a.start_time || a.time;
let timeB = b.start_time || b.time;
return new Date(timeB).getTime() - new Date(timeA).getTime();
});
return dynamicList;
}
/**选导师 */
import { selectDataListByParam, selectOneDataByParam, selectDataCountByParam } from "../../data/findData";
import { updateManyData } from "../../data/updateData";
import { TABLENAME, TABLEID } from "../../config/dbEnum";
import { MATCHTYPE, GENDERLIMIT } from "../../config/enum";
import * as verificationEnumTools from "../../util/verificationEnum";
import { getCurrentSemester } from "../common/semesterService";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
import { randomId } from "../../tools/systemTools";
import { getMySqlMs } from "../../tools/systemTools";
import { addData } from "../../data/addData";
/**
* 获取导师选择开放时间及选择状态
* @param studentId 学生ID
*/
export async function getSelectionTime(studentId: string) {
/**获取当前学期 */
let semester = await getCurrentSemester();
/**查询统一配置(全局设置) */
let globalConfig = await selectOneDataByParam(TABLENAME.导师匹配统一配置表, {
semester_id: semester.id
});
/**检查学生是否已选择导师 */
let existingMatch = await selectOneDataByParam(TABLENAME.师生匹配表, {
student_id: studentId,
semester_id: semester.id,
is_active: true
});
let hasSelected = !!(existingMatch.data && existingMatch.data.id);
return {
start_time: globalConfig.data ? globalConfig.data.start_time : null,
end_time: globalConfig.data ? globalConfig.data.end_time : null,
has_selected: hasSelected
};
}
/**
* 获取可选导师列表
* @param studentId 学生ID
* @param teacherName 导师姓名(可选,模糊搜索)
* @param subject 任教学科(可选)
*/
export async function getAvailableTeachers(studentId: string, teacherName?: string, subject?: string) {
/**获取当前学期 */
let semester = await getCurrentSemester();
/**获取统一配置(用于获取max_students) */
let globalConfig = await selectOneDataByParam(TABLENAME.导师匹配统一配置表, {
semester_id: semester.id
});
let globalMaxStudents = globalConfig.data ? globalConfig.data.max_students : 0;
/**获取学生信息(用于性别、班级筛选) */
let student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: studentId });
let studentProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, { user_id: studentId });
if (!student.data) {
throw new BizError(ERRORENUM.未找到数据, '学生不存在');
}
/**获取所有导师配置 */
let teacherConfigs = await selectDataListByParam(TABLENAME.导师配置表, { semester_id: semester.id });
let availableTeachers = [];
for (let config of teacherConfigs.data) {
/**检查性别限制 */
if (config.gender_limit === GENDERLIMIT.只限男生 && student.data.gender !== '男') continue;
if (config.gender_limit === GENDERLIMIT.只限女生 && student.data.gender !== '女') continue;
/**检查班级限制 */
if (config.restrict_to_class && studentProfile.data && studentProfile.data.class_id) {
let teacherClasses = await selectDataListByParam(TABLENAME.导师任教班级表, {
teacher_id: config.teacher_id
});
let classIds = teacherClasses.data.map((item: any) => item.class_id);
if (!classIds.includes(studentProfile.data.class_id)) continue;
}
/**获取导师信息 */
let teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: config.teacher_id });
let teacherProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, { user_id: config.teacher_id });
/**按导师姓名筛选(模糊匹配) */
if (teacherName && teacher.data && !teacher.data.user_name.includes(teacherName)) {
continue;
}
/**获取任教科目 */
let subjects = await selectDataListByParam(TABLENAME.教师任教科目表, {
teacher_id: config.teacher_id,
semester_id: semester.id
});
let subjectList = subjects.data.map((s: any) => s.subject);
/**按科目筛选 */
if (subject && !subjectList.includes(subject)) {
continue;
}
/**获取已选学生数量 */
let selectedCount = await selectDataCountByParam(TABLENAME.师生匹配表, {
teacher_id: config.teacher_id,
semester_id: semester.id,
is_active: true
});
/**获取任教班级 */
let teacherClasses = await selectDataListByParam(TABLENAME.导师任教班级表, {
teacher_id: config.teacher_id
});
let classNames = [];
for (let tc of teacherClasses.data) {
let classInfo = await selectOneDataByParam(TABLENAME.班级表, { id: tc.class_id });
if (classInfo.data) {
classNames.push(classInfo.data.full_name);
}
}
let maxStudents = globalMaxStudents;
let selectedCountNum = selectedCount.data;
availableTeachers.push({
teacher_id: config.teacher_id,
teacher_name: teacher.data ? teacher.data.user_name : '',
gender: teacher.data ? teacher.data.gender : '',
political_status: teacherProfile.data ? teacherProfile.data.political_status : '',
subjects: subjectList.join('、'),
classes: classNames.join('、'),
max_students: maxStudents,
selected_count: selectedCountNum,
remaining: Math.max(0, maxStudents - selectedCountNum)
});
}
/**按剩余席位排序(剩余多的在前) */
availableTeachers.sort((a, b) => b.remaining - a.remaining);
return availableTeachers;
}
/**
* 选择导师
* @param studentId 学生ID
* @param teacherId 导师ID
*/
export async function selectTeacher(studentId: string, teacherId: string) {
/**获取当前学期 */
let semester = await getCurrentSemester();
/**获取统一配置(用于获取max_students和开放时间) */
let globalConfig = await selectOneDataByParam(TABLENAME.导师匹配统一配置表, {
semester_id: semester.id
});
if (!globalConfig.data) {
throw new BizError(ERRORENUM.未找到数据, '导师匹配配置不存在,请联系管理员');
}
/**检查是否在开放时间内 */
let now = getMySqlMs();
if (globalConfig.data.start_time && globalConfig.data.end_time) {
if (now < globalConfig.data.start_time || now > globalConfig.data.end_time) {
throw new BizError(ERRORENUM.操作失败, '不在选导师开放时间内');
}
}
/**检查学生是否已选择导师 */
let existingMatch = await selectOneDataByParam(TABLENAME.师生匹配表, {
student_id: studentId,
semester_id: semester.id,
is_active: true
});
if (Object.keys(existingMatch.data).length) {
throw new BizError(ERRORENUM.重复操作, '您已经选择了导师,不能重复选择');
}
/**检查导师配置是否存在 */
let teacherConfig = await selectOneDataByParam(TABLENAME.导师配置表, {
teacher_id: teacherId,
semester_id: semester.id
});
if (!teacherConfig.data) {
throw new BizError(ERRORENUM.未找到数据, '导师配置不存在');
}
/**检查导师是否还有名额 */
let selectedCount = await selectDataCountByParam(TABLENAME.师生匹配表, {
teacher_id: teacherId,
semester_id: semester.id,
is_active: true
});
if (selectedCount.data >= globalConfig.data.max_students) {
throw new BizError(ERRORENUM.操作失败, '该导师名额已满');
}
/**创建匹配 */
await addData(TABLENAME.师生匹配表, {
student_id: studentId,
teacher_id: teacherId,
semester_id: semester.id,
match_type: MATCHTYPE.主动选择,
match_time: getMySqlMs(),
is_active: true
});
return { isSuccess: true };
}
/**
* 检查学生是否已选择导师
* @param studentId 学生ID
*/
export async function checkHasSelectedTeacher(studentId: string) {
/**获取当前学期 */
let semester = await getCurrentSemester();
/**检查学生是否已选择导师 */
let existingMatch = await selectOneDataByParam(TABLENAME.师生匹配表, {
student_id: studentId,
semester_id: semester.id,
is_active: true
});
return {
has_selected: !!(existingMatch.data && existingMatch.data.id),
teacher_id: existingMatch.data ? existingMatch.data.teacher_id : null
};
}
// AIGrowthMessage.ts
import { post, postForm } from '../../util/request';
import { addGrowthMessage } from './growthMessage'; // 已有的保存方法
import { ERRORENUM } from "../../config/errorEnum";
import { BizError } from '../../util/bizError';
import { getMySqlMs } from '../../tools/systemTools';
import { academic_level, class_role, growth_points, personality_tags, rank_change, writing_style } from '../../config/label';
import { selectOneDataByParam } from '../../data/findData';
import { TABLENAME } from '../../config/dbEnum';
/** GraphQL 端点 */
const GRAPHQL_ENDPOINT = 'https://saas.ketanyun.cn/bus/graphql/copilot';
/** OAuth2 Token 端点 */
const TOKEN_ENDPOINT = 'https://saas.ketanyun.cn/sso/oauth2/token';
/** OAuth2 客户端信息 */
const CLIENT_ID = 'mcV2XJPOd6Z4KyV4eFPp';
const CLIENT_SECRET = '8397B3027920F861D58FFDFE439785250E79252FC189A225'; // 请在此处填写你的秘钥
/** 默认智能体ID */
const DEFAULT_COPILOT_ID = '01JQQKA0WR5GYXPT0TYJXJ8SR3';
/** 默认提示词模板名称 */
const DEFAULT_PROMPT_NAME = 'evaluation-generator';
/** 缓存 token */
let cachedToken: string | null = null;
let tokenExpireTime: number = 0;
/**
* 获取 OAuth2 Access Token
*/
async function getAuthToken(): Promise<string> {
if (cachedToken && Date.now() < tokenExpireTime - 5 * 60 * 1000) {
return cachedToken;
}
try {
const formObject = {
grant_type: 'client_credentials',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
};
// 使用 postForm 并传入普通对象
const result: any = await postForm(TOKEN_ENDPOINT, formObject, {});
if (!result.access_token) {
throw new Error('获取 access_token 失败');
}
cachedToken = result.access_token;
tokenExpireTime = Date.now() + (result.expires_in || 3600) * 1000;
return cachedToken;
} catch (error: any) {
console.error('获取 OAuth2 Token 失败:', error);
throw new BizError(ERRORENUM.操作失败, `获取认证令牌失败: ${error.message}`);
}
}
/**
* 仅生成成长寄语(预览,不保存)
* @param studentId 学生ID(用于查询学生姓名)
* @param personalityTags 性格标签数组
* @param academicLevel 学业水平
* @param rankChange 排名变化
* @param classRole 班级职务(可选)
* @param growthPoints 成长亮点数组
* @param writingStyle 评语文风(可选)
* @param copilotId 智能体ID(可选)
* @param promptTemplateName 提示词模板名称(可选)
* @returns 生成的评语文本
*/
export async function generateGrowthMessagePreview(
studentId: string,
personalityTags: string[],
academicLevel: string,
rankChange: string,
classRole?: string,
growthPoints?: string[],
writingStyle?: string,
copilotId: string = DEFAULT_COPILOT_ID,
promptTemplateName: string = DEFAULT_PROMPT_NAME
): Promise<string> {
// 1. 根据 studentId 查询学生姓名
const studentInfo = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: studentId });
if (!studentInfo.data) {
throw new BizError(ERRORENUM.未找到数据, '学生不存在');
}
const studentName = studentInfo.data.user_name;
// 2. 构建 AI 需要的数据对象
const finalData = {
student_name: studentName,
personality_tags: personalityTags || [],
academic_level: academicLevel || '进步明显',
rank_change: rankChange || '上升10名',
class_role: classRole || '无职务',
growth_points: growthPoints || [],
writing_style: writingStyle || '温暖鼓励型'
};
// 3. 构造 GraphQL 请求(以下代码不变)
const graphqlQuery = {
query: `
query GenerateGrowthMessage($copilot: ID!, $prompt: String!, $data: String!) {
generate(copilot: $copilot, prompt: $prompt, data: $data) {
choices {
message {
text
contents {
kind
text
imageUrl
}
}
}
}
}
`,
variables: {
copilot: copilotId,
prompt: promptTemplateName,
data: JSON.stringify(finalData)
}
};
const token = await getAuthToken();
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
try {
const result: any = await post(GRAPHQL_ENDPOINT, graphqlQuery, headers);
if (result.errors) {
throw new Error(`GraphQL 错误: ${JSON.stringify(result.errors)}`);
}
const choices = result.data?.generate?.choices;
if (!choices || choices.length === 0) {
throw new Error('生成寄语失败:返回数据为空');
}
const message = choices[0]?.message;
if (!message) {
throw new Error('生成寄语失败:message 为空');
}
let content = message.text;
if (!content && message.contents && message.contents.length > 0) {
content = message.contents
.filter((c: any) => c.kind === 'text' && c.text)
.map((c: any) => c.text)
.join('\n');
}
if (!content) {
throw new Error('生成寄语失败:未找到文本内容');
}
return content;
} catch (error: any) {
console.error('调用 generate 接口失败:', error);
throw new BizError(ERRORENUM.操作失败, `生成成长寄语失败: ${error.message}`);
}
}
/**
* 保存成长寄语(导师调整后提交)
* 直接调用已有的 addGrowthMessage 方法
* @param teacherId 导师ID
* @param studentId 学生ID
* @param content 评语内容(已调整)
* @param date 寄语日期(可选,默认为当前时间)
* @param semesterId 学期ID(可选)
*/
export async function saveGrowthMessage(
teacherId: string,
studentId: string,
content: string,
date?: string,
semesterId?: number
) {
return await addGrowthMessage({
teacher_id: teacherId,
student_id: studentId,
date: date || getMySqlMs(),
content: content,
semester_id: semesterId || null
});
}
/**
* 获取所有评语标签数据
*/
export function getAllLabels() {
return {
personality_tags: [
...personality_tags.positive,
...personality_tags.neutral,
...personality_tags.negative
],
academic_level: [
...academic_level.positive,
...academic_level.neutral,
...academic_level.negative
],
rank_change: [
...rank_change.positive,
...rank_change.neutral,
...rank_change.negative
],
class_role: [
...class_role.positive,
...class_role.neutral
],
growth_points: [
...growth_points.positive,
...growth_points.neutral,
...growth_points.negative
],
writing_style: [
...writing_style.recommended,
...writing_style.optional,
...writing_style.uncommon
]
};
}
export function getPersonalityTags(): string[] {
return [...personality_tags.positive, ...personality_tags.neutral, ...personality_tags.negative];
}
export function getGrowthPoints(): string[] {
return [...growth_points.positive, ...growth_points.neutral, ...growth_points.negative];
}
export function getAcademicLevel(): string[] {
return [...academic_level.positive, ...academic_level.neutral, ...academic_level.negative];
}
/**
* 导师案例
*/
import { selectDataListByParam, selectOneDataByParam, selectPaginatedDataWithOrder, selectDataWithCustomOrder } from "../../data/findData";
import { updateManyData } from "../../data/updateData";
import { delData } from "../../data/delData";
import { TABLENAME, TABLEID } from "../../config/dbEnum";
import { getCurrentSemester } from "../common/semesterService";
import { BizError } from "../../util/bizError";
import { ERRORENUM } from "../../config/errorEnum";
import { getMySqlMs } from "../../tools/systemTools";
import { addData } from "../../data/addData";
import { formatAttachment, formatAttachmentNameUrl, stringifyAttachments } from "../../tools/system";
import moment, { now } from "moment";
/**
* 创建案例
* @param data 案例数据
*/
export async function createCase(data: any) {
/**参数校验 */
if (!data.case_name) {
throw new BizError(ERRORENUM.参数错误, '案例名称不能为空');
}
/**获取当前学期 */
let semester = await getCurrentSemester();
if (!semester) {
throw new BizError(ERRORENUM.操作失败, '当前没有进行中的学期');
}
/**创建案例 */
await addData(TABLENAME.导师案例表, {
semester_id: semester.id,
teacher_id: data.teacher_id,
case_name: data.case_name,
attachment: formatAttachment(data.attachment),
upload_time: getMySqlMs(),
created_at: getMySqlMs()
});
return { isSuccess: true };
}
/**
* 获取案例列表
* @param teacherId 导师ID
* @param case_name 案例名称(可选,支持模糊搜索)
* @param page 页码
* @param pageSize 每页大小
*/
export async function getCaseList(teacherId: string, case_name?: string, page: number = 1, pageSize: number = 10) {
/**获取当前学期 */
let semester = await getCurrentSemester();
let selectParam: any = {
teacher_id: teacherId
};
if (semester) {
selectParam.semester_id = semester.id;
}
// 按案例名称模糊搜索
if (case_name) {
selectParam.case_name = {
"%like%": case_name
};
}
let result = await selectPaginatedDataWithOrder(
TABLENAME.导师案例表,
selectParam,
["id", "case_name", "attachment", "upload_time", "created_at"],
page,
pageSize,
[["upload_time", "DESC"]]
);
// 格式化附件字段
function formatAttachmentField(attachment: any): string[] {
if (!attachment) {
return [];
}
if (Array.isArray(attachment)) {
return attachment;
}
try {
const parsed = JSON.parse(attachment);
if (Array.isArray(parsed)) {
return parsed;
}
return [attachment];
} catch (e) {
return attachment ? [attachment] : [];
}
}
// 格式化数据列表
let dataList = result.data.map(item => ({
id: item.id,
case_name: item.case_name,
attachment: formatAttachmentField(item.attachment),
upload_time: item.upload_time
}));
return {
count: result.pagination.total,
dataList: dataList
};
}
/**
* 获取案例列表(不分页,用于下拉选择等场景)
* @param teacherId 导师ID
* @param case_name 案例名称(可选,支持模糊搜索)
*/
export async function getCaseListSimple(teacherId: string, case_name?: string) {
/**获取当前学期 */
let semester = await getCurrentSemester();
let selectParam: any = {
teacher_id: teacherId
};
if (semester) {
selectParam.semester_id = semester.id;
}
// 按案例名称模糊搜索
if (case_name) {
selectParam.case_name = {
"%like%": case_name
};
}
// 使用支持排序的查询方法
let result = await selectDataWithCustomOrder(
TABLENAME.导师案例表,
selectParam,
["id", "case_name", "attachment", "upload_time"],
[["upload_time", "DESC"]]
);
// 格式化附件字段
function formatAttachmentField(attachment: any): string[] {
if (!attachment) {
return [];
}
if (Array.isArray(attachment)) {
return attachment;
}
try {
const parsed = JSON.parse(attachment);
if (Array.isArray(parsed)) {
return parsed;
}
return [attachment];
} catch (e) {
return attachment ? [attachment] : [];
}
}
// 格式化数据列表
let dataList = result.data.map(item => ({
id: item.id,
case_name: item.case_name,
attachment: formatAttachmentField(item.attachment),
upload_time: item.upload_time
}));
return dataList;
}
/**
* 获取案例详情
* @param teacherId 导师ID
* @param caseId 案例ID
*/
export async function getCaseDetail(teacherId: string, caseId: string) {
/**参数校验 */
if (!caseId) {
throw new BizError(ERRORENUM.参数错误, '案例ID不能为空');
}
/**查询案例 */
let caseData = await selectOneDataByParam(TABLENAME.导师案例表, {
id: caseId,
teacher_id: teacherId
});
if (!caseData.data) {
throw new BizError(ERRORENUM.未找到数据, '案例不存在');
}
return {
id: caseData.data.id,
case_name: caseData.data.case_name,
attachment: formatAttachmentNameUrl(caseData.data.attachment),
upload_time: caseData.data.upload_time
};
}
/**
* 编辑案例
* @param teacherId 导师ID
* @param caseId 案例ID
* @param updateData 更新数据
*/
export async function updateCase(teacherId: string, caseId: number, updateData: { case_name?:string, attachment?:any }) {
/**参数校验 */
if (!caseId) {
throw new BizError(ERRORENUM.参数错误, '案例ID不能为空');
}
if (!updateData.case_name && !updateData.attachment) {
throw new BizError(ERRORENUM.参数错误, '没有需要更新的内容');
}
/**查询案例是否存在 */
let caseData = await selectOneDataByParam(TABLENAME.导师案例表, {
id: caseId,
teacher_id: teacherId
});
if (!caseData.data) {
throw new BizError(ERRORENUM.未找到数据, '案例不存在');
}
/**构建更新数据 */
let updateFields: any = {};
if (updateData.case_name !== undefined) {
if (!updateData.case_name) {
throw new BizError(ERRORENUM.参数错误, '案例名称不能为空');
}
updateFields.case_name = updateData.case_name;
}
if (updateData.attachment !== undefined) {
updateFields.attachment = stringifyAttachments(updateData.attachment);
}
updateFields.upload_time = getMySqlMs();
/**执行更新 */
await updateManyData(TABLENAME.导师案例表, updateFields, { id: caseId });
return { isSuccess: true };
}
/**
* 删除案例
* @param teacherId 导师ID
* @param caseId 案例ID
*/
export async function deleteCase(teacherId: string, caseId: string) {
/**参数校验 */
if (!caseId) {
throw new BizError(ERRORENUM.参数错误, '案例ID不能为空');
}
/**查询案例 */
let caseData = await selectOneDataByParam(TABLENAME.导师案例表, {
id: caseId,
teacher_id: teacherId
});
if (!caseData.data) {
throw new BizError(ERRORENUM.未找到数据, '案例不存在');
}
/**删除案例 */
await delData(TABLENAME.导师案例表, { id: caseId });
return { isSuccess: true };
}
/**
* 导师数据看板
*/
import { selectDataCountByParam, selectDataListByParam, selectOneDataByParam } from "../../data/findData";
import { TABLENAME } from "../../config/dbEnum";
import { getCurrentSemester } from "../common/semesterService";
import moment from "moment";
/**
* 导师首页数据看板
* @param teacherId 导师ID
*/
export async function teacherDashboard(teacherId: string) {
const semester = await getCurrentSemester();
// 1. 个人信息
const personalInfo = await getTeacherPersonalInfo(teacherId);
// 2. 统计数据
const statistics = await getTeacherStatistics(teacherId, semester);
// 3. 近期记录(整合交流、寄语、见面会)
const recentRecords = await getRecentRecords(teacherId, semester);
return {
personalInfo,
statistics,
recentRecords
};
}
/**
* 获取导师个人信息
*/
async function getTeacherPersonalInfo(teacherId: string) {
// 基本信息
const teacher = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: teacherId });
const teacherProfile = await selectOneDataByParam(TABLENAME.用户扩展信息表, { user_id: teacherId });
// 任教学科(当前学期,去重)
const semester = await getCurrentSemester();
let subjects = '';
if (semester) {
const subjectRows = await selectDataListByParam(TABLENAME.教师任教科目表, {
teacher_id: teacherId,
semester_id: semester.id
});
const subjectSet = new Set(subjectRows.data.map((s: any) => s.subject));
subjects = Array.from(subjectSet).join('、');
}
// 任教班级(所有学期的班级,去重)
const classRows = await selectDataListByParam(TABLENAME.导师任教班级表, { teacher_id: teacherId });
const classNames = new Set<string>();
for (const row of classRows.data) {
const classInfo = await selectOneDataByParam(TABLENAME.班级表, { id: row.class_id });
if (classInfo.data?.full_name) {
classNames.add(classInfo.data.full_name);
}
}
const classes = Array.from(classNames).join('、');
return {
teacherName: teacher.data?.user_name || '',
teacherSubjects: subjects,
teacherClasses: classes,
teacherGender: teacher.data?.gender || '',
politicalStatus: teacherProfile.data?.political_status || ''
};
}
/**
* 获取统计数据
*/
async function getTeacherStatistics(teacherId: string, semester: any) {
if (!semester) {
return {
totalStudents: 0,
monthlyCommunications: 0,
pendingRecords: 0,
totalCommunications: 0,
studentWorks: 0
};
}
// 我的学生列表
const matches = await selectDataListByParam(TABLENAME.师生匹配表, {
teacher_id: teacherId,
semester_id: semester.id,
is_active: true
});
const studentIds = matches.data.map((m: any) => m.student_id);
const totalStudents = studentIds.length;
// 本月交流次数
const monthStart = moment().startOf('month').format('YYYY-MM-DD');
const monthEnd = moment().endOf('month').format('YYYY-MM-DD');
let monthlyComm = 0;
if (studentIds.length) {
const commCount = await selectDataCountByParam(TABLENAME.交流记录表, {
teacher_id: teacherId,
student_id: { "%in%": studentIds },
date: { "%gte%": monthStart, "%lte%": monthEnd }
});
monthlyComm = commCount.data || 0;
}
// 总交流记录数(本学期所有交流)
let totalComm = 0;
if (studentIds.length) {
const totalCommRes = await selectDataCountByParam(TABLENAME.交流记录表, {
teacher_id: teacherId,
student_id: { "%in%": studentIds }
});
totalComm = totalCommRes.data || 0;
}
// 学生作品数(学生自己上传的作品 + 导师上传且关联该学生的作品)
let studentWorks = 0;
if (studentIds.length) {
// 学生个人上传
const selfWorks = await selectDataCountByParam(TABLENAME.作品表, {
uploader_id: { "%in%": studentIds },
type: '个人上传'
});
// 导师上传且关联到这些学生的作品(通过作品学生关联表)
const relationWorks = await selectDataListByParam(TABLENAME.作品学生关联表, {
student_id: { "%in%": studentIds }
});
const workIds = relationWorks.data.map((w: any) => w.work_id);
let teacherWorksCount = 0;
if (workIds.length) {
const countRes = await selectDataCountByParam(TABLENAME.作品表, {
id: { "%in%": workIds },
type: '导师上传'
});
teacherWorksCount = countRes.data || 0;
}
studentWorks = (selfWorks.data || 0) + teacherWorksCount;
}
// 待完善记录数:本学期还未给所有学生发送过成长寄语的学生数
let pendingRecords = 0;
if (studentIds.length) {
// 已收到寄语的学生(去重)
const growthMessages = await selectDataListByParam(TABLENAME.成长寄语表, {
semester_id: semester.id,
teacher_id: teacherId,
student_id: { "%in%": studentIds }
});
const receivedStudentIds = new Set(growthMessages.data.map((g: any) => g.student_id));
pendingRecords = studentIds.length - receivedStudentIds.size;
}
return {
totalStudents,
monthlyCommunications: monthlyComm,
pendingRecords,
totalCommunications: totalComm,
studentWorks
};
}
/**
* 获取近期记录(整合师生交流、成长寄语、导师见面会)
*/
async function getRecentRecords(teacherId: string, semester: any) {
const records: any[] = [];
// 1. 师生交流记录(最近5条)
const communications = await selectDataListByParam(TABLENAME.交流记录表, {
teacher_id: teacherId,
"%orderDesc%": "date",
"%limit%": 5
});
for (const comm of communications.data) {
let targetName = '';
if (comm.student_id) {
const student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: comm.student_id });
targetName = student.data?.user_name || '';
} else if (comm.parent_id) {
const parent = await selectOneDataByParam(TABLENAME.家长表, { parent_id: comm.parent_id });
targetName = parent.data?.parent_name || '';
}
records.push({
time: comm.date,
type: '师生交流记录',
content: `${targetName}${comm.content}`,
location: comm.location || '',
attachment: '' // 附件字段,若无则留空
});
}
// 2. 成长寄语(最近5条)
if (semester) {
const growths = await selectDataListByParam(TABLENAME.成长寄语表, {
teacher_id: teacherId,
semester_id: semester.id,
"%orderDesc%": "date",
"%limit%": 5
});
for (const g of growths.data) {
const student = await selectOneDataByParam(TABLENAME.统一用户表, { user_id: g.student_id });
records.push({
time: g.date,
type: '成长寄语',
content: `给 ${student.data?.user_name || '学生'} 的寄语:${g.content}`,
location: '',
attachment: ''
});
}
}
// 3. 导师见面会(最近5条)
const meetings = await selectDataListByParam(TABLENAME.导师见面会表, {
teacher_id: teacherId,
"%orderDesc%": "start_time",
"%limit%": 5
});
for (const meeting of meetings.data) {
records.push({
time: meeting.start_time,
type: '导师见面会',
content: meeting.content || '见面会',
location: meeting.location || '',
attachment: meeting.attachment || ''
});
}
// 按时间倒序排序,取最近10条(可根据需要调整)
records.sort((a, b) => (b.time || 0) - (a.time || 0));
return records.slice(0, 10);
}
\ No newline at end of file
/**
* 表名
*/
export enum TABLENAME {
// 基础表
统一用户表 = 'uac_user',
用户扩展信息表 = 'user_profile',
家长表 = 'parent',
学期表 = 'semester',
班级表 = 'class',
// 教师相关
教师任教科目表 = 'teacher_subject',
导师任教班级表 = 'teacher_class',
// 匹配相关
初始匹配表 = 'initial_match',
导师匹配统一配置表 = 'teacher_match_global_config',
导师配置表 = 'teacher_config',
师生匹配表 = 'student_teacher_match',
// 业务表
交流记录表 = 'communication',
交流记录子类型表 = 'communication_subtype',
交流提醒记录表 = 'communication_reminder',
成长寄语表 = 'growth_message',
导师见面会表 = 'meeting',
见面会学生表 = 'meeting_students',
导师案例表 = 'teacher_case',
预约表 = 'appointment',
作品表 = 'work',
作品学生关联表 = 'work_students',
消息通知表 = 'notification',
消息已读表 = 'notification_read',
用户登录日志表 = 'user_login_log',
角色切换日志表 = 'role_switch_log',
};
/**
* 表ID前缀枚举(用于randomId生成)
*/
export enum TABLEID {
初始匹配表 = 'IM',
导师匹配统一配置表 = 'TMGC',
导师配置表 = 'TC',
师生匹配表 = 'SM',
交流记录表 = 'CM',
交流记录子类型表 = 'CMS',
交流提醒记录表 = 'CR',
成长寄语表 = 'GM',
导师见面会表 = 'MT',
导师案例表 = 'CS',
预约表 = 'AP',
作品表 = 'WK',
消息通知表 = 'NT',
消息已读表 = "NR",
用户登录日志表 = 'LOG',
角色切换日志表 = 'RSL',
};
/**
* 校验表单参数配置 【学生选导师平台】
* 使用场景: 验证客户端请求参数
* 限制: 1.使用端不同不能共用一份配置
* 2.需要搭配 util/verificationParam -> eccFormParam() 方法使用
* 说明: notMustHave = true 时说明该字段是非必填的;不配该字段说明是必填的
*/
/**
* 使用端: 管理后台
* 场景: 新增/修改导师配置
* 备注:
*/
export const TeacherConfigAddConfig = {
teacher_id:{type:"String"}, //导师ID
start_time:{type:"Number", notMustHave:true}, //可选学生开始时间
end_time:{type:"Number", notMustHave:true}, //可选学生结束时间
max_students:{type:"Number"}, //可选学生数量上限
gender_limit:{type:"Number"}, //性别限制(1-无,2-只限男生,3-只限女生)
restrict_to_class:{type:"Boolean"} //是否限制只能带本班级学生
};
/**
* 使用端: 管理后台
* 场景: 初始分配学生
* 备注:
*/
export const InitialMatchAddConfig = {
teacher_id:{type:"String"}, //导师ID
student_ids:{type:"[String]"} //学生ID数组
};
/**
* 使用端: 管理后台
* 场景: 新增交流记录
* 备注:
*/
export const CommunicationAddConfig = {
type:{type:"Number"}, //交流类型(1-师生交流,2-家校沟通)
teacher_id:{type:"String"}, //导师ID
student_id:{type:"String", notMustHave:true}, //学生ID
parent_id:{type:"String", notMustHave:true}, //家长ID
date:{type:"Number"}, //交流日期
location:{type:"String", notMustHave:true}, //地点
content:{type:"String"}, //交流内容
attachment:{type:"String", notMustHave:true} //附件路径
};
/**
* 使用端: 管理后台/导师
* 场景: 新增成长寄语
* 备注:
*/
export const GrowthMessageAddConfig = {
teacher_id:{type:"String"}, //导师ID
student_id:{type:"String"}, //学生ID
date:{type:"Number"}, //寄语日期
content:{type:"String"} //寄语内容
};
/**
* 使用端: 学生/家长/导师
* 场景: 新增预约
* 备注:
*/
export const AppointmentAddConfig = {
initiator_id:{type:"String"}, //发起人ID
initiator_type:{type:"Number"}, //发起方类型(1-学生,2-家长,3-导师)
target_id:{type:"String"}, //预约对象ID
student_id:{type:"String", notMustHave:true}, //关联的学生ID
appointment_time:{type:"Number"}, //预约时间
location:{type:"String", notMustHave:true}, //预约地点
content:{type:"String", notMustHave:true} //预约消息内容
};
/**
* 使用端: 学生/导师
* 场景: 新增作品
* 备注:
*/
export const WorkAddConfig = {
uploader_id:{type:"String"}, //上传人ID
uploader_type:{type:"Number"}, //上传人类型(1-学生,2-导师)
content:{type:"String", notMustHave:true}, //作品内容描述
attachment:{type:"String", notMustHave:true}, //附件路径
student_ids:{type:"[String]", notMustHave:true} //关联的学生ID数组(导师上传时)
};
/**
* 使用端: 导师
* 场景: 新增导师见面会
* 备注:
*/
export const MeetingAddConfig = {
teacher_id:{type:"String"}, //组织导师ID
title:{type:"String"}, //见面会标题
start_time:{type:"Number"}, //开始时间
end_time:{type:"Number"}, //结束时间
location:{type:"String"}, //地点
content:{type:"String", notMustHave:true}, //内容描述
student_ids:{type:"[String]", notMustHave:true} //参与学生ID数组
};
/**
* 使用端: 导师
* 场景: 新增导师案例
* 备注:
*/
export const TeacherCaseAddConfig = {
teacher_id:{type:"String"}, //上传导师ID
case_name:{type:"String"}, //案例名称
attachment:{type:"String", notMustHave:true}, //附件路径
description:{type:"String", notMustHave:true} //案例描述
};
/**
* 使用端: 管理后台
* 场景: 修改导师信息
* 备注:
*/
export const TeacherUpdateConfig = {
political_status:{type:"String", notMustHave:true}, //政治面貌
is_class_teacher:{type:"Boolean", notMustHave:true}, //是否班主任
max_students:{type:"Number", notMustHave:true}, //最大可带学生数
class_ids:{type:"[Number]", notMustHave:true}, //任教班级ID数组
subjects:{type:"[String]", notMustHave:true} //任教科目数组
};
/**
* 使用端: 管理后台
* 场景: 修改学生信息
* 备注:
*/
export const StudentUpdateConfig = {
student_no:{type:"String", notMustHave:true}, //学号
class_id:{type:"Number", notMustHave:true}, //班级ID
is_youth_party_school:{type:"Boolean", notMustHave:true}, //是否青年党校
middle_school:{type:"String", notMustHave:true} //初中学校
};
/**
* 使用端: 管理后台
* 场景: 新增家长账号
* 备注:
*/
export const ParentAddConfig = {
student_id:{type:"String"}, //关联的学生ID
parent_name:{type:"String"}, //家长姓名
phone:{type:"String", notMustHave:true}, //手机号
relation:{type:"String", notMustHave:true} //与学生的关系
};
export enum DIRNAMEENUM {
管理后台上传 = 1
}
export enum OPERATIONTYPEENUM {
= 1,
,
,
}
/**上传文件类型 */
export enum FILETYPE {
word = 1,
pdf,
图片,
视频,
多类型
}
export enum TYPEENUM {
string = 1,
number,
object,
array,
boolean,
}
export enum AUTHENTICATIONTYPEENNUM {
一般注册用户 = 0,
行政管理人员 = 1,
教职员工,
学生,
家长
}
export enum STATE {
= 0,
= 1
}
/**
* 用户角色
*/
export enum USERROLE {
管理员 = 1,
教师,
学生,
家长,
// 班主任,
};
/**
* 匹配方式
*/
export enum MATCHTYPE {
主动选择 = 1,
抢课分配,
// 初始分配
};
/**
* 预约状态
*/
export enum APPOINTMENTSTATUS {
待确认 = 1,
已确认,
已拒绝,
已取消
};
/**
* 交流类型
*/
export enum COMMUNICATIONTYPE {
师生交流 = 1,
家校沟通
};
/**
* 性别限制
*/
export enum GENDERLIMIT {
= 1,
只限男生,
只限女生
};
/**
* 消息类型
*/
export enum NOTIFICATIONTYPE {
匹配导师 = 1,
成长寄语,
预约,
交流记录,
系统通知
};
/**
* 预约发起方类型(对应预约表type字段)
*/
export enum APPOINTMENTTYPE {
学生预约 = "学生预约",
家长预约 = "家长预约",
导师预约 = "导师预约"
};
/**
* 预约发起方类型(对应预约表type字段)
*/
export enum TARGETROLETYPE {
学生 = "学生",
家长 = "家长",
导师 = "导师"
};
/**
* 提醒类型枚举
*/
export enum REMINDERTYPE {
师生交流 = 1,
家校沟通,
成长寄语,
导师案例
};
/**
* 完成状态
*/
export enum COMPLETIONSTATUS {
已完成 = 1,
未完成
};
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
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