269 lines
7.3 KiB
Go
269 lines
7.3 KiB
Go
package controllers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"time"
|
|
|
|
"server/models"
|
|
"server/pkg/jwtutil"
|
|
|
|
"github.com/beego/beego/v2/client/orm"
|
|
beego "github.com/beego/beego/v2/server/web"
|
|
)
|
|
|
|
// BackendCrmPoolController 客户公海控制器
|
|
// 公海语义:in_pool=1 的客户处于公海中(租户共享,无个人负责人);
|
|
// 移入公海会置 in_pool=1 并释放负责人,领取/分配/移出会置 in_pool=0 并绑定负责人。
|
|
type BackendCrmPoolController struct {
|
|
beego.Controller
|
|
}
|
|
|
|
func (c *BackendCrmPoolController) poolClaims() (*jwtutil.Claims, error) {
|
|
auth := c.Ctx.Request.Header.Get("Authorization")
|
|
if auth == "" {
|
|
return nil, fmt.Errorf("未登录")
|
|
}
|
|
parts := strings.SplitN(auth, " ", 2)
|
|
if len(parts) != 2 || parts[0] != "Bearer" {
|
|
return nil, fmt.Errorf("认证信息格式错误")
|
|
}
|
|
claims, err := jwtutil.ParseToken(parts[1])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("无效的token")
|
|
}
|
|
if claims.UserType != "backend" {
|
|
return nil, fmt.Errorf("无权访问")
|
|
}
|
|
return claims, nil
|
|
}
|
|
|
|
func (c *BackendCrmPoolController) poolJsonErr(httpStatus, bizCode int, msg string) {
|
|
c.Ctx.Output.SetStatus(httpStatus)
|
|
c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg}
|
|
_ = c.ServeJSON()
|
|
}
|
|
|
|
func (c *BackendCrmPoolController) poolOk(data interface{}) {
|
|
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": data}
|
|
_ = c.ServeJSON()
|
|
}
|
|
|
|
// List GET /backend/crm/pool/list 公海列表(无负责人、租户内共享)
|
|
func (c *BackendCrmPoolController) List() {
|
|
claims, err := c.poolClaims()
|
|
if err != nil {
|
|
c.poolJsonErr(401, 401, err.Error())
|
|
return
|
|
}
|
|
|
|
page, _ := c.GetInt("page", 1)
|
|
pageSize, _ := c.GetInt("pageSize", 20)
|
|
keyword := strings.TrimSpace(c.GetString("keyword"))
|
|
customerType := strings.TrimSpace(c.GetString("customer_type"))
|
|
customerLevel := strings.TrimSpace(c.GetString("customer_level"))
|
|
startTime := strings.TrimSpace(c.GetString("start_time"))
|
|
endTime := strings.TrimSpace(c.GetString("end_time"))
|
|
if page < 1 {
|
|
page = 1
|
|
}
|
|
if pageSize < 1 || pageSize > 100 {
|
|
pageSize = 20
|
|
}
|
|
|
|
cond := orm.NewCondition().
|
|
And("tenant_id", fmt.Sprintf("%d", claims.TenantId)).
|
|
And("delete_time__isnull", true).
|
|
And("in_pool", 1)
|
|
if keyword != "" {
|
|
kw := orm.NewCondition().
|
|
Or("customer_name__contains", keyword).
|
|
Or("contact_person__contains", keyword).
|
|
Or("contact_phone__contains", keyword)
|
|
cond = cond.AndCond(kw)
|
|
}
|
|
if customerType != "" {
|
|
cond = cond.And("customer_type", customerType)
|
|
}
|
|
if customerLevel != "" {
|
|
cond = cond.And("customer_level", customerLevel)
|
|
}
|
|
if startTime != "" {
|
|
cond = cond.And("pool_in_time__gte", startTime)
|
|
}
|
|
if endTime != "" {
|
|
cond = cond.And("pool_in_time__lte", endTime+" 23:59:59")
|
|
}
|
|
|
|
qs := models.Orm.QueryTable(new(models.TenantCrmCustomer)).SetCond(cond)
|
|
total, _ := qs.Count()
|
|
var list []models.TenantCrmCustomer
|
|
if total > 0 {
|
|
_, _ = qs.OrderBy("-pool_in_time").Offset((page - 1) * pageSize).Limit(pageSize).All(&list)
|
|
}
|
|
|
|
c.poolOk(map[string]interface{}{
|
|
"list": list,
|
|
"total": total,
|
|
"page": page,
|
|
"pageSize": pageSize,
|
|
})
|
|
}
|
|
|
|
// Move POST /backend/crm/pool/move 移入公海:释放负责人,记录原负责人与原因
|
|
func (c *BackendCrmPoolController) Move() {
|
|
claims, err := c.poolClaims()
|
|
if err != nil {
|
|
c.poolJsonErr(401, 401, err.Error())
|
|
return
|
|
}
|
|
var p struct {
|
|
IDs []uint64 `json:"ids"`
|
|
Reason string `json:"reason"`
|
|
}
|
|
raw, _ := io.ReadAll(c.Ctx.Request.Body)
|
|
if err := json.Unmarshal(raw, &p); err != nil {
|
|
c.poolJsonErr(400, 400, "参数错误")
|
|
return
|
|
}
|
|
if len(p.IDs) == 0 {
|
|
c.poolJsonErr(400, 400, "请选择要移入公海客户")
|
|
return
|
|
}
|
|
reason := strings.TrimSpace(p.Reason)
|
|
if reason == "" {
|
|
c.poolJsonErr(400, 400, "请填写移入原因")
|
|
return
|
|
}
|
|
|
|
now := time.Now()
|
|
updated := 0
|
|
for _, id := range p.IDs {
|
|
var cust models.TenantCrmCustomer
|
|
err := models.Orm.QueryTable(new(models.TenantCrmCustomer)).
|
|
Filter("id", id).
|
|
Filter("tenant_id", fmt.Sprintf("%d", claims.TenantId)).
|
|
Filter("delete_time__isnull", true).
|
|
One(&cust)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
// 记录原负责人(移入公海前的负责人),再清空负责人并置入公海
|
|
cust.LastOwnerName = cust.OwnerUserName
|
|
cust.OwnerUserID = ""
|
|
cust.OwnerUserName = ""
|
|
cust.InPool = 1
|
|
cust.PoolReason = reason
|
|
cust.PoolInTime = &now
|
|
cust.UpdateTime = now
|
|
if _, err := models.Orm.Update(&cust,
|
|
"last_owner_name", "owner_user_id", "owner_user_name", "in_pool",
|
|
"pool_reason", "pool_in_time", "update_time"); err == nil {
|
|
updated++
|
|
}
|
|
}
|
|
c.poolOk(map[string]interface{}{"updated": updated})
|
|
}
|
|
|
|
// Claim POST /backend/crm/pool/claim 领取:将公海客户归属为当前登录用户
|
|
func (c *BackendCrmPoolController) Claim() {
|
|
claims, err := c.poolClaims()
|
|
if err != nil {
|
|
c.poolJsonErr(401, 401, err.Error())
|
|
return
|
|
}
|
|
var p struct {
|
|
IDs []uint64 `json:"ids"`
|
|
}
|
|
raw, _ := io.ReadAll(c.Ctx.Request.Body)
|
|
if err := json.Unmarshal(raw, &p); err != nil {
|
|
c.poolJsonErr(400, 400, "参数错误")
|
|
return
|
|
}
|
|
if len(p.IDs) == 0 {
|
|
c.poolJsonErr(400, 400, "请选择客户")
|
|
return
|
|
}
|
|
|
|
now := time.Now()
|
|
uid := fmt.Sprintf("%d", claims.UserID)
|
|
updated := 0
|
|
for _, id := range p.IDs {
|
|
var cust models.TenantCrmCustomer
|
|
err := models.Orm.QueryTable(new(models.TenantCrmCustomer)).
|
|
Filter("id", id).
|
|
Filter("tenant_id", fmt.Sprintf("%d", claims.TenantId)).
|
|
Filter("delete_time__isnull", true).
|
|
One(&cust)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
cust.OwnerUserID = uid
|
|
cust.OwnerUserName = resolveUserName(claims)
|
|
cust.InPool = 0
|
|
cust.PoolInTime = nil
|
|
cust.PoolReason = ""
|
|
cust.UpdateTime = now
|
|
if _, err := models.Orm.Update(&cust,
|
|
"owner_user_id", "owner_user_name", "in_pool", "pool_in_time", "pool_reason", "update_time"); err == nil {
|
|
updated++
|
|
}
|
|
}
|
|
c.poolOk(map[string]interface{}{"updated": updated})
|
|
}
|
|
|
|
// Assign POST /backend/crm/pool/assign 分配:将公海客户分配给指定负责人
|
|
func (c *BackendCrmPoolController) Assign() {
|
|
claims, err := c.poolClaims()
|
|
if err != nil {
|
|
c.poolJsonErr(401, 401, err.Error())
|
|
return
|
|
}
|
|
var p struct {
|
|
IDs []uint64 `json:"ids"`
|
|
OwnerUserID interface{} `json:"owner_user_id"`
|
|
OwnerUserName string `json:"owner_user_name"`
|
|
}
|
|
raw, _ := io.ReadAll(c.Ctx.Request.Body)
|
|
if err := json.Unmarshal(raw, &p); err != nil {
|
|
c.poolJsonErr(400, 400, "参数错误")
|
|
return
|
|
}
|
|
if len(p.IDs) == 0 {
|
|
c.poolJsonErr(400, 400, "请选择客户")
|
|
return
|
|
}
|
|
ownerID := strings.TrimSpace(fmt.Sprintf("%v", p.OwnerUserID))
|
|
if ownerID == "" {
|
|
c.poolJsonErr(400, 400, "请指定负责人")
|
|
return
|
|
}
|
|
|
|
now := time.Now()
|
|
updated := 0
|
|
for _, id := range p.IDs {
|
|
var cust models.TenantCrmCustomer
|
|
err := models.Orm.QueryTable(new(models.TenantCrmCustomer)).
|
|
Filter("id", id).
|
|
Filter("tenant_id", fmt.Sprintf("%d", claims.TenantId)).
|
|
Filter("delete_time__isnull", true).
|
|
One(&cust)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
cust.OwnerUserID = ownerID
|
|
cust.OwnerUserName = strings.TrimSpace(p.OwnerUserName)
|
|
cust.InPool = 0
|
|
cust.PoolInTime = nil
|
|
cust.PoolReason = ""
|
|
cust.UpdateTime = now
|
|
if _, err := models.Orm.Update(&cust,
|
|
"owner_user_id", "owner_user_name", "in_pool", "pool_in_time", "pool_reason", "update_time"); err == nil {
|
|
updated++
|
|
}
|
|
}
|
|
c.poolOk(map[string]interface{}{"updated": updated})
|
|
}
|