批量更新功能

This commit is contained in:
2026-09-14 16:15:44 +08:00
parent 6f106e43af
commit a26c98b92b
79 changed files with 4529 additions and 724 deletions
+35 -2
View File
@@ -2,6 +2,7 @@ package controllers
import (
"encoding/json"
"fmt"
"io"
"strconv"
"strings"
@@ -29,6 +30,8 @@ type cluePayload struct {
Amount float64 `json:"amount"` // 预计金额
NextContactTime string `json:"next_contact_time"`
ClueLevel string `json:"clue_level"`
// 线索状态:1跟进中 / 2已转化 / 3已废弃(编辑时可调整;新增固定为跟进中)
Status string `json:"status"`
ContactPerson string `json:"contact_person"`
ContactPosition string `json:"contact_position"`
ContactPhone string `json:"contact_phone"`
@@ -89,8 +92,9 @@ func (c *BackendCrmClueController) List() {
total, _ := qs.Count()
var list []models.TenantCrmClue
if total > 0 {
// 未转化的排前面,已转化的(locked=1)沉到列表下方
_, _ = qs.OrderBy("locked", "-id").Offset((page - 1) * pageSize).Limit(pageSize).All(&list)
// 列表排列:跟进中(1) → 已转化(2) → 已废弃(3),同状态下按新→旧。
// 状态值本身即为期望的展示顺序,按 status 升序即可(排序在数据库侧完成,翻页后整体顺序一致)。
_, _ = qs.OrderBy("status", "-id").Offset((page - 1) * pageSize).Limit(pageSize).All(&list)
}
pipelineOk(&c.Controller, map[string]interface{}{
"list": list, "total": total, "page": page, "pageSize": pageSize,
@@ -262,16 +266,45 @@ func (c *BackendCrmClueController) Update() {
clue.ContactQQ = strings.TrimSpace(p.ContactQQ)
clue.Address = strings.TrimSpace(p.Address)
clue.Remark = p.Remark
// 线索状态:编辑时可直接管理(1跟进中 / 2已转化 / 3已废弃)。
// 标为「已转化」时与转化流程保持一致:同时锁定(locked=1),列表中沉底且不能再编辑 / 转化;
// 改回跟进中 / 已废弃则解除锁定(历史数据同样兜底)。
prevStatus := clue.Status
if s := strings.TrimSpace(p.Status); s != "" {
if v, err := strconv.Atoi(s); err == nil && v >= 1 && v <= 3 {
clue.Status = int8(v)
clue.Locked = 0
if clue.Status == 2 {
clue.Locked = 1
}
}
}
clue.UpdateTime = time.Now()
if _, err := models.Orm.Update(&clue); err != nil {
pipelineErr(&c.Controller, 500, 500, "更新失败: "+err.Error())
return
}
if clue.Status != prevStatus {
crmWriteLog(clue.TenantID, 1, clue.ID, "status",
fmt.Sprintf("线索状态:%s → %s", clueStatusName(prevStatus), clueStatusName(clue.Status)), claims)
}
crmWriteLog(clue.TenantID, 1, clue.ID, "update", "更新线索:"+clue.ClueName, claims)
pipelineOk(&c.Controller, map[string]interface{}{"id": clue.ID})
}
// clueStatusName 线索状态文案(用于操作日志):1跟进中 / 2已转化 / 3已废弃
func clueStatusName(s int8) string {
switch s {
case 2:
return "已转化"
case 3:
return "已废弃"
default:
return "跟进中"
}
}
// Delete DELETE /backend/crm/clue/:id
func (c *BackendCrmClueController) Delete() {
claims, err := pipelineClaims(&c.Controller)