Files
lone-services/services/product/internal/apply/apply.go
T
2026-08-21 17:38:39 +08:00

211 lines
5.0 KiB
Go

package apply
import (
"context"
"lone-services/pkg/redis"
"lone-services/pkg/utils"
"lone-services/services/product/internal/dao"
"lone-services/services/product/internal/model"
"lone-services/services/product/internal/wecom"
"strconv"
"time"
jsoniter "github.com/json-iterator/go"
"github.com/zeromicro/go-zero/core/logx"
)
const (
applyProductEditKey = "apply:edit:product:"
applyEditTimeOut = 60 * 24 // 分钟
applyMd5Key = "keys:"
)
// Data Redis 中的编辑申请状态
type Data struct {
Uid int `json:"uid"`
Id int `json:"id"`
Reason string `json:"reason"`
Status uint8 `json:"status"` // 9待审 1通过 2驳回 0未申请
Time string `json:"time"`
Type uint8 `json:"type"`
}
func redisKey(uId, objId int) string {
return applyProductEditKey + strconv.Itoa(uId) + "_" + strconv.Itoa(objId)
}
func md5MapKey(md5 string) string {
return applyProductEditKey + applyMd5Key + md5
}
// Get 读取申请状态
func Get(ctx context.Context, uId, objId int) (Data, error) {
var data Data
if redis.Client == nil {
return data, nil
}
result, err := redis.Client.Get(ctx, redisKey(uId, objId)).Result()
if err == redis.Nil {
return data, nil
}
if err != nil {
return data, err
}
if len(result) < utils.NumberFive {
return data, nil
}
if err = jsoniter.Unmarshal([]byte(result), &data); err != nil {
return data, err
}
return data, nil
}
// Del 删除申请缓存(编辑成功后清除)
func Del(ctx context.Context, uId, objId int) error {
if redis.Client == nil {
return nil
}
return redis.Client.Del(ctx, redisKey(uId, objId)).Err()
}
// Set 发起编辑申请:写 Redis + action_apply_log,企微消息预留
func Set(ctx context.Context, uId, objId int, reason string) error {
data := Data{
Uid: uId,
Id: objId,
Reason: reason,
Status: dao.ApplyStatusWaitPass,
Type: dao.EditLogTypeProduct,
Time: time.Now().Format(time.DateTime),
}
md5, err := saveRedis(ctx, &data)
if err != nil {
return err
}
add := dao.ActionApplyLogCreate{
AdminId: uId,
ObjId: objId,
Type: dao.EditLogTypeProduct,
Reason: reason,
Status: dao.ApplyStatusWaitPass,
}
err = model.ActionApplyLogModel{}.Init().Create(&add)
if err != nil {
_ = Del(ctx, uId, objId)
logx.WithContext(ctx).Errorf("action apply log create: %v", err)
return err
}
wecom.NotifyProduct(wecom.NotifyJob{
ObjId: objId,
ObjType: dao.EditLogTypeProduct,
Type: wecom.ProductApplyReview,
Reason: reason,
Key: md5,
})
return nil
}
func saveRedis(ctx context.Context, data *Data) (string, error) {
if redis.Client == nil {
return "", nil
}
key := redisKey(data.Uid, data.Id)
md5 := utils.MD5Encrypt(strconv.Itoa(data.Uid) + strconv.Itoa(data.Id) + data.Time)
payload, err := jsoniter.Marshal(data)
if err != nil {
return md5, err
}
expire := time.Duration(applyEditTimeOut) * time.Minute
if err = redis.Client.Set(ctx, key, string(payload), expire).Err(); err != nil {
return md5, err
}
if data.Status == dao.ApplyStatusWaitPass {
if err = redis.Client.Set(ctx, md5MapKey(md5), key, expire).Err(); err != nil {
return md5, err
}
}
return md5, nil
}
// CanEdit 是否已获编辑权限(申请通过)
func CanEdit(ctx context.Context, uId, objId int) bool {
data, err := Get(ctx, uId, objId)
if err != nil {
logx.WithContext(ctx).Errorf("apply get: %v", err)
return false
}
return data.Status == dao.ApplyStatusDone
}
// Pass 临时:将编辑申请置为通过(企微审批对接后删除)
func Pass(ctx context.Context, uId, objId int) error {
data, err := Get(ctx, uId, objId)
if err != nil {
return err
}
if data.Status == dao.ApplyStatusDone {
return nil
}
if data.Status != dao.ApplyStatusWaitPass && data.Status != 0 {
return errAlreadyHandled
}
reason := data.Reason
if data.Status == 0 {
data = Data{
Uid: uId,
Id: objId,
Reason: "临时通过",
Type: dao.EditLogTypeProduct,
Time: time.Now().Format(time.DateTime),
}
reason = data.Reason
}
data.Status = dao.ApplyStatusDone
if data.Time == "" {
data.Time = time.Now().Format(time.DateTime)
}
if _, err = saveRedis(ctx, &data); err != nil {
return err
}
add := dao.ActionApplyLogCreate{
AdminId: uId,
ObjId: objId,
Type: dao.EditLogTypeProduct,
Reason: reason,
Status: dao.ApplyStatusDone,
}
err = model.ActionApplyLogModel{}.Init().Create(&add)
if err != nil {
logx.WithContext(ctx).Errorf("action apply log pass: %v", err)
return err
}
wecom.NotifyProduct(wecom.NotifyJob{
ObjId: objId,
ObjType: dao.EditLogTypeProduct,
Type: wecom.ProductNeedReview,
Action: dao.ApplyStatusDone,
Reason: reason,
})
return nil
}
// errAlreadyHandled 申请已驳回等不可再通过
var errAlreadyHandled = errApply("申请状态不可通过")
type errApply string
func (e errApply) Error() string { return string(e) }
// IsAlreadyHandled 是否为「状态不可通过」
func IsAlreadyHandled(err error) bool {
_, ok := err.(errApply)
return ok
}