批量修复,增加组织架构

This commit is contained in:
2025-11-04 17:35:01 +08:00
parent 86c4060843
commit a7bde8bb72
29 changed files with 5200 additions and 88 deletions
+87
View File
@@ -0,0 +1,87 @@
package models
import (
"time"
"github.com/beego/beego/v2/client/orm"
)
// Department 部门模型
type Department struct {
Id int `orm:"auto" json:"id"`
TenantId int `orm:"column(tenant_id);default(0)" json:"tenant_id"`
Name string `orm:"size(100)" json:"name"`
Code string `orm:"size(50);null" json:"code"`
ParentId int `orm:"column(parent_id);default(0)" json:"parent_id"`
Description string `orm:"type(text);null" json:"description"`
ManagerId int `orm:"column(manager_id);null" json:"manager_id"`
SortOrder int `orm:"column(sort_order);default(0)" json:"sort_order"`
Status int8 `orm:"default(1)" json:"status"` // 1-启用,0-禁用
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
DeleteTime *time.Time `orm:"column(delete_time);null;type(datetime)" json:"delete_time,omitempty"`
}
// TableName 设置表名
func (d *Department) TableName() string {
return "yz_tenant_departments"
}
func init() {
orm.RegisterModel(new(Department))
}
// GetTenantDepartments 获取租户下的所有部门
func GetTenantDepartments(tenantId int) ([]*Department, error) {
o := orm.NewOrm()
var departments []*Department
_, err := o.QueryTable("yz_tenant_departments").
Filter("tenant_id", tenantId).
Filter("delete_time__isnull", true).
OrderBy("sort_order", "create_time").
All(&departments)
return departments, err
}
// GetDepartmentById 根据ID获取部门信息
func GetDepartmentById(id int) (*Department, error) {
o := orm.NewOrm()
department := &Department{Id: id}
err := o.Read(department)
if err != nil {
return nil, err
}
// 检查是否已删除
if department.DeleteTime != nil {
return nil, orm.ErrNoRows
}
return department, nil
}
// AddDepartment 添加部门
func AddDepartment(department *Department) (int64, error) {
o := orm.NewOrm()
id, err := o.Insert(department)
return id, err
}
// UpdateDepartment 更新部门信息
func UpdateDepartment(department *Department) error {
o := orm.NewOrm()
_, err := o.Update(department, "name", "code", "parent_id", "description", "manager_id", "sort_order", "status", "update_time")
return err
}
// DeleteDepartment 软删除部门
func DeleteDepartment(id int) error {
o := orm.NewOrm()
department := &Department{Id: id}
if err := o.Read(department); err != nil {
return err
}
now := time.Now()
department.DeleteTime = &now
_, err := o.Update(department, "delete_time")
return err
}
+242
View File
@@ -0,0 +1,242 @@
package models
import (
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"time"
"github.com/beego/beego/v2/client/orm"
"golang.org/x/crypto/scrypt"
)
// Employee 员工模型
type Employee struct {
Id int `orm:"auto" json:"id"`
TenantId int `orm:"column(tenant_id);default(0)" json:"tenant_id"`
EmployeeNo string `orm:"column(employee_no);size(50)" json:"employee_no"`
Name string `orm:"size(50)" json:"name"`
Phone string `orm:"size(20);null" json:"phone"`
Email string `orm:"size(100);null" json:"email"`
DepartmentId int `orm:"column(department_id);null;default(0)" json:"department_id"`
PositionId int `orm:"column(position_id);null;default(0)" json:"position_id"`
BankName string `orm:"column(bank_name);size(100);null" json:"bank_name"`
BankAccount string `orm:"column(bank_account);size(50);null" json:"bank_account"`
Password string `orm:"size(255);null" json:"-"` // 不返回给前端
Salt string `orm:"size(100);null" json:"-"` // 不返回给前端
LastLoginTime *time.Time `orm:"column(last_login_time);null;type(datetime)" json:"last_login_time,omitempty"`
LastLoginIp string `orm:"column(last_login_ip);null;size(50)" json:"last_login_ip,omitempty"`
Status int8 `orm:"column(status);default(1)" json:"status"` // 1-在职,0-离职
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
DeleteTime *time.Time `orm:"column(delete_time);null;type(datetime)" json:"delete_time,omitempty"`
}
// TableName 设置表名
func (e *Employee) TableName() string {
return "yz_tenant_employees"
}
func init() {
orm.RegisterModel(new(Employee))
}
// GetTenantEmployees 获取租户下的所有员工
func GetTenantEmployees(tenantId int) ([]*Employee, error) {
o := orm.NewOrm()
var employees []*Employee
_, err := o.QueryTable("yz_tenant_employees").
Filter("tenant_id", tenantId).
Filter("delete_time__isnull", true).
OrderBy("-create_time").
All(&employees)
return employees, err
}
// GetEmployeeById 根据ID获取员工信息
func GetEmployeeById(id int) (*Employee, error) {
o := orm.NewOrm()
employee := &Employee{Id: id}
err := o.Read(employee)
if err != nil {
return nil, err
}
// 检查是否已删除
if employee.DeleteTime != nil {
return nil, orm.ErrNoRows
}
return employee, nil
}
// generateSalt 生成随机盐值
func generateEmployeeSalt() (string, error) {
salt := make([]byte, 16)
_, err := rand.Read(salt)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(salt), nil
}
// hashEmployeePassword 使用scrypt算法对密码进行加密
func hashEmployeePassword(password, salt string) (string, error) {
saltBytes, err := base64.URLEncoding.DecodeString(salt)
if err != nil {
return "", err
}
const (
N = 16384
r = 8
p = 1
)
hashBytes, err := scrypt.Key([]byte(password), saltBytes, N, r, p, 32)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(hashBytes), nil
}
// AddEmployee 添加员工(自动设置默认密码)
func AddEmployee(employee *Employee, defaultPassword string) (int64, error) {
// 生成盐值
salt, err := generateEmployeeSalt()
if err != nil {
return 0, fmt.Errorf("生成盐值失败: %v", err)
}
employee.Salt = salt
// 加密默认密码
hashedPassword, err := hashEmployeePassword(defaultPassword, salt)
if err != nil {
return 0, fmt.Errorf("密码加密失败: %v", err)
}
employee.Password = hashedPassword
o := orm.NewOrm()
id, err := o.Insert(employee)
return id, err
}
// UpdateEmployee 更新员工信息
func UpdateEmployee(employee *Employee) error {
o := orm.NewOrm()
_, err := o.Update(employee, "employee_no", "name", "phone", "email", "department_id", "position_id", "bank_name", "bank_account", "status", "update_time")
return err
}
// ResetEmployeePassword 重置员工密码为默认密码
func ResetEmployeePassword(employeeId int, defaultPassword string) error {
o := orm.NewOrm()
employee := &Employee{Id: employeeId}
if err := o.Read(employee); err != nil {
return fmt.Errorf("员工不存在: %v", err)
}
// 生成新盐值
salt, err := generateEmployeeSalt()
if err != nil {
return fmt.Errorf("生成盐值失败: %v", err)
}
employee.Salt = salt
// 加密默认密码
hashedPassword, err := hashEmployeePassword(defaultPassword, salt)
if err != nil {
return fmt.Errorf("密码加密失败: %v", err)
}
employee.Password = hashedPassword
_, err = o.Update(employee, "Password", "Salt")
return err
}
// ChangeEmployeePassword 修改员工密码
func ChangeEmployeePassword(employeeId int, oldPassword, newPassword string) error {
o := orm.NewOrm()
employee := &Employee{Id: employeeId}
if err := o.Read(employee); err != nil {
return fmt.Errorf("员工不存在: %v", err)
}
// 验证旧密码
if !verifyEmployeePassword(oldPassword, employee.Salt, employee.Password) {
return errors.New("旧密码不正确")
}
// 加密新密码
hashedPassword, err := hashEmployeePassword(newPassword, employee.Salt)
if err != nil {
return fmt.Errorf("密码加密失败: %v", err)
}
employee.Password = hashedPassword
_, err = o.Update(employee, "Password")
return err
}
// verifyEmployeePassword 验证密码是否正确
func verifyEmployeePassword(password, salt, storedHash string) bool {
hash, err := hashEmployeePassword(password, salt)
if err != nil {
return false
}
return hash == storedHash
}
// ValidateEmployee 验证员工登录信息(使用工号作为登录账号)
func ValidateEmployee(employeeNo, password string, tenantId int) (*Employee, error) {
o := orm.NewOrm()
// 1. 根据工号和租户ID查询员工(排除已删除的)
var employee Employee
err := o.QueryTable("yz_tenant_employees").
Filter("employee_no", employeeNo).
Filter("tenant_id", tenantId).
Filter("delete_time__isnull", true).
Filter("status", 1). // 只允许在职员工登录
One(&employee)
if err == orm.ErrNoRows {
return nil, errors.New("员工不存在或已离职")
}
if err != nil {
return nil, fmt.Errorf("查询员工失败: %v", err)
}
// 2. 检查密码和盐是否存在
if employee.Password == "" || employee.Salt == "" {
return nil, errors.New("员工密码未设置,请联系管理员")
}
// 3. 验证密码
if verifyEmployeePassword(password, employee.Salt, employee.Password) {
return &employee, nil
}
return nil, errors.New("密码不正确")
}
// DeleteEmployee 软删除员工
func DeleteEmployee(id int) error {
o := orm.NewOrm()
employee := &Employee{Id: id}
if err := o.Read(employee); err != nil {
return err
}
now := time.Now()
employee.DeleteTime = &now
_, err := o.Update(employee, "delete_time")
return err
}
// GetAllEmployees 获取所有员工(排除已删除的)
func GetAllEmployees() ([]*Employee, error) {
o := orm.NewOrm()
var employees []*Employee
_, err := o.QueryTable("yz_tenant_employees").
Filter("delete_time__isnull", true).
OrderBy("-create_time").
All(&employees)
return employees, err
}
+26 -18
View File
@@ -8,20 +8,21 @@ import (
// Menu 菜单模型
type Menu struct {
Id int `orm:"auto"`
Name string `orm:"size(100)"`
Path string `orm:"size(255)"`
ParentId int `orm:"default(0)"`
Icon string `orm:"size(100)"`
Order int `orm:"default(0)"`
Status int8 `orm:"default(1)"`
ComponentPath string `orm:"size(500);null"`
IsExternal int8 `orm:"default(0)"`
ExternalUrl string `orm:"size(1000);null"`
MenuType int8 `orm:"default(1)"`
Permission string `orm:"size(200);null"`
CreateTime time.Time `orm:"auto_now_add;type(datetime)"`
UpdateTime time.Time `orm:"auto_now;type(datetime)"`
Id int `orm:"auto"`
Name string `orm:"size(100)"`
Path string `orm:"size(255)"`
ParentId int `orm:"default(0)"`
Icon string `orm:"size(100)"`
Order int `orm:"default(0)"`
Status int8 `orm:"default(1)"`
ComponentPath string `orm:"size(500);null"`
IsExternal int8 `orm:"default(0)"`
ExternalUrl string `orm:"size(1000);null"`
MenuType int8 `orm:"default(1)"`
Permission string `orm:"size(200);null"`
CreateTime time.Time `orm:"auto_now_add;type(datetime)"`
UpdateTime time.Time `orm:"auto_now;type(datetime)"`
DeleteTime *time.Time `orm:"null;type(datetime)"`
}
// TableName 设置表名
@@ -29,11 +30,11 @@ func (m *Menu) TableName() string {
return "yz_menus"
}
// GetAllMenus 获取所有菜单
// GetAllMenus 获取所有菜单(未删除的)
func GetAllMenus() ([]map[string]interface{}, error) {
o := orm.NewOrm()
var menus []*Menu
_, err := o.QueryTable("yz_menus").Filter("Status", 1).All(&menus)
_, err := o.QueryTable("yz_menus").Filter("delete_time__isnull", true).All(&menus)
if err != nil {
return nil, err
}
@@ -46,6 +47,7 @@ func GetAllMenus() ([]map[string]interface{}, error) {
"parentId": m.ParentId,
"icon": m.Icon,
"order": m.Order,
"status": m.Status,
"componentPath": m.ComponentPath,
"isExternal": m.IsExternal,
"externalUrl": m.ExternalUrl,
@@ -82,9 +84,15 @@ func UpdateMenuStatus(id int, status int8) error {
return err
}
// DeleteMenu 删除菜单
// DeleteMenu 删除菜单(软删除)
func DeleteMenu(id int) error {
o := orm.NewOrm()
_, err := o.Delete(&Menu{Id: id})
menu := Menu{Id: id}
if err := o.Read(&menu); err != nil {
return err
}
now := time.Now()
menu.DeleteTime = &now
_, err := o.Update(&menu, "DeleteTime")
return err
}
+3 -3
View File
@@ -99,12 +99,12 @@ func GetRolePermissions(roleId int) (*RolePermission, error) {
}, nil
}
// GetAllMenuPermissions 获取所有菜单权限列表(用于分配权限时展示)
// GetAllMenuPermissions 获取所有菜单权限列表(用于分配权限时展示,未删除的
func GetAllMenuPermissions() ([]*MenuPermission, error) {
o := orm.NewOrm()
var menus []*MenuPermission
_, err := o.Raw("SELECT id as menu_id, name as menu_name, path, menu_type, permission, parent_id FROM yz_menus WHERE status = 1 ORDER BY parent_id, `order`").QueryRows(&menus)
_, err := o.Raw("SELECT id as menu_id, name as menu_name, path, menu_type, permission, parent_id FROM yz_menus WHERE delete_time IS NULL ORDER BY parent_id, `order`").QueryRows(&menus)
if err != nil {
return nil, fmt.Errorf("获取菜单列表失败: %v", err)
}
@@ -259,7 +259,7 @@ func GetUserMenuTree(userId int) ([]*MenuTreeNode, error) {
placeholders[i] = "?"
args[i] = id
}
query := fmt.Sprintf("SELECT * FROM yz_menus WHERE id IN (%s) AND menu_type = 1 AND status = 1 ORDER BY parent_id, `order`", strings.Join(placeholders, ","))
query := fmt.Sprintf("SELECT * FROM yz_menus WHERE id IN (%s) AND menu_type = 1 AND delete_time IS NULL ORDER BY parent_id, `order`", strings.Join(placeholders, ","))
_, err = o.Raw(query, args...).QueryRows(&menus)
if err != nil {
return nil, fmt.Errorf("获取菜单列表失败: %v", err)
+100
View File
@@ -0,0 +1,100 @@
package models
import (
"time"
"github.com/beego/beego/v2/client/orm"
)
// Position 职位模型
type Position struct {
Id int `orm:"auto" json:"id"`
TenantId int `orm:"column(tenant_id);default(0)" json:"tenant_id"`
Name string `orm:"size(100)" json:"name"`
Code string `orm:"size(50);null" json:"code"`
DepartmentId int `orm:"column(department_id);null" json:"department_id"`
Level int `orm:"default(0)" json:"level"`
Description string `orm:"type(text);null" json:"description"`
SortOrder int `orm:"column(sort_order);default(0)" json:"sort_order"`
Status int8 `orm:"default(1)" json:"status"` // 1-启用,0-禁用
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
UpdateTime time.Time `orm:"column(update_time);type(datetime);auto_now" json:"update_time"`
DeleteTime *time.Time `orm:"column(delete_time);null;type(datetime)" json:"delete_time,omitempty"`
}
// TableName 设置表名
func (p *Position) TableName() string {
return "yz_tenant_positions"
}
func init() {
orm.RegisterModel(new(Position))
}
// GetTenantPositions 获取租户下的所有职位
func GetTenantPositions(tenantId int) ([]*Position, error) {
o := orm.NewOrm()
var positions []*Position
_, err := o.QueryTable("yz_tenant_positions").
Filter("tenant_id", tenantId).
Filter("delete_time__isnull", true).
OrderBy("sort_order", "create_time").
All(&positions)
return positions, err
}
// GetPositionsByDepartment 根据部门ID获取职位列表
func GetPositionsByDepartment(departmentId int) ([]*Position, error) {
o := orm.NewOrm()
var positions []*Position
_, err := o.QueryTable("yz_tenant_positions").
Filter("department_id", departmentId).
Filter("delete_time__isnull", true).
Filter("status", 1).
OrderBy("sort_order", "create_time").
All(&positions)
return positions, err
}
// GetPositionById 根据ID获取职位信息
func GetPositionById(id int) (*Position, error) {
o := orm.NewOrm()
position := &Position{Id: id}
err := o.Read(position)
if err != nil {
return nil, err
}
// 检查是否已删除
if position.DeleteTime != nil {
return nil, orm.ErrNoRows
}
return position, err
}
// AddPosition 添加职位
func AddPosition(position *Position) (int64, error) {
o := orm.NewOrm()
id, err := o.Insert(position)
return id, err
}
// UpdatePosition 更新职位信息
func UpdatePosition(position *Position) error {
o := orm.NewOrm()
_, err := o.Update(position, "name", "code", "department_id", "level", "description", "sort_order", "status", "update_time")
return err
}
// DeletePosition 软删除职位
func DeletePosition(id int) error {
o := orm.NewOrm()
position := &Position{Id: id}
if err := o.Read(position); err != nil {
return err
}
now := time.Now()
position.DeleteTime = &now
_, err := o.Update(position, "delete_time")
return err
}
+45 -24
View File
@@ -26,6 +26,8 @@ type User struct {
Nickname string
Status int `orm:"column(status);default(1)" json:"status"`
Role int `orm:"column(role);default(0)" json:"role"`
DepartmentId int `orm:"column(department_id);null;default(0)" json:"department_id"`
PositionId int `orm:"column(position_id);null;default(0)" json:"position_id"`
DeleteTime *time.Time `orm:"column(delete_time);null;type(datetime)" json:"delete_time"`
LastLoginTime *time.Time `orm:"column(last_login_time);null;type(datetime)" json:"last_login_time"`
LastLoginIp string `orm:"column(last_login_ip);null;size(50)" json:"last_login_ip"`
@@ -193,8 +195,8 @@ func GetUserInfo(userId int, username string, tenantId int) (*User, error) {
return user, nil
}
// ValidateUser 验证用户登录信息
func ValidateUser(username, password string, tenantName string) (*User, error) {
// ValidateUser 验证用户登录信息(先检查用户表,找不到再检查员工表)
func ValidateUser(username, password string, tenantName string) (*User, *Employee, error) {
o := orm.NewOrm()
// 1. 根据租户名称查询租户(只查询未删除的)
@@ -206,39 +208,45 @@ func ValidateUser(username, password string, tenantName string) (*User, error) {
err := o.Raw("SELECT id, status, delete_time FROM yz_tenants WHERE name = ? AND delete_time IS NULL", tenantName).QueryRow(&tenant)
if err == orm.ErrNoRows {
// 租户不存在(数据库中根本没有这个名称)
return nil, errors.New("租户不存在")
return nil, nil, errors.New("租户不存在")
}
if err != nil {
return nil, fmt.Errorf("查询租户失败: %v", err)
return nil, nil, fmt.Errorf("查询租户失败: %v", err)
}
// 检查租户状态
if tenant.Status == "disabled" {
return nil, errors.New("租户已被禁用")
return nil, nil, errors.New("租户已被禁用")
}
if tenant.Status != "enabled" {
return nil, fmt.Errorf("租户状态异常: %s", tenant.Status)
return nil, nil, fmt.Errorf("租户状态异常: %s", tenant.Status)
}
tenantId := tenant.Id
// 2. 获取租户下的用户
// 2. 先尝试从用户表获取
user, err := GetUserInfo(0, username, tenantId)
if err != nil {
// 用户存在或查询失败
return nil, err
if err == nil && user != nil {
// 用户存在,验证密码
if verifyPassword(password, user.Salt, user.Password) {
return user, nil, nil
}
return nil, nil, errors.New("密码不正确")
}
// 3. 验证密码
if verifyPassword(password, user.Salt, user.Password) {
return user, nil
// 3. 用户表中没有找到,尝试从员工表获取
employee, err := ValidateEmployee(username, password, tenantId)
if err != nil {
return nil, nil, err
}
return nil, errors.New("密码不正确")
// 员工验证成功,返回员工信息(user为nil表示是员工登录)
return nil, employee, nil
}
// AddUser 向数据库添加新用户
func AddUser(username, password, email, nickname, avatar string, tenantId, role int) (*User, error) {
func AddUser(username, password, email, nickname, avatar string, tenantId, role, departmentId, positionId int) (*User, error) {
// 1. 验证租户是否存在且有效
o := orm.NewOrm()
var tenantExists bool
@@ -273,14 +281,17 @@ func AddUser(username, password, email, nickname, avatar string, tenantId, role
// 4. 构建用户对象
user := &User{
TenantId: tenantId,
Username: username,
Password: hashedPassword,
Salt: salt,
Email: email,
Nickname: nickname,
Avatar: avatar,
Role: role, // 设置角色ID
TenantId: tenantId,
Username: username,
Password: hashedPassword,
Salt: salt,
Email: email,
Nickname: nickname,
Avatar: avatar,
Role: role,
DepartmentId: departmentId,
PositionId: positionId,
Status: 1,
}
// 5. 插入数据库(使用之前定义的 o)
@@ -294,7 +305,7 @@ func AddUser(username, password, email, nickname, avatar string, tenantId, role
}
// EditUser 更新用户信息
func EditUser(id int, username, email, nickname, avatar, status string, roleId int) (*User, error) {
func EditUser(id int, username, email, nickname, avatar, status string, roleId, departmentId, positionId int) (*User, error) {
// 根据ID查询用户
o := orm.NewOrm()
user := &User{}
@@ -339,6 +350,16 @@ func EditUser(id int, username, email, nickname, avatar, status string, roleId i
user.Role = roleId
}
// 更新部门ID
if departmentId >= 0 {
user.DepartmentId = departmentId
}
// 更新职位ID
if positionId >= 0 {
user.PositionId = positionId
}
// 执行数据库更新
_, err = o.Update(user)
if err != nil {