Initial commit (code only without large binaries)

This commit is contained in:
robin
2026-02-15 18:58:44 +08:00
commit 35df75498f
9442 changed files with 1495866 additions and 0 deletions

View File

@@ -0,0 +1,288 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package tickets
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/tickets"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// UserTicketService 工单服务
type UserTicketService struct {
services.BaseService
}
// CreateUserTicket 创建工单
func (this *UserTicketService) CreateUserTicket(ctx context.Context, req *pb.CreateUserTicketRequest) (*pb.CreateUserTicketResponse, error) {
userId, err := this.ValidateUserNode(ctx, true)
if err != nil {
return nil, err
}
// 检查工单分类是否存在
if req.UserTicketCategoryId > 0 {
// TODO 检查工单分类是否存在
}
var tx = this.NullTx()
ticketId, err := tickets.SharedUserTicketDAO.CreateTicket(tx, userId, req.UserTicketCategoryId, req.Subject, req.Body)
if err != nil {
return nil, err
}
return &pb.CreateUserTicketResponse{
UserTicketId: ticketId,
}, nil
}
// UpdateUserTicket 修改工单
func (this *UserTicketService) UpdateUserTicket(ctx context.Context, req *pb.UpdateUserTicketRequest) (*pb.RPCSuccess, error) {
userId, err := this.ValidateUserNode(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = tickets.SharedUserTicketDAO.CheckUserTicket(tx, userId, req.UserTicketId)
if err != nil {
return nil, err
}
err = tickets.SharedUserTicketDAO.UpdateTicket(tx, req.UserTicketId, req.UserTicketCategoryId, req.Subject, req.Body)
if err != nil {
return nil, err
}
// 创建日志
ticketStatus, err := tickets.SharedUserTicketDAO.FindTicketStatus(tx, req.UserTicketId)
if err != nil {
return nil, err
}
_, err = tickets.SharedUserTicketLogDAO.CreateLog(tx, 0, userId, req.UserTicketId, ticketStatus, "修改工单内容", true /** 系统记录,不允许删除 **/)
if err != nil {
return nil, err
}
return this.Success()
}
// DeleteUserTicket 删除工单
func (this *UserTicketService) DeleteUserTicket(ctx context.Context, req *pb.DeleteUserTicketRequest) (*pb.RPCSuccess, error) {
userId, err := this.ValidateUserNode(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = tickets.SharedUserTicketDAO.CheckUserTicket(tx, userId, req.UserTicketId)
if err != nil {
return nil, err
}
ticketStatus, err := tickets.SharedUserTicketDAO.FindTicketStatus(tx, req.UserTicketId)
if err != nil {
return nil, err
}
err = tickets.SharedUserTicketDAO.DisableUserTicket(tx, req.UserTicketId)
if err != nil {
return nil, err
}
// 创建日志
_, err = tickets.SharedUserTicketLogDAO.CreateLog(tx, 0, userId, req.UserTicketId, ticketStatus, "删除工单", true /** 系统记录,不允许删除 **/)
if err != nil {
return nil, err
}
return this.Success()
}
// CountUserTickets 计算工单数量
func (this *UserTicketService) CountUserTickets(ctx context.Context, req *pb.CountUserTicketsRequest) (*pb.RPCCountResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
req.UserId = userId
}
count, err := tickets.SharedUserTicketDAO.CountAllTickets(tx, req.UserId, req.UserTicketCategoryId, req.Status)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// ListUserTickets 列出单页工单
func (this *UserTicketService) ListUserTickets(ctx context.Context, req *pb.ListUserTicketsRequest) (*pb.ListUserTicketsResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
req.UserId = userId
}
ticketList, err := tickets.SharedUserTicketDAO.ListTickets(tx, req.UserId, req.UserTicketCategoryId, req.Status, req.Offset, req.Size)
if err != nil {
return nil, err
}
var pbTickets = []*pb.UserTicket{}
for _, ticket := range ticketList {
// 分类
category, err := tickets.SharedUserTicketCategoryDAO.FindEnabledUserTicketCategory(tx, int64(ticket.CategoryId))
if err != nil {
return nil, err
}
var pbCategory *pb.UserTicketCategory
if category != nil {
pbCategory = &pb.UserTicketCategory{
Id: int64(category.Id),
Name: category.Name,
IsOn: category.IsOn,
}
}
// 用户
user, err := models.SharedUserDAO.FindEnabledBasicUser(tx, int64(ticket.UserId))
if err != nil {
return nil, err
}
var pbUser *pb.User
if user != nil {
pbUser = &pb.User{
Id: int64(user.Id),
Fullname: user.Fullname,
Username: user.Username,
}
}
// 最新一条日志
latestLog, err := tickets.SharedUserTicketLogDAO.FindLatestTicketLog(tx, int64(ticket.Id))
if err != nil {
return nil, err
}
var pbLatestLog *pb.UserTicketLog
if latestLog != nil {
var pbLogAdmin *pb.Admin
if latestLog.AdminId > 0 {
logAdmin, err := models.SharedAdminDAO.FindBasicAdmin(tx, int64(latestLog.AdminId))
if err != nil {
return nil, err
}
if logAdmin != nil {
pbLogAdmin = &pb.Admin{
Id: int64(logAdmin.Id),
Username: logAdmin.Username,
Fullname: logAdmin.Fullname,
}
}
}
pbLatestLog = &pb.UserTicketLog{
Id: int64(latestLog.Id),
CreatedAt: int64(latestLog.CreatedAt),
Admin: pbLogAdmin,
}
}
pbTickets = append(pbTickets, &pb.UserTicket{
Id: int64(ticket.Id),
CategoryId: int64(ticket.CategoryId),
UserId: int64(ticket.UserId),
Subject: ticket.Subject,
Body: ticket.Body,
Status: ticket.Status,
CreatedAt: int64(ticket.CreatedAt),
LastLogAt: int64(ticket.LastLogAt),
UserTicketCategory: pbCategory,
User: pbUser,
LatestUserTicketLog: pbLatestLog,
})
}
return &pb.ListUserTicketsResponse{
UserTickets: pbTickets,
}, nil
}
// FindUserTicket 查找单个工单
func (this *UserTicketService) FindUserTicket(ctx context.Context, req *pb.FindUserTicketRequest) (*pb.FindUserTicketResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
err = tickets.SharedUserTicketDAO.CheckUserTicket(tx, userId, req.UserTicketId)
if err != nil {
return nil, err
}
}
ticket, err := tickets.SharedUserTicketDAO.FindEnabledUserTicket(tx, req.UserTicketId)
if err != nil {
return nil, err
}
if ticket == nil {
return &pb.FindUserTicketResponse{
UserTicket: nil,
}, nil
}
// 分类
category, err := tickets.SharedUserTicketCategoryDAO.FindEnabledUserTicketCategory(tx, int64(ticket.CategoryId))
if err != nil {
return nil, err
}
var pbCategory *pb.UserTicketCategory
if category != nil {
pbCategory = &pb.UserTicketCategory{
Id: int64(category.Id),
Name: category.Name,
IsOn: category.IsOn,
}
}
// 用户
user, err := models.SharedUserDAO.FindEnabledBasicUser(tx, int64(ticket.UserId))
if err != nil {
return nil, err
}
var pbUser *pb.User
if user != nil {
pbUser = &pb.User{
Id: int64(user.Id),
Fullname: user.Fullname,
Username: user.Username,
}
}
return &pb.FindUserTicketResponse{
UserTicket: &pb.UserTicket{
Id: int64(ticket.Id),
CategoryId: int64(ticket.CategoryId),
UserId: int64(ticket.UserId),
Subject: ticket.Subject,
Body: ticket.Body,
Status: ticket.Status,
CreatedAt: int64(ticket.CreatedAt),
LastLogAt: int64(ticket.LastLogAt),
UserTicketCategory: pbCategory,
User: pbUser,
},
}, nil
}

