✨ 请假功能
This commit is contained in:
@@ -35,3 +35,52 @@ type CpLeaveUploadReq struct {
|
||||
File *ghttp.UploadFile `json:"file"`
|
||||
CpUserId int64 `json:"cpUserId"`
|
||||
}
|
||||
|
||||
// 请假 - 检查是否允许请假
|
||||
type CpLeaveCheckReq struct {
|
||||
g.Meta `path:"/leave/check/{cpUserId}" method:"get" tags:"CpLeave" summary:"检查是否允许请假"`
|
||||
CpUserId int64 `json:"cpUserId" v:"required#今日校园账号ID不能为空"`
|
||||
}
|
||||
|
||||
// 请假 - 获取请假类型
|
||||
type CpLeaveTypesReq struct {
|
||||
g.Meta `path:"/leave/types/{cpUserId}" method:"get" tags:"CpLeave" summary:"获取请假类型列表"`
|
||||
CpUserId int64 `json:"cpUserId" v:"required#今日校园账号ID不能为空"`
|
||||
}
|
||||
|
||||
// 请假 - 查询请假类型配置(是否需要审批等)
|
||||
type CpLeaveTypeCfgReq struct {
|
||||
g.Meta `path:"/leave/typeCfg" method:"post" tags:"CpLeave" summary:"查询请假类型配置"`
|
||||
CpUserId int64 `json:"cpUserId" v:"required#今日校园账号ID不能为空"`
|
||||
Code int `json:"code" v:"required#请假类型code不能为空"`
|
||||
}
|
||||
|
||||
// 请假 - 获取审批人列表
|
||||
type CpLeaveApproveFlowReq struct {
|
||||
g.Meta `path:"/leave/approveFlow" method:"post" tags:"CpLeave" summary:"获取审批人列表"`
|
||||
CpUserId int64 `json:"cpUserId" v:"required#今日校园账号ID不能为空"`
|
||||
LeaveType int `json:"leaveType" v:"required#请假类型不能为空"`
|
||||
StartTime string `json:"startTime" v:"required#开始时间不能为空"`
|
||||
EndTime string `json:"endTime" v:"required#结束时间不能为空"`
|
||||
}
|
||||
|
||||
// 请假 - 提交请假申请
|
||||
type CpLeaveApplyReq struct {
|
||||
g.Meta `path:"/leave/apply" method:"post" tags:"CpLeave" summary:"提交请假申请"`
|
||||
CpUserId int64 `json:"cpUserId" v:"required#今日校园账号ID不能为空"`
|
||||
LeaveType int `json:"leaveType" v:"required#请假类型不能为空"`
|
||||
StartTime string `json:"startTime" v:"required#开始时间不能为空"`
|
||||
EndTime string `json:"endTime" v:"required#结束时间不能为空"`
|
||||
UrgencyMobile string `json:"urgencyMobile" v:"required#紧急联系人手机号不能为空"`
|
||||
LeaveReason string `json:"leaveReason" v:"required#请假原因不能为空"`
|
||||
OutStatus bool `json:"outStatus"`
|
||||
Address string `json:"address" v:"required#目的地不能为空"`
|
||||
DetailAddress string `json:"detailAddress" v:"required#详细地址不能为空"`
|
||||
Longitude string `json:"longitude" v:"required#经度不能为空"`
|
||||
Latitude string `json:"latitude" v:"required#纬度不能为空"`
|
||||
LocationAddr string `json:"locationAddr" v:"required#定位地址不能为空"`
|
||||
ImageUrl string `json:"imageUrl"`
|
||||
ApproverWid string `json:"approverWid"`
|
||||
ApproverId string `json:"approverId"`
|
||||
ApproverName string `json:"approverName"`
|
||||
}
|
||||
|
||||
@@ -31,6 +31,31 @@ func (c CpLeaveCtrlV1) Upload(ctx context.Context, req *v1.CpLeaveUploadReq) (re
|
||||
return service.Global.CpLeave.Upload(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c CpLeaveCtrlV1) CheckLeave(ctx context.Context, req *v1.CpLeaveCheckReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpLeave.CheckLeave(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c CpLeaveCtrlV1) GetLeaveTypes(ctx context.Context, req *v1.CpLeaveTypesReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpLeave.GetLeaveTypes(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c CpLeaveCtrlV1) GetLeaveTypeCfg(ctx context.Context, req *v1.CpLeaveTypeCfgReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpLeave.GetLeaveTypeCfg(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c CpLeaveCtrlV1) GetApproveFlow(ctx context.Context, req *v1.CpLeaveApproveFlowReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpLeave.GetApproveFlow(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c CpLeaveCtrlV1) Apply(ctx context.Context, req *v1.CpLeaveApplyReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpLeave.Apply(ctx, req), nil
|
||||
}
|
||||
|
||||
func NewCpLeaveCtrlV1() ICpLeaveCtrlV1 {
|
||||
return &CpLeaveCtrlV1{}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,9 @@ type ICpLeaveCtrlV1 interface {
|
||||
List(ctx context.Context, req *v1.CpLeaveListReq) (*utils.Response[[]*ent.CpLeave], error)
|
||||
Report(ctx context.Context, req *v1.CpLeaveReportReq) (*utils.Response[any], error)
|
||||
Upload(ctx context.Context, req *v1.CpLeaveUploadReq) (*utils.Response[string], error)
|
||||
CheckLeave(ctx context.Context, req *v1.CpLeaveCheckReq) (*utils.Response[any], error)
|
||||
GetLeaveTypes(ctx context.Context, req *v1.CpLeaveTypesReq) (*utils.Response[any], error)
|
||||
GetLeaveTypeCfg(ctx context.Context, req *v1.CpLeaveTypeCfgReq) (*utils.Response[any], error)
|
||||
GetApproveFlow(ctx context.Context, req *v1.CpLeaveApproveFlowReq) (*utils.Response[any], error)
|
||||
Apply(ctx context.Context, req *v1.CpLeaveApplyReq) (*utils.Response[any], error)
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ type Type string
|
||||
// Type values.
|
||||
const (
|
||||
TypeReport Type = "report"
|
||||
TypeApply Type = "apply"
|
||||
)
|
||||
|
||||
func (_type Type) String() string {
|
||||
@@ -135,7 +136,7 @@ func (_type Type) String() string {
|
||||
// TypeValidator is a validator for the "type" field enum values. It is called by the builders before save.
|
||||
func TypeValidator(_type Type) error {
|
||||
switch _type {
|
||||
case TypeReport:
|
||||
case TypeReport, TypeApply:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("cpleave: invalid enum value for type field: %q", _type)
|
||||
|
||||
@@ -77,7 +77,7 @@ var (
|
||||
{Name: "leave_id", Type: field.TypeString},
|
||||
{Name: "title", Type: field.TypeString},
|
||||
{Name: "status", Type: field.TypeEnum, Enums: []string{"done", "fail"}},
|
||||
{Name: "type", Type: field.TypeEnum, Enums: []string{"report"}},
|
||||
{Name: "type", Type: field.TypeEnum, Enums: []string{"report", "apply"}},
|
||||
{Name: "desc", Type: field.TypeString, Nullable: true, Size: 2147483647},
|
||||
{Name: "cp_user_id", Type: field.TypeInt64},
|
||||
{Name: "user_id", Type: field.TypeInt64},
|
||||
|
||||
@@ -21,7 +21,7 @@ func (CpLeave) Fields() []ent.Field {
|
||||
field.String("leave_id").NotEmpty(),
|
||||
field.String("title").NotEmpty(),
|
||||
field.Enum("status").Values("done", "fail"),
|
||||
field.Enum("type").Values("report"),
|
||||
field.Enum("type").Values("report", "apply"),
|
||||
field.Text("desc").Optional(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,3 +208,175 @@ func (v CpLeaveServiceV1) Upload(ctx context.Context, req *v1.CpLeaveUploadReq)
|
||||
func NewCpLeaveServiceV1() *CpLeaveServiceV1 {
|
||||
return &CpLeaveServiceV1{}
|
||||
}
|
||||
|
||||
// CheckLeave 检查是否允许请假
|
||||
func (v CpLeaveServiceV1) CheckLeave(ctx context.Context, req *v1.CpLeaveCheckReq) *utils.Response[any] {
|
||||
user := utils.GetUserInfoFromCtx(ctx)
|
||||
|
||||
cpUser := db2.Global.CpUser.Query().
|
||||
Where(cpuser.ID(req.CpUserId), cpuser.HasSysuserWith(sysuser.ID(user.ID))).
|
||||
WithSysuser().WithSchool().OnlyX(ctx)
|
||||
if cpUser.Edges.Sysuser == nil {
|
||||
utils.OkOrPanic(errors2.NewBusinessError(400, "非法的今日校园账号"))
|
||||
}
|
||||
|
||||
schoolDetail := school.GetSchoolDetail(ctx, cpUser.SchoolID)
|
||||
refreshResult := login.EnsureCookieValid(ctx, &login.RefreshCookieParams{
|
||||
ID: cpUser.ID, Cookie: cpUser.Cookie, Tgc: cpUser.Tgc,
|
||||
LoginType: cpUser.LoginType, Username: cpUser.Username,
|
||||
Password: cpUser.Password, SchoolID: cpUser.SchoolID,
|
||||
}, &schoolDetail)
|
||||
if refreshResult.Cookie != cpUser.Cookie {
|
||||
db2.Global.CpUser.UpdateOneID(cpUser.ID).SetCookie(refreshResult.Cookie).SetTgc(refreshResult.Tgc).ExecX(ctx)
|
||||
}
|
||||
|
||||
reportApp := leave.NewCpdailyReportApp(refreshResult.Client, schoolDetail.WecloudUrl)
|
||||
err := reportApp.CheckOnceLeave()
|
||||
if err != nil {
|
||||
utils.OkOrPanic(err)
|
||||
}
|
||||
return utils.SuccessWithMsg("允许请假")
|
||||
}
|
||||
|
||||
// GetLeaveTypes 获取请假类型列表
|
||||
func (v CpLeaveServiceV1) GetLeaveTypes(ctx context.Context, req *v1.CpLeaveTypesReq) *utils.Response[any] {
|
||||
user := utils.GetUserInfoFromCtx(ctx)
|
||||
|
||||
cpUser := db2.Global.CpUser.Query().
|
||||
Where(cpuser.ID(req.CpUserId), cpuser.HasSysuserWith(sysuser.ID(user.ID))).
|
||||
WithSysuser().WithSchool().OnlyX(ctx)
|
||||
if cpUser.Edges.Sysuser == nil {
|
||||
utils.OkOrPanic(errors2.NewBusinessError(400, "非法的今日校园账号"))
|
||||
}
|
||||
|
||||
schoolDetail := school.GetSchoolDetail(ctx, cpUser.SchoolID)
|
||||
refreshResult := login.EnsureCookieValid(ctx, &login.RefreshCookieParams{
|
||||
ID: cpUser.ID, Cookie: cpUser.Cookie, Tgc: cpUser.Tgc,
|
||||
LoginType: cpUser.LoginType, Username: cpUser.Username,
|
||||
Password: cpUser.Password, SchoolID: cpUser.SchoolID,
|
||||
}, &schoolDetail)
|
||||
if refreshResult.Cookie != cpUser.Cookie {
|
||||
db2.Global.CpUser.UpdateOneID(cpUser.ID).SetCookie(refreshResult.Cookie).SetTgc(refreshResult.Tgc).ExecX(ctx)
|
||||
}
|
||||
|
||||
reportApp := leave.NewCpdailyReportApp(refreshResult.Client, schoolDetail.WecloudUrl)
|
||||
leaveTypes := reportApp.QueryLeaveTypes()
|
||||
return utils.SuccessWithData[any](leaveTypes.Value())
|
||||
}
|
||||
|
||||
// GetLeaveTypeCfg 查询请假类型配置
|
||||
func (v CpLeaveServiceV1) GetLeaveTypeCfg(ctx context.Context, req *v1.CpLeaveTypeCfgReq) *utils.Response[any] {
|
||||
user := utils.GetUserInfoFromCtx(ctx)
|
||||
|
||||
cpUser := db2.Global.CpUser.Query().
|
||||
Where(cpuser.ID(req.CpUserId), cpuser.HasSysuserWith(sysuser.ID(user.ID))).
|
||||
WithSysuser().WithSchool().OnlyX(ctx)
|
||||
if cpUser.Edges.Sysuser == nil {
|
||||
utils.OkOrPanic(errors2.NewBusinessError(400, "非法的今日校园账号"))
|
||||
}
|
||||
|
||||
schoolDetail := school.GetSchoolDetail(ctx, cpUser.SchoolID)
|
||||
refreshResult := login.EnsureCookieValid(ctx, &login.RefreshCookieParams{
|
||||
ID: cpUser.ID, Cookie: cpUser.Cookie, Tgc: cpUser.Tgc,
|
||||
LoginType: cpUser.LoginType, Username: cpUser.Username,
|
||||
Password: cpUser.Password, SchoolID: cpUser.SchoolID,
|
||||
}, &schoolDetail)
|
||||
if refreshResult.Cookie != cpUser.Cookie {
|
||||
db2.Global.CpUser.UpdateOneID(cpUser.ID).SetCookie(refreshResult.Cookie).SetTgc(refreshResult.Tgc).ExecX(ctx)
|
||||
}
|
||||
|
||||
reportApp := leave.NewCpdailyReportApp(refreshResult.Client, schoolDetail.WecloudUrl)
|
||||
cfg := reportApp.QueryLeaveTypeCfg(req.Code)
|
||||
return utils.SuccessWithData[any](cfg.Value())
|
||||
}
|
||||
|
||||
// GetApproveFlow 获取审批人列表
|
||||
func (v CpLeaveServiceV1) GetApproveFlow(ctx context.Context, req *v1.CpLeaveApproveFlowReq) *utils.Response[any] {
|
||||
user := utils.GetUserInfoFromCtx(ctx)
|
||||
|
||||
cpUser := db2.Global.CpUser.Query().
|
||||
Where(cpuser.ID(req.CpUserId), cpuser.HasSysuserWith(sysuser.ID(user.ID))).
|
||||
WithSysuser().WithSchool().OnlyX(ctx)
|
||||
if cpUser.Edges.Sysuser == nil {
|
||||
utils.OkOrPanic(errors2.NewBusinessError(400, "非法的今日校园账号"))
|
||||
}
|
||||
|
||||
schoolDetail := school.GetSchoolDetail(ctx, cpUser.SchoolID)
|
||||
refreshResult := login.EnsureCookieValid(ctx, &login.RefreshCookieParams{
|
||||
ID: cpUser.ID, Cookie: cpUser.Cookie, Tgc: cpUser.Tgc,
|
||||
LoginType: cpUser.LoginType, Username: cpUser.Username,
|
||||
Password: cpUser.Password, SchoolID: cpUser.SchoolID,
|
||||
}, &schoolDetail)
|
||||
if refreshResult.Cookie != cpUser.Cookie {
|
||||
db2.Global.CpUser.UpdateOneID(cpUser.ID).SetCookie(refreshResult.Cookie).SetTgc(refreshResult.Tgc).ExecX(ctx)
|
||||
}
|
||||
|
||||
reportApp := leave.NewCpdailyReportApp(refreshResult.Client, schoolDetail.WecloudUrl)
|
||||
flow := reportApp.ObtainApproveFlow(req.LeaveType, req.StartTime, req.EndTime)
|
||||
return utils.SuccessWithData[any](flow.Value())
|
||||
}
|
||||
|
||||
// Apply 提交请假申请
|
||||
func (v CpLeaveServiceV1) Apply(ctx context.Context, req *v1.CpLeaveApplyReq) *utils.Response[any] {
|
||||
user := utils.GetUserInfoFromCtx(ctx)
|
||||
|
||||
cpUser := db2.Global.CpUser.Query().
|
||||
Where(cpuser.ID(req.CpUserId), cpuser.HasSysuserWith(sysuser.ID(user.ID))).
|
||||
WithSysuser().WithSchool().OnlyX(ctx)
|
||||
if cpUser.Edges.Sysuser == nil {
|
||||
utils.OkOrPanic(errors2.NewBusinessError(400, "非法的今日校园账号"))
|
||||
}
|
||||
|
||||
// 计算扣款金额
|
||||
basePoint, err := decimal.NewFromString(db2.Global.SysConfig.Query().Where(sysconfig.KeyEQ(cst2.ConfigRedisCpdailyLeave)).OnlyX(ctx).Value)
|
||||
utils.OkOrPanic(err)
|
||||
if user.Edges.Agent != nil {
|
||||
basePoint = basePoint.Mul(user.Edges.Agent.Rate)
|
||||
}
|
||||
|
||||
// 先扣款
|
||||
balance.BalanceService.ChangeUserBalance(ctx, user.ID, basePoint.Neg(), "今日校园请假")
|
||||
|
||||
// 创建请假记录
|
||||
leaveRecord := db2.Global.CpLeave.Create().
|
||||
SetCpUserID(req.CpUserId).
|
||||
SetUserID(user.ID).
|
||||
SetLeaveID(fmt.Sprintf("apply_%d", req.CpUserId)).
|
||||
SetTitle(fmt.Sprintf("请假申请: %s ~ %s", req.StartTime, req.EndTime)).
|
||||
SetStatus(cpleave.StatusFail).
|
||||
SetType(cpleave.TypeApply).
|
||||
SetDesc("正在处理中...").
|
||||
SaveX(ctx)
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
balance.BalanceService.ChangeUserBalance(ctx, user.ID, basePoint, "请假失败退款")
|
||||
desc := fmt.Sprintf("请假失败: %v", r)
|
||||
db2.Global.CpLeave.UpdateOne(leaveRecord).
|
||||
SetStatus(cpleave.StatusFail).
|
||||
SetDesc(desc).
|
||||
ExecX(ctx)
|
||||
utils.OkOrPanic(errors2.NewBusinessError(500, desc))
|
||||
}
|
||||
}()
|
||||
|
||||
schoolDetail := school.GetSchoolDetail(ctx, cpUser.SchoolID)
|
||||
refreshResult := login.EnsureCookieValid(ctx, &login.RefreshCookieParams{
|
||||
ID: cpUser.ID, Cookie: cpUser.Cookie, Tgc: cpUser.Tgc,
|
||||
LoginType: cpUser.LoginType, Username: cpUser.Username,
|
||||
Password: cpUser.Password, SchoolID: cpUser.SchoolID,
|
||||
}, &schoolDetail)
|
||||
if refreshResult.Cookie != cpUser.Cookie {
|
||||
db2.Global.CpUser.UpdateOneID(cpUser.ID).SetCookie(refreshResult.Cookie).SetTgc(refreshResult.Tgc).ExecX(ctx)
|
||||
}
|
||||
|
||||
reportApp := leave.NewCpdailyReportApp(refreshResult.Client, schoolDetail.WecloudUrl)
|
||||
reportApp.SubmitLeaveApply(ctx, req, cpUser.Username, cpUser.MobileCode)
|
||||
|
||||
db2.Global.CpLeave.UpdateOne(leaveRecord).
|
||||
SetStatus(cpleave.StatusDone).
|
||||
SetDesc("已提交").
|
||||
ExecX(ctx)
|
||||
|
||||
return utils.SuccessWithMsg("请假申请提交成功")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user