Re-migrate code
This commit is contained in:
@@ -125,7 +125,7 @@ func (s *AuthService) ValidateUser(username, password string) (models.User, erro
|
|||||||
var user models.User
|
var user models.User
|
||||||
err := database.DB.Where("username = ?", username).First(&user).Error
|
err := database.DB.Where("username = ?", username).First(&user).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return models.User{}, errors.New("用户名或密码错误")
|
return models.User{}, errors.New("用户名或密码不正确")
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
@@ -149,6 +149,9 @@ func (c *AuthController) Login(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- Use `ErrorResponse` for API errors so messages are user-friendly and consistent.
|
||||||
|
- Do not leak raw DB/stack errors to clients; log internal details and return safe messages.
|
||||||
|
|
||||||
### Response Format
|
### Response Format
|
||||||
**Success response**:
|
**Success response**:
|
||||||
```json
|
```json
|
||||||
@@ -158,6 +161,8 @@ func (c *AuthController) Login(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Some endpoints also return Node-compatible top-level keys (e.g. `serial`, `serials`, `pagination`) to preserve frontend compatibility.
|
||||||
|
|
||||||
**Error response**:
|
**Error response**:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -240,6 +240,8 @@ swag init -g main.go
|
|||||||
| PUT | `/api/auth/profile` | 更新用户信息 | 是 |
|
| PUT | `/api/auth/profile` | 更新用户信息 | 是 |
|
||||||
| POST | `/api/auth/change-password` | 修改密码 | 是 |
|
| POST | `/api/auth/change-password` | 修改密码 | 是 |
|
||||||
|
|
||||||
|
> 错误提示已做用户友好化,例如登录失败统一返回:`用户名或密码不正确`。
|
||||||
|
|
||||||
### 序列号管理
|
### 序列号管理
|
||||||
|
|
||||||
| 方法 | 路径 | 描述 | 需要认证 | 角色 |
|
| 方法 | 路径 | 描述 | 需要认证 | 角色 |
|
||||||
@@ -279,6 +281,12 @@ swag init -g main.go
|
|||||||
| PUT | `/api/employee-serials/:serialNumber` | 更新员工序列号信息 | 是 | 管理员 |
|
| PUT | `/api/employee-serials/:serialNumber` | 更新员工序列号信息 | 是 | 管理员 |
|
||||||
| POST | `/api/employee-serials/:serialNumber/revoke` | 吊销员工序列号 | 是 | 管理员 |
|
| POST | `/api/employee-serials/:serialNumber/revoke` | 吊销员工序列号 | 是 | 管理员 |
|
||||||
|
|
||||||
|
### Node 对齐说明
|
||||||
|
|
||||||
|
- Go 版路由已与 `backend-node` 对齐(含 `PATCH` 更新接口、企业详情、企业吊销、删除企业下单个序列号)。
|
||||||
|
- 企业统计与企业详情接口统一返回 `{ message, data }` 结构。
|
||||||
|
- 序列号相关返回字段已对齐前端使用(如 `serialNumber`、`validUntil`、`createdBy`、`status`)。
|
||||||
|
|
||||||
**员工序列号特点**:
|
**员工序列号特点**:
|
||||||
- 无有效期限制(与企业赋码不同)
|
- 无有效期限制(与企业赋码不同)
|
||||||
- 包含部门(department)和员工姓名(employeeName)信息
|
- 包含部门(department)和员工姓名(employeeName)信息
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ func (c *EmployeeSerialsController) Generate(ctx *gin.Context) {
|
|||||||
generateData.EmployeeName,
|
generateData.EmployeeName,
|
||||||
generateData.Quantity,
|
generateData.Quantity,
|
||||||
userModel.ID,
|
userModel.ID,
|
||||||
|
generateData.SerialPrefix,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ErrorResponse(ctx, http.StatusInternalServerError, err.Error())
|
ErrorResponse(ctx, http.StatusInternalServerError, err.Error())
|
||||||
@@ -226,3 +227,28 @@ func (c *EmployeeSerialsController) Revoke(ctx *gin.Context) {
|
|||||||
|
|
||||||
SuccessResponse(ctx, "员工序列号吊销成功")
|
SuccessResponse(ctx, "员工序列号吊销成功")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete 删除员工序列号
|
||||||
|
// @Summary 删除员工序列号
|
||||||
|
// @Description 删除指定员工序列号(物理删除)
|
||||||
|
// @Tags 员工赋码管理
|
||||||
|
// @Produce json
|
||||||
|
// @Security BearerAuth
|
||||||
|
// @Param serialNumber path string true "序列号"
|
||||||
|
// @Success 200 {object} models.BaseResponse
|
||||||
|
// @Failure 400 {object} models.ErrorResponse
|
||||||
|
// @Failure 401 {object} models.ErrorResponse
|
||||||
|
// @Failure 404 {object} models.ErrorResponse
|
||||||
|
// @Failure 500 {object} models.ErrorResponse
|
||||||
|
// @Router /employee-serials/{serialNumber} [delete]
|
||||||
|
func (c *EmployeeSerialsController) Delete(ctx *gin.Context) {
|
||||||
|
serialNumber := ctx.Param("serialNumber")
|
||||||
|
|
||||||
|
err := c.employeeSerialsService.Delete(serialNumber)
|
||||||
|
if err != nil {
|
||||||
|
ErrorResponse(ctx, http.StatusBadRequest, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
SuccessResponse(ctx, "员工序列号删除成功")
|
||||||
|
}
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ type GenerateEmployeeSerialDTO struct {
|
|||||||
Department string `json:"department" validate:"required"`
|
Department string `json:"department" validate:"required"`
|
||||||
EmployeeName string `json:"employeeName" validate:"required"`
|
EmployeeName string `json:"employeeName" validate:"required"`
|
||||||
Quantity int `json:"quantity" validate:"min=1,max=1000"`
|
Quantity int `json:"quantity" validate:"min=1,max=1000"`
|
||||||
|
SerialPrefix string `json:"serialPrefix,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEmployeeSerialDTO 员工序列号更新请求数据
|
// UpdateEmployeeSerialDTO 员工序列号更新请求数据
|
||||||
|
|||||||
@@ -71,5 +71,6 @@ func SetupAPIRoutes(r *gin.RouterGroup) {
|
|||||||
employeeSerialsRoutes.GET("/", middleware.JWTAuthMiddleware(), employeeSerialsController.FindAll)
|
employeeSerialsRoutes.GET("/", middleware.JWTAuthMiddleware(), employeeSerialsController.FindAll)
|
||||||
employeeSerialsRoutes.PUT("/:serialNumber", middleware.JWTAuthMiddleware(), middleware.AdminMiddleware(), employeeSerialsController.Update)
|
employeeSerialsRoutes.PUT("/:serialNumber", middleware.JWTAuthMiddleware(), middleware.AdminMiddleware(), employeeSerialsController.Update)
|
||||||
employeeSerialsRoutes.POST("/:serialNumber/revoke", middleware.JWTAuthMiddleware(), middleware.AdminMiddleware(), employeeSerialsController.Revoke)
|
employeeSerialsRoutes.POST("/:serialNumber/revoke", middleware.JWTAuthMiddleware(), middleware.AdminMiddleware(), employeeSerialsController.Revoke)
|
||||||
|
employeeSerialsRoutes.DELETE("/:serialNumber", middleware.JWTAuthMiddleware(), middleware.AdminMiddleware(), employeeSerialsController.Delete)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package services
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -311,8 +312,14 @@ func (s *CompaniesService) GetStats() (map[string]any, error) {
|
|||||||
return nil, errors.New("查询序列号统计失败")
|
return nil, errors.New("查询序列号统计失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var employeeSerials []models.EmployeeSerial
|
||||||
|
if err := database.DB.Order("created_at DESC").Find(&employeeSerials).Error; err != nil {
|
||||||
|
return nil, errors.New("查询员工序列号统计失败")
|
||||||
|
}
|
||||||
|
|
||||||
companyCount := len(companies)
|
companyCount := len(companies)
|
||||||
serialCount := len(serials)
|
serialCount := len(serials)
|
||||||
|
employeeSerialCount := len(employeeSerials)
|
||||||
activeCount := 0
|
activeCount := 0
|
||||||
for _, serial := range serials {
|
for _, serial := range serials {
|
||||||
if serial.IsActive && (serial.ValidUntil == nil || serial.ValidUntil.After(now)) {
|
if serial.IsActive && (serial.ValidUntil == nil || serial.ValidUntil.After(now)) {
|
||||||
@@ -355,24 +362,43 @@ func (s *CompaniesService) GetStats() (map[string]any, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
recentSerials := make([]map[string]any, 0)
|
recentSerials := make([]map[string]any, 0)
|
||||||
for i, serial := range serials {
|
// 添加企业序列号
|
||||||
if i >= 10 {
|
for _, serial := range serials {
|
||||||
break
|
|
||||||
}
|
|
||||||
recentSerials = append(recentSerials, map[string]any{
|
recentSerials = append(recentSerials, map[string]any{
|
||||||
"serialNumber": serial.SerialNumber,
|
"serialNumber": serial.SerialNumber,
|
||||||
"companyName": serial.CompanyName,
|
"companyName": serial.CompanyName,
|
||||||
"isActive": serial.IsActive,
|
"isActive": serial.IsActive,
|
||||||
"createdAt": serial.CreatedAt,
|
"createdAt": serial.CreatedAt,
|
||||||
|
"type": "company",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 添加员工序列号
|
||||||
|
for _, serial := range employeeSerials {
|
||||||
|
recentSerials = append(recentSerials, map[string]any{
|
||||||
|
"serialNumber": serial.SerialNumber,
|
||||||
|
"companyName": serial.CompanyName,
|
||||||
|
"isActive": serial.IsActive,
|
||||||
|
"createdAt": serial.CreatedAt,
|
||||||
|
"type": "employee",
|
||||||
|
"department": serial.Department,
|
||||||
|
"employeeName": serial.EmployeeName,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 按创建时间排序,保留最新的10条
|
||||||
|
sort.Slice(recentSerials, func(i, j int) bool {
|
||||||
|
return recentSerials[i]["createdAt"].(time.Time).After(recentSerials[j]["createdAt"].(time.Time))
|
||||||
|
})
|
||||||
|
if len(recentSerials) > 10 {
|
||||||
|
recentSerials = recentSerials[:10]
|
||||||
|
}
|
||||||
|
|
||||||
return map[string]any{
|
return map[string]any{
|
||||||
"overview": map[string]any{
|
"overview": map[string]any{
|
||||||
"totalCompanies": companyCount,
|
"totalCompanies": companyCount,
|
||||||
"totalSerials": serialCount,
|
"totalSerials": serialCount,
|
||||||
"activeSerials": activeCount,
|
"totalEmployeeSerials": employeeSerialCount,
|
||||||
"inactiveSerials": inactiveCount,
|
"activeSerials": activeCount,
|
||||||
|
"inactiveSerials": inactiveCount,
|
||||||
},
|
},
|
||||||
"monthlyStats": monthlyItems,
|
"monthlyStats": monthlyItems,
|
||||||
"recentCompanies": recentCompanies,
|
"recentCompanies": recentCompanies,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ func (s *EmployeeSerialsService) Generate(
|
|||||||
employeeName string,
|
employeeName string,
|
||||||
quantity int,
|
quantity int,
|
||||||
userId uint,
|
userId uint,
|
||||||
|
serialPrefix string,
|
||||||
) ([]models.EmployeeSerial, error) {
|
) ([]models.EmployeeSerial, error) {
|
||||||
var serials []models.EmployeeSerial
|
var serials []models.EmployeeSerial
|
||||||
|
|
||||||
@@ -45,8 +46,12 @@ func (s *EmployeeSerialsService) Generate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成序列号前缀 (EMP + 年份后两位)
|
// 生成序列号前缀
|
||||||
serialPrefix := fmt.Sprintf("EMP%d", time.Now().Year()%100)
|
if serialPrefix == "" {
|
||||||
|
serialPrefix = fmt.Sprintf("EMP%d", time.Now().Year()%100)
|
||||||
|
}
|
||||||
|
// 标准化前缀(转大写,去除空格)
|
||||||
|
serialPrefix = strings.ToUpper(strings.TrimSpace(serialPrefix))
|
||||||
|
|
||||||
// 预生成所有序列号
|
// 预生成所有序列号
|
||||||
serialNumbers := make(map[string]bool)
|
serialNumbers := make(map[string]bool)
|
||||||
@@ -199,6 +204,22 @@ func (s *EmployeeSerialsService) Revoke(serialNumber string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete 删除员工序列号(物理删除)
|
||||||
|
func (s *EmployeeSerialsService) Delete(serialNumber string) error {
|
||||||
|
var serial models.EmployeeSerial
|
||||||
|
result := database.DB.Where("serial_number = ?", strings.ToUpper(serialNumber)).First(&serial)
|
||||||
|
if result.Error != nil {
|
||||||
|
return fmt.Errorf("查询员工序列号失败: %w", errors.New("序列号不存在"))
|
||||||
|
}
|
||||||
|
|
||||||
|
result = database.DB.Delete(&serial)
|
||||||
|
if result.Error != nil {
|
||||||
|
return fmt.Errorf("删除员工序列号失败: %w", result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GenerateQRCode 生成员工二维码
|
// GenerateQRCode 生成员工二维码
|
||||||
func (s *EmployeeSerialsService) GenerateQRCode(
|
func (s *EmployeeSerialsService) GenerateQRCode(
|
||||||
serialNumber string,
|
serialNumber string,
|
||||||
|
|||||||
Reference in New Issue
Block a user