增加CRM模块

This commit is contained in:
2025-11-13 17:24:59 +08:00
parent 117e2b3440
commit 695bf2194f
32 changed files with 5340 additions and 44 deletions
+90
View File
@@ -0,0 +1,90 @@
package controllers
import (
"encoding/json"
"strconv"
"server/models"
"server/services"
beego "github.com/beego/beego/v2/server/web"
)
type ContactController struct {
beego.Controller
}
// List GET /api/crm/contact/list?tenant_id=&related_type=&related_id=
func (c *ContactController) List() {
tenantId := c.GetString("tenant_id")
relatedType, _ := strconv.Atoi(c.GetString("related_type"))
relatedId := c.GetString("related_id")
if tenantId == "" || relatedType == 0 || relatedId == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "缺少必要参数"}
c.ServeJSON()
return
}
list, err := services.ListContacts(tenantId, relatedType, relatedId)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok", "data": list}
}
c.ServeJSON()
}
// Add POST /api/crm/contact/add
func (c *ContactController) Add() {
var m models.Contact
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误"}
c.ServeJSON()
return
}
if err := services.CreateContact(&m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok", "data": m}
}
c.ServeJSON()
}
// Edit POST /api/crm/contact/edit
func (c *ContactController) Edit() {
var m models.Contact
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误"}
c.ServeJSON()
return
}
if m.Id == 0 {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
if err := services.UpdateContact(&m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok"}
}
c.ServeJSON()
}
// Delete POST /api/crm/contact/delete
func (c *ContactController) Delete() {
var body struct {
Id int64 `json:"id"`
TenantId string `json:"tenant_id"`
}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &body); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误"}
c.ServeJSON()
return
}
if err := services.DeleteContact(body.Id, body.TenantId); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok"}
}
c.ServeJSON()
}
+155
View File
@@ -0,0 +1,155 @@
package controllers
import (
"encoding/json"
"fmt"
"strconv"
"server/models"
"server/services"
beego "github.com/beego/beego/v2/server/web"
)
type CustomerController struct {
beego.Controller
}
// List GET /api/crm/customer/list
func (c *CustomerController) List() {
tenantId := c.GetString("tenantId")
keyword := c.GetString("keyword")
status := c.GetString("status")
page, _ := strconv.Atoi(c.GetString("page"))
pageSize, _ := strconv.Atoi(c.GetString("pageSize"))
list, total, err := services.ListCustomers(tenantId, keyword, status, page, pageSize)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok", "data": map[string]interface{}{"list": list, "total": total}}
}
c.ServeJSON()
}
// Detail GET /api/crm/customer/detail?id=...
func (c *CustomerController) Detail() {
id := c.GetString("id")
if id == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
m, err := services.GetCustomer(id)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok", "data": m}
}
c.ServeJSON()
}
// Add POST /api/crm/customer/add
func (c *CustomerController) Add() {
var m models.Customer
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误"}
c.ServeJSON()
return
}
if err := services.CreateCustomer(&m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok", "data": m}
}
c.ServeJSON()
}
// Edit POST /api/crm/customer/edit body: {id, ...}
func (c *CustomerController) Edit() {
var body map[string]interface{}
_ = json.Unmarshal(c.Ctx.Input.RequestBody, &body)
id, _ := body["id"].(string)
if id == "" {
// 也允许前端直接在JSON中传 id 字段,下面会再从结构体取
}
var m models.Customer
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &m); err != nil {
// 回退:从通用map中提取已知字段,避免类型不匹配导致失败
if body == nil {
_ = json.Unmarshal(c.Ctx.Input.RequestBody, &body)
}
toStr := func(v interface{}) string {
switch t := v.(type) {
case nil:
return ""
case string:
return t
case json.Number:
return t.String()
default:
return fmt.Sprint(v)
}
}
m = models.Customer{
Id: toStr(body["id"]),
TenantId: toStr(body["tenant_id"]),
CustomerName: toStr(body["customer_name"]),
CustomerType: toStr(body["customer_type"]),
ContactPerson: toStr(body["contact_person"]),
ContactPhone: toStr(body["contact_phone"]),
ContactEmail: toStr(body["contact_email"]),
CustomerLevel: toStr(body["customer_level"]),
Industry: toStr(body["industry"]),
Address: toStr(body["address"]),
Status: toStr(body["status"]),
Remark: toStr(body["remark"]),
}
if m.Id == "" {
if id == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
m.Id = id
}
}
if m.Id == "" {
if id == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
m.Id = id
}
if err := services.UpdateCustomer(&m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok"}
}
c.ServeJSON()
}
// Delete POST /api/crm/customer/delete body: {id, tenantId}
func (c *CustomerController) Delete() {
var body struct {
Id string `json:"id"`
TenantId string `json:"tenantId"`
}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &body); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误"}
c.ServeJSON()
return
}
if body.Id == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
if err := services.SoftDeleteCustomer(body.Id); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok"}
}
c.ServeJSON()
}
+36 -8
View File
@@ -123,9 +123,9 @@ func (c *MenuController) UpdateMenu() {
return
}
// 直接使用 Beego 的 BindJSON 方法
var menu models.Menu
if err := c.BindJSON(&menu); err != nil {
// 解析请求体为通用map,进行部分字段更新,避免未提供字段被置零
var body map[string]interface{}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &body); err != nil {
c.Data["json"] = map[string]interface{}{
"success": false,
"message": "请求参数错误",
@@ -135,11 +135,40 @@ func (c *MenuController) UpdateMenu() {
return
}
// 设置 ID
menu.Id = id
// 允许更新的字段映射:前端Key -> 数据库列名
allowed := map[string]string{
"Name": "name",
"Path": "path",
"ParentId": "parent_id",
"Icon": "icon",
"Order": "order",
"Status": "status",
"ComponentPath": "component_path",
"IsExternal": "is_external",
"ExternalUrl": "external_url",
"MenuType": "menu_type",
"Permission": "permission",
"IsShow": "is_show",
}
// 更新菜单
if err := models.UpdateMenu(&menu); err != nil {
params := orm.Params{}
for k, col := range allowed {
if v, ok := body[k]; ok {
params[col] = v
}
}
if len(params) == 0 {
c.Data["json"] = map[string]interface{}{
"success": false,
"message": "无可更新的字段",
}
c.ServeJSON()
return
}
o := orm.NewOrm()
if _, err := o.QueryTable("yz_menus").Filter("id", id).Update(params); err != nil {
c.Data["json"] = map[string]interface{}{
"success": false,
"message": "更新菜单失败",
@@ -149,7 +178,6 @@ func (c *MenuController) UpdateMenu() {
c.Data["json"] = map[string]interface{}{
"success": true,
"message": "更新菜单成功",
// "data": menu,
}
}
+110
View File
@@ -0,0 +1,110 @@
package controllers
import (
"encoding/json"
"strconv"
"server/models"
"server/services"
beego "github.com/beego/beego/v2/server/web"
)
type SupplierController struct {
beego.Controller
}
func (c *SupplierController) List() {
tenantId := c.GetString("tenantId")
keyword := c.GetString("keyword")
status := c.GetString("status")
page, _ := strconv.Atoi(c.GetString("page"))
pageSize, _ := strconv.Atoi(c.GetString("pageSize"))
list, total, err := services.ListSuppliers(tenantId, keyword, status, page, pageSize)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok", "data": map[string]interface{}{"list": list, "total": total}}
}
c.ServeJSON()
}
func (c *SupplierController) Detail() {
id := c.GetString("id")
if id == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
m, err := services.GetSupplier(id)
if err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok", "data": m}
}
c.ServeJSON()
}
func (c *SupplierController) Add() {
var m models.Supplier
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误"}
c.ServeJSON()
return
}
if err := services.CreateSupplier(&m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok", "data": m}
}
c.ServeJSON()
}
func (c *SupplierController) Edit() {
var body map[string]interface{}
_ = json.Unmarshal(c.Ctx.Input.RequestBody, &body)
id, _ := body["id"].(string)
var m models.Supplier
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误"}
c.ServeJSON()
return
}
if m.Id == "" {
if id == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
m.Id = id
}
if err := services.UpdateSupplier(&m); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok"}
}
c.ServeJSON()
}
func (c *SupplierController) Delete() {
var body struct {
Id string `json:"id"`
TenantId string `json:"tenantId"`
}
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &body); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "请求参数格式错误"}
c.ServeJSON()
return
}
if body.Id == "" {
c.Data["json"] = map[string]interface{}{"code": 1, "message": "id不能为空"}
c.ServeJSON()
return
}
if err := services.SoftDeleteSupplier(body.Id); err != nil {
c.Data["json"] = map[string]interface{}{"code": 1, "message": err.Error()}
} else {
c.Data["json"] = map[string]interface{}{"code": 0, "message": "ok"}
}
c.ServeJSON()
}