소스 검색

add:公司修改为树形结构

zoie 2 일 전
부모
커밋
c78094f7ee
3개의 변경된 파일490개의 추가작업 그리고 14개의 파일을 삭제
  1. 122 2
      controllers/User.go
  2. 360 7
      models/Account/User.go
  3. 8 5
      routers/User.go

+ 122 - 2
controllers/User.go

@@ -6,8 +6,9 @@ import (
 	"ColdVerify_server/models/Account"
 	"ColdVerify_server/models/Distributor"
 	"ColdVerify_server/models/System"
-	beego "github.com/beego/beego/v2/server/web"
 	"math"
+
+	beego "github.com/beego/beego/v2/server/web"
 )
 
 type UserController struct {
@@ -103,7 +104,18 @@ func (c *UserController) Add() {
 	T_pass := c.GetString("T_pass")
 	T_passstr := c.GetString("T_passstr")
 	T_Distributor_id := c.GetString("T_Distributor_id")
-	if len(user_r.T_Distributor_id) > 0 {
+	T_pid, _ := c.GetInt("T_pid") // 父级ID
+
+	// 如果T_pid大于0,则需要获取该T_pid的公司的T_Distributor_id
+	if T_pid > 0 {
+		parentUser, is := Account.Read_User_ById(T_pid)
+		if !is {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "父级公司不存在!"}
+			c.ServeJSON()
+			return
+		}
+		T_Distributor_id = parentUser.T_Distributor_id
+	} else if len(user_r.T_Distributor_id) > 0 {
 		T_Distributor_id = user_r.T_Distributor_id
 	}
 
@@ -115,6 +127,7 @@ func (c *UserController) Add() {
 		T_Show:           1,
 		T_State:          1,
 		T_Distributor_id: T_Distributor_id, // 经销商id
+		T_pid:            T_pid,            // 父级ID
 	}
 
 	if _, is := Account.Read_UserByT_name(T_name); is {
@@ -129,6 +142,15 @@ func (c *UserController) Add() {
 		c.ServeJSON()
 		return
 	}
+
+	// 更新路径
+	err := Account.UpdateUserPath(int(Id))
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "更新路径失败!"}
+		c.ServeJSON()
+		return
+	}
+
 	System.Add_UserLogs_T(user_r.T_uuid, "用户管理", "添加", var_)
 
 	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Id}
@@ -188,6 +210,14 @@ func (c *UserController) Up() {
 		c.ServeJSON()
 		return
 	}
+
+	// 更新路径
+	err := Account.UpdateUserPath(r.Id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "更新路径失败!"}
+		c.ServeJSON()
+		return
+	}
 	System.Add_UserLogs_T(user_r.T_uuid, "用户管理", "修改", r)
 
 	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
@@ -422,3 +452,93 @@ func (c *UserController) Signature_Del() {
 
 	return
 }
+
+// 树形结构展示公司列表
+func (c *UserController) TreeList() {
+	// 验证登录 User_is, User_r
+	User_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	var T_Distributor_id string
+	// 优先使用经销商id
+	if len(User_r.T_Distributor_id) > 0 {
+		T_Distributor_id = User_r.T_Distributor_id
+	} else {
+		T_Distributor_id = c.GetString("T_Distributor_id")
+	}
+
+	// 获取名称搜索参数
+	T_name := c.GetString("T_name")
+
+	// 获取分销商映射
+	distributorList := Distributor.Read_Distributor_List_ALL("")
+	distributorMap := Distributor.DistributorListToMap(distributorList)
+
+	// 获取所有用户数据(支持名称过滤)
+	var users []Account.User_R
+	var err error
+	if len(T_name) > 0 {
+		users, err = Account.Read_User_Tree_List_WithFilter(T_Distributor_id, T_name, distributorMap)
+	} else {
+		users, err = Account.Read_User_Tree_List(T_Distributor_id, distributorMap)
+	}
+
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取数据失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 构建树形结构
+	tree := Account.BuildUserTree(users)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: tree}
+	c.ServeJSON()
+	return
+}
+
+// 移动公司到另一个公司下面
+func (c *UserController) MoveToParent() {
+	// 验证登录 User_is, User_r
+	user_r, User_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+	if !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_id, err := c.GetInt("T_id")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "用户ID错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_pid, err := c.GetInt("T_pid")
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "父级ID错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 执行移动操作
+	err = Account.MoveUserToParent(T_id, T_pid)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(user_r.T_uuid, "用户管理", "移动公司", map[string]interface{}{
+		"Id":          T_id,
+		"newParentId": T_pid,
+	})
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "移动成功!"}
+	c.ServeJSON()
+	return
+}