View File

@@ -0,0 +1,139 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package tickets
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/tickets"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// UserTicketCategoryService 工单分类服务
type UserTicketCategoryService struct {
services.BaseService
}
// CreateUserTicketCategory 创建分类
func (this *UserTicketCategoryService) CreateUserTicketCategory(ctx context.Context, req *pb.CreateUserTicketCategoryRequest) (*pb.CreateUserTicketCategoryResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
categoryId, err := tickets.SharedUserTicketCategoryDAO.CreateCategory(tx, req.Name)
if err != nil {
return nil, err
}
return &pb.CreateUserTicketCategoryResponse{
UserTicketCategoryId: categoryId,
}, nil
}
// UpdateUserTicketCategory 修改分类
func (this *UserTicketCategoryService) UpdateUserTicketCategory(ctx context.Context, req *pb.UpdateUserTicketCategoryRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = tickets.SharedUserTicketCategoryDAO.UpdateCategory(tx, req.UserTicketCategoryId, req.Name, req.IsOn)
if err != nil {
return nil, err
}
return this.Success()
}
// DeleteUserTicketCategory 删除分类
func (this *UserTicketCategoryService) DeleteUserTicketCategory(ctx context.Context, req *pb.DeleteUserTicketCategoryRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = tickets.SharedUserTicketCategoryDAO.DisableUserTicketCategory(tx, req.UserTicketCategoryId)
if err != nil {
return nil, err
}
return this.Success()
}
// FindAllUserTicketCategories 查找所有分类
func (this *UserTicketCategoryService) FindAllUserTicketCategories(ctx context.Context, req *pb.FindAllUserTicketCategoriesRequest) (*pb.FindAllUserTicketCategoriesResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
categories, err := tickets.SharedUserTicketCategoryDAO.FindAllEnabledCategories(tx)
if err != nil {
return nil, err
}
var pbCategories = []*pb.UserTicketCategory{}
for _, category := range categories {
pbCategories = append(pbCategories, &pb.UserTicketCategory{
Id: int64(category.Id),
Name: category.Name,
IsOn: category.IsOn,
})
}
return &pb.FindAllUserTicketCategoriesResponse{
UserTicketCategories: pbCategories,
}, nil
}
// FindAllAvailableUserTicketCategories 查找所有启用中的分类
func (this *UserTicketCategoryService) FindAllAvailableUserTicketCategories(ctx context.Context, req *pb.FindAllAvailableUserTicketCategoriesRequest) (*pb.FindAllAvailableUserTicketCategoriesResponse, error) {
_, _, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
categories, err := tickets.SharedUserTicketCategoryDAO.FindAllEnabledAndOnCategories(tx)
if err != nil {
return nil, err
}
var pbCategories = []*pb.UserTicketCategory{}
for _, category := range categories {
pbCategories = append(pbCategories, &pb.UserTicketCategory{
Id: int64(category.Id),
Name: category.Name,
IsOn: category.IsOn,
})
}
return &pb.FindAllAvailableUserTicketCategoriesResponse{
UserTicketCategories: pbCategories,
}, nil
}
// FindUserTicketCategory 查询单个分类
func (this *UserTicketCategoryService) FindUserTicketCategory(ctx context.Context, req *pb.FindUserTicketCategoryRequest) (*pb.FindUserTicketCategoryResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
category, err := tickets.SharedUserTicketCategoryDAO.FindEnabledUserTicketCategory(tx, req.UserTicketCategoryId)
if err != nil {
return nil, err
}
if category == nil {
return &pb.FindUserTicketCategoryResponse{
UserTicketCategory: nil,
}, nil
}
return &pb.FindUserTicketCategoryResponse{
UserTicketCategory: &pb.UserTicketCategory{
Id: int64(category.Id),
Name: category.Name,
IsOn: category.IsOn,
},
}, nil
}

