七月迭代短暂完结,还有很多后端的关键东西没有弄,这是一版赶时间做的东西
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s

This commit is contained in:
2026-07-25 17:06:58 +08:00
parent ad9f613dd6
commit 73f5125d3d
249 changed files with 17137 additions and 877 deletions

View File

@@ -63,6 +63,14 @@ func registerAccountRoutes(api fiber.Router, h *admin.AccountHandler, doc *opena
Auth: true,
})
Register(accounts, doc, accountsPath, "PUT", "/:id/wecom-binding", h.BindWeCom, RouteSpec{
Summary: "绑定账号企业微信成员",
Tags: []string{"账号管理", "企业微信审批"},
Input: new(dto.BindAccountWeComParams),
Output: new(dto.AccountResponse),
Auth: true,
})
// 删除账号
Register(accounts, doc, accountsPath, "DELETE", "/:id", h.Delete, RouteSpec{
Summary: "删除账号",

View File

@@ -121,6 +121,7 @@ func RegisterAdminRoutes(router fiber.Router, handlers *bootstrap.Handlers, midd
}
if handlers.Asset != nil {
registerAssetRoutes(authGroup, handlers.Asset, handlers.AssetWallet, doc, basePath)
registerPackageExpiryRoutes(authGroup, handlers.Asset, doc, basePath)
}
if handlers.WechatConfig != nil {
registerWechatConfigRoutes(authGroup, handlers.WechatConfig, doc, basePath)
@@ -134,10 +135,16 @@ func RegisterAdminRoutes(router fiber.Router, handlers *bootstrap.Handlers, midd
if handlers.OrderPackageInvalidate != nil {
registerOrderPackageInvalidateRoutes(authGroup, handlers.OrderPackageInvalidate, doc, basePath)
}
if handlers.AssetPackageBatchOrder != nil {
registerAssetPackageBatchOrderRoutes(authGroup, handlers.AssetPackageBatchOrder, doc, basePath)
}
if handlers.SuperAdmin != nil {
registerSuperAdminRoutes(authGroup, handlers.SuperAdmin, doc, basePath)
}
if handlers.SystemConfig != nil {
registerSystemConfigRoutes(authGroup, handlers.SystemConfig, doc, basePath)
}
if handlers.WeCom != nil {
registerWeComRoutes(authGroup, handlers.WeCom, doc, basePath)
}
}

View File

@@ -0,0 +1,25 @@
package routes
import (
"github.com/gofiber/fiber/v2"
"github.com/break/junhong_cmp_fiber/internal/handler/admin"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
"github.com/break/junhong_cmp_fiber/pkg/openapi"
)
// registerAssetPackageBatchOrderRoutes 注册资产套餐批量订购任务路由。
func registerAssetPackageBatchOrderRoutes(router fiber.Router, handler *admin.AssetPackageBatchOrderHandler, doc *openapi.Generator, basePath string) {
Register(router, doc, basePath, "POST", "/asset-package-batch-orders", handler.Create, RouteSpec{
Summary: "创建资产套餐批量订购任务", Description: "上传单列CSV对象存储Key并为整批选择一个套餐和支付方式不选择代理。",
Tags: []string{"批量订购套餐"}, Input: new(dto.CreateAssetPackageBatchOrderRequest), Output: new(dto.AssetPackageBatchOrderTaskResponse), Auth: true,
})
Register(router, doc, basePath, "GET", "/asset-package-batch-orders", handler.List, RouteSpec{
Summary: "查询资产套餐批量订购任务列表", Tags: []string{"批量订购套餐"},
Input: new(dto.ListAssetPackageBatchOrderRequest), Output: new(dto.AssetPackageBatchOrderTaskListResponse), Auth: true,
})
Register(router, doc, basePath, "GET", "/asset-package-batch-orders/:id", handler.Get, RouteSpec{
Summary: "查询资产套餐批量订购任务详情", Tags: []string{"批量订购套餐"},
Input: new(dto.GetAssetPackageBatchOrderRequest), Output: new(dto.AssetPackageBatchOrderTaskDetailResponse), Auth: true,
})
}

View File

@@ -21,6 +21,15 @@ func registerDeviceRoutes(router fiber.Router, handler *admin.DeviceHandler, imp
Auth: true,
})
Register(devices, doc, groupPath, "POST", "/batch-update-realname-policy", handler.BatchUpdateRealnamePolicy, RouteSpec{
Summary: "批量更新设备实名认证策略",
Description: "单次最多500条先校验整批资产及数据权限再在单事务内全成全败更新。设备下卡存在策略冲突时C端以设备策略为准。",
Tags: []string{"设备管理"},
Input: new(dto.BatchUpdateAssetRealnamePolicyRequest),
Output: new(dto.BatchUpdateAssetRealnamePolicyResponse),
Auth: true,
})
Register(devices, doc, groupPath, "DELETE", "/:virtual_no", handler.Delete, RouteSpec{
Summary: "删除设备",
Description: "仅平台用户可操作。删除设备时自动解绑所有卡(卡不会被删除)。",
@@ -115,6 +124,15 @@ func registerDeviceRoutes(router fiber.Router, handler *admin.DeviceHandler, imp
Auth: true,
})
Register(devices, doc, groupPath, "POST", "/import/allocations", importHandler.CreateAllocation, RouteSpec{
Summary: "创建CSV设备批量分配任务",
Description: "复用设备导入任务。CSV只能包含一列设备标识每行支持VirtualNo、IMEI或SN整批选择分配目标代理或设置目标套餐系列。",
Tags: []string{"设备管理"},
Input: new(dto.CreateDeviceBatchAllocationRequest),
Output: new(dto.CreateDeviceBatchAllocationResponse),
Auth: true,
})
Register(devices, doc, groupPath, "GET", "/import/tasks/:id", importHandler.GetByID, RouteSpec{
Summary: "导入任务详情",
Description: "仅平台用户可操作。包含跳过和失败记录的详细信息。",
@@ -142,15 +160,6 @@ func registerDeviceRoutes(router fiber.Router, handler *admin.DeviceHandler, imp
Auth: true,
})
Register(devices, doc, groupPath, "PUT", "/by-identifier/:identifier/speed-limit", handler.SetSpeedLimit, RouteSpec{
Summary: "设置限速",
Description: "通过虚拟号/IMEI/SN 设置设备限速。设备必须已配置 IMEI。",
Tags: []string{"设备管理"},
Input: new(dto.SetSpeedLimitRequest),
Output: new(dto.EmptyResponse),
Auth: true,
})
Register(devices, doc, groupPath, "PUT", "/by-identifier/:identifier/wifi", handler.SetWiFi, RouteSpec{
Summary: "设置 WiFi",
Description: "通过虚拟号/IMEI/SN 设置设备 WiFi。设备必须已配置 IMEI。",

View File

@@ -21,6 +21,15 @@ func registerIotCardRoutes(router fiber.Router, handler *admin.IotCardHandler, i
Auth: true,
})
Register(iotCards, doc, groupPath, "POST", "/batch-update-realname-policy", handler.BatchUpdateRealnamePolicy, RouteSpec{
Summary: "批量更新卡实名认证策略",
Description: "单次最多500条先校验整批资产及数据权限再在单事务内全成全败更新。",
Tags: []string{"IoT卡管理"},
Input: new(dto.BatchUpdateAssetRealnamePolicyRequest),
Output: new(dto.BatchUpdateAssetRealnamePolicyResponse),
Auth: true,
})
Register(iotCards, doc, groupPath, "POST", "/import", importHandler.Import, RouteSpec{
Summary: "批量导入IoT卡ICCID+MSISDN",
Description: `仅平台用户可操作。
@@ -118,4 +127,13 @@ func registerIotCardRoutes(router fiber.Router, handler *admin.IotCardHandler, i
Auth: true,
})
Register(iotCards, doc, groupPath, "PUT", "/:iccid/speed-tier", handler.SetSpeedTier, RouteSpec{
Summary: "设置卡固定限速档位",
Description: "仅对有权限的 IoT 卡按 ICCID 设置固定 Gateway 限速档位;-1 表示恢复不限速。不支持设备限速,也不会通过设备绑定关系间接限速。",
Tags: []string{"IoT卡管理"},
Input: new(dto.SetIotCardSpeedTierRequest),
Output: new(dto.SetIotCardSpeedTierResponse),
Auth: true,
})
}

View File

@@ -32,7 +32,7 @@ func registerNotificationRoutes(router fiber.Router, handler *admin.Notification
Register(notifications, doc, groupPath, "GET", "", handler.List, RouteSpec{
Summary: "查询通知列表",
Description: "仅返回当前认证后台账号的未过期通知,固定按创建时间和通知 ID 倒序。",
Description: "仅返回当前认证后台账号的未过期通知,固定按创建时间和通知 ID 倒序。ref_type/ref_id/ref_key 是受控资源引用,不是前端路由;点击通知时应调用 GET /api/admin/notifications/{id}/target以返回的 target_type 和 available 决定是否跳转。",
Tags: []string{"站内通知"},
Input: new(dto.NotificationListRequest),
Output: new(dto.NotificationListResponse),
@@ -50,7 +50,7 @@ func registerNotificationRoutes(router fiber.Router, handler *admin.Notification
Register(notifications, doc, groupPath, "GET", "/:id/target", handler.Target, RouteSpec{
Summary: "解析通知受控目标",
Description: "先校验通知属于当前认证后台账号,再复核目标资源当前权限;只返回白名单结构化目标,不返回任意 URL。",
Description: "先校验通知属于当前认证后台账号,再复核目标资源当前权限;只返回白名单结构化目标,不返回任意 URL。前端维护 target_type 到页面的白名单映射available=false 或 target_type 为空时只展示通知正文,不执行跳转。",
Tags: []string{"站内通知"},
Input: new(dto.NotificationIDParams),
Output: new(dto.NotificationTargetResponse),

View File

@@ -0,0 +1,21 @@
package routes
import (
"github.com/gofiber/fiber/v2"
"github.com/break/junhong_cmp_fiber/internal/handler/admin"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
"github.com/break/junhong_cmp_fiber/pkg/openapi"
)
// registerPackageExpiryRoutes 注册后台和代理共用的临期资产查询路由。
func registerPackageExpiryRoutes(router fiber.Router, handler *admin.AssetHandler, doc *openapi.Generator, basePath string) {
Register(router, doc, basePath, "GET", "/expiring-assets", handler.ListExpiring, RouteSpec{
Summary: "查询临期资产列表",
Description: "分页返回当前账号店铺权限范围内剩余 0 至 15 个上海自然日的卡和设备,并提供卡、设备数量、高亮等级及 0 至 3 天优先标识。企业账号禁止调用。",
Tags: []string{"资产管理"},
Input: new(dto.ExpiringAssetListRequest),
Output: new(dto.ExpiringAssetListResponse),
Auth: true,
})
}

View File

@@ -23,7 +23,7 @@ func registerPersonalNotificationRoutes(router fiber.Router, handler *apphandler
Register(notifications, doc, groupPath, "GET", "", handler.List, RouteSpec{
Summary: "查询个人客户通知列表",
Description: "仅返回当前认证个人客户的未过期业务通知,固定按创建时间和通知 ID 倒序。",
Description: "仅返回当前认证个人客户的未过期业务通知,可按已读状态筛选,固定按创建时间和通知 ID 倒序。当前 C 端契约只承诺列表展示和未读弹窗ref_type/ref_id/ref_key 是资源引用与展示快照不是URL也不承诺可直接拼接页面路由。",
Tags: []string{"个人客户 - 站内通知"},
Input: new(dto.PersonalNotificationListRequest),
Output: new(dto.PersonalNotificationListResponse),

View File

@@ -62,4 +62,8 @@ func RegisterRoutesWithDoc(app *fiber.App, handlers *bootstrap.Handlers, middlew
callbackGroup := app.Group("/api/callback")
registerCUCCCallbackRoutes(callbackGroup, handlers.CUCCRealnameRemovalCallback, doc, "/api/callback")
}
if handlers.WeComApprovalCallback != nil {
callbackGroup := app.Group("/api/callback")
registerWeComApprovalCallbackRoutes(callbackGroup, handlers.WeComApprovalCallback, doc, "/api/callback")
}
}

View File

@@ -134,6 +134,8 @@ await api.post('/iot-cards/import', {
| 值 | 说明 | 生成路径格式 |
|---|------|-------------|
| iot_import | ICCID/设备导入 (Excel) | imports/YYYY/MM/DD/uuid.xlsx |
| batch_purchase | 资产套餐批量订购 (CSV) | batch-purchases/YYYY/MM/DD/uuid.csv |
| device_batch_allocation | 设备批量分配代理或套餐系列 (CSV) | device-batch-allocations/YYYY/MM/DD/uuid.csv |
| export | 数据导出 | exports/YYYY/MM/DD/uuid.xlsx |
| attachment | 附件上传 | attachments/YYYY/MM/DD/uuid.ext |

80
internal/routes/wecom.go Normal file
View File

@@ -0,0 +1,80 @@
package routes
import (
"github.com/gofiber/fiber/v2"
"github.com/break/junhong_cmp_fiber/internal/handler/admin"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/middleware"
"github.com/break/junhong_cmp_fiber/pkg/openapi"
)
func registerWeComRoutes(router fiber.Router, handler *admin.WeComHandler, doc *openapi.Generator, basePath string) {
group := router.Group("/wecom", func(c *fiber.Ctx) error {
userType := middleware.GetUserTypeFromContext(c.UserContext())
if userType != constants.UserTypeSuperAdmin && userType != constants.UserTypePlatform {
return errors.New(errors.CodeForbidden, "无权限访问企业微信审批配置")
}
return c.Next()
})
groupPath := basePath + "/wecom"
Register(group, doc, groupPath, "POST", "/applications", handler.Save, RouteSpec{
Summary: "创建或更新企业微信应用配置",
Tags: []string{"企业微信审批"},
Input: new(dto.SaveWeComApplicationRequest),
Output: new(dto.WeComApplicationResponse),
Auth: true,
})
Register(group, doc, groupPath, "GET", "/applications", handler.List, RouteSpec{
Summary: "查询企业微信应用配置",
Tags: []string{"企业微信审批"},
Input: new(dto.WeComApplicationListRequest),
Output: new(dto.WeComApplicationListResponse),
Auth: true,
})
Register(group, doc, groupPath, "POST", "/applications/:id/test", handler.Test, RouteSpec{
Summary: "测试企业微信应用连接",
Tags: []string{"企业微信审批"},
Input: new(dto.IDReq),
Output: new(dto.WeComConnectionTestResponse),
Auth: true,
})
Register(group, doc, groupPath, "PUT", "/applications/:id/default-creator", handler.SaveDefaultCreator, RouteSpec{
Summary: "保存企业微信应用默认审批发起人",
Tags: []string{"企业微信审批"},
Input: new(dto.SaveWeComDefaultCreatorParams),
Output: new(dto.WeComApplicationResponse),
Auth: true,
})
Register(group, doc, groupPath, "POST", "/applications/:id/members/sync", handler.SyncMembers, RouteSpec{
Summary: "同步企业微信应用可见成员",
Tags: []string{"企业微信审批"},
Input: new(dto.IDReq),
Output: new(dto.WeComMemberSyncResponse),
Auth: true,
})
Register(group, doc, groupPath, "GET", "/applications/:id/members", handler.ListMembers, RouteSpec{
Summary: "分页查询企业微信应用可见成员",
Tags: []string{"企业微信审批"},
Input: new(dto.WeComMemberListParams),
Output: new(dto.WeComMemberListResponse),
Auth: true,
})
Register(group, doc, groupPath, "PUT", "/scenes/:business_type", handler.SaveScene, RouteSpec{
Summary: "保存并校验企业微信审批场景模板映射",
Tags: []string{"企业微信审批"},
Input: new(dto.SaveWeComApprovalSceneParams),
Output: new(dto.WeComApprovalSceneResponse),
Auth: true,
})
Register(group, doc, groupPath, "GET", "/scenes", handler.ListScenes, RouteSpec{
Summary: "分页查询企业微信审批场景配置",
Tags: []string{"企业微信审批"},
Input: new(dto.WeComApprovalSceneListRequest),
Output: new(dto.WeComApprovalSceneListResponse),
Auth: true,
})
}

View File

@@ -0,0 +1,24 @@
package routes
import (
"github.com/gofiber/fiber/v2"
"github.com/break/junhong_cmp_fiber/internal/handler/callback"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
"github.com/break/junhong_cmp_fiber/pkg/openapi"
)
func registerWeComApprovalCallbackRoutes(router fiber.Router, handler *callback.WeComApprovalHandler, doc *openapi.Generator, basePath string) {
Register(router, doc, basePath, "GET", "/wecom/approval/:application_id", handler.Verify, RouteSpec{
Summary: "验证企业微信审批回调地址",
Tags: []string{"企业微信审批回调"},
Input: new(dto.WeComApprovalCallbackRequest),
Auth: false,
})
Register(router, doc, basePath, "POST", "/wecom/approval/:application_id", handler.Receive, RouteSpec{
Summary: "接收企业微信审批状态变化回调",
Tags: []string{"企业微信审批回调"},
Input: new(dto.WeComApprovalCallbackRequest),
Auth: false,
})
}