1. 需求确认
2. 结构的一些变更
This commit is contained in:
46
cmd/gendocs/main.go
Normal file
46
cmd/gendocs/main.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
|
"github.com/break/junhong_cmp_fiber/internal/bootstrap"
|
||||||
|
"github.com/break/junhong_cmp_fiber/internal/handler/admin"
|
||||||
|
"github.com/break/junhong_cmp_fiber/internal/routes"
|
||||||
|
"github.com/break/junhong_cmp_fiber/pkg/openapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 1. 创建生成器
|
||||||
|
adminDoc := openapi.NewGenerator("Admin API", "1.0")
|
||||||
|
|
||||||
|
// 2. 模拟 Fiber App
|
||||||
|
app := fiber.New()
|
||||||
|
|
||||||
|
// 3. 模拟 Handler
|
||||||
|
// 我们创建一个伪造的 handler。因为我们不执行请求,nil 依赖是可以的。
|
||||||
|
accHandler := admin.NewAccountHandler(nil)
|
||||||
|
roleHandler := admin.NewRoleHandler(nil)
|
||||||
|
permHandler := admin.NewPermissionHandler(nil)
|
||||||
|
|
||||||
|
handlers := &bootstrap.Handlers{
|
||||||
|
Account: accHandler,
|
||||||
|
Role: roleHandler,
|
||||||
|
Permission: permHandler,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 注册路由
|
||||||
|
adminGroup := app.Group("/api/admin")
|
||||||
|
routes.RegisterAdminRoutes(adminGroup, handlers, adminDoc, "/api/admin")
|
||||||
|
|
||||||
|
// 5. 保存规范
|
||||||
|
outputFile := "./docs/admin-openapi.yaml"
|
||||||
|
if err := adminDoc.Save(outputFile); err != nil {
|
||||||
|
log.Fatalf("保存规范失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
absPath, _ := filepath.Abs(outputFile)
|
||||||
|
log.Printf("成功在以下位置生成 OpenAPI 规范: %s", absPath)
|
||||||
|
}
|
||||||
1019
docs/admin-openapi.yaml
Normal file
1019
docs/admin-openapi.yaml
Normal file
File diff suppressed because it is too large
Load Diff
11
docs/待沟通/2025-12-23T17:39:57沟通.md
Normal file
11
docs/待沟通/2025-12-23T17:39:57沟通.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
## 2025-12-23T17:39:31 沟通
|
||||||
|
|
||||||
|
1. 一次性佣金(组合佣金)冲突问题
|
||||||
|
|
||||||
|
2. 阻断不合理的问题(以下都是以同为一个套餐系列下的大前提)
|
||||||
|
- 一次性佣金套餐与长期佣金不能共存(分配时阻断)
|
||||||
|
- 组合佣金与另外两种佣金不能共存(分配时应当阻断)
|
||||||
|
- 次月生效的其他套餐系列怎么处理(疑问?)
|
||||||
|
|
||||||
|
|
||||||
|
3. 聚水潭,可能存在入库是20位/19位 出库时变成19位/20位
|
||||||
845
docs/待沟通/一次性佣金出现两个套餐的情况.excalidraw
Normal file
845
docs/待沟通/一次性佣金出现两个套餐的情况.excalidraw
Normal file
@@ -0,0 +1,845 @@
|
|||||||
|
{
|
||||||
|
"type": "excalidraw",
|
||||||
|
"version": 2,
|
||||||
|
"source": "https://mindmap.so",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"id": "7R70pfEhLX0PX16Qkn1Pf",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 331.5,
|
||||||
|
"y": 158,
|
||||||
|
"width": 450,
|
||||||
|
"height": 503,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 661345629,
|
||||||
|
"version": 58,
|
||||||
|
"versionNonce": 1402242749,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1766478975006,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "xMvve7y3VXeV0E3Xho43W",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 373,
|
||||||
|
"y": 231,
|
||||||
|
"width": 358,
|
||||||
|
"height": 91,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [
|
||||||
|
"RStTR2i2emmHx8XucgL0k"
|
||||||
|
],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 676835485,
|
||||||
|
"version": 51,
|
||||||
|
"versionNonce": 740750611,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"id": "nUMun3kvf0N6NybORV9Kt",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1766479178090,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "XUgJvaNQeNV_XQIP0xk4f",
|
||||||
|
"type": "text",
|
||||||
|
"x": 412,
|
||||||
|
"y": 251,
|
||||||
|
"width": 229.10000610351562,
|
||||||
|
"height": 50,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [
|
||||||
|
"RStTR2i2emmHx8XucgL0k"
|
||||||
|
],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 935124733,
|
||||||
|
"version": 55,
|
||||||
|
"versionNonce": 858142429,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1766479038207,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "套餐A\n预存 100 返代理佣金 50",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"textAlign": "left",
|
||||||
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "套餐A\n预存 100 返代理佣金 50",
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bUH4Ir1WYfhzpfRHnPBKI",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 382.54442367331444,
|
||||||
|
"y": 446,
|
||||||
|
"width": 346,
|
||||||
|
"height": 100.5,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [
|
||||||
|
"jIcVk7sEqssxoWdPXbFaF"
|
||||||
|
],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 258241363,
|
||||||
|
"version": 63,
|
||||||
|
"versionNonce": 351461469,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"id": "n1FvokZgL_6Z0aYcbltDk",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1766479197157,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "wSwWH9NlU8QysDyvFKvgu",
|
||||||
|
"type": "text",
|
||||||
|
"x": 420.04442367331444,
|
||||||
|
"y": 473,
|
||||||
|
"width": 229.53334045410156,
|
||||||
|
"height": 50,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [
|
||||||
|
"jIcVk7sEqssxoWdPXbFaF"
|
||||||
|
],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 177000307,
|
||||||
|
"version": 43,
|
||||||
|
"versionNonce": 734560637,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1766479197157,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "套餐B\n预存 100 返代理佣金 60",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"textAlign": "left",
|
||||||
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "套餐B\n预存 100 返代理佣金 60",
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "-glD1Y1WuHzxh3lyXYsW_",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 1003.071680819518,
|
||||||
|
"y": 119.33225782014824,
|
||||||
|
"width": 586.5467583232241,
|
||||||
|
"height": 486.72780698207305,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 1780605853,
|
||||||
|
"version": 151,
|
||||||
|
"versionNonce": 232493277,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"id": "qSXz0n40ttVNf8QFsDzza",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1766479193903,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "l0EWorlcCk5lYVs8G09pL",
|
||||||
|
"type": "text",
|
||||||
|
"x": 1243.3438468796337,
|
||||||
|
"y": 219.96233993799694,
|
||||||
|
"width": 103.76667022705078,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 2005419091,
|
||||||
|
"version": 20,
|
||||||
|
"versionNonce": 1626040947,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1766479056726,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "余额 0 元",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"textAlign": "left",
|
||||||
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "余额 0 元",
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5L_NILlIufWZdwpkYJLtR",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 1199.1761692950536,
|
||||||
|
"y": 338.33171586467176,
|
||||||
|
"width": 217.30497371613433,
|
||||||
|
"height": 110.41919396145033,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 936455635,
|
||||||
|
"version": 48,
|
||||||
|
"versionNonce": 471636563,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"id": "k2gj7fxntIiWGBdYZLRDK"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1766479065620,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "k2gj7fxntIiWGBdYZLRDK",
|
||||||
|
"type": "text",
|
||||||
|
"x": 1287.8286561531208,
|
||||||
|
"y": 381.04131284539693,
|
||||||
|
"width": 40,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1694248957,
|
||||||
|
"version": 6,
|
||||||
|
"versionNonce": 915898387,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1766479067105,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "充值",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": "5L_NILlIufWZdwpkYJLtR",
|
||||||
|
"originalText": "充值",
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "qSXz0n40ttVNf8QFsDzza",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 1293.634684275165,
|
||||||
|
"y": 614.0102467674457,
|
||||||
|
"width": 28.18478618454128,
|
||||||
|
"height": 225.18293290636473,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 772212819,
|
||||||
|
"version": 101,
|
||||||
|
"versionNonce": 1187560861,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"id": "KFI__zjuOAnhhEL14zurl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1766479193904,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-28.18478618454128,
|
||||||
|
225.18293290636473
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "-glD1Y1WuHzxh3lyXYsW_",
|
||||||
|
"focus": -0.0888623571550402,
|
||||||
|
"gap": 7.950181965224374
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "r85LyxyV3LekZp3zyMcmX",
|
||||||
|
"focus": -0.13056110404939236,
|
||||||
|
"gap": 5.300121310149507
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "KFI__zjuOAnhhEL14zurl",
|
||||||
|
"type": "text",
|
||||||
|
"x": 1238.0780089113427,
|
||||||
|
"y": 713.6239250572853,
|
||||||
|
"width": 82.96666717529297,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 2065498877,
|
||||||
|
"version": 12,
|
||||||
|
"versionNonce": 607232115,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1766479094170,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "充值 100",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": "qSXz0n40ttVNf8QFsDzza",
|
||||||
|
"originalText": "充值 100",
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "r85LyxyV3LekZp3zyMcmX",
|
||||||
|
"type": "rectangle",
|
||||||
|
"x": 1000.4216201644431,
|
||||||
|
"y": 844.4933009839599,
|
||||||
|
"width": 570.6463943927752,
|
||||||
|
"height": 299.4568540234534,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"seed": 2113391891,
|
||||||
|
"version": 114,
|
||||||
|
"versionNonce": 570390515,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"id": "qSXz0n40ttVNf8QFsDzza",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1766479085841,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "GK3W5X5r5RJIASgt0of4s",
|
||||||
|
"type": "text",
|
||||||
|
"x": 1109.0741070225101,
|
||||||
|
"y": 985.0187384779189,
|
||||||
|
"width": 367.6666564941406,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1629507315,
|
||||||
|
"version": 91,
|
||||||
|
"versionNonce": 134830867,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1766479150857,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "这时候应该是套餐A 还是 套餐 B 的返佣",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"textAlign": "left",
|
||||||
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "这时候应该是套餐A 还是 套餐 B 的返佣",
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "eOglLhGtYymUk0TgFMeRF",
|
||||||
|
"type": "text",
|
||||||
|
"x": 1057.0410279697514,
|
||||||
|
"y": 812.0799974504081,
|
||||||
|
"width": 140,
|
||||||
|
"height": 25,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1869180381,
|
||||||
|
"version": 19,
|
||||||
|
"versionNonce": 786890365,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1766479150301,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "代理到账的佣金",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"textAlign": "left",
|
||||||
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "代理到账的佣金",
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rectangle",
|
||||||
|
"version": 194,
|
||||||
|
"versionNonce": 1120688563,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "khEXHiUFbo8xYH20Q9Pz7",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 1773.811826114777,
|
||||||
|
"y": 105.2615755168747,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"width": 586.5467583232241,
|
||||||
|
"height": 486.72780698207305,
|
||||||
|
"seed": 958733939,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"id": "nUMun3kvf0N6NybORV9Kt",
|
||||||
|
"type": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "n1FvokZgL_6Z0aYcbltDk",
|
||||||
|
"type": "arrow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1766479182525,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"version": 70,
|
||||||
|
"versionNonce": 1851133235,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "f4Jm-0ni3hXHS_wC8CuF5",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 2014.0839921748925,
|
||||||
|
"y": 206.84723396140896,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"width": 122.96666717529297,
|
||||||
|
"height": 25,
|
||||||
|
"seed": 914282515,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": null,
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1766479171523,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"text": "余额 100 元",
|
||||||
|
"textAlign": "left",
|
||||||
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "余额 100 元",
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "rectangle",
|
||||||
|
"version": 90,
|
||||||
|
"versionNonce": 2000876371,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "txF94hHhoDTDYdnK2Rpud",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 1969.9163145903126,
|
||||||
|
"y": 325.2166098880838,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"width": 217.30497371613433,
|
||||||
|
"height": 110.41919396145033,
|
||||||
|
"seed": 2142264755,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": {
|
||||||
|
"type": 3
|
||||||
|
},
|
||||||
|
"boundElements": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"id": "4XMPCNO1ejl96mLC1C01G"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"updated": 1766479168359,
|
||||||
|
"link": null,
|
||||||
|
"locked": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"version": 48,
|
||||||
|
"versionNonce": 533663987,
|
||||||
|
"isDeleted": false,
|
||||||
|
"id": "4XMPCNO1ejl96mLC1C01G",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"angle": 0,
|
||||||
|
"x": 2058.56880144838,
|
||||||
|
"y": 367.92620686880895,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"width": 40,
|
||||||
|
"height": 25,
|
||||||
|
"seed": 1608527699,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": null,
|
||||||
|
"boundElements": [],
|
||||||
|
"updated": 1766479168359,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"text": "充值",
|
||||||
|
"textAlign": "center",
|
||||||
|
"verticalAlign": "middle",
|
||||||
|
"containerId": "txF94hHhoDTDYdnK2Rpud",
|
||||||
|
"originalText": "充值",
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "nUMun3kvf0N6NybORV9Kt",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 1762.2563570636948,
|
||||||
|
"y": 86.79756549606759,
|
||||||
|
"width": 1029.155703840349,
|
||||||
|
"height": 268.51694779864243,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 779606077,
|
||||||
|
"version": 171,
|
||||||
|
"versionNonce": 1315938387,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1766479343039,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-609.6576964253877,
|
||||||
|
-97.4687853219271
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-1029.155703840349,
|
||||||
|
171.04816247671533
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "khEXHiUFbo8xYH20Q9Pz7",
|
||||||
|
"focus": 0.7341701363472869,
|
||||||
|
"gap": 18.46401002080711
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "xMvve7y3VXeV0E3Xho43W",
|
||||||
|
"focus": 0.6076267460111122,
|
||||||
|
"gap": 2.100653223345944
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "n1FvokZgL_6Z0aYcbltDk",
|
||||||
|
"type": "arrow",
|
||||||
|
"x": 1793.994491291626,
|
||||||
|
"y": 611.5600639208494,
|
||||||
|
"width": 1059.7378903038618,
|
||||||
|
"height": 248.44984493824586,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": {
|
||||||
|
"type": 2
|
||||||
|
},
|
||||||
|
"seed": 1878971997,
|
||||||
|
"version": 409,
|
||||||
|
"versionNonce": 298474365,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1766479361268,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"points": [
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-585.9724037055564,
|
||||||
|
179.49725434247648
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-1059.7378903038618,
|
||||||
|
-68.95259059576938
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"lastCommittedPoint": null,
|
||||||
|
"startBinding": {
|
||||||
|
"elementId": "khEXHiUFbo8xYH20Q9Pz7",
|
||||||
|
"focus": -0.5380556689521092,
|
||||||
|
"gap": 19.570681421901668
|
||||||
|
},
|
||||||
|
"endBinding": {
|
||||||
|
"elementId": "bUH4Ir1WYfhzpfRHnPBKI",
|
||||||
|
"focus": -0.33596246021680487,
|
||||||
|
"gap": 5.712177314449718
|
||||||
|
},
|
||||||
|
"startArrowhead": null,
|
||||||
|
"endArrowhead": "arrow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Fnsk0wbTUHGz9Oq7sUe0o",
|
||||||
|
"type": "text",
|
||||||
|
"x": 1190.8217137057295,
|
||||||
|
"y": 267.4014912396386,
|
||||||
|
"width": 99.06666564941406,
|
||||||
|
"height": 50,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1386888435,
|
||||||
|
"version": 18,
|
||||||
|
"versionNonce": 2062378163,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1766479223488,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "套餐A 90\n",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"textAlign": "left",
|
||||||
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "套餐A 90\n",
|
||||||
|
"lineHeight": 1.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "K8sqFrWDj3dAJJ0w8zIJU",
|
||||||
|
"type": "text",
|
||||||
|
"x": 369.0260727561474,
|
||||||
|
"y": 99.22005774297998,
|
||||||
|
"width": 205.06666564941406,
|
||||||
|
"height": 50,
|
||||||
|
"angle": 0,
|
||||||
|
"strokeColor": "#1e1e1e",
|
||||||
|
"backgroundColor": "transparent",
|
||||||
|
"fillStyle": "solid",
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"strokeStyle": "solid",
|
||||||
|
"roughness": 1,
|
||||||
|
"opacity": 100,
|
||||||
|
"groupIds": [],
|
||||||
|
"frameId": null,
|
||||||
|
"roundness": null,
|
||||||
|
"seed": 1868189053,
|
||||||
|
"version": 26,
|
||||||
|
"versionNonce": 14547869,
|
||||||
|
"isDeleted": false,
|
||||||
|
"boundElements": null,
|
||||||
|
"updated": 1766479255684,
|
||||||
|
"link": null,
|
||||||
|
"locked": false,
|
||||||
|
"text": "套餐系列 (一次性佣金)\n",
|
||||||
|
"fontSize": 20,
|
||||||
|
"fontFamily": 1,
|
||||||
|
"textAlign": "left",
|
||||||
|
"verticalAlign": "top",
|
||||||
|
"containerId": null,
|
||||||
|
"originalText": "套餐系列 (一次性佣金)\n",
|
||||||
|
"lineHeight": 1.25
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"appState": {
|
||||||
|
"gridSize": null,
|
||||||
|
"viewBackgroundColor": "#ffffff"
|
||||||
|
},
|
||||||
|
"files": {}
|
||||||
|
}
|
||||||
@@ -265,3 +265,34 @@ flowchart TD
|
|||||||
1. 确认上面的东西是不是对的
|
1. 确认上面的东西是不是对的
|
||||||
2. 确认一下是否还有别的业务
|
2. 确认一下是否还有别的业务
|
||||||
3. 跟我讲一下我们的实际业务
|
3. 跟我讲一下我们的实际业务
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
1. 代理的销售价格不能大于平台给他的成本价两倍(奇成是写死的)
|
||||||
|
2. 物联网卡行业中的佣金=实际售价-平台给的成本价(这个其实是长期分佣)(阴阳菜单)
|
||||||
|
3. 一次性佣金关于客户的逻辑 客户充值100 只能≤一百(流量卡)
|
||||||
|
(号卡 可能≥100)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
A 用户买了一个A产品,那么现在给代理的成本价60 售价 90 (一次性佣金)(首次购买时预存100 佣金10块)
|
||||||
|
|
||||||
|
当一个套餐被设置一次性佣金后他第一次去购买只能通过钱包付款
|
||||||
|
|
||||||
|
组合佣金(一次性佣金+长期分佣)(1.某个时间点后,2. 使用套餐个数(只作用于一个物联网卡 例如 某个套餐的使用套餐个数是10,那么这个张卡需要达到10个套餐周期后才能开始分佣,只有这一张卡才会分佣))
|
||||||
|
|
||||||
|
|
||||||
|
阶梯分佣基于一次性佣金以及长期佣金之上,当到达某个条件后,变更分佣值
|
||||||
|
阶梯分佣(提货量/激活量(实名+历史存在过套餐)/保证金(未来做的))
|
||||||
|
|
||||||
|
|
||||||
|
1. 激活量根据当前时间态统计
|
||||||
|
2. 如果是进行时统计,例如年底汇报 1-12月 每月的激活量时 应该是固定的,例如 1月的激活是10 2月的激活是20,3月的激活是30,4月的激活是40,5月的激活是50,6月的激活是60,7月的激活是70,8月的激活是80,9月的激活是90,10月的激活是100,11月的激活是110,12月的激活是120
|
||||||
|
|
||||||
|
可能会存在1月的激活中因为是历史数据,会存在同一个iccid在2月的激活量中存在,这是可以接受的,需要业务方知道
|
||||||
|
|
||||||
|
1. 一次性佣金满足 激活(实名) + 达到累计/首次充值金额 = 产生佣金(冻结) (可能是[7]天后 状态变成解冻中 同步产生一条佣金解冻审批等待审批)
|
||||||
|
2. 长期佣金满足 激活(实名) + 达到累计/首次充值金额 + 在网状态(必须是正常的)(能不能拿到在网状态 存疑) + 三无(能不能拿到 存疑) = 产生佣金(冻结 必须通过excel导入, 状态 变成 解冻中 同步产生对应的佣金解冻审批 等待审批)
|
||||||
|
3. 阶梯分佣满足 激活(实名 + 达到累计/首次充值金额 + 在网状态(必须是正常的)(能不能拿到在网状态 存疑) ) = 激活
|
||||||
|
|||||||
6
go.mod
6
go.mod
@@ -14,6 +14,7 @@ require (
|
|||||||
github.com/redis/go-redis/v9 v9.16.0
|
github.com/redis/go-redis/v9 v9.16.0
|
||||||
github.com/spf13/viper v1.21.0
|
github.com/spf13/viper v1.21.0
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
|
github.com/swaggest/openapi-go v0.2.60
|
||||||
github.com/testcontainers/testcontainers-go v0.40.0
|
github.com/testcontainers/testcontainers-go v0.40.0
|
||||||
github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0
|
github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0
|
||||||
github.com/testcontainers/testcontainers-go/modules/redis v0.38.0
|
github.com/testcontainers/testcontainers-go/modules/redis v0.38.0
|
||||||
@@ -21,6 +22,7 @@ require (
|
|||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/crypto v0.44.0
|
golang.org/x/crypto v0.44.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
gorm.io/driver/postgres v1.6.0
|
gorm.io/driver/postgres v1.6.0
|
||||||
gorm.io/driver/sqlite v1.6.0
|
gorm.io/driver/sqlite v1.6.0
|
||||||
gorm.io/gorm v1.31.1
|
gorm.io/gorm v1.31.1
|
||||||
@@ -102,6 +104,8 @@ require (
|
|||||||
github.com/spf13/pflag v1.0.10 // indirect
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
github.com/stretchr/objx v0.5.2 // indirect
|
github.com/stretchr/objx v0.5.2 // indirect
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
|
github.com/swaggest/jsonschema-go v0.3.74 // indirect
|
||||||
|
github.com/swaggest/refl v1.3.1 // indirect
|
||||||
github.com/tinylib/msgp v1.2.5 // indirect
|
github.com/tinylib/msgp v1.2.5 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||||
@@ -123,5 +127,5 @@ require (
|
|||||||
golang.org/x/time v0.14.0 // indirect
|
golang.org/x/time v0.14.0 // indirect
|
||||||
google.golang.org/grpc v1.75.1 // indirect
|
google.golang.org/grpc v1.75.1 // indirect
|
||||||
google.golang.org/protobuf v1.36.10 // indirect
|
google.golang.org/protobuf v1.36.10 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
22
go.sum
22
go.sum
@@ -8,6 +8,10 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
|
|||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
|
||||||
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||||
|
github.com/bool64/dev v0.2.39 h1:kP8DnMGlWXhGYJEZE/J0l/gVBdbuhoPGL+MJG4QbofE=
|
||||||
|
github.com/bool64/dev v0.2.39/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
|
||||||
|
github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E=
|
||||||
|
github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs=
|
||||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||||
@@ -100,6 +104,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
|
|||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
github.com/hibiken/asynq v0.25.1 h1:phj028N0nm15n8O2ims+IvJ2gz4k2auvermngh9JhTw=
|
github.com/hibiken/asynq v0.25.1 h1:phj028N0nm15n8O2ims+IvJ2gz4k2auvermngh9JhTw=
|
||||||
github.com/hibiken/asynq v0.25.1/go.mod h1:pazWNOLBu0FEynQRBvHA26qdIKRSmfdIfUm4HdsLmXg=
|
github.com/hibiken/asynq v0.25.1/go.mod h1:pazWNOLBu0FEynQRBvHA26qdIKRSmfdIfUm4HdsLmXg=
|
||||||
|
github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc=
|
||||||
|
github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE=
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||||
@@ -181,6 +187,8 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR
|
|||||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||||
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||||
|
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||||
|
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||||
github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
|
github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
|
||||||
github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
|
github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
@@ -210,6 +218,14 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
|
|||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
|
github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ=
|
||||||
|
github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU=
|
||||||
|
github.com/swaggest/jsonschema-go v0.3.74 h1:hkAZBK3RxNWU013kPqj0Q/GHGzYCCm9WcUTnfg2yPp0=
|
||||||
|
github.com/swaggest/jsonschema-go v0.3.74/go.mod h1:qp+Ym2DIXHlHzch3HKz50gPf2wJhKOrAB/VYqLS2oJU=
|
||||||
|
github.com/swaggest/openapi-go v0.2.60 h1:kglHH/WIfqAglfuWL4tu0LPakqNYySzklUWx06SjSKo=
|
||||||
|
github.com/swaggest/openapi-go v0.2.60/go.mod h1:jmFOuYdsWGtHU0BOuILlHZQJxLqHiAE6en+baE+QQUk=
|
||||||
|
github.com/swaggest/refl v1.3.1 h1:XGplEkYftR7p9cz1lsiwXMM2yzmOymTE9vneVVpaOh4=
|
||||||
|
github.com/swaggest/refl v1.3.1/go.mod h1:4uUVFVfPJ0NSX9FPwMPspeHos9wPFlCMGoPRllUbpvA=
|
||||||
github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU=
|
github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU=
|
||||||
github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY=
|
github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY=
|
||||||
github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 h1:s2bIayFXlbDFexo96y+htn7FzuhpXLYJNnIuglNKqOk=
|
github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0 h1:s2bIayFXlbDFexo96y+htn7FzuhpXLYJNnIuglNKqOk=
|
||||||
@@ -230,6 +246,10 @@ github.com/valyala/fasthttp v1.66.0 h1:M87A0Z7EayeyNaV6pfO3tUTUiYO0dZfEJnRGXTVNu
|
|||||||
github.com/valyala/fasthttp v1.66.0/go.mod h1:Y4eC+zwoocmXSVCB1JmhNbYtS7tZPRI2ztPB72EVObs=
|
github.com/valyala/fasthttp v1.66.0/go.mod h1:Y4eC+zwoocmXSVCB1JmhNbYtS7tZPRI2ztPB72EVObs=
|
||||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||||
|
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
|
||||||
|
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
|
||||||
|
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
|
||||||
|
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||||
@@ -297,6 +317,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
|
|||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
package bootstrap
|
package bootstrap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/break/junhong_cmp_fiber/internal/handler"
|
"github.com/break/junhong_cmp_fiber/internal/handler/admin"
|
||||||
)
|
)
|
||||||
|
|
||||||
// initHandlers 初始化所有 Handler 实例
|
// initHandlers 初始化所有 Handler 实例
|
||||||
func initHandlers(svc *services) *Handlers {
|
func initHandlers(svc *services) *Handlers {
|
||||||
return &Handlers{
|
return &Handlers{
|
||||||
Account: handler.NewAccountHandler(svc.Account),
|
Account: admin.NewAccountHandler(svc.Account),
|
||||||
Role: handler.NewRoleHandler(svc.Role),
|
Role: admin.NewRoleHandler(svc.Role),
|
||||||
Permission: handler.NewPermissionHandler(svc.Permission),
|
Permission: admin.NewPermissionHandler(svc.Permission),
|
||||||
// TODO: 新增 Handler 在此初始化
|
// TODO: 新增 Handler 在此初始化
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package bootstrap
|
package bootstrap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/break/junhong_cmp_fiber/internal/handler"
|
"github.com/break/junhong_cmp_fiber/internal/handler/admin"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handlers 封装所有 HTTP 处理器
|
// Handlers 封装所有 HTTP 处理器
|
||||||
// 用于路由注册
|
// 用于路由注册
|
||||||
type Handlers struct {
|
type Handlers struct {
|
||||||
Account *handler.AccountHandler
|
Account *admin.AccountHandler
|
||||||
Role *handler.RoleHandler
|
Role *admin.RoleHandler
|
||||||
Permission *handler.PermissionHandler
|
Permission *admin.PermissionHandler
|
||||||
// TODO: 新增 Handler 在此添加字段
|
// TODO: 新增 Handler 在此添加字段
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package handler
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package handler
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package handler
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package handler
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -2,48 +2,56 @@ package model
|
|||||||
|
|
||||||
// CreateAccountRequest 创建账号请求
|
// CreateAccountRequest 创建账号请求
|
||||||
type CreateAccountRequest struct {
|
type CreateAccountRequest struct {
|
||||||
Username string `json:"username" validate:"required,min=3,max=50"`
|
Username string `json:"username" validate:"required,min=3,max=50" required:"true" minLength:"3" maxLength:"50" description:"用户名"`
|
||||||
Phone string `json:"phone" validate:"required,len=11"`
|
Phone string `json:"phone" validate:"required,len=11" required:"true" minLength:"11" maxLength:"11" description:"手机号"`
|
||||||
Password string `json:"password" validate:"required,min=8,max=32"`
|
Password string `json:"password" validate:"required,min=8,max=32" required:"true" minLength:"8" maxLength:"32" description:"密码"`
|
||||||
UserType int `json:"user_type" validate:"required,min=1,max=4"`
|
UserType int `json:"user_type" validate:"required,min=1,max=4" required:"true" minimum:"1" maximum:"4" description:"用户类型 (1:Root, 2:Admin, 3:Agent, 4:Merchant)"`
|
||||||
ShopID *uint `json:"shop_id"`
|
ShopID *uint `json:"shop_id" description:"关联店铺ID"`
|
||||||
ParentID *uint `json:"parent_id"`
|
ParentID *uint `json:"parent_id" description:"父账号ID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateAccountRequest 更新账号请求
|
// UpdateAccountRequest 更新账号请求
|
||||||
type UpdateAccountRequest struct {
|
type UpdateAccountRequest struct {
|
||||||
Username *string `json:"username" validate:"omitempty,min=3,max=50"`
|
Username *string `json:"username" validate:"omitempty,min=3,max=50" minLength:"3" maxLength:"50" description:"用户名"`
|
||||||
Phone *string `json:"phone" validate:"omitempty,len=11"`
|
Phone *string `json:"phone" validate:"omitempty,len=11" minLength:"11" maxLength:"11" description:"手机号"`
|
||||||
Password *string `json:"password" validate:"omitempty,min=8,max=32"`
|
Password *string `json:"password" validate:"omitempty,min=8,max=32" minLength:"8" maxLength:"32" description:"密码"`
|
||||||
Status *int `json:"status" validate:"omitempty,min=0,max=1"`
|
Status *int `json:"status" validate:"omitempty,min=0,max=1" minimum:"0" maximum:"1" description:"状态 (0:禁用, 1:启用)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccountListRequest 账号列表查询请求
|
// AccountListRequest 账号列表查询请求
|
||||||
type AccountListRequest struct {
|
type AccountListRequest struct {
|
||||||
Page int `json:"page" query:"page" validate:"omitempty,min=1"`
|
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码"`
|
||||||
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100"`
|
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量"`
|
||||||
Username string `json:"username" query:"username" validate:"omitempty,max=50"`
|
Username string `json:"username" query:"username" validate:"omitempty,max=50" maxLength:"50" description:"用户名模糊查询"`
|
||||||
Phone string `json:"phone" query:"phone" validate:"omitempty,max=20"`
|
Phone string `json:"phone" query:"phone" validate:"omitempty,max=20" maxLength:"20" description:"手机号模糊查询"`
|
||||||
UserType *int `json:"user_type" query:"user_type" validate:"omitempty,min=1,max=4"`
|
UserType *int `json:"user_type" query:"user_type" validate:"omitempty,min=1,max=4" minimum:"1" maximum:"4" description:"用户类型"`
|
||||||
Status *int `json:"status" query:"status" validate:"omitempty,min=0,max=1"`
|
Status *int `json:"status" query:"status" validate:"omitempty,min=0,max=1" minimum:"0" maximum:"1" description:"状态"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccountResponse 账号响应
|
// AccountResponse 账号响应
|
||||||
type AccountResponse struct {
|
type AccountResponse struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id" description:"账号ID"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username" description:"用户名"`
|
||||||
Phone string `json:"phone"`
|
Phone string `json:"phone" description:"手机号"`
|
||||||
UserType int `json:"user_type"`
|
UserType int `json:"user_type" description:"用户类型"`
|
||||||
ShopID *uint `json:"shop_id,omitempty"`
|
ShopID *uint `json:"shop_id,omitempty" description:"关联店铺ID"`
|
||||||
ParentID *uint `json:"parent_id,omitempty"`
|
ParentID *uint `json:"parent_id,omitempty" description:"父账号ID"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status" description:"状态"`
|
||||||
Creator uint `json:"creator"`
|
Creator uint `json:"creator" description:"创建人ID"`
|
||||||
Updater uint `json:"updater"`
|
Updater uint `json:"updater" description:"更新人ID"`
|
||||||
CreatedAt string `json:"created_at"`
|
CreatedAt string `json:"created_at" description:"创建时间"`
|
||||||
UpdatedAt string `json:"updated_at"`
|
UpdatedAt string `json:"updated_at" description:"更新时间"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssignRolesRequest 分配角色请求
|
// AssignRolesRequest 分配角色请求
|
||||||
type AssignRolesRequest struct {
|
type AssignRolesRequest struct {
|
||||||
RoleIDs []uint `json:"role_ids" validate:"required,min=1"`
|
RoleIDs []uint `json:"role_ids" validate:"required,min=1" required:"true" minItems:"1" description:"角色ID列表"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccountPageResult 账号分页响应
|
||||||
|
type AccountPageResult struct {
|
||||||
|
Items []AccountResponse `json:"items" description:"账号列表"`
|
||||||
|
Total int64 `json:"total" description:"总记录数"`
|
||||||
|
Page int `json:"page" description:"当前页码"`
|
||||||
|
Size int `json:"size" description:"每页数量"`
|
||||||
}
|
}
|
||||||
|
|||||||
24
internal/model/common.go
Normal file
24
internal/model/common.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
// IDReq 通用 ID 路径参数请求
|
||||||
|
type IDReq struct {
|
||||||
|
ID uint `path:"id" description:"ID" required:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateAccountParams 更新账号聚合参数 (用于文档生成)
|
||||||
|
type UpdateAccountParams struct {
|
||||||
|
IDReq
|
||||||
|
UpdateAccountRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssignRolesParams 分配角色聚合参数 (用于文档生成)
|
||||||
|
type AssignRolesParams struct {
|
||||||
|
IDReq
|
||||||
|
AssignRolesRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveRoleParams 移除角色聚合参数
|
||||||
|
type RemoveRoleParams struct {
|
||||||
|
AccountID uint `path:"account_id" description:"账号ID" required:"true"`
|
||||||
|
RoleID uint `path:"role_id" description:"角色ID" required:"true"`
|
||||||
|
}
|
||||||
@@ -2,58 +2,72 @@ package model
|
|||||||
|
|
||||||
// CreatePermissionRequest 创建权限请求
|
// CreatePermissionRequest 创建权限请求
|
||||||
type CreatePermissionRequest struct {
|
type CreatePermissionRequest struct {
|
||||||
PermName string `json:"perm_name" validate:"required,min=1,max=50"`
|
PermName string `json:"perm_name" validate:"required,min=1,max=50" required:"true" minLength:"1" maxLength:"50" description:"权限名称"`
|
||||||
PermCode string `json:"perm_code" validate:"required,min=1,max=100"`
|
PermCode string `json:"perm_code" validate:"required,min=1,max=100" required:"true" minLength:"1" maxLength:"100" description:"权限编码"`
|
||||||
PermType int `json:"perm_type" validate:"required,min=1,max=2"`
|
PermType int `json:"perm_type" validate:"required,min=1,max=2" required:"true" minimum:"1" maximum:"2" description:"权限类型 (1:菜单, 2:按钮)"`
|
||||||
URL string `json:"url" validate:"omitempty,max=255"`
|
URL string `json:"url" validate:"omitempty,max=255" maxLength:"255" description:"请求路径"`
|
||||||
ParentID *uint `json:"parent_id"`
|
ParentID *uint `json:"parent_id" description:"父权限ID"`
|
||||||
Sort int `json:"sort" validate:"omitempty,min=0"`
|
Sort int `json:"sort" validate:"omitempty,min=0" minimum:"0" description:"排序值"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePermissionRequest 更新权限请求
|
// UpdatePermissionRequest 更新权限请求
|
||||||
type UpdatePermissionRequest struct {
|
type UpdatePermissionRequest struct {
|
||||||
PermName *string `json:"perm_name" validate:"omitempty,min=1,max=50"`
|
PermName *string `json:"perm_name" validate:"omitempty,min=1,max=50" minLength:"1" maxLength:"50" description:"权限名称"`
|
||||||
PermCode *string `json:"perm_code" validate:"omitempty,min=1,max=100"`
|
PermCode *string `json:"perm_code" validate:"omitempty,min=1,max=100" minLength:"1" maxLength:"100" description:"权限编码"`
|
||||||
URL *string `json:"url" validate:"omitempty,max=255"`
|
URL *string `json:"url" validate:"omitempty,max=255" maxLength:"255" description:"请求路径"`
|
||||||
ParentID *uint `json:"parent_id"`
|
ParentID *uint `json:"parent_id" description:"父权限ID"`
|
||||||
Sort *int `json:"sort" validate:"omitempty,min=0"`
|
Sort *int `json:"sort" validate:"omitempty,min=0" minimum:"0" description:"排序值"`
|
||||||
Status *int `json:"status" validate:"omitempty,min=0,max=1"`
|
Status *int `json:"status" validate:"omitempty,min=0,max=1" minimum:"0" maximum:"1" description:"状态 (0:禁用, 1:启用)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatePermissionParams 更新权限参数聚合
|
||||||
|
type UpdatePermissionParams struct {
|
||||||
|
IDReq
|
||||||
|
UpdatePermissionRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
// PermissionListRequest 权限列表查询请求
|
// PermissionListRequest 权限列表查询请求
|
||||||
type PermissionListRequest struct {
|
type PermissionListRequest struct {
|
||||||
Page int `json:"page" query:"page" validate:"omitempty,min=1"`
|
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码"`
|
||||||
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100"`
|
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量"`
|
||||||
PermName string `json:"perm_name" query:"perm_name" validate:"omitempty,max=50"`
|
PermName string `json:"perm_name" query:"perm_name" validate:"omitempty,max=50" maxLength:"50" description:"权限名称模糊查询"`
|
||||||
PermCode string `json:"perm_code" query:"perm_code" validate:"omitempty,max=100"`
|
PermCode string `json:"perm_code" query:"perm_code" validate:"omitempty,max=100" maxLength:"100" description:"权限编码模糊查询"`
|
||||||
PermType *int `json:"perm_type" query:"perm_type" validate:"omitempty,min=1,max=2"`
|
PermType *int `json:"perm_type" query:"perm_type" validate:"omitempty,min=1,max=2" minimum:"1" maximum:"2" description:"权限类型"`
|
||||||
ParentID *uint `json:"parent_id" query:"parent_id"`
|
ParentID *uint `json:"parent_id" query:"parent_id" description:"父权限ID"`
|
||||||
Status *int `json:"status" query:"status" validate:"omitempty,min=0,max=1"`
|
Status *int `json:"status" query:"status" validate:"omitempty,min=0,max=1" minimum:"0" maximum:"1" description:"状态"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PermissionResponse 权限响应
|
// PermissionResponse 权限响应
|
||||||
type PermissionResponse struct {
|
type PermissionResponse struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id" description:"权限ID"`
|
||||||
PermName string `json:"perm_name"`
|
PermName string `json:"perm_name" description:"权限名称"`
|
||||||
PermCode string `json:"perm_code"`
|
PermCode string `json:"perm_code" description:"权限编码"`
|
||||||
PermType int `json:"perm_type"`
|
PermType int `json:"perm_type" description:"权限类型"`
|
||||||
URL string `json:"url,omitempty"`
|
URL string `json:"url,omitempty" description:"请求路径"`
|
||||||
ParentID *uint `json:"parent_id,omitempty"`
|
ParentID *uint `json:"parent_id,omitempty" description:"父权限ID"`
|
||||||
Sort int `json:"sort"`
|
Sort int `json:"sort" description:"排序值"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status" description:"状态"`
|
||||||
Creator uint `json:"creator"`
|
Creator uint `json:"creator" description:"创建人ID"`
|
||||||
Updater uint `json:"updater"`
|
Updater uint `json:"updater" description:"更新人ID"`
|
||||||
CreatedAt string `json:"created_at"`
|
CreatedAt string `json:"created_at" description:"创建时间"`
|
||||||
UpdatedAt string `json:"updated_at"`
|
UpdatedAt string `json:"updated_at" description:"更新时间"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PermissionPageResult 权限分页响应
|
||||||
|
type PermissionPageResult struct {
|
||||||
|
Items []PermissionResponse `json:"items" description:"权限列表"`
|
||||||
|
Total int64 `json:"total" description:"总记录数"`
|
||||||
|
Page int `json:"page" description:"当前页码"`
|
||||||
|
Size int `json:"size" description:"每页数量"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PermissionTreeNode 权限树节点(用于层级展示)
|
// PermissionTreeNode 权限树节点(用于层级展示)
|
||||||
type PermissionTreeNode struct {
|
type PermissionTreeNode struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id" description:"权限ID"`
|
||||||
PermName string `json:"perm_name"`
|
PermName string `json:"perm_name" description:"权限名称"`
|
||||||
PermCode string `json:"perm_code"`
|
PermCode string `json:"perm_code" description:"权限编码"`
|
||||||
PermType int `json:"perm_type"`
|
PermType int `json:"perm_type" description:"权限类型"`
|
||||||
URL string `json:"url,omitempty"`
|
URL string `json:"url,omitempty" description:"请求路径"`
|
||||||
Sort int `json:"sort"`
|
Sort int `json:"sort" description:"排序值"`
|
||||||
Children []*PermissionTreeNode `json:"children,omitempty"`
|
Children []*PermissionTreeNode `json:"children,omitempty" description:"子权限列表"`
|
||||||
}
|
}
|
||||||
@@ -2,41 +2,67 @@ package model
|
|||||||
|
|
||||||
// CreateRoleRequest 创建角色请求
|
// CreateRoleRequest 创建角色请求
|
||||||
type CreateRoleRequest struct {
|
type CreateRoleRequest struct {
|
||||||
RoleName string `json:"role_name" validate:"required,min=1,max=50"`
|
RoleName string `json:"role_name" validate:"required,min=1,max=50" required:"true" minLength:"1" maxLength:"50" description:"角色名称"`
|
||||||
RoleDesc string `json:"role_desc" validate:"omitempty,max=255"`
|
RoleDesc string `json:"role_desc" validate:"omitempty,max=255" maxLength:"255" description:"角色描述"`
|
||||||
RoleType int `json:"role_type" validate:"required,min=1,max=3"`
|
RoleType int `json:"role_type" validate:"required,min=1,max=3" required:"true" minimum:"1" maximum:"3" description:"角色类型 (1:超级管理员, 2:普通管理员, 3:操作员)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateRoleRequest 更新角色请求
|
// UpdateRoleRequest 更新角色请求
|
||||||
type UpdateRoleRequest struct {
|
type UpdateRoleRequest struct {
|
||||||
RoleName *string `json:"role_name" validate:"omitempty,min=1,max=50"`
|
RoleName *string `json:"role_name" validate:"omitempty,min=1,max=50" minLength:"1" maxLength:"50" description:"角色名称"`
|
||||||
RoleDesc *string `json:"role_desc" validate:"omitempty,max=255"`
|
RoleDesc *string `json:"role_desc" validate:"omitempty,max=255" maxLength:"255" description:"角色描述"`
|
||||||
Status *int `json:"status" validate:"omitempty,min=0,max=1"`
|
Status *int `json:"status" validate:"omitempty,min=0,max=1" minimum:"0" maximum:"1" description:"状态 (0:禁用, 1:启用)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRoleParams 更新角色参数聚合
|
||||||
|
type UpdateRoleParams struct {
|
||||||
|
IDReq
|
||||||
|
UpdateRoleRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoleListRequest 角色列表查询请求
|
// RoleListRequest 角色列表查询请求
|
||||||
type RoleListRequest struct {
|
type RoleListRequest struct {
|
||||||
Page int `json:"page" query:"page" validate:"omitempty,min=1"`
|
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码"`
|
||||||
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100"`
|
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量"`
|
||||||
RoleName string `json:"role_name" query:"role_name" validate:"omitempty,max=50"`
|
RoleName string `json:"role_name" query:"role_name" validate:"omitempty,max=50" maxLength:"50" description:"角色名称模糊查询"`
|
||||||
RoleType *int `json:"role_type" query:"role_type" validate:"omitempty,min=1,max=3"`
|
RoleType *int `json:"role_type" query:"role_type" validate:"omitempty,min=1,max=3" minimum:"1" maximum:"3" description:"角色类型"`
|
||||||
Status *int `json:"status" query:"status" validate:"omitempty,min=0,max=1"`
|
Status *int `json:"status" query:"status" validate:"omitempty,min=0,max=1" minimum:"0" maximum:"1" description:"状态"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoleResponse 角色响应
|
// RoleResponse 角色响应
|
||||||
type RoleResponse struct {
|
type RoleResponse struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id" description:"角色ID"`
|
||||||
RoleName string `json:"role_name"`
|
RoleName string `json:"role_name" description:"角色名称"`
|
||||||
RoleDesc string `json:"role_desc"`
|
RoleDesc string `json:"role_desc" description:"角色描述"`
|
||||||
RoleType int `json:"role_type"`
|
RoleType int `json:"role_type" description:"角色类型"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status" description:"状态"`
|
||||||
Creator uint `json:"creator"`
|
Creator uint `json:"creator" description:"创建人ID"`
|
||||||
Updater uint `json:"updater"`
|
Updater uint `json:"updater" description:"更新人ID"`
|
||||||
CreatedAt string `json:"created_at"`
|
CreatedAt string `json:"created_at" description:"创建时间"`
|
||||||
UpdatedAt string `json:"updated_at"`
|
UpdatedAt string `json:"updated_at" description:"更新时间"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RolePageResult 角色分页响应
|
||||||
|
type RolePageResult struct {
|
||||||
|
Items []RoleResponse `json:"items" description:"角色列表"`
|
||||||
|
Total int64 `json:"total" description:"总记录数"`
|
||||||
|
Page int `json:"page" description:"当前页码"`
|
||||||
|
Size int `json:"size" description:"每页数量"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssignPermissionsRequest 分配权限请求
|
// AssignPermissionsRequest 分配权限请求
|
||||||
type AssignPermissionsRequest struct {
|
type AssignPermissionsRequest struct {
|
||||||
PermIDs []uint `json:"perm_ids" validate:"required,min=1"`
|
PermIDs []uint `json:"perm_ids" validate:"required,min=1" required:"true" minItems:"1" description:"权限ID列表"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssignPermissionsParams 分配权限参数聚合
|
||||||
|
type AssignPermissionsParams struct {
|
||||||
|
IDReq
|
||||||
|
AssignPermissionsRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemovePermissionParams 移除权限参数聚合
|
||||||
|
type RemovePermissionParams struct {
|
||||||
|
RoleID uint `path:"role_id" required:"true" description:"角色ID"`
|
||||||
|
PermID uint `path:"perm_id" required:"true" description:"权限ID"`
|
||||||
}
|
}
|
||||||
@@ -3,22 +3,71 @@ package routes
|
|||||||
import (
|
import (
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
"github.com/break/junhong_cmp_fiber/internal/handler"
|
"github.com/break/junhong_cmp_fiber/internal/handler/admin"
|
||||||
|
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||||
|
"github.com/break/junhong_cmp_fiber/pkg/openapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// registerAccountRoutes 注册账号相关路由
|
// registerAccountRoutes 注册账号相关路由
|
||||||
func registerAccountRoutes(api fiber.Router, h *handler.AccountHandler) {
|
func registerAccountRoutes(api fiber.Router, h *admin.AccountHandler, doc *openapi.Generator, basePath string) {
|
||||||
accounts := api.Group("/accounts")
|
accounts := api.Group("/accounts")
|
||||||
|
groupPath := basePath + "/accounts"
|
||||||
|
|
||||||
// 账号 CRUD
|
// 账号 CRUD
|
||||||
accounts.Post("", h.Create) // POST /api/v1/accounts
|
Register(accounts, doc, groupPath, "POST", "", h.Create, RouteSpec{
|
||||||
accounts.Get("", h.List) // GET /api/v1/accounts
|
Summary: "创建账号",
|
||||||
accounts.Get("/:id", h.Get) // GET /api/v1/accounts/:id
|
Tags: []string{"Account"},
|
||||||
accounts.Put("/:id", h.Update) // PUT /api/v1/accounts/:id
|
Input: new(model.CreateAccountRequest),
|
||||||
accounts.Delete("/:id", h.Delete) // DELETE /api/v1/accounts/:id
|
Output: new(model.AccountResponse),
|
||||||
|
})
|
||||||
|
|
||||||
|
Register(accounts, doc, groupPath, "GET", "", h.List, RouteSpec{
|
||||||
|
Summary: "账号列表",
|
||||||
|
Tags: []string{"Account"},
|
||||||
|
Input: new(model.AccountListRequest),
|
||||||
|
Output: new(model.AccountPageResult),
|
||||||
|
})
|
||||||
|
|
||||||
|
Register(accounts, doc, groupPath, "GET", "/:id", h.Get, RouteSpec{
|
||||||
|
Summary: "获取账号详情",
|
||||||
|
Tags: []string{"Account"},
|
||||||
|
Input: new(model.IDReq),
|
||||||
|
Output: new(model.AccountResponse),
|
||||||
|
})
|
||||||
|
|
||||||
|
Register(accounts, doc, groupPath, "PUT", "/:id", h.Update, RouteSpec{
|
||||||
|
Summary: "更新账号",
|
||||||
|
Tags: []string{"Account"},
|
||||||
|
Input: new(model.UpdateAccountParams),
|
||||||
|
Output: new(model.AccountResponse),
|
||||||
|
})
|
||||||
|
|
||||||
|
Register(accounts, doc, groupPath, "DELETE", "/:id", h.Delete, RouteSpec{
|
||||||
|
Summary: "删除账号",
|
||||||
|
Tags: []string{"Account"},
|
||||||
|
Input: new(model.IDReq),
|
||||||
|
Output: nil,
|
||||||
|
})
|
||||||
|
|
||||||
// 账号-角色关联
|
// 账号-角色关联
|
||||||
accounts.Post("/:id/roles", h.AssignRoles) // POST /api/v1/accounts/:id/roles
|
Register(accounts, doc, groupPath, "POST", "/:id/roles", h.AssignRoles, RouteSpec{
|
||||||
accounts.Get("/:id/roles", h.GetRoles) // GET /api/v1/accounts/:id/roles
|
Summary: "分配角色",
|
||||||
accounts.Delete("/:account_id/roles/:role_id", h.RemoveRole) // DELETE /api/v1/accounts/:account_id/roles/:role_id
|
Tags: []string{"Account"},
|
||||||
|
Input: new(model.AssignRolesParams),
|
||||||
|
Output: nil, // TODO: Define AccountRole response DTO
|
||||||
|
})
|
||||||
|
|
||||||
|
Register(accounts, doc, groupPath, "GET", "/:id/roles", h.GetRoles, RouteSpec{
|
||||||
|
Summary: "获取账号角色",
|
||||||
|
Tags: []string{"Account"},
|
||||||
|
Input: new(model.IDReq),
|
||||||
|
Output: new([]model.Role),
|
||||||
|
})
|
||||||
|
|
||||||
|
Register(accounts, doc, groupPath, "DELETE", "/:account_id/roles/:role_id", h.RemoveRole, RouteSpec{
|
||||||
|
Summary: "移除角色",
|
||||||
|
Tags: []string{"Account"},
|
||||||
|
Input: new(model.RemoveRoleParams),
|
||||||
|
Output: nil,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user