Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nanMoMentorPlatform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
node_server
nanMoMentorPlatform
Commits
346a9e74
Commit
346a9e74
authored
Jun 24, 2026
by
PC-20251223ZVQQ\Administrator
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
导师/班主任端-成长寄语
parent
b50b20c3
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
330 additions
and
3 deletions
+330
-3
abilityComparison.ts
src/biz/common/abilityComparison.ts
+95
-0
dianxinService.ts
src/biz/common/dianxinService.ts
+71
-0
growthMessageSummary.ts
src/biz/headteacher/growthMessageSummary.ts
+52
-0
growthMessage.ts
src/biz/teacher/growthMessage.ts
+73
-1
errorEnum.ts
src/config/errorEnum.ts
+2
-1
headteacher.ts
src/routers/headteacher.ts
+18
-0
teacher.ts
src/routers/teacher.ts
+19
-1
No files found.
src/biz/common/abilityComparison.ts
0 → 100644
View file @
346a9e74
import
{
post
}
from
"../../util/request"
;
import
{
systemConfig
}
from
"../../config/serverConfig"
;
/**
* 通过学生ID获取公智能信息
* @param studentId
* @returns
*/
export
async
function
getAbilityComparison
(
studentId
:
string
// 学生id
)
{
let
abilityData
=
await
post
(
systemConfig
.
abilitycomparison
,
{
student_id
:
studentId
},
{});
let
abilityModel
=
transformAbilityData
(
abilityData
);
let
avatarInfo
=
extractAvatarInfo
(
abilityData
);
let
threeScores
=
calculateDirectionScoresFromDimensions
(
abilityModel
.
abilityScores
);
return
{
abilityModel
,
avatarInfo
,
threeScores
};
}
/** 转换九大能力数据格式 */
function
transformAbilityData
(
apiData
:
any
)
{
if
(
!
apiData
||
!
apiData
.
data
||
!
apiData
.
data
.
hasData
)
{
return
{
hasData
:
false
,
message
:
apiData
?.
data
?.
message
||
'该学生暂无答题记录'
,
totalScore
:
{
currentScore
:
0
,
previousScore
:
null
,
yoyChange
:
null
,
yoyPercent
:
null
},
abilityScores
:
{
jgqh
:
0
,
gjsy
:
0
,
zrdd
:
0
,
xyzs
:
0
,
yycx
:
0
,
syxx
:
0
,
jksh
:
0
,
smqq
:
0
,
ldys
:
0
},
currentAnswerTime
:
null
,
previousAnswerTime
:
null
};
}
const
data
=
apiData
.
data
;
return
{
hasData
:
data
.
hasData
,
message
:
data
.
message
||
'获取成功'
,
totalScore
:
{
currentScore
:
data
.
totalScore
?.
currentScore
||
0
,
previousScore
:
data
.
totalScore
?.
previousScore
||
null
,
yoyChange
:
data
.
totalScore
?.
yoyChange
||
null
,
yoyPercent
:
data
.
totalScore
?.
yoyPercent
||
null
},
abilityScores
:
{
jgqh
:
data
.
abilities
?.
jgqh
?.
currentScore
||
0
,
gjsy
:
data
.
abilities
?.
gjsy
?.
currentScore
||
0
,
zrdd
:
data
.
abilities
?.
zrdd
?.
currentScore
||
0
,
xyzs
:
data
.
abilities
?.
xyzs
?.
currentScore
||
0
,
yycx
:
data
.
abilities
?.
yycx
?.
currentScore
||
0
,
syxx
:
data
.
abilities
?.
syxx
?.
currentScore
||
0
,
jksh
:
data
.
abilities
?.
jksh
?.
currentScore
||
0
,
smqq
:
data
.
abilities
?.
smqq
?.
currentScore
||
0
,
ldys
:
data
.
abilities
?.
ldys
?.
currentScore
||
0
},
currentAnswerTime
:
data
.
currentAnswerTime
||
null
,
previousAnswerTime
:
data
.
previousAnswerTime
||
null
};
}
/** 提取动态头像信息(狮子形象图) */
function
extractAvatarInfo
(
apiData
:
any
)
{
if
(
!
apiData
||
!
apiData
.
data
||
!
apiData
.
data
.
hasData
)
{
return
{
lionImage
:
''
,
lionLevel
:
0
,
lionDescription
:
''
};
}
const
data
=
apiData
.
data
;
return
{
lionImage
:
data
.
lionImageInfo
?.
lionImage
||
''
,
lionLevel
:
data
.
lionImageInfo
?.
level
||
0
,
lionDescription
:
data
.
lionImageInfo
?.
description
||
''
};
}
// 根据维度得分计算三大方向得分
function
calculateDirectionScoresFromDimensions
(
dimensionScores
:
{
[
key
:
string
]:
number
})
{
return
{
gong
:
(
dimensionScores
[
'jgqh'
]
||
0
)
+
(
dimensionScores
[
'gjsy'
]
||
0
)
+
(
dimensionScores
[
'zrdd'
]
||
0
),
zhi
:
(
dimensionScores
[
'xyzs'
]
||
0
)
+
(
dimensionScores
[
'yycx'
]
||
0
)
+
(
dimensionScores
[
'syxx'
]
||
0
),
neng
:
(
dimensionScores
[
'jksh'
]
||
0
)
+
(
dimensionScores
[
'smqq'
]
||
0
)
+
(
dimensionScores
[
'ldys'
]
||
0
)
};
}
src/biz/common/dianxinService.ts
0 → 100644
View file @
346a9e74
import
{
post
}
from
"../../util/request"
;
import
{
BizError
}
from
"../../util/bizError"
;
import
{
ERRORENUM
}
from
"../../config/errorEnum"
;
const
BASE_URL
=
'http://58.246.54.66:8000'
;
const
CLIENT_ID
=
'1103b3776c534c0f98d38f1f7d6697f9'
;
let
tokenQueue
=
""
;
let
tokenMs
=
0
;
/** 获取电讯平台 token(缓存3分钟) */
async
function
getToken
()
{
let
nowMs
=
new
Date
().
valueOf
();
if
(
tokenMs
&&
(
nowMs
-
tokenMs
)
<
(
3
*
60
*
1000
))
{
return
tokenQueue
;
}
let
tokenRes
:
any
=
await
post
(
`
${
BASE_URL
}
/restcloud/rest/core/auth2/login`
,
{
username
:
"nmzxdp"
,
password
:
"NmzxDp258"
},
{}
);
tokenMs
=
nowMs
;
try
{
tokenQueue
=
tokenRes
.
access_token
;
return
tokenQueue
;
}
catch
(
err
)
{
throw
new
BizError
(
ERRORENUM
.
TOKEN
认证失败
,
"请求返回值"
,
tokenRes
);
}
}
/** 调用电讯平台 POST 接口 */
async
function
callDianXinApi
(
url
:
string
,
params
:
Record
<
string
,
any
>
)
{
let
token
=
await
getToken
();
let
result
=
await
post
(
`
${
BASE_URL
}${
url
}
`
,
{
...
params
,
client_id
:
CLIENT_ID
},
{
identitytoken
:
token
}
);
return
result
;
}
/** 获取学生最近成绩(各科分数 + 总分 + 班级排名) */
export
async
function
getStudentLatestScore
(
stuno
:
string
,
xuenian
:
string
)
{
let
params
:
Record
<
string
,
any
>
=
{
stuno
};
if
(
xuenian
)
{
params
.
xuenian
=
xuenian
;
}
let
result
:
any
=
await
callDianXinApi
(
'/service/api/nmzx/student_score'
,
params
);
return
result
?.
data
||
null
;
}
/** 获取学生获奖情况列表 */
export
async
function
getStudentAwards
(
username
:
string
)
{
let
result
:
any
=
await
callDianXinApi
(
'/service/api/nmzx/student_hjry'
,
{
username
});
return
result
?.
data
||
[];
}
/**
* 将学期名称转换为电讯平台的 xuenian 格式
* 例:"2023-2024学年第一学期" → "2024学年上学期"
* 例:"2023-2024学年第二学期" → "2024学年下学期"
*/
export
function
semesterNameToXuenian
(
semesterName
:
string
):
string
{
if
(
!
semesterName
)
return
''
;
// 匹配格式:XXXX-XXXX学年第X学期
let
match
=
semesterName
.
match
(
/
(\d{4})
-
(\d{4})
学年
(
第一|第二
)
学期/
);
if
(
!
match
)
return
semesterName
;
let
year
=
match
[
2
];
// 后一个年份
let
term
=
match
[
3
]
===
'第一'
?
'上学期'
:
'下学期'
;
return
`
${
year
}
学年
${
term
}
`
;
}
src/biz/headteacher/growthMessageSummary.ts
View file @
346a9e74
...
@@ -5,6 +5,7 @@ import { TABLENAME } from "../../config/dbEnum";
...
@@ -5,6 +5,7 @@ import { TABLENAME } from "../../config/dbEnum";
import
{
getCurrentSemester
}
from
"../common/semesterService"
;
import
{
getCurrentSemester
}
from
"../common/semesterService"
;
import
{
BizError
}
from
"../../util/bizError"
;
import
{
BizError
}
from
"../../util/bizError"
;
import
{
ERRORENUM
}
from
"../../config/errorEnum"
;
import
{
ERRORENUM
}
from
"../../config/errorEnum"
;
import
{
getAbilityComparison
}
from
"../common/abilityComparison"
;
/**
/**
* 获取所在班学生列表
* 获取所在班学生列表
...
@@ -249,5 +250,56 @@ export async function exportClassGrowthMessages(headteacherId: string) {
...
@@ -249,5 +250,56 @@ export async function exportClassGrowthMessages(headteacherId: string) {
return
exportData
;
return
exportData
;
}
}
/**
* 获取本班学生九大能力模型和动态头像
* @param headteacherId 班主任ID
* @param studentId 学生ID
* @param semesterId 学期ID
*/
export
async
function
getClassStudentPower
(
headteacherId
:
string
,
studentId
:
string
,
_semesterId
:
number
// 预留学期参数,后续扩展使用
)
{
// 1. 权限校验:确认班主任身份及学生是否在本班
let
classInfo
=
await
selectOneDataByParam
(
TABLENAME
.
班级表
,
{
head_teacher_id
:
headteacherId
,
});
if
(
!
classInfo
.
data
)
{
throw
new
BizError
(
ERRORENUM
.
权限不足
,
'您不是班主任'
);
}
const
classId
=
classInfo
.
data
.
id
;
// 校验学生是否在本班且为学生角色
let
studentProfile
=
await
selectOneDataByParam
(
TABLENAME
.
用户扩展信息表
,
{
user_id
:
studentId
,
class_id
:
classId
,
roles
:
{
"%like%"
:
'3'
},
});
if
(
!
studentProfile
.
data
)
{
throw
new
BizError
(
ERRORENUM
.
权限不足
,
'该学生不在您管理的班级'
);
}
// 2. 获取学生基本信息
let
student
=
await
selectOneDataByParam
(
TABLENAME
.
统一用户表
,
{
user_id
:
studentId
});
if
(
!
student
.
data
)
{
throw
new
BizError
(
ERRORENUM
.
未找到数据
,
'学生不存在'
);
}
const
studentName
=
student
.
data
.
user_name
;
const
className
=
classInfo
.
data
.
full_name
;
// 3. 获取九大能力模型 + 动态头像(调用外部能力对比接口)
let
abilityData
=
await
getAbilityComparison
(
studentId
);
return
{
student_id
:
studentId
,
student_name
:
studentName
,
class_name
:
className
,
ability_model
:
abilityData
.
abilityModel
,
avatar_info
:
abilityData
.
avatarInfo
};
}
src/biz/teacher/growthMessage.ts
View file @
346a9e74
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
* 导师成长寄语
* 导师成长寄语
*/
*/
import
{
selectOneDataByParam
,
selectPaginatedDataWithOrder
}
from
"../../data/findData"
;
import
{
selectOneDataByParam
,
select
DataListByParam
,
select
PaginatedDataWithOrder
}
from
"../../data/findData"
;
import
{
addData
}
from
"../../data/addData"
;
import
{
addData
}
from
"../../data/addData"
;
import
{
TABLENAME
,
TABLEID
}
from
"../../config/dbEnum"
;
import
{
TABLENAME
,
TABLEID
}
from
"../../config/dbEnum"
;
import
{
getCurrentSemester
}
from
"../common/semesterService"
;
import
{
getCurrentSemester
}
from
"../common/semesterService"
;
...
@@ -13,6 +13,8 @@ import { getMySqlMs } from "../../tools/systemTools";
...
@@ -13,6 +13,8 @@ import { getMySqlMs } from "../../tools/systemTools";
import
*
as
notificationBiz
from
"../headteacher/notification"
;
import
*
as
notificationBiz
from
"../headteacher/notification"
;
import
{
updateManyData
}
from
"../../data/updateData"
;
import
{
updateManyData
}
from
"../../data/updateData"
;
import
{
delData
}
from
"../../data/delData"
;
import
{
delData
}
from
"../../data/delData"
;
import
{
getAbilityComparison
}
from
"../common/abilityComparison"
;
import
{
getStudentLatestScore
,
getStudentAwards
,
semesterNameToXuenian
}
from
"../common/dianxinService"
;
/**
/**
...
@@ -301,7 +303,77 @@ async function getClassName(classId: number): Promise<string> {
...
@@ -301,7 +303,77 @@ async function getClassName(classId: number): Promise<string> {
return
classInfo
.
data
?
classInfo
.
data
.
full_name
:
''
;
return
classInfo
.
data
?
classInfo
.
data
.
full_name
:
''
;
}
}
/**
* 获取学生信息和公智能评测
* @param studentId
*/
export
async
function
getGrowthStudent
(
studentId
:
string
,
_semesterId
:
number
// 预留学期参数,后续扩展使用
)
{
// 1. 获取学生基本信息
let
student
=
await
selectOneDataByParam
(
TABLENAME
.
统一用户表
,
{
user_id
:
studentId
});
if
(
!
student
.
data
)
{
throw
new
BizError
(
ERRORENUM
.
未找到数据
,
'学生不存在'
);
}
const
studentName
=
student
.
data
.
user_name
;
const
gender
=
student
.
data
.
gender
||
''
;
// 2. 获取学生扩展信息(班级、学号等)
let
studentProfile
=
await
selectOneDataByParam
(
TABLENAME
.
用户扩展信息表
,
{
user_id
:
studentId
});
let
className
=
''
;
let
studentNo
=
''
;
if
(
studentProfile
.
data
)
{
studentNo
=
studentProfile
.
data
.
student_no
||
''
;
if
(
studentProfile
.
data
.
class_id
)
{
let
classInfo
=
await
selectOneDataByParam
(
TABLENAME
.
班级表
,
{
id
:
studentProfile
.
data
.
class_id
});
className
=
classInfo
.
data
?.
full_name
||
''
;
}
}
// 3. 获取当前导师信息
let
semester
=
await
getCurrentSemester
();
let
teacherName
=
''
;
let
teacherId
=
''
;
if
(
semester
)
{
let
match
=
await
selectOneDataByParam
(
TABLENAME
.
师生匹配表
,
{
student_id
:
studentId
,
semester_id
:
semester
.
id
,
is_active
:
true
});
if
(
match
.
data
&&
match
.
data
.
teacher_id
)
{
teacherId
=
match
.
data
.
teacher_id
;
let
teacher
=
await
selectOneDataByParam
(
TABLENAME
.
统一用户表
,
{
user_id
:
teacherId
});
teacherName
=
teacher
.
data
?.
user_name
||
''
;
}
}
// 4. 获取公智能评测数据(九大能力模型 + 动态头像)
let
{
abilityModel
,
avatarInfo
,
threeScores
}
=
await
getAbilityComparison
(
studentId
);
// 5. 获取最近成绩(语数英物化生...)、总分、班级排名
let
xuenian
=
semesterNameToXuenian
(
semester
?
semester
.
name
:
''
);
let
latestScore
=
await
getStudentLatestScore
(
studentNo
,
xuenian
);
// 6. 获取获奖情况列表(获奖内容、获奖时间)
let
awards
=
await
getStudentAwards
(
studentNo
);
return
{
student_info
:
{
student_id
:
studentId
,
student_name
:
studentName
,
gender
:
gender
,
student_no
:
studentNo
,
class_name
:
className
,
teacher_name
:
teacherName
,
latest_score
:
latestScore
,
awards
:
awards
},
ability_model
:
abilityModel
,
avatar_info
:
avatarInfo
,
ability_scores
:
threeScores
};
}
...
...
src/config/errorEnum.ts
View file @
346a9e74
...
@@ -45,7 +45,8 @@ export enum ERRORENUM {
...
@@ -45,7 +45,8 @@ export enum ERRORENUM {
文件上传失败
,
文件上传失败
,
只能上传
doc
或
docx
或
excel
或
png
或
jpg
图片
,
只能上传
doc
或
docx
或
excel
或
png
或
jpg
图片
,
该时间段已有预约
,
该时间段已有预约
,
班级不属于年级
班级不属于年级
,
TOKEN
认证失败
}
}
/**
/**
...
...
src/routers/headteacher.ts
View file @
346a9e74
...
@@ -33,6 +33,9 @@ export function setRouter(httpServer) {
...
@@ -33,6 +33,9 @@ export function setRouter(httpServer) {
/** 导出本班成长寄语 - growthMessageSummary.ts */
/** 导出本班成长寄语 - growthMessageSummary.ts */
httpServer
.
post
(
'/api/headteacher/growth/export'
,
checkUser
,
checkClassTeacher
(),
asyncHandler
(
exportClassGrowthMessages
));
httpServer
.
post
(
'/api/headteacher/growth/export'
,
checkUser
,
checkClassTeacher
(),
asyncHandler
(
exportClassGrowthMessages
));
/** 获取本班学生九大能力模型和动态头像 - growthMessageSummary.ts */
httpServer
.
post
(
'/api/headteacher/student/power'
,
checkUser
,
checkClassTeacher
(),
asyncHandler
(
getClassStudentPower
));
// ===== 消息通知 =====
// ===== 消息通知 =====
/** 获取消息通知列表 - notification.ts */
/** 获取消息通知列表 - notification.ts */
...
@@ -176,6 +179,21 @@ async function exportClassGrowthMessages(req, res) {
...
@@ -176,6 +179,21 @@ async function exportClassGrowthMessages(req, res) {
/**
/**
* 获取本班学生九大能力模型和动态头像
*/
async
function
getClassStudentPower
(
req
,
res
)
{
const
userInfo
=
req
.
userInfo
;
let
reqConf
=
{
studentId
:
'String'
,
semesterId
:
'Number'
};
const
NotMustHaveKeys
=
[];
let
{
studentId
,
semesterId
}
=
eccReqParamater
(
reqConf
,
req
.
body
,
NotMustHaveKeys
);
let
result
=
await
growthMessageSummaryBiz
.
getClassStudentPower
(
userInfo
.
userId
,
studentId
,
semesterId
);
res
.
success
(
result
);
}
/**
* 获取消息通知列表
* 获取消息通知列表
* @param startDate 开始日期(可选)
* @param startDate 开始日期(可选)
* @param endDate 结束日期(可选)
* @param endDate 结束日期(可选)
...
...
src/routers/teacher.ts
View file @
346a9e74
...
@@ -83,7 +83,10 @@ export function setRouter(httpServer) {
...
@@ -83,7 +83,10 @@ export function setRouter(httpServer) {
/** AI 生成成长寄语预览(仅生成,不保存) */
/** AI 生成成长寄语预览(仅生成,不保存) */
httpServer
.
post
(
'/api/teacher/growth/aipreview'
,
checkUser
,
checkRole
(
USERROLE
.
教师
),
asyncHandler
(
aiPreviewGrowthMessage
));
httpServer
.
post
(
'/api/teacher/growth/aipreview'
,
checkUser
,
checkRole
(
USERROLE
.
教师
),
asyncHandler
(
aiPreviewGrowthMessage
));
/** 获取学生九大能力模型和动态头像 - growthMessage.ts */
httpServer
.
post
(
'/api/teacher/growth/student'
,
checkUser
,
checkRole
(
USERROLE
.
教师
),
asyncHandler
(
getGrowthStudent
));
// ===== 导师案例 =====
// ===== 导师案例 =====
/** 上传案例 - case.ts */
/** 上传案例 - case.ts */
httpServer
.
post
(
'/api/teacher/case/create'
,
checkUser
,
checkRole
(
USERROLE
.
教师
),
asyncHandler
(
createCase
));
httpServer
.
post
(
'/api/teacher/case/create'
,
checkUser
,
checkRole
(
USERROLE
.
教师
),
asyncHandler
(
createCase
));
...
@@ -561,6 +564,21 @@ async function aiPreviewGrowthMessage(req, res) {
...
@@ -561,6 +564,21 @@ async function aiPreviewGrowthMessage(req, res) {
res
.
success
({
content
});
res
.
success
({
content
});
}
}
/**
* 获取学生九大能力模型和动态头像
* @param req
* @param res
*/
async
function
getGrowthStudent
(
req
,
res
)
{
const
userInfo
=
req
.
userInfo
;
let
reqConf
=
{
studentId
:
'String'
,
semesterId
:
'Number'
};
const
NotMustHaveKeys
=
[
'semesterId'
];
let
{
studentId
,
semesterId
}
=
eccReqParamater
(
reqConf
,
req
.
body
,
NotMustHaveKeys
);
let
result
=
await
growthMessageBiz
.
getGrowthStudent
(
studentId
,
semesterId
);
res
.
success
(
result
);
}
/**
/**
* 未读预约数量
* 未读预约数量
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment