优化线索、商机、项目相关开发
This commit is contained in:
@@ -3,6 +3,8 @@ package controllers
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -39,6 +41,39 @@ func (c *BackendCrmFollowController) List() {
|
||||
relatedID := strings.TrimSpace(c.GetString("related_id"))
|
||||
followType := strings.TrimSpace(c.GetString("follow_type"))
|
||||
keyword := strings.TrimSpace(c.GetString("keyword"))
|
||||
includeSource := strings.TrimSpace(c.GetString("include_source")) == "1"
|
||||
|
||||
// 详情页链路模式(include_source=1):按 线索→商机→项目 累积返回上游 + 自身的数据
|
||||
if includeSource && relatedType != "" && relatedID != "" && relatedID != "0" {
|
||||
rid, _ := strconv.ParseUint(relatedID, 10, 64)
|
||||
rt, _ := strconv.Atoi(relatedType)
|
||||
refs := relatedChain(tenantID, int8(rt), rid)
|
||||
var merged []models.TenantCrmFollow
|
||||
for _, r := range refs {
|
||||
var rows []models.TenantCrmFollow
|
||||
sub := orm.NewCondition().
|
||||
And("tenant_id", tenantID).
|
||||
And("delete_time__isnull", true).
|
||||
And("related_type", r.Type).
|
||||
And("related_id", r.ID)
|
||||
_, _ = models.Orm.QueryTable(new(models.TenantCrmFollow)).SetCond(sub).All(&rows)
|
||||
merged = append(merged, rows...)
|
||||
}
|
||||
sort.Slice(merged, func(i, j int) bool {
|
||||
ti, tj := merged[i].FollowTime, merged[j].FollowTime
|
||||
if ti != nil && tj != nil && !ti.Equal(*tj) {
|
||||
return ti.After(*tj)
|
||||
}
|
||||
if (ti == nil) != (tj == nil) {
|
||||
return ti != nil
|
||||
}
|
||||
return merged[i].ID > merged[j].ID
|
||||
})
|
||||
pipelineOk(&c.Controller, map[string]interface{}{
|
||||
"list": merged, "total": len(merged), "page": 1, "pageSize": len(merged),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
cond := orm.NewCondition().And("tenant_id", tenantID).And("delete_time__isnull", true)
|
||||
if relatedType != "" {
|
||||
@@ -72,6 +107,7 @@ type followPayload struct {
|
||||
RelatedType int8 `json:"related_type"`
|
||||
RelatedID uint64 `json:"related_id"`
|
||||
RelatedName string `json:"related_name"`
|
||||
Stage int8 `json:"stage"` // 创建阶段:不传时默认取 related_type
|
||||
FollowType string `json:"follow_type"`
|
||||
FollowTime string `json:"follow_time"`
|
||||
Content string `json:"content"`
|
||||
@@ -106,17 +142,23 @@ func (c *BackendCrmFollowController) Add() {
|
||||
followTime = &t
|
||||
}
|
||||
nextContact := parsePipelineDateTime(p.NextContactTime)
|
||||
// 创建阶段:默认取当前关联类型(线索/商机/项目)
|
||||
stage := p.Stage
|
||||
if stage != 1 && stage != 2 && stage != 3 {
|
||||
stage = p.RelatedType
|
||||
}
|
||||
row := models.TenantCrmFollow{
|
||||
TenantID: tenantID,
|
||||
RelatedType: p.RelatedType,
|
||||
RelatedID: p.RelatedID,
|
||||
RelatedName: strings.TrimSpace(p.RelatedName),
|
||||
Stage: stage,
|
||||
FollowType: firstNonEmpty(p.FollowType, "1"),
|
||||
FollowTime: followTime,
|
||||
Content: p.Content,
|
||||
NextContactTime: nextContact,
|
||||
OwnerUserID: pipelineUID(claims),
|
||||
OwnerUserName: claims.Username,
|
||||
OwnerUserName: resolveUserName(claims),
|
||||
CreateTime: time.Now(),
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
@@ -159,6 +201,11 @@ func (c *BackendCrmFollowController) Edit() {
|
||||
return
|
||||
}
|
||||
row.FollowType = firstNonEmpty(p.FollowType, row.FollowType)
|
||||
// 回访阶段(所属阶段)允许修正:仅在传入合法阶段(1线索/2商机/3项目)时更新,
|
||||
// 保证"记录创建时所在阶段"可被纠正为沟通实际发生的阶段。
|
||||
if p.Stage == 1 || p.Stage == 2 || p.Stage == 3 {
|
||||
row.Stage = p.Stage
|
||||
}
|
||||
if t := parsePipelineDateTime(p.FollowTime); t != nil {
|
||||
row.FollowTime = t
|
||||
}
|
||||
@@ -237,17 +284,35 @@ func (c *BackendCrmAttachController) List() {
|
||||
}
|
||||
relatedType := strings.TrimSpace(c.GetString("related_type"))
|
||||
relatedID := strings.TrimSpace(c.GetString("related_id"))
|
||||
cond := orm.NewCondition().
|
||||
And("tenant_id", pipelineTenantID(claims)).
|
||||
And("delete_time__isnull", true)
|
||||
if relatedType != "" {
|
||||
cond = cond.And("related_type", relatedType)
|
||||
}
|
||||
if relatedID != "" {
|
||||
cond = cond.And("related_id", relatedID)
|
||||
}
|
||||
includeSource := strings.TrimSpace(c.GetString("include_source")) == "1"
|
||||
tenantID := pipelineTenantID(claims)
|
||||
|
||||
var list []models.TenantCrmAttach
|
||||
_, _ = models.Orm.QueryTable(new(models.TenantCrmAttach)).SetCond(cond).OrderBy("-id").All(&list)
|
||||
if includeSource && relatedType != "" && relatedID != "" && relatedID != "0" {
|
||||
// 链路模式:线索 → 商机 → 项目 累积
|
||||
rid, _ := strconv.ParseUint(relatedID, 10, 64)
|
||||
rt, _ := strconv.Atoi(relatedType)
|
||||
for _, r := range relatedChain(tenantID, int8(rt), rid) {
|
||||
var rows []models.TenantCrmAttach
|
||||
sub := orm.NewCondition().
|
||||
And("tenant_id", tenantID).
|
||||
And("delete_time__isnull", true).
|
||||
And("related_type", r.Type).
|
||||
And("related_id", r.ID)
|
||||
_, _ = models.Orm.QueryTable(new(models.TenantCrmAttach)).SetCond(sub).All(&rows)
|
||||
list = append(list, rows...)
|
||||
}
|
||||
sort.Slice(list, func(i, j int) bool { return list[i].ID > list[j].ID })
|
||||
} else {
|
||||
cond := orm.NewCondition().And("tenant_id", tenantID).And("delete_time__isnull", true)
|
||||
if relatedType != "" {
|
||||
cond = cond.And("related_type", relatedType)
|
||||
}
|
||||
if relatedID != "" {
|
||||
cond = cond.And("related_id", relatedID)
|
||||
}
|
||||
_, _ = models.Orm.QueryTable(new(models.TenantCrmAttach)).SetCond(cond).OrderBy("-id").All(&list)
|
||||
}
|
||||
pipelineOk(&c.Controller, map[string]interface{}{"list": list, "total": len(list)})
|
||||
}
|
||||
|
||||
@@ -290,7 +355,7 @@ func (c *BackendCrmAttachController) Add() {
|
||||
FileURL: strings.TrimSpace(p.FileURL),
|
||||
FileSize: p.FileSize,
|
||||
UploaderID: pipelineUID(claims),
|
||||
UploaderName: claims.Username,
|
||||
UploaderName: resolveUserName(claims),
|
||||
CreateTime: time.Now(),
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
@@ -350,18 +415,41 @@ func (c *BackendCrmEntityContactController) List() {
|
||||
}
|
||||
relatedType := strings.TrimSpace(c.GetString("related_type"))
|
||||
relatedID := strings.TrimSpace(c.GetString("related_id"))
|
||||
cond := orm.NewCondition().
|
||||
And("tenant_id", pipelineTenantID(claims)).
|
||||
And("delete_time__isnull", true)
|
||||
if relatedType != "" {
|
||||
cond = cond.And("related_type", relatedType)
|
||||
}
|
||||
if relatedID != "" {
|
||||
cond = cond.And("related_id", relatedID)
|
||||
}
|
||||
includeSource := strings.TrimSpace(c.GetString("include_source")) == "1"
|
||||
tenantID := pipelineTenantID(claims)
|
||||
|
||||
var list []models.TenantCrmEntityContact
|
||||
_, _ = models.Orm.QueryTable(new(models.TenantCrmEntityContact)).SetCond(cond).
|
||||
OrderBy("-is_primary", "-id").All(&list)
|
||||
if includeSource && relatedType != "" && relatedID != "" && relatedID != "0" {
|
||||
// 链路模式:线索 → 商机 → 项目 累积
|
||||
rid, _ := strconv.ParseUint(relatedID, 10, 64)
|
||||
rt, _ := strconv.Atoi(relatedType)
|
||||
for _, r := range relatedChain(tenantID, int8(rt), rid) {
|
||||
var rows []models.TenantCrmEntityContact
|
||||
sub := orm.NewCondition().
|
||||
And("tenant_id", tenantID).
|
||||
And("delete_time__isnull", true).
|
||||
And("related_type", r.Type).
|
||||
And("related_id", r.ID)
|
||||
_, _ = models.Orm.QueryTable(new(models.TenantCrmEntityContact)).SetCond(sub).All(&rows)
|
||||
list = append(list, rows...)
|
||||
}
|
||||
sort.Slice(list, func(i, j int) bool {
|
||||
if list[i].IsPrimary != list[j].IsPrimary {
|
||||
return list[i].IsPrimary > list[j].IsPrimary
|
||||
}
|
||||
return list[i].ID > list[j].ID
|
||||
})
|
||||
} else {
|
||||
cond := orm.NewCondition().And("tenant_id", tenantID).And("delete_time__isnull", true)
|
||||
if relatedType != "" {
|
||||
cond = cond.And("related_type", relatedType)
|
||||
}
|
||||
if relatedID != "" {
|
||||
cond = cond.And("related_id", relatedID)
|
||||
}
|
||||
_, _ = models.Orm.QueryTable(new(models.TenantCrmEntityContact)).SetCond(cond).
|
||||
OrderBy("-is_primary", "-id").All(&list)
|
||||
}
|
||||
pipelineOk(&c.Controller, map[string]interface{}{"list": list, "total": len(list)})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user