修复个人中心问题

This commit is contained in:
2026-09-29 18:25:09 +08:00
parent 0dc5c2f075
commit ca4220f92c
44 changed files with 1793 additions and 310 deletions
+63 -3
View File
@@ -92,9 +92,9 @@ func (c *BackendCrmClueController) List() {
total, _ := qs.Count()
var list []models.TenantCrmClue
if total > 0 {
// 列表排列:跟进中(1) → 已转化(2) → 已废弃(3),同状态下按新→旧。
// 状态值本身即为期望的展示顺序,按 status 升序即可(排序在数据库侧完成,翻页后整体顺序一致)。
_, _ = qs.OrderBy("status", "-id").Offset((page - 1) * pageSize).Limit(pageSize).All(&list)
// 列表排列:按 id 倒序,最新创建的线索排在最前。
// 排序在数据库侧完成,翻页后整体顺序保持一致。
_, _ = qs.OrderBy("-id").Offset((page - 1) * pageSize).Limit(pageSize).All(&list)
}
pipelineOk(&c.Controller, map[string]interface{}{
"list": list, "total": total, "page": page, "pageSize": pageSize,
@@ -293,6 +293,66 @@ func (c *BackendCrmClueController) Update() {
pipelineOk(&c.Controller, map[string]interface{}{"id": clue.ID})
}
// ChangeStatus POST /backend/crm/clue/:id/status
// 线索状态流转:1=跟进中 / 3=已废弃。
// 「已转化(2)」不开放本接口——必须通过 Convert 完成(会落地正式客户并锁定线索),
// 否则会出现「状态已转化但客户未落地」的脏数据。
func (c *BackendCrmClueController) ChangeStatus() {
claims, err := pipelineClaims(&c.Controller)
if err != nil {
pipelineErr(&c.Controller, 401, 401, err.Error())
return
}
id, _ := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
if id == 0 {
pipelineErr(&c.Controller, 400, 400, "无效的ID")
return
}
raw, _ := io.ReadAll(c.Ctx.Request.Body)
var p struct {
Status int8 `json:"status"`
}
if err := json.Unmarshal(raw, &p); err != nil {
pipelineErr(&c.Controller, 400, 400, "参数错误")
return
}
if p.Status != 1 && p.Status != 3 {
pipelineErr(&c.Controller, 400, 400, "仅支持流转为「跟进中 / 已废弃」,转为已转化请使用「转化商机」")
return
}
tenantID := pipelineTenantID(claims)
var clue models.TenantCrmClue
if err := models.Orm.QueryTable(new(models.TenantCrmClue)).
Filter("id", id).Filter("tenant_id", tenantID).
Filter("delete_time__isnull", true).One(&clue); err != nil {
pipelineErr(&c.Controller, 404, 404, "线索未找到")
return
}
// 数据范围校验:非管理员仅能操作本人(负责人或创建人)的数据
if !canAccessCrmRecord(claims, clue.OwnerUserID, clue.CreateUserID) {
pipelineErr(&c.Controller, 403, 403, "无权操作该线索数据")
return
}
if clue.Locked == 1 || clue.Status == 2 {
pipelineErr(&c.Controller, 400, 400, "线索已转化并锁定,不能流转状态")
return
}
// 状态未变化:直接幂等返回,不写日志
if clue.Status == p.Status {
pipelineOk(&c.Controller, map[string]interface{}{"id": clue.ID, "status": clue.Status})
return
}
if _, err := models.Orm.QueryTable(new(models.TenantCrmClue)).
Filter("id", id).Filter("tenant_id", tenantID).
Update(map[string]interface{}{"status": p.Status, "update_time": time.Now()}); err != nil {
pipelineErr(&c.Controller, 500, 500, "状态更新失败: "+err.Error())
return
}
crmWriteLog(tenantID, 1, clue.ID, "status",
fmt.Sprintf("线索状态:%s → %s", clueStatusName(clue.Status), clueStatusName(p.Status)), claims)
pipelineOk(&c.Controller, map[string]interface{}{"id": clue.ID, "status": p.Status})
}
// clueStatusName 线索状态文案(用于操作日志):1跟进中 / 2已转化 / 3已废弃
func clueStatusName(s int8) string {
switch s {