+ 360 - 7
models/Account/User.go

@@ -3,12 +3,16 @@ package Account
 import (
 	"ColdVerify_server/lib"
 	"ColdVerify_server/logs"
+	"errors"
+	"log"
+	"strconv"
+	"strings"
+	"time"
+
 	"github.com/beego/beego/v2/adapter/orm"
 	orm2 "github.com/beego/beego/v2/client/orm"
 	_ "github.com/go-sql-driver/mysql"
 	uuid "github.com/satori/go.uuid"
-	"log"
-	"time"
 )
 
 type User struct {
@@ -16,21 +20,27 @@ type User struct {
 	T_Distributor_id string `orm:"size(256);null"` // 分销商id
 	T_uuid           string `orm:"size(256);null"` //
 	//T_power    int       `orm:"size(2);default(0)"`                                    // 权限
-	T_name     string    `orm:"size(256);null"`                                        // 某某公司名称
-	T_pass     string    `orm:"size(256);null"`                                        // 密码 MD5
-	T_passstr  string    `orm:"size(256);null"`                                        // 密码明文
+	T_name    string `orm:"size(256);null"`      // 某某公司名称
+	T_pass    string `orm:"size(256);null"`      // 密码 MD5
+	T_passstr string `orm:"size(256);null"`      // 密码明文
+	T_pid     int    `orm:"size(11);default(0)"` // 父级ID
+	T_path    string `orm:"size(1000);null"`     // 路径,如:1/2/3
+
 	T_Show     int       `orm:"size(200);default(1)"`                                  // 0隐藏  1公开
 	T_State    int       `orm:"size(200);default(1)"`                                  // 0删除  1正常
 	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
 	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
 }
 type User_R struct {
+	Id                 int    // ID
 	T_uuid             string //
 	T_Distributor_id   string //
 	T_Distributor_name string //
 	//T_power   int    // 权限
 	T_name    string // 某某公司名称
 	T_passstr string // 密码明文
+	T_pid     int    // 父级ID
+	T_path    string // 路径
 	T_Show    int    //  0  1
 	T_State   int    //  0  1
 }
@@ -47,6 +57,7 @@ func init() {
 
 // -------------------------------------------------------------
 func UserToUser_R(T User, distributorMap map[string]string) (T_r User_R) {
+	T_r.Id = T.Id
 	T_r.T_uuid = T.T_uuid
 	T_r.T_Distributor_id = T.T_Distributor_id
 	T_Distributor_name, ok := distributorMap[T.T_Distributor_id]
@@ -57,6 +68,8 @@ func UserToUser_R(T User, distributorMap map[string]string) (T_r User_R) {
 	//T_r.T_power = T.T_power
 	T_r.T_name = T.T_name
 	T_r.T_passstr = T.T_passstr
+	T_r.T_pid = T.T_pid
+	T_r.T_path = T.T_path
 	T_r.T_Show = T.T_Show
 	T_r.T_State = T.T_State
 
@@ -88,7 +101,7 @@ func Read_User_verification(T_user string, T_pass string) (error, User) {
 func Read_User_ById(id int) (r User, is bool) {
 	o := orm.NewOrm()
 	r = User{Id: id, T_State: 1}
-	err := o.Read(&r, "T_State") // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
+	err := o.Read(&r, "Id", "T_State") // o.Read(&r,"Tokey") 如果不是 主键 就得指定字段名
 	if err != nil {
 		logs.Error(lib.FuncName(), err)
 		return r, false
@@ -195,7 +208,19 @@ func Read_User_List(T_Distributor_id string, T_name string, page int, page_z int
 		offset = int64((page - 1) * page_z)
 	}
 	cond := orm.NewCondition()
-	cond1 := cond.And("T_State", 1).AndCond(cond.Or("T_name__icontains", T_name))
+	cond1 := cond.And("T_State", 1)
+
+	// 如果有名称搜索,获取包含所有子公司的ID列表
+	if len(T_name) > 0 {
+		userIds, err := GetUserIdsByNameWithChildren(T_Distributor_id, T_name)
+		if err == nil && len(userIds) > 0 {
+			cond1 = cond1.And("Id__in", userIds)
+		} else {
+			// 如果没有匹配结果,使用原来的模糊搜索
+			cond1 = cond1.And("T_name__icontains", T_name)
+		}
+	}
+
 	if len(T_Distributor_id) > 0 {
 		cond1 = cond1.And("T_Distributor_id", T_Distributor_id)
 	}
@@ -288,3 +313,331 @@ func Read_User_T_uuid_ListByT_name(T_name string) (list []string) {
 
 	return list
 }
+
+// 树形结构相关函数
+
+// 根据公司名称获取公司ID列表(包含所有子公司)
+func GetUserIdsByNameWithChildren(T_Distributor_id string, T_name string) ([]int, error) {
+	if T_name == "" {
+		return nil, nil
+	}
+
+	o := orm.NewOrm()
+	var matchedUsers []User
+	qs := o.QueryTable(new(User))
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1).And("T_name__icontains", T_name)
+	if len(T_Distributor_id) > 0 {
+		cond1 = cond1.And("T_Distributor_id", T_Distributor_id)
+	}
+
+	_, err := qs.SetCond((*orm2.Condition)(cond1)).All(&matchedUsers)
+	if err != nil {
+		return nil, err
+	}
+
+	// 收集所有匹配的公司ID及其子公司ID
+	userIds := make([]int, 0)
+	for _, user := range matchedUsers {
+		userIds = append(userIds, user.Id)
+		// 获取所有子公司ID
+		childIds, err := getChildUserIds(o, user.Id)
+		if err == nil {
+			userIds = append(userIds, childIds...)
+		}
+	}
+
+	return userIds, nil
+}
+
+// 递归获取所有子公司ID
+func getChildUserIds(o orm.Ormer, parentId int) ([]int, error) {
+	var children []User
+	_, err := o.QueryTable(new(User)).Filter("T_pid", parentId).Filter("T_State", 1).All(&children)
+	if err != nil {
+		return nil, err
+	}
+
+	childIds := make([]int, 0)
+	for _, child := range children {
+		childIds = append(childIds, child.Id)
+		// 递归获取子公司的子公司
+		subChildIds, err := getChildUserIds(o, child.Id)
+		if err == nil {
+			childIds = append(childIds, subChildIds...)
+		}
+	}
+
+	return childIds, nil
+}
+
+// 获取所有用户用于构建树形结构
+func Read_User_Tree_List(T_Distributor_id string, distributorMap map[string]string) ([]User_R, error) {
+	o := orm.NewOrm()
+	var r []User
+	qs := o.QueryTable(new(User))
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1)
+	if len(T_Distributor_id) > 0 {
+		cond1 = cond1.And("T_Distributor_id", T_Distributor_id)
+	}
+
+	_, err := qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_pid", "Id").All(&r)
+	if err != nil {
+		return nil, err
+	}
+
+	// 转换
+	var User_r []User_R
+	for _, v := range r {
+		User_r = append(User_r, UserToUser_R(v, distributorMap))
+	}
+
+	return User_r, nil
+}
+
+// 获取指定公司的所有子公司(用于树形展示的过滤)
+func Read_User_Tree_List_WithFilter(T_Distributor_id string, T_name string, distributorMap map[string]string) ([]User_R, error) {
+	o := orm.NewOrm()
+	var r []User
+	qs := o.QueryTable(new(User))
+
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_State", 1)
+
+	// 如果有名称搜索,获取包含所有子公司的ID列表
+	if len(T_name) > 0 {
+		userIds, err := GetUserIdsByNameWithChildren(T_Distributor_id, T_name)
+		if err == nil && len(userIds) > 0 {
+			cond1 = cond1.And("Id__in", userIds)
+		} else {
+			// 如果没有匹配结果,返回空列表
+			return []User_R{}, nil
+		}
+	}
+
+	if len(T_Distributor_id) > 0 {
+		cond1 = cond1.And("T_Distributor_id", T_Distributor_id)
+	}
+
+	_, err := qs.SetCond((*orm2.Condition)(cond1)).OrderBy("T_pid", "Id").All(&r)
+	if err != nil {
+		return nil, err
+	}
+
+	// 转换
+	var User_r []User_R
+	for _, v := range r {
+		User_r = append(User_r, UserToUser_R(v, distributorMap))
+	}
+
+	return User_r, nil
+}
+
+// 构建树形结构
+type UserTreeNode struct {
+	User_R
+	Children []UserTreeNode `json:"children"`
+}
+
+// 内部使用的指针版本
+type userTreeNodePtr struct {
+	User_R
+	Children []*userTreeNodePtr
+}
+
+func BuildUserTree(users []User_R) []UserTreeNode {
+	// 创建ID到节点的映射(使用指针以便修改)
+	nodeMap := make(map[int]*userTreeNodePtr)
+	var rootNodes []*userTreeNodePtr
+
+	// 首先创建所有节点
+	for i := range users {
+		node := &userTreeNodePtr{
+			User_R:   users[i],
+			Children: make([]*userTreeNodePtr, 0),
+		}
+		nodeMap[users[i].Id] = node
+	}
+
+	// 然后建立父子关系(使用指针)
+	for i := range users {
+		node := nodeMap[users[i].Id]
+		if users[i].T_pid == 0 {
+			// 根节点
+			rootNodes = append(rootNodes, node)
+		} else {
+			// 子节点 - 将指针添加到父节点的Children
+			if parent, exists := nodeMap[users[i].T_pid]; exists {
+				parent.Children = append(parent.Children, node)
+			}
+		}
+	}
+
+	// 递归转换为值类型返回
+	result := make([]UserTreeNode, len(rootNodes))
+	for i, node := range rootNodes {
+		result[i] = convertNodeToValue(node)
+	}
+
+	return result
+}
+
+// 递归将指针类型的节点树转换为值类型
+func convertNodeToValue(node *userTreeNodePtr) UserTreeNode {
+	valueNode := UserTreeNode{
+		User_R:   node.User_R,
+		Children: make([]UserTreeNode, len(node.Children)),
+	}
+
+	// 递归转换所有子节点
+	for i, child := range node.Children {
+		valueNode.Children[i] = convertNodeToValue(child)
+	}
+
+	return valueNode
+}
+
+// 更新用户路径
+func UpdateUserPath(userId int) error {
+	o := orm.NewOrm()
+
+	// 获取当前用户
+	var user User
+	err := o.QueryTable(new(User)).Filter("Id", userId).One(&user)
+	if err != nil {
+		return err
+	}
+
+	// 构建路径
+	var path string
+	if user.T_pid == 0 {
+		path = strconv.Itoa(userId)
+	} else {
+		// 获取父级路径
+		var parent User
+		err = o.QueryTable(new(User)).Filter("Id", user.T_pid).One(&parent)
+		if err != nil {
+			return err
+		}
+		if parent.T_path != "" {
+			path = parent.T_path + "/" + strconv.Itoa(userId)
+		} else {
+			path = strconv.Itoa(user.T_pid) + "/" + strconv.Itoa(userId)
+		}
+	}
+
+	// 更新当前用户路径
+	user.T_path = path
+	_, err = o.Update(&user, "T_path")
+	if err != nil {
+		return err
+	}
+
+	// 递归更新所有子节点的路径
+	return updateChildrenPath(o, userId)
+}
+
+// 递归更新子节点路径
+func updateChildrenPath(o orm.Ormer, parentId int) error {
+	var children []User
+	_, err := o.QueryTable(new(User)).Filter("T_pid", parentId).All(&children)
+	if err != nil {
+		return err
+	}
+
+	for _, child := range children {
+		// 获取父级路径
+		var parent User
+		err = o.QueryTable(new(User)).Filter("Id", child.T_pid).One(&parent)
+		if err != nil {
+			continue
+		}
+
+		// 构建新的路径
+		var newPath string
+		if parent.T_path != "" {
+			newPath = parent.T_path + "/" + strconv.Itoa(child.Id)
+		} else {
+			newPath = strconv.Itoa(child.T_pid) + "/" + strconv.Itoa(child.Id)
+		}
+
+		// 更新子节点路径
+		child.T_path = newPath
+		_, err = o.Update(&child, "T_path")
+		if err != nil {
+			continue
+		}
+
+		// 递归更新子节点的子节点
+		updateChildrenPath(o, child.Id)
+	}
+
+	return nil
+}
+
+// 移动公司到另一个公司下面
+func MoveUserToParent(userId int, newParentId int) error {
+	o := orm.NewOrm()
+
+	// 获取要移动的用户
+	var user User
+	err := o.QueryTable(new(User)).Filter("Id", userId).One(&user)
+	if err != nil {
+		return err
+	}
+
+	// 检查新父级是否存在(如果newParentId不为0)
+
+	if newParentId != 0 {
+		var parent User
+		err = o.QueryTable(new(User)).Filter("Id", newParentId).Filter("T_State", 1).One(&parent)
+		if err != nil {
+			return err
+		}
+		if user.T_Distributor_id != parent.T_Distributor_id {
+			return errors.New("不能将公司移动到不同经销商下面")
+		}
+	}
+
+	// 检查是否会造成循环引用
+	if newParentId != 0 {
+		if isCircularReference(o, userId, newParentId) {
+			return errors.New("不能将公司移动到其子级公司下面")
+		}
+	}
+
+	// 更新父级ID
+	user.T_pid = newParentId
+	_, err = o.Update(&user, "T_pid")
+	if err != nil {
+		return err
+	}
+
+	// 更新路径
+	return UpdateUserPath(userId)
+}
+
+// 检查是否会造成循环引用
+func isCircularReference(o orm.Ormer, userId int, newParentId int) bool {
+	// 获取新父级的路径
+	var parent User
+	err := o.QueryTable(new(User)).Filter("Id", newParentId).One(&parent)
+	if err != nil {
+		return false
+	}
+
+	// 如果新父级的路径包含当前用户ID,则会造成循环引用
+	if parent.T_path != "" {
+		pathParts := strings.Split(parent.T_path, "/")
+		for _, part := range pathParts {
+			if part == strconv.Itoa(userId) {
+				return true
+			}
+		}
+	}
+
+	return false
+}

+ 8 - 5
routers/User.go

@@ -2,15 +2,18 @@ package routers
 
 import (
 	"ColdVerify_server/controllers"
+
 	beego "github.com/beego/beego/v2/server/web"
 )
 
 func init() {
-	beego.Router("/User/List", &controllers.UserController{}, "*:List")              // 用户列表
-	beego.Router("/User/Add", &controllers.UserController{}, "*:Add")                // 添加用户
-	beego.Router("/User/Up", &controllers.UserController{}, "*:Up")                  // 编辑用户
-	beego.Router("/User/Del", &controllers.UserController{}, "*:Del")                // 删除用户
-	beego.Router("/User/Up_Password", &controllers.UserController{}, "*:UpPassword") // 用户-修改密码
+	beego.Router("/User/List", &controllers.UserController{}, "*:List")                 // 用户列表
+	beego.Router("/User/Add", &controllers.UserController{}, "*:Add")                   // 添加用户
+	beego.Router("/User/Up", &controllers.UserController{}, "*:Up")                     // 编辑用户
+	beego.Router("/User/Del", &controllers.UserController{}, "*:Del")                   // 删除用户
+	beego.Router("/User/Up_Password", &controllers.UserController{}, "*:UpPassword")    // 用户-修改密码
+	beego.Router("/User/TreeList", &controllers.UserController{}, "*:TreeList")         // 树形结构展示公司列表
+	beego.Router("/User/MoveToParent", &controllers.UserController{}, "*:MoveToParent") // 移动公司到另一个公司下面
 
 	beego.Router("/UserSignature/List", &controllers.UserController{}, "*:Signature_List") // 用户签名列表
 	beego.Router("/UserSignature/Add", &controllers.UserController{}, "*:Signature_Add")   // 添加用户签名