Files
cpdaily_xiaozhushou/backed/internal/handler/leave_extend.go
T
becomer ef03130980
ci/woodpecker/tag/build Pipeline was successful
请假/销假全部入口补齐独立学工系统分流,修复点销假仍报 420
问题:上一版只在 GetLeaveTypes 加了 xsgz/xsfw 分支,其余请假入口仍走辅导猫
旧链路。用户点销假按钮(走 /leave/pending-list)时仍拿到辅导猫的 HTTP 420
「产品已到期」,提示误导且无法自助解决。

改动:新增 rejectExternalLeaveSystem 统一守卫,接入全部 7 个请假相关入口:
- GetLeaveTypes / GetLeaveApplyApprovers / ExecuteLeaveApply(请假侧)
- GetPendingLeaves / GetLeaveApprovers / ExecuteLeave(销假侧)
- GetLeaveExtendPrefill(续假)
命中 xsgz/xsfw 时短路返回明确文案「XX大学 的请假由学校「学工系统」独立提供,
不支持在今日校园内提交,请前往学校学工系统办理」,不再让用户看到 420。

新增单测验证分流判定与文案(纯静态映射,不触发网络)。
2026-10-17 17:12:52 +08:00

103 lines
3.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handler
import (
"log/slog"
"strings"
cpd "cpdaily-new/internal/service/cpdaily"
"cpdaily-new/internal/utils"
"github.com/gofiber/fiber/v2"
)
// 续假(仅新套 wec-counselor-leave-new-apps)。
// 续假复用请假提交接口 /stu/leave/apply(body 带 reApply/isExtend/leaveId/extendId);
// 执行逻辑并入 ExecuteLeaveApply(见 leaveNewExecuteApply 的续假分支),本文件仅提供「续假预填」查询。
// GetLeaveExtendPrefill 续假预填:返回原假单的类型、原结束时间(续假开始时间)、原因、是否离校等。
// 前端据此预填续假表单(开始时间锁定为原结束时间,用户只改新的结束时间)。
func GetLeaveExtendPrefill(c *fiber.Ctx) error {
user, err := loadLeaveUser(c)
if err != nil {
return utils.FailAuth(c, err.Error())
}
var req struct {
LeaveID string `json:"leaveId"`
}
if err := c.BodyParser(&req); err != nil {
return utils.FailParam(c, "请求参数错误")
}
req.LeaveID = strings.TrimSpace(req.LeaveID)
if req.LeaveID == "" {
return utils.FailParam(c, "缺少请假单 ID")
}
cookieMap := cpd.ParseCookieJSON(user.Cookie)
host := getSchoolHost(user.SchoolID)
// 学校独立学工系统:续假也不经辅导猫
if rejectExternalLeaveSystem(c, user, cookieMap) {
return nil
}
// 旧套:续假预填取自请假详情(类型 code + 原结束时间作为续假开始时间)
if schoolLeaveFlavor(user, cookieMap) != cpd.LeaveFlavorNew {
d, err := cpd.FetchLeaveDetail(cookieMap, host, req.LeaveID)
if err != nil && isCookieExpired(err) {
if refreshErr := refreshCpdailyCookie(user); refreshErr == nil {
cookieMap = cpd.ParseCookieJSON(user.Cookie)
d, err = cpd.FetchLeaveDetail(cookieMap, host, req.LeaveID)
} else {
err = wrapNeedReLogin(refreshErr)
}
}
if err != nil {
slog.Error("获取续假预填失败(旧套)", "userId", user.ID, "leaveId", req.LeaveID, "error", err)
if needReLoginSignal(err) {
return utils.Fail(c, 401, "登录凭证已过期,请重新登录")
}
return utils.Fail(c, 503, "获取续假信息失败: "+err.Error())
}
return utils.Success(c, fiber.Map{
"leaveId": req.LeaveID,
"typeWid": d.LeaveCodeNum,
"beginTime": d.EndTime, // 续假开始时间 = 原假单结束时间
"endTime": d.EndTime,
"leaveReason": "",
"isLeaveOut": "",
})
}
rd, err := cpd.FetchLeaveNewReplyDetail(cookieMap, host, req.LeaveID)
if err != nil && isCookieExpired(err) {
if refreshErr := refreshCpdailyCookie(user); refreshErr == nil {
cookieMap = cpd.ParseCookieJSON(user.Cookie)
rd, err = cpd.FetchLeaveNewReplyDetail(cookieMap, host, req.LeaveID)
} else {
err = wrapNeedReLogin(refreshErr)
}
}
if err != nil {
slog.Error("获取续假预填失败", "userId", user.ID, "leaveId", req.LeaveID, "error", err)
if needReLoginSignal(err) {
return utils.Fail(c, 401, "登录凭证已过期,请重新登录")
}
return utils.Fail(c, 503, "获取续假信息失败: "+err.Error())
}
// extendId 为空通常意味着该假单当前不可续假(已销假/已结束/未到可续假状态)
if strings.TrimSpace(rd.ExtendID) == "" && strings.TrimSpace(rd.BeginTime) == "" {
return utils.Fail(c, 400, "该请假单当前不可续假")
}
return utils.Success(c, fiber.Map{
"leaveId": rd.LeaveID,
"typeWid": rd.TypeWid,
"beginTime": rd.BeginTime, // 续假开始时间 = 原假单结束时间
"endTime": rd.EndTime,
"leaveReason": rd.LeaveReason,
"isLeaveOut": rd.IsLeaveOut,
})
}