View File

@@ -0,0 +1,175 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package tickets
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/tickets"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// UserTicketLogService 工单日志服务
type UserTicketLogService struct {
services.BaseService
}
// CreateUserTicketLog 创建日志
func (this *UserTicketLogService) CreateUserTicketLog(ctx context.Context, req *pb.CreateUserTicketLogRequest) (*pb.CreateUserTicketLogResponse, error) {
adminId, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
// 如果没有指定状态,就使用上次的状态
if len(req.Status) == 0 {
status, err := tickets.SharedUserTicketDAO.FindTicketStatus(tx, req.UserTicketId)
if err != nil {
return nil, err
}
req.Status = status
}
logId, err := tickets.SharedUserTicketLogDAO.CreateLog(tx, adminId, userId, req.UserTicketId, req.Status, req.Comment, false)
if err != nil {
return nil, err
}
return &pb.CreateUserTicketLogResponse{
UserTicketLogId: logId,
}, nil
}
// DeleteUserTicketLog 删除日志
func (this *UserTicketLogService) DeleteUserTicketLog(ctx context.Context, req *pb.DeleteUserTicketLogRequest) (*pb.RPCSuccess, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
err = tickets.SharedUserTicketLogDAO.CheckUserLog(tx, userId, req.UserTicketLogId)
if err != nil {
return nil, err
}
}
isReadonly, err := tickets.SharedUserTicketLogDAO.CheckLogReadonly(tx, req.UserTicketLogId)
if err != nil {
return nil, err
}
if isReadonly {
return nil, errors.New("the log is readonly")
}
err = tickets.SharedUserTicketLogDAO.DisableLog(tx, req.UserTicketLogId)
if err != nil {
return nil, err
}
return this.Success()
}
// CountUserTicketLogs 查询日志数量
func (this *UserTicketLogService) CountUserTicketLogs(ctx context.Context, req *pb.CountUserTicketLogsRequest) (*pb.RPCCountResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
err = tickets.SharedUserTicketDAO.CheckUserTicket(tx, userId, req.UserTicketId)
if err != nil {
return nil, err
}
}
count, err := tickets.SharedUserTicketLogDAO.CountTicketLogs(tx, req.UserTicketId)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// ListUserTicketLogs 列出单页日志
func (this *UserTicketLogService) ListUserTicketLogs(ctx context.Context, req *pb.ListUserTicketLogsRequest) (*pb.ListUserTicketLogsResponse, error) {
adminId, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
err = tickets.SharedUserTicketDAO.CheckUserTicket(tx, userId, req.UserTicketId)
if err != nil {
return nil, err
}
}
logs, err := tickets.SharedUserTicketLogDAO.ListTicketLogs(tx, req.UserTicketId, req.Offset, req.Size)
if err != nil {
return nil, err
}
var pbLogs = []*pb.UserTicketLog{}
for _, log := range logs {
// 只有管理员才可以看到管理员信息
var pbAdmin *pb.Admin
var pbUser *pb.User
if adminId > 0 {
if log.AdminId > 0 {
admin, err := models.SharedAdminDAO.FindBasicAdmin(tx, int64(log.AdminId))
if err != nil {
return nil, err
}
if admin != nil {
pbAdmin = &pb.Admin{
Id: int64(admin.Id),
Fullname: admin.Fullname,
Username: admin.Username,
}
}
}
if log.UserId > 0 {
user, err := models.SharedUserDAO.FindEnabledBasicUser(tx, int64(log.UserId))
if err != nil {
return nil, err
}
if user != nil {
pbUser = &pb.User{
Id: int64(user.Id),
Fullname: user.Fullname,
Username: user.Username,
}
}
}
}
pbLogs = append(pbLogs, &pb.UserTicketLog{
Id: int64(log.Id),
AdminId: int64(log.AdminId),
UserId: int64(log.UserId),
TicketId: int64(log.TicketId),
Status: log.Status,
Comment: log.Comment,
CreatedAt: int64(log.CreatedAt),
IsReadonly: log.IsReadonly,
Admin: pbAdmin,
User: pbUser,
})
}
return &pb.ListUserTicketLogsResponse{
UserTicketLogs: pbLogs,
}, nil
}