first commit

This commit is contained in:
何昌清
2026-03-26 22:13:03 +08:00
parent bbe1faa363
commit a2685f7f1e
51 changed files with 11244 additions and 0 deletions

59
services/com_service.go Normal file
View File

@@ -0,0 +1,59 @@
package services
import (
"Quincy_admin/repositories"
"Quincy_admin/schemas"
"bufio"
"log"
"os"
"strings"
)
type CommonService struct {
repo *repositories.CommonRepository
}
func NewCommonService(repo *repositories.CommonRepository) *CommonService {
return &CommonService{repo: repo}
}
// GetLoginLogList 获取登录日志列表
func (s *CommonService) GetLoginLogList(req *schemas.LoginLogListRequest) ([]*schemas.LoginLog, int64, error) {
return s.repo.GetLoginLogList(req)
}
// ReadLastLines 读取文件最后几行
func (s *CommonService) ReadLastLines(filepath string, lines int) (string, error) {
file, err := os.Open(filepath)
if err != nil {
return "", err
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
log.Println("Error closing file:", err)
}
}(file)
// 使用Scanner按行读取
scanner := bufio.NewScanner(file)
var allLines []string
for scanner.Scan() {
allLines = append(allLines, scanner.Text())
}
if err := scanner.Err(); err != nil {
return "", err
}
// 获取最后几行
totalLines := len(allLines)
start := totalLines - lines
if start < 0 {
start = 0
}
result := allLines[start:]
return strings.Join(result, "\n"), nil
}

122
services/cron_service.go Normal file
View File

@@ -0,0 +1,122 @@
// Package services/cron_service.go
package services
import (
"Quincy_admin/crontask"
"Quincy_admin/repositories"
"Quincy_admin/schemas"
"fmt"
"log"
)
type CronService struct {
cronRepo *repositories.CronRepository
cronManager *crontask.CronManager
}
func NewCronService(cronRepo *repositories.CronRepository, cronManager *crontask.CronManager) *CronService {
return &CronService{
cronRepo: cronRepo,
cronManager: cronManager,
}
}
// GetCronList 获取定时任务列表
func (s *CronService) GetCronList(req *schemas.CronListRequest) ([]*schemas.CronJob, int64, error) {
return s.cronRepo.GetCronList(req)
}
// AddCron 添加定时任务
func (s *CronService) AddCron(req *schemas.CronJobUpdateRequest) (int64, error) {
return s.cronRepo.AddCron(req)
}
// UpdateCron 修改定时任务
func (s *CronService) UpdateCron(req *schemas.CronJobUpdateRequest) error {
// 更新数据库
err := s.cronRepo.UpdateCron(req)
if err != nil {
return err
}
// 先移除现有的任务
err = s.cronManager.RemoveJob(int(req.ID))
if err != nil {
return err
}
err = s.cronManager.AddJobByID(int(req.ID))
return nil
}
// UpdateCronStatus 启用/停用定时任务
func (s *CronService) UpdateCronStatus(id int, enable int) error {
// 先更新数据库状态
err := s.cronRepo.UpdateCronStatus(id, enable)
if err != nil {
return err
}
// 根据 enabled 状态决定是否移除或添加任务
// 数据库更新成功后再处理任务管理器
var jobErr error
if enable == 0 {
// 停用:移除任务
jobErr = s.cronManager.RemoveJob(id)
} else if enable == 1 {
// 启用:添加任务
jobErr = s.cronManager.AddJobByID(id)
}
// 如果任务管理器操作失败,回滚数据库状态
if jobErr != nil {
rollbackEnable := 1 - enable
rollbackErr := s.cronRepo.UpdateCronStatus(id, rollbackEnable)
if rollbackErr != nil {
log.Printf("failed to rollback job status: %v\n", rollbackErr)
}
return fmt.Errorf("failed to update job status: %v", jobErr)
}
return nil
}
// DeleteCron 删除定时任务
func (s *CronService) DeleteCron(id int) error {
// 删除数据库记录
err := s.cronRepo.DeleteCron(id)
if err != nil {
return err
}
// 触发任务刷新(需传入 CronManager 实例)
go func() {
err := s.cronManager.RemoveJob(id)
if err != nil {
}
}()
return nil
}
// RestartCron 重启定时任务
func (s *CronService) RestartCron() error {
err := s.cronRepo.UpdateAllCronStatus(1)
if err != nil {
return err
}
return s.cronManager.Restart()
}
// StopCron 停止定时任务
func (s *CronService) StopCron() error {
err := s.cronRepo.UpdateAllCronStatus(0)
if err != nil {
return err
}
return s.cronManager.Stop()
}
// GetCronLogList 获取定时任务日志列表
func (s *CronService) GetCronLogList(req *schemas.CronJobLogListRequest) ([]*schemas.CronJobLog, int64, error) {
return s.cronRepo.GetCronLogList(req)
}

