更新oa代码

This commit is contained in:
2025-11-06 15:56:29 +08:00
parent 9c67793fc3
commit 6a9b5d413a
60 changed files with 6194 additions and 2757 deletions
+51
View File
@@ -0,0 +1,51 @@
package services
import (
"crypto/rand"
"encoding/base64"
"golang.org/x/crypto/scrypt"
)
// generateUserSalt 生成随机盐值(用于用户密码)
func generateUserSalt() (string, error) {
salt := make([]byte, 16)
_, err := rand.Read(salt)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(salt), nil
}
// hashUserPassword 使用scrypt算法对密码进行加密(用于用户密码)
func hashUserPassword(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
}
// verifyUserPassword 验证用户密码是否正确
func verifyUserPassword(password, salt, storedHash string) bool {
hash, err := hashUserPassword(password, salt)
if err != nil {
return false
}
return hash == storedHash
}
// hashPassword 通用密码加密函数(用于员工密码,与用户密码使用相同算法)
func hashPassword(password, salt string) (string, error) {
return hashUserPassword(password, salt)
}
+284
View File
@@ -0,0 +1,284 @@
package services
import (
"errors"
"fmt"
"server/models"
"time"
"github.com/beego/beego/v2/client/orm"
)
// verifyEmployeePassword 验证员工密码是否正确
func verifyEmployeePassword(password, salt, storedHash string) bool {
hash, err := hashPassword(password, salt)
if err != nil {
return false
}
return hash == storedHash
}
// GetTenantEmployees 获取租户下的所有员工
func GetTenantEmployees(tenantId int) ([]*models.Employee, error) {
o := orm.NewOrm()
var employees []*models.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) (*models.Employee, error) {
o := orm.NewOrm()
employee := &models.Employee{Id: id}
err := o.Read(employee)
if err != nil {
return nil, err
}
// 检查是否已删除
if employee.DeleteTime != nil {
return nil, orm.ErrNoRows
}
return employee, nil
}
// EmployeeDetail 员工详细信息(包含关联的部门、职位、角色信息)
type EmployeeDetail struct {
Employee *models.Employee `json:"employee"`
Department *models.Department `json:"department,omitempty"`
Position *models.Position `json:"position,omitempty"`
Role *models.Role `json:"role,omitempty"`
}
// GetEmployeeDetailWithRelations 根据ID获取员工详细信息(包含关联的部门、职位、角色)
// 使用并行查询优化性能
func GetEmployeeDetailWithRelations(id int) (*EmployeeDetail, error) {
// 先获取员工基本信息
employee, err := GetEmployeeById(id)
if err != nil {
return nil, err
}
detail := &EmployeeDetail{
Employee: employee,
}
// 使用 goroutine 并行查询关联数据,提高性能
type deptResult struct {
department *models.Department
err error
}
type posResult struct {
position *models.Position
err error
}
type roleResult struct {
role *models.Role
err error
}
deptChan := make(chan deptResult, 1)
posChan := make(chan posResult, 1)
roleChan := make(chan roleResult, 1)
// 并行查询部门信息
if employee.DepartmentId > 0 {
go func() {
dept, err := models.GetDepartmentById(employee.DepartmentId)
deptChan <- deptResult{department: dept, err: err}
}()
} else {
deptChan <- deptResult{department: nil, err: nil}
}
// 并行查询职位信息
if employee.PositionId > 0 {
go func() {
pos, err := models.GetPositionById(employee.PositionId)
posChan <- posResult{position: pos, err: err}
}()
} else {
posChan <- posResult{position: nil, err: nil}
}
// 并行查询角色信息
if employee.Role > 0 {
go func() {
role, err := models.GetRoleById(employee.Role)
roleChan <- roleResult{role: role, err: err}
}()
} else {
roleChan <- roleResult{role: nil, err: nil}
}
// 接收所有结果
deptRes := <-deptChan
posRes := <-posChan
roleRes := <-roleChan
// 设置关联数据(忽略错误,如果不存在就不设置)
if deptRes.department != nil && deptRes.err == nil {
detail.Department = deptRes.department
}
if posRes.position != nil && posRes.err == nil {
detail.Position = posRes.position
}
if roleRes.role != nil && roleRes.err == nil {
detail.Role = roleRes.role
}
return detail, nil
}
// GetAllEmployees 获取所有员工(排除已删除的)
func GetAllEmployees() ([]*models.Employee, error) {
o := orm.NewOrm()
var employees []*models.Employee
_, err := o.QueryTable("yz_tenant_employees").
Filter("delete_time__isnull", true).
OrderBy("-create_time").
All(&employees)
return employees, err
}
// AddEmployee 添加员工(自动设置默认密码)
func AddEmployee(employee *models.Employee, defaultPassword string) (int64, error) {
// 生成盐值
salt, err := generateUserSalt()
if err != nil {
return 0, fmt.Errorf("生成盐值失败: %v", err)
}
employee.Salt = salt
// 加密默认密码
hashedPassword, err := hashPassword(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 *models.Employee) error {
o := orm.NewOrm()
_, err := o.Update(employee, "employee_no", "name", "phone", "email", "department_id", "position_id", "role", "bank_name", "bank_account", "status", "update_time")
return err
}
// ResetEmployeePassword 重置员工密码为默认密码
func ResetEmployeePassword(employeeId int, defaultPassword string) error {
o := orm.NewOrm()
employee := &models.Employee{Id: employeeId}
if err := o.Read(employee); err != nil {
return fmt.Errorf("员工不存在: %v", err)
}
// 生成新盐值
salt, err := generateUserSalt()
if err != nil {
return fmt.Errorf("生成盐值失败: %v", err)
}
employee.Salt = salt
// 加密默认密码
hashedPassword, err := hashPassword(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 := &models.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 := hashPassword(newPassword, employee.Salt)
if err != nil {
return fmt.Errorf("密码加密失败: %v", err)
}
employee.Password = hashedPassword
_, err = o.Update(employee, "Password")
return err
}
// ValidateEmployee 验证员工登录信息(使用工号作为登录账号)
func ValidateEmployee(employeeNo, password string, tenantId int) (*models.Employee, error) {
o := orm.NewOrm()
// 1. 根据工号和租户ID查询员工(排除已删除的)
var employee models.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 := &models.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
}
// IsEmployee 检查指定的ID是否是员工(用于判断登录类型)
func IsEmployee(id int) bool {
o := orm.NewOrm()
employee := &models.Employee{Id: id}
err := o.Read(employee)
if err != nil {
return false
}
// 检查是否已删除
if employee.DeleteTime != nil {
return false
}
return true
}
+76
View File
@@ -0,0 +1,76 @@
package services
import (
"fmt"
"server/models"
)
// OABaseData 基础数据结构
type OABaseData struct {
Departments []*models.Department `json:"departments"`
Positions []*models.Position `json:"positions"`
Roles []*models.Role `json:"roles"`
}
// GetOABaseData 获取OA基础数据(部门、职位、角色)
// 这是一个合并接口,用于一次性获取所有基础数据,减少网络请求次数
// 使用 goroutine 并行查询,提高性能
func GetOABaseData(tenantId int) (*OABaseData, error) {
type deptResult struct {
departments []*models.Department
err error
}
type posResult struct {
positions []*models.Position
err error
}
type roleResult struct {
roles []*models.Role
err error
}
deptChan := make(chan deptResult, 1)
posChan := make(chan posResult, 1)
roleChan := make(chan roleResult, 1)
// 并行获取部门数据
go func() {
depts, err := models.GetTenantDepartments(tenantId)
deptChan <- deptResult{departments: depts, err: err}
}()
// 并行获取职位数据
go func() {
pos, err := models.GetTenantPositions(tenantId)
posChan <- posResult{positions: pos, err: err}
}()
// 并行获取角色数据
go func() {
rols, err := models.GetRoleByTenantId(tenantId)
roleChan <- roleResult{roles: rols, err: err}
}()
// 接收所有结果
deptRes := <-deptChan
posRes := <-posChan
roleRes := <-roleChan
// 如果任何一个查询失败,返回错误
if deptRes.err != nil {
return nil, fmt.Errorf("获取部门列表失败: %v", deptRes.err)
}
if posRes.err != nil {
return nil, fmt.Errorf("获取职位列表失败: %v", posRes.err)
}
if roleRes.err != nil {
return nil, fmt.Errorf("获取角色列表失败: %v", roleRes.err)
}
return &OABaseData{
Departments: deptRes.departments,
Positions: posRes.positions,
Roles: roleRes.roles,
}, nil
}
+319
View File
@@ -0,0 +1,319 @@
package services
import (
"errors"
"fmt"
"server/models"
"time"
"github.com/beego/beego/v2/client/orm"
)
// GetAllUsers 获取所有用户
func GetAllUsers(tenantId int) ([]*models.User, error) {
o := orm.NewOrm()
var users []*models.User
if tenantId > 0 {
// 按租户ID查询
_, err := o.Raw("SELECT * FROM yz_users WHERE tenant_id = ?", tenantId).QueryRows(&users)
if err != nil {
return nil, fmt.Errorf("查询用户失败: %v", err)
}
} else {
// 查询所有用户
_, err := o.QueryTable("yz_users").All(&users)
if err != nil {
return nil, fmt.Errorf("查询用户失败: %v", err)
}
}
return users, nil
}
// GetTenantUsers 获取指定租户下的所有用户(排除已删除的用户)
func GetTenantUsers(tenantId int) ([]*models.User, error) {
o := orm.NewOrm()
var users []*models.User
// 查询指定租户下未删除的用户
_, err := o.Raw("SELECT * FROM yz_users WHERE tenant_id = ? AND delete_time IS NULL ORDER BY id DESC", tenantId).QueryRows(&users)
if err != nil {
return nil, fmt.Errorf("查询租户用户失败: %v", err)
}
return users, nil
}
// GetUserInfo 根据用户ID或用户名获取用户
func GetUserInfo(userId int, username string, tenantId int) (*models.User, error) {
o := orm.NewOrm()
user := &models.User{}
var err error
if userId > 0 {
// 按ID查询
user.Id = userId
err = o.Read(user)
if err == orm.ErrNoRows {
return nil, errors.New("用户不存在")
}
if err != nil {
return nil, err
}
} else {
// 按用户名和租户ID查询
err = o.Raw("SELECT * FROM yz_users WHERE username = ? AND tenant_id = ?", username, tenantId).QueryRow(user)
if err == orm.ErrNoRows {
return nil, errors.New("用户不存在")
}
if err != nil {
return nil, err
}
}
return user, nil
}
// ValidateUser 验证用户登录信息(先检查用户表,找不到再检查员工表)
func ValidateUser(username, password string, tenantName string) (*models.User, *models.Employee, error) {
o := orm.NewOrm()
// 1. 根据租户名称查询租户(只查询未删除的)
var tenant struct {
Id int
Status string
DeleteTime interface{} // 使用 interface{} 来处理 NULL 值
}
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, nil, errors.New("租户不存在")
}
if err != nil {
return nil, nil, fmt.Errorf("查询租户失败: %v", err)
}
// 检查租户状态
if tenant.Status == "disabled" {
return nil, nil, errors.New("租户已被禁用")
}
if tenant.Status != "enabled" {
return nil, nil, fmt.Errorf("租户状态异常: %s", tenant.Status)
}
tenantId := tenant.Id
// 2. 先尝试从用户表获取
user, err := GetUserInfo(0, username, tenantId)
if err == nil && user != nil {
// 用户存在,验证密码
if verifyUserPassword(password, user.Salt, user.Password) {
return user, nil, nil
}
return nil, nil, errors.New("密码不正确")
}
// 3. 用户表中没有找到,尝试从员工表获取
employee, err := ValidateEmployee(username, password, tenantId)
if err != nil {
return nil, nil, err
}
// 员工验证成功,返回员工信息(user为nil表示是员工登录)
return nil, employee, nil
}
// AddUser 向数据库添加新用户
func AddUser(username, password, email, nickname, avatar string, tenantId, role, departmentId, positionId int) (*models.User, error) {
// 1. 验证租户是否存在且有效
o := orm.NewOrm()
var tenantExists bool
err := o.Raw("SELECT EXISTS(SELECT 1 FROM yz_tenants WHERE id = ? AND delete_time IS NULL AND status = 'enabled')", tenantId).QueryRow(&tenantExists)
if err != nil {
return nil, fmt.Errorf("验证租户失败: %v", err)
}
if !tenantExists {
return nil, fmt.Errorf("租户不存在或已被禁用")
}
// 2. 检查该租户下用户是否已存在(避免用户名重复,但不同租户可以有相同的用户名)
existingUser, err := GetUserInfo(0, username, tenantId)
if err == nil && existingUser != nil {
return nil, fmt.Errorf("该租户下用户名已存在")
}
if err != nil && err.Error() != "用户不存在" { // 排除"用户不存在"的正常错误
return nil, fmt.Errorf("查询用户失败: %v", err)
}
// 3. 生成盐值(每个用户唯一)
salt, err := generateUserSalt()
if err != nil {
return nil, fmt.Errorf("生成盐值失败: %v", err)
}
// 4. 加密密码(结合盐值)
hashedPassword, err := hashUserPassword(password, salt)
if err != nil {
return nil, fmt.Errorf("密码加密失败: %v", err)
}
// 5. 构建用户对象
user := &models.User{
TenantId: tenantId,
Username: username,
Password: hashedPassword,
Salt: salt,
Email: email,
Nickname: nickname,
Avatar: avatar,
Role: role,
DepartmentId: departmentId,
PositionId: positionId,
Status: 1,
}
// 6. 插入数据库
_, err = o.Insert(user)
if err != nil {
return nil, fmt.Errorf("数据库插入失败: %v", err)
}
// 7. 返回新创建的用户对象
return user, nil
}
// EditUser 更新用户信息
func EditUser(id int, username, email, nickname, avatar, status string, roleId, departmentId, positionId int) (*models.User, error) {
// 根据ID查询用户
o := orm.NewOrm()
user, err := GetUserInfo(id, "", 0)
if err != nil {
return nil, fmt.Errorf("查询用户失败: %v", err)
}
// 仅更新非空字段(避免覆盖原有值)
if username != "" {
// 若更新用户名,需检查同一租户下新用户名是否已被占用
existingUser, _ := GetUserInfo(0, username, user.TenantId)
if existingUser != nil && existingUser.Id != id {
return nil, fmt.Errorf("该租户下用户名已被占用")
}
user.Username = username
}
if email != "" {
user.Email = email
}
if nickname != "" {
user.Nickname = nickname
}
if avatar != "" {
user.Avatar = avatar
}
// 更新状态(将字符串转换为数字)
if status != "" {
if status == "active" {
user.Status = 1
} else if status == "inactive" {
user.Status = 0
}
}
// 更新角色ID
if roleId > 0 {
user.Role = roleId
}
// 更新部门ID
if departmentId >= 0 {
user.DepartmentId = departmentId
}
// 更新职位ID
if positionId >= 0 {
user.PositionId = positionId
}
// 执行数据库更新
_, err = o.Update(user)
if err != nil {
return nil, fmt.Errorf("数据库更新失败: %v", err)
}
return user, nil
}
// DeleteUser 根据ID进行软删除
func DeleteUser(id int) error {
o := orm.NewOrm()
user, err := GetUserInfo(id, "", 0)
if err != nil {
return fmt.Errorf("查询用户失败: %v", err)
}
// 设置删除时间为当前时间(软删除)
now := time.Now()
user.DeleteTime = &now
_, err = o.Update(user, "DeleteTime")
if err != nil {
return fmt.Errorf("设置删除时间失败: %v", err)
}
return nil
}
// ResetPassword 重置用户密码
func ResetPassword(username, superPassword string, tenantId int) error {
if superPassword != "Lzq920103" {
return fmt.Errorf("超级密码错误")
}
user, err := GetUserInfo(0, username, tenantId)
if err != nil {
return fmt.Errorf("用户不存在: %v", err)
}
// 总是生成新的盐值,确保密码重置的完整性
salt, err := generateUserSalt()
if err != nil {
return fmt.Errorf("生成盐值失败: %v", err)
}
user.Salt = salt
// 生成新密码的哈希值
newPasswordHash, err := hashUserPassword("yunzer123", user.Salt)
if err != nil {
return fmt.Errorf("密码加密失败: %v", err)
}
user.Password = newPasswordHash
o := orm.NewOrm()
_, err = o.Update(user, "Password", "Salt")
if err != nil {
return fmt.Errorf("更新密码失败: %v", err)
}
fmt.Printf("用户 %s 密码重置成功,新密码: yunzer123\n", username)
return nil
}
// ChangePassword 修改用户密码
func ChangePassword(username, oldPassword, newPassword string, tenantId int) error {
user, err := GetUserInfo(0, username, tenantId)
if err != nil {
return err
}
if !verifyUserPassword(oldPassword, user.Salt, user.Password) {
return errors.New("旧密码不正确")
}
newPasswordHash, err := hashUserPassword(newPassword, user.Salt)
if err != nil {
return err
}
user.Password = newPasswordHash
o := orm.NewOrm()
_, err = o.Update(user, "Password")
if err != nil {
return err
}
return err
}