package controllers import ( "encoding/json" "fmt" "io" "strconv" "strings" "time" "server/models" "server/pkg/jwtutil" beego "github.com/beego/beego/v2/server/web" ) // BackendErpCustomerController ERP客户管理控制器 type BackendErpCustomerController struct { beego.Controller } func (c *BackendErpCustomerController) customerClaims() (*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 *BackendErpCustomerController) customerJsonErr(httpStatus, bizCode int, msg string) { c.Ctx.Output.SetStatus(httpStatus) c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg} _ = c.ServeJSON() } func (c *BackendErpCustomerController) customerOk(data interface{}) { c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": data} _ = c.ServeJSON() } type customerFormPayload struct { CustomerName string `json:"customer_name"` CustomerType string `json:"customer_type"` ContactPerson string `json:"contact_person"` ContactPhone string `json:"contact_phone"` ContactEmail string `json:"contact_email"` CustomerLevel string `json:"customer_level"` Industry string `json:"industry"` RegisteredCapital string `json:"registered_capital"` PaidCapital string `json:"paid_capital"` EstablishDate string `json:"establish_date"` AdministrativeDivision string `json:"administrative_division"` EnterpriseType string `json:"enterprise_type"` TaxpayerQualification string `json:"taxpayer_qualification"` BusinessScope string `json:"business_scope"` Address string `json:"address"` RegisterTime string `json:"register_time"` ExpireTime string `json:"expire_time"` Status string `json:"status"` IsDraft int8 `json:"is_draft"` Remark string `json:"remark"` InvoiceTitle string `json:"invoice_title"` TaxNumber string `json:"tax_number"` BankName string `json:"bank_name"` BankAccount string `json:"bank_account"` RegisteredAddress string `json:"registered_address"` RegisteredPhone string `json:"registered_phone"` } // List GET /backend/erp/customer/list func (c *BackendErpCustomerController) List() { claims, err := c.customerClaims() if err != nil { c.customerJsonErr(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")) status := strings.TrimSpace(c.GetString("status")) isDraft := strings.TrimSpace(c.GetString("is_draft")) if page < 1 { page = 1 } if pageSize < 1 || pageSize > 100 { pageSize = 20 } // 已移入公海(in_pool=1)的客户不在客户列表中展示,公海请到 /backend/crm/pool/list 查看 qs := models.Orm.QueryTable(new(models.TenantCrmCustomer)). Filter("tenant_id", fmt.Sprintf("%d", claims.TenantId)). Filter("delete_time__isnull", true). Filter("in_pool", 0) if keyword != "" { qs = qs.Filter("customer_name__contains", keyword) } if customerType != "" { qs = qs.Filter("customer_type", customerType) } if customerLevel != "" { qs = qs.Filter("customer_level", customerLevel) } if status != "" { qs = qs.Filter("status", status) } if isDraft != "" { if isDraft == "1" { qs = qs.Filter("is_draft", 1) } else { qs = qs.Filter("is_draft", 0) } } total, _ := qs.Count() var list []models.TenantCrmCustomer _, err = qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&list) if err != nil { c.customerJsonErr(500, 500, "查询失败: "+err.Error()) return } c.customerOk(map[string]interface{}{ "list": list, "total": total, "page": page, "pageSize": pageSize, }) } // Detail GET /backend/erp/customer/:id func (c *BackendErpCustomerController) Detail() { claims, err := c.customerClaims() if err != nil { c.customerJsonErr(401, 401, err.Error()) return } idStr := c.Ctx.Input.Param(":id") id, _ := strconv.ParseUint(idStr, 10, 64) if id == 0 { c.customerJsonErr(400, 400, "无效的ID") return } var customer models.TenantCrmCustomer err = models.Orm.QueryTable(new(models.TenantCrmCustomer)). Filter("id", id). Filter("tenant_id", fmt.Sprintf("%d", claims.TenantId)). One(&customer) if err != nil { c.customerJsonErr(404, 404, "客户未找到") return } c.customerOk(customer) } // Create POST /backend/erp/customer func (c *BackendErpCustomerController) Create() { claims, err := c.customerClaims() if err != nil { c.customerJsonErr(401, 401, err.Error()) return } raw, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { c.customerJsonErr(400, 400, "参数错误") return } var p customerFormPayload if err := json.Unmarshal(raw, &p); err != nil { c.customerJsonErr(400, 400, "参数错误") return } if strings.TrimSpace(p.CustomerName) == "" { c.customerJsonErr(400, 400, "客户名称不能为空") return } // 正式保存时验证联系电话,草稿不强制 if p.IsDraft == 0 && strings.TrimSpace(p.ContactPhone) == "" { c.customerJsonErr(400, 400, "联系人电话不能为空") return } customer := models.TenantCrmCustomer{ TenantID: fmt.Sprintf("%d", claims.TenantId), CustomerName: strings.TrimSpace(p.CustomerName), CustomerType: p.CustomerType, ContactPerson: strings.TrimSpace(p.ContactPerson), ContactPhone: strings.TrimSpace(p.ContactPhone), ContactEmail: strings.TrimSpace(p.ContactEmail), CustomerLevel: p.CustomerLevel, Industry: strings.TrimSpace(p.Industry), RegisteredCapital: strings.TrimSpace(p.RegisteredCapital), PaidCapital: strings.TrimSpace(p.PaidCapital), AdministrativeDivision: strings.TrimSpace(p.AdministrativeDivision), EnterpriseType: strings.TrimSpace(p.EnterpriseType), TaxpayerQualification: strings.TrimSpace(p.TaxpayerQualification), BusinessScope: strings.TrimSpace(p.BusinessScope), Address: strings.TrimSpace(p.Address), Status: p.Status, IsDraft: p.IsDraft, Remark: p.Remark, InvoiceTitle: strings.TrimSpace(p.InvoiceTitle), TaxNumber: strings.TrimSpace(p.TaxNumber), BankName: strings.TrimSpace(p.BankName), BankAccount: strings.TrimSpace(p.BankAccount), RegisteredAddress: strings.TrimSpace(p.RegisteredAddress), RegisteredPhone: strings.TrimSpace(p.RegisteredPhone), OwnerUserID: fmt.Sprintf("%d", claims.UserID), OwnerUserName: claims.Username, CreateUserID: fmt.Sprintf("%d", claims.UserID), CreateTime: time.Now(), UpdateTime: time.Now(), } if p.RegisterTime != "" { if t, err := time.ParseInLocation("2006-01-02", p.RegisterTime, time.Local); err == nil { customer.RegisterTime = &t } } if p.ExpireTime != "" { if t, err := time.ParseInLocation("2006-01-02", p.ExpireTime, time.Local); err == nil { customer.ExpireTime = &t } } if p.EstablishDate != "" { if t, err := time.ParseInLocation("2006-01-02", p.EstablishDate, time.Local); err == nil { customer.EstablishDate = &t } } if customer.CustomerLevel == "" { customer.CustomerLevel = "3" } if customer.Status == "" { customer.Status = "1" } id, err := models.Orm.Insert(&customer) if err != nil { c.customerJsonErr(500, 500, "创建失败: "+err.Error()) return } c.customerOk(map[string]interface{}{"id": id}) } // Update PUT /backend/erp/customer/:id func (c *BackendErpCustomerController) Update() { claims, err := c.customerClaims() if err != nil { c.customerJsonErr(401, 401, err.Error()) return } idStr := c.Ctx.Input.Param(":id") id, _ := strconv.ParseUint(idStr, 10, 64) if id == 0 { c.customerJsonErr(400, 400, "无效的ID") return } raw, err := io.ReadAll(c.Ctx.Request.Body) if err != nil { c.customerJsonErr(400, 400, "参数错误") return } var p customerFormPayload if err := json.Unmarshal(raw, &p); err != nil { c.customerJsonErr(400, 400, "参数错误") return } var customer models.TenantCrmCustomer err = models.Orm.QueryTable(new(models.TenantCrmCustomer)). Filter("id", id). Filter("tenant_id", fmt.Sprintf("%d", claims.TenantId)). One(&customer) if err != nil { c.customerJsonErr(404, 404, "客户未找到") return } customer.CustomerName = strings.TrimSpace(p.CustomerName) customer.CustomerType = p.CustomerType customer.ContactPerson = strings.TrimSpace(p.ContactPerson) customer.ContactPhone = strings.TrimSpace(p.ContactPhone) customer.ContactEmail = strings.TrimSpace(p.ContactEmail) customer.CustomerLevel = p.CustomerLevel customer.Industry = strings.TrimSpace(p.Industry) customer.RegisteredCapital = strings.TrimSpace(p.RegisteredCapital) customer.PaidCapital = strings.TrimSpace(p.PaidCapital) customer.AdministrativeDivision = strings.TrimSpace(p.AdministrativeDivision) customer.EnterpriseType = strings.TrimSpace(p.EnterpriseType) customer.TaxpayerQualification = strings.TrimSpace(p.TaxpayerQualification) customer.BusinessScope = strings.TrimSpace(p.BusinessScope) customer.Address = strings.TrimSpace(p.Address) customer.Status = p.Status customer.IsDraft = p.IsDraft customer.Remark = p.Remark customer.InvoiceTitle = strings.TrimSpace(p.InvoiceTitle) customer.TaxNumber = strings.TrimSpace(p.TaxNumber) customer.BankName = strings.TrimSpace(p.BankName) customer.BankAccount = strings.TrimSpace(p.BankAccount) customer.RegisteredAddress = strings.TrimSpace(p.RegisteredAddress) customer.RegisteredPhone = strings.TrimSpace(p.RegisteredPhone) customer.UpdateTime = time.Now() if p.RegisterTime != "" { if t, err := time.ParseInLocation("2006-01-02", p.RegisterTime, time.Local); err == nil { customer.RegisterTime = &t } } else { customer.RegisterTime = nil } if p.ExpireTime != "" { if t, err := time.ParseInLocation("2006-01-02", p.ExpireTime, time.Local); err == nil { customer.ExpireTime = &t } } else { customer.ExpireTime = nil } if p.EstablishDate != "" { if t, err := time.ParseInLocation("2006-01-02", p.EstablishDate, time.Local); err == nil { customer.EstablishDate = &t } } else { customer.EstablishDate = nil } _, err = models.Orm.Update(&customer) if err != nil { c.customerJsonErr(500, 500, "更新失败: "+err.Error()) return } c.customerOk(nil) } // Delete DELETE /backend/erp/customer/:id func (c *BackendErpCustomerController) Delete() { claims, err := c.customerClaims() if err != nil { c.customerJsonErr(401, 401, err.Error()) return } idStr := c.Ctx.Input.Param(":id") id, _ := strconv.ParseUint(idStr, 10, 64) if id == 0 { c.customerJsonErr(400, 400, "无效的ID") return } // 删除权限:仅平台管理员、租户管理员或创建人本人可删除 var cust models.TenantCrmCustomer if 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); err != nil { c.customerJsonErr(404, 404, "客户未找到") return } if !canDeleteCrmRecord(claims, cust.CreateUserID) { c.customerJsonErr(403, 403, "只有创建人、租户管理员或平台管理员可以删除该客户") return } // 软删除:仅置 delete_time,不物理删除 now := time.Now() _, err = models.Orm.QueryTable(new(models.TenantCrmCustomer)). Filter("id", id). Filter("tenant_id", fmt.Sprintf("%d", claims.TenantId)). Update(map[string]interface{}{ "delete_time": now, "update_time": now, }) if err != nil { c.customerJsonErr(500, 500, "删除失败: "+err.Error()) return } c.customerOk(nil) } // ToggleStatus POST /backend/erp/customer/:id/status func (c *BackendErpCustomerController) ToggleStatus() { claims, err := c.customerClaims() if err != nil { c.customerJsonErr(401, 401, err.Error()) return } idStr := c.Ctx.Input.Param(":id") id, _ := strconv.ParseUint(idStr, 10, 64) if id == 0 { c.customerJsonErr(400, 400, "无效的ID") return } raw, _ := io.ReadAll(c.Ctx.Request.Body) var p struct { Status string `json:"status"` } _ = json.Unmarshal(raw, &p) _, err = models.Orm.QueryTable(new(models.TenantCrmCustomer)). Filter("id", id). Filter("tenant_id", fmt.Sprintf("%d", claims.TenantId)). Update(map[string]interface{}{ "status": p.Status, "update_time": time.Now(), }) if err != nil { c.customerJsonErr(500, 500, "操作失败: "+err.Error()) return } c.customerOk(nil) }