196
services/pms_service.go Normal file
View File

@@ -0,0 +1,196 @@
// Package services/pms_service.go
package services
import (
"Quincy_admin/repositories"
"Quincy_admin/schemas"
)
type PermissionService struct {
pmsRepo *repositories.PermissionRepository
}
func NewPermissionService(repo *repositories.PermissionRepository) *PermissionService {
return &PermissionService{pmsRepo: repo}
}
// GetRoutesByID 获取侧边栏菜单权限
func (s *PermissionService) GetRoutesByID(roleID int) (*schemas.Routes, error) {
// 从仓库获取菜单数据
var menuItems []*schemas.MenuItems
var err error
// 超级管理员ID为1(超管),获取所有菜单数据
if roleID == 1 {
menuItems, err = s.pmsRepo.GetRoutes()
} else {
// 从仓库获取菜单数据
menuItems, err = s.pmsRepo.GetRoutesByID(roleID)
}
if err != nil {
return nil, err
}
// 构建树形结构
var rootNodes []*schemas.Routes
// 存储所有节点的映射,便于查找子节点
nodeMap := make(map[int]*schemas.Routes)
for _, item := range menuItems {
node := &schemas.Routes{
ID: item.ID,
ParentID: item.ParentID,
Title: item.Title,
Path: item.Path,
Component: item.Component,
Icon: item.Icon,
Sort: item.Sort,
Visible: item.Visible,
Status: item.Status,
}
nodeMap[item.ID] = node
// 如果是根节点parent_id = 0
if item.ParentID == 0 {
rootNodes = append(rootNodes, node)
}
}
// 为每个节点添加子节点
for _, node := range nodeMap {
if node.ParentID != 0 {
parentNode, exists := nodeMap[node.ParentID]
if exists {
if parentNode.Children == nil {
parentNode.Children = []*schemas.Routes{}
}
parentNode.Children = append(parentNode.Children, node)
}
}
}
// 返回根节点数组
return &schemas.Routes{Children: rootNodes}, nil
}
// GetMenuList 获取菜单列表
func (s *PermissionService) GetMenuList(page, pageSize int) ([]*schemas.MenuItems, int64, error) {
return s.pmsRepo.GetMenuList(page, pageSize)
}
// UpdateMenuStatus 启用/停用菜单
func (s *PermissionService) UpdateMenuStatus(id int, status int) error {
return s.pmsRepo.UpdateMenuStatus(id, status)
}
// GetPermission 获取权限信息
func (s *PermissionService) GetPermission(roleID int, typeStr string) (*[]string, error) {
// 超级管理员ID为1(超管),获取所有菜单数据
if roleID == 1 {
return s.pmsRepo.GetAllPermission(typeStr)
} else {
return s.pmsRepo.GetPermission(roleID, typeStr)
}
}
// GetAllPermission 获取系统所有权限信息
func (s *PermissionService) GetAllPermission() (*schemas.PermissionItems, error) {
// 获取所有权限数据
items, err := s.pmsRepo.GetAllNewPermission()
if err != nil {
return nil, err
}
// 构建树形结构
root := &schemas.PermissionItems{
ID: 0,
Name: "root",
Title: "根节点",
Children: make([]*schemas.PermissionItems, 0), // 使用指针切片
}
nodeMap := make(map[int64]*schemas.PermissionItems)
// 先建立映射
for i := range items {
nodeMap[items[i].ID] = items[i] // 直接使用指针
}
// 遍历所有节点,挂载到父节点下
for _, item := range items {
if item.ParentID == 0 {
root.Children = append(root.Children, item) // 使用指针
} else {
if parent, exists := nodeMap[item.ParentID]; exists {
parent.Children = append(parent.Children, item) // 使用指针
}
}
}
return root, nil
}
// GetRolePermission 获取角色权限信息
func (s *PermissionService) GetRolePermission(roleID int, typeStr string) (*[]int, error) {
return s.pmsRepo.GetRolePermission(roleID, typeStr)
}
// AssignPermission 为角色分配权限
func (s *PermissionService) AssignPermission(roleID int, permissionIDs []int) error {
// 获取角色现有的权限ID列表
existingPermIDs, err := s.GetRolePermissionIDs(roleID)
if err != nil {
return err
}
// 构建现有权限ID映射
existingPermMap := make(map[int]bool)
for _, pid := range existingPermIDs {
existingPermMap[pid] = true
}
// 构建请求权限ID映射
requestPermMap := make(map[int]bool)
for _, pid := range permissionIDs {
requestPermMap[pid] = true
}
// 分离需要新增和需要删除的权限ID
var toInsert []int
var toDelete []int
// 找出需要新增的权限(存在于请求中但不存在于现有权限中)
for _, pid := range permissionIDs {
if !existingPermMap[pid] {
toInsert = append(toInsert, pid)
}
}
// 找出需要删除的权限(存在于现有权限中但不存在于请求中)
for _, pid := range existingPermIDs {
if !requestPermMap[pid] {
toDelete = append(toDelete, pid)
}
}
// 执行插入操作
if len(toInsert) > 0 {
if err := s.pmsRepo.InsertRolePermissions(roleID, toInsert); err != nil {
return err
}
}
// 执行删除操作
if len(toDelete) > 0 {
if err := s.pmsRepo.DeleteRolePermissions(roleID, toDelete); err != nil {
return err
}
}
return nil
}
// GetRolePermissionIDs 获取角色已有的权限ID列表
func (s *PermissionService) GetRolePermissionIDs(roleID int) ([]int, error) {
return s.pmsRepo.GetRolePermissionIDs(roleID)
}

294
services/user_service.go Normal file
View File

@@ -0,0 +1,294 @@
package services
import (
"Quincy_admin/repositories"
"Quincy_admin/schemas"
"Quincy_admin/utils"
"fmt"
"net"
"time"
"golang.org/x/crypto/bcrypt"
)
type UserService struct {
repo *repositories.UserRepository
}
func NewUserService(repo *repositories.UserRepository) (*UserService, error) {
service := &UserService{repo: repo}
return service, nil
}
// CreateUser 创建用户
func (s *UserService) CreateUser(userReq *schemas.CreateUser) error {
// 只有当密码不为空时才进行加密处理
if userReq.Password != "" {
hashedPassword, err := s.HashPassword(userReq.Password)
if err != nil {
return fmt.Errorf("密码加密失败: %v", err)
}
userReq.Password = hashedPassword
} else {
return fmt.Errorf("密码不能为空")
}
//添加默认值
userReq.RoleCode = 0
userReq.Status = schemas.UserStatusDisabled
// 如果 UserCode 为空,生成一个唯一的 UserCode确保与数据库中已有的不重复
foundUniqueCode := false
for i := 0; i < 5; i++ { // 最多尝试5次
userReq.SessionCode = utils.GenerateUserCode("S10", 7)
// 检查数据库是否已存在该 sessioncode
count, err := s.repo.IsUserCodeExists(userReq.SessionCode)
if err != nil {
return err
}
if count == 0 {
foundUniqueCode = true
break
}
}
// 如果5次尝试后仍未找到唯一code返回错误
if !foundUniqueCode {
return fmt.Errorf("无法生成唯一的用户编码已尝试5次")
}
// 生成唯一的 Username确保与数据库中已有的不重复
foundUniqueName := false
for i := 0; i < 5; i++ {
userReq.Username, _ = utils.GenerateUsername(8)
// 检查数据库是否已存在该 Username
count, err := s.repo.IsUsernameExists(userReq.Username)
if err != nil {
return err
}
if count == 0 {
foundUniqueName = true
break
}
}
// 如果5次尝试后仍未找到唯一username返回错误
if !foundUniqueName {
return fmt.Errorf("无法生成唯一的用户名已尝试5次")
}
return s.repo.Create(userReq)
}
// IsEmailExists 检查邮箱是否已存在
func (s *UserService) IsEmailExists(email string) (int, error) {
return s.repo.IsEmailExists(email)
}
// GetUserByID 通过用户ID查找用户
func (s *UserService) GetUserByID(scode string) (*schemas.UserInfo, error) {
return s.repo.FindByID(scode)
}
// GetUserByUsername 通过用户名查找用户
func (s *UserService) GetUserByUsername(username string) (*schemas.UserInfo, error) {
return s.repo.FindByUsername(username)
}
// GetUserLocation 获取用户地理位置信息
func (s *UserService) GetUserLocation(ipAddress string) (map[string]string, error) {
geoDB := utils.GetGeoIP()
if geoDB == nil {
return nil, fmt.Errorf("GeoIP database not initialized")
}
// 解析 IP 地址
ip := net.ParseIP(ipAddress)
if ip == nil {
return nil, fmt.Errorf("invalid IP address: %s", ipAddress)
}
// 查询地理位置
record, err := geoDB.City(ip)
if err != nil {
return nil, fmt.Errorf("failed to query GeoIP database: %v", err)
}
// 构造返回结果
location := map[string]string{
"ip": ipAddress,
"country": record.Country.Names["zh-CN"],
"country_code": record.Country.IsoCode,
"province": "",
"city": "",
"latitude": fmt.Sprintf("%f", record.Location.Latitude),
"longitude": fmt.Sprintf("%f", record.Location.Longitude),
}
// 获取省份/州信息
if len(record.Subdivisions) > 0 {
location["province"] = record.Subdivisions[0].Names["zh-CN"]
}
// 获取城市信息
if record.City.Names["zh-CN"] != "" {
location["city"] = record.City.Names["zh-CN"]
}
//fmt.Println("location:", location)
return location, nil
}
// StoreLoginSession 存储登录会话
//func (s *UserService) StoreLoginSession(sessionKey string, userInfo *schemas.UserInfo, expireTime time.Duration) error {
// InitRedis := utils.GetRedis()
// ctx := utils.GetContext()
//
// // 将用户信息序列化后存储到Redis
// userInfoBytes, err := json.Marshal(userInfo)
// if err != nil {
// return err
// }
//
// err = InitRedis.Set(ctx, sessionKey, userInfoBytes, expireTime).Err()
// if err != nil {
// return err
// }
//
// return nil
//}
// RecordLoginLog 记录登录日志
func (s *UserService) RecordLoginLog(userID int, username string, ipAddress string, userAgent string, status int, failureReason string) error {
// 获取地理位置信息
locationInfo, err := s.GetUserLocation("60.255.157.229")
var locationStr string
if err == nil {
locationStr = fmt.Sprintf("%s%s%s",
locationInfo["country"],
locationInfo["province"],
locationInfo["city"])
} else {
locationStr = "未知位置"
}
// 创建登录日志记录
now := time.Now()
loginLog := &schemas.LoginLog{
UserID: userID,
Username: username,
IPAddress: ipAddress,
Location: locationStr,
UserAgent: userAgent,
LoginTime: schemas.NewCustomTime(&now),
Status: status,
FailureReason: failureReason,
CreateTime: schemas.NewCustomTime(&now),
}
// 插入数据库
return s.repo.RecordLoginLog(loginLog)
}
// UpdateUser 更新用户信息
func (s *UserService) UpdateUser(user *schemas.UpdateUser) (int, error) {
// 检查是否尝试修改超级管理员账户ID=1
if user.ID == 1 {
return 0, fmt.Errorf("无法修改超级管理员账户信息")
}
// 只有当密码不为空时才进行加密处理
if user.Password != "" {
hashedPassword, err := s.HashPassword(user.Password)
if err != nil {
return 0, fmt.Errorf("密码加密失败: %v", err)
}
user.Password = hashedPassword
} else {
// 如果密码为空,则不更新密码字段
user.Password = ""
}
return s.repo.Update(user)
}
// UpdateLastLoginTime 更新用户最后登录时间
func (s *UserService) UpdateLastLoginTime(scode string) error {
return s.repo.UpdateLastLoginTime(scode, time.Now())
}
// UpdateStatus 删除用户
func (s *UserService) UpdateStatus(id int, enable int) error {
// 防止修改超级管理员账户ID=1
if id == 1 {
return fmt.Errorf("无权限修改超级管理员账户")
}
return s.repo.UpdateStatus(id, enable)
}
// HashPassword 对密码进行加密
func (s *UserService) HashPassword(password string) (string, error) {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(hashedPassword), nil
}
// VerifyPassword 验证密码
func (s *UserService) VerifyPassword(plainPassword, hashedPassword string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(plainPassword))
return err == nil
}
// GetUserList 获取用户列表
func (s *UserService) GetUserList(req *schemas.UserListRequest) ([]*schemas.UserInfo, int64, error) {
return s.repo.GetUserList(req)
}
// GetRoleList 获取角色列表
func (s *UserService) GetRoleList(req *schemas.RoleListRequest) ([]*schemas.RoleResponseList, int64, error) {
return s.repo.GetRoleList(req)
}
// GetLoginLogList 获取登录日志列表
func (s *UserService) GetLoginLogList(req *schemas.LoginLogListRequest) ([]*schemas.LoginLog, int64, error) {
return s.repo.GetLoginLogList(req)
}
// AssignRole 分配角色
func (s *UserService) AssignRole(userIdValue, roleIdValue int) error {
// 检查用户是否已分配角色
exists, err := s.repo.AssignRoleExists(userIdValue)
if err != nil {
return err
}
if !exists {
// 用户未分配角色,执行插入操作
return s.repo.AssignRole(userIdValue, roleIdValue)
} else {
// 用户已分配角色,执行更新操作
return s.repo.UpdateAssignRole(userIdValue, roleIdValue)
}
}
// UpdateRoleStatus 删除用户
func (s *UserService) UpdateRoleStatus(id int, enable int) error {
// 防止修改超级管理员账户ID=1
if id == 1 {
return fmt.Errorf("无权限修改超级管理员账户")
}
return s.repo.UpdateRoleStatus(id, enable)
}
// CreateRole 创建角色
func (s *UserService) CreateRole(req *schemas.CreateRole) error {
return s.repo.CreateRole(req)
}
// UpdateRole 更新角色
func (s *UserService) UpdateRole(req *schemas.CreateRole) error {
return s.repo.UpdateRole(req)
}