@robsun/create-keystone-app 0.2.15 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -44
- package/dist/create-keystone-app.js +347 -10
- package/dist/create-module.js +1217 -1187
- package/package.json +1 -1
- package/template/.claude/skills/keystone-implement/SKILL.md +113 -0
- package/template/.claude/skills/keystone-implement/references/CHECKLIST.md +91 -0
- package/template/.claude/skills/keystone-implement/references/PATTERNS.md +1088 -0
- package/template/.claude/skills/keystone-implement/references/SCHEMA.md +135 -0
- package/template/.claude/skills/keystone-implement/references/TESTING.md +231 -0
- package/template/.claude/skills/keystone-requirements/SKILL.md +296 -0
- package/template/.claude/skills/keystone-requirements/references/CONFIRM_TEMPLATE.md +170 -0
- package/template/.claude/skills/keystone-requirements/references/SCHEMA.md +135 -0
- package/template/.eslintrc.js +3 -0
- package/template/.github/workflows/ci.yml +30 -0
- package/template/.github/workflows/release.yml +32 -0
- package/template/.golangci.yml +11 -0
- package/template/README.md +82 -81
- package/template/apps/server/README.md +8 -0
- package/template/apps/server/cmd/server/main.go +27 -185
- package/template/apps/server/config.example.yaml +31 -1
- package/template/apps/server/config.yaml +31 -1
- package/template/apps/server/go.mod +61 -19
- package/template/apps/server/go.sum +185 -32
- package/template/apps/server/internal/frontend/embed.go +3 -8
- package/template/apps/server/internal/modules/example/README.md +18 -0
- package/template/apps/server/internal/modules/example/api/handler/handler_test.go +9 -0
- package/template/apps/server/internal/modules/example/api/handler/item_handler.go +468 -165
- package/template/apps/server/internal/modules/example/bootstrap/seeds/item.go +217 -8
- package/template/apps/server/internal/modules/example/domain/models/item.go +40 -7
- package/template/apps/server/internal/modules/example/domain/service/approval_callback.go +68 -0
- package/template/apps/server/internal/modules/example/domain/service/approval_schema.go +41 -0
- package/template/apps/server/internal/modules/example/domain/service/errors.go +20 -22
- package/template/apps/server/internal/modules/example/domain/service/item_service.go +267 -7
- package/template/apps/server/internal/modules/example/domain/service/item_service_test.go +281 -0
- package/template/apps/server/internal/modules/example/i18n/keys.go +32 -20
- package/template/apps/server/internal/modules/example/i18n/locales/en-US.json +30 -18
- package/template/apps/server/internal/modules/example/i18n/locales/zh-CN.json +30 -18
- package/template/apps/server/internal/modules/example/infra/exporter/item_exporter.go +119 -0
- package/template/apps/server/internal/modules/example/infra/importer/item_importer.go +77 -0
- package/template/apps/server/internal/modules/example/infra/repository/item_repository.go +99 -49
- package/template/apps/server/internal/modules/example/module.go +171 -97
- package/template/apps/server/internal/modules/example/tests/integration_test.go +7 -0
- package/template/apps/server/internal/modules/manifest.go +7 -7
- package/template/apps/web/README.md +4 -2
- package/template/apps/web/package.json +1 -1
- package/template/apps/web/src/app.config.ts +8 -6
- package/template/apps/web/src/index.css +7 -3
- package/template/apps/web/src/main.tsx +2 -5
- package/template/apps/web/src/modules/example/help/en-US/faq.md +27 -0
- package/template/apps/web/src/modules/example/help/en-US/items.md +30 -0
- package/template/apps/web/src/modules/example/help/en-US/overview.md +31 -0
- package/template/apps/web/src/modules/example/help/zh-CN/faq.md +27 -0
- package/template/apps/web/src/modules/example/help/zh-CN/items.md +31 -0
- package/template/apps/web/src/modules/example/help/zh-CN/overview.md +32 -0
- package/template/apps/web/src/modules/example/locales/en-US/example.json +99 -32
- package/template/apps/web/src/modules/example/locales/zh-CN/example.json +85 -18
- package/template/apps/web/src/modules/example/pages/ExampleItemsPage.tsx +840 -237
- package/template/apps/web/src/modules/example/services/exampleItems.ts +79 -8
- package/template/apps/web/src/modules/example/types.ts +14 -1
- package/template/apps/web/src/modules/index.ts +1 -0
- package/template/apps/web/vite.config.ts +9 -3
- package/template/docs/CONVENTIONS.md +17 -17
- package/template/package.json +4 -5
- package/template/pnpm-lock.yaml +76 -5
- package/template/scripts/build.bat +15 -3
- package/template/scripts/build.sh +9 -3
- package/template/scripts/check-help.js +249 -0
- package/template/scripts/compress-assets.js +89 -0
- package/template/scripts/test.bat +23 -0
- package/template/scripts/test.sh +16 -0
- package/template/.claude/skills/keystone-dev/SKILL.md +0 -90
- package/template/.claude/skills/keystone-dev/references/ADVANCED_PATTERNS.md +0 -716
- package/template/.claude/skills/keystone-dev/references/APPROVAL.md +0 -121
- package/template/.claude/skills/keystone-dev/references/CAPABILITIES.md +0 -261
- package/template/.claude/skills/keystone-dev/references/CHECKLIST.md +0 -285
- package/template/.claude/skills/keystone-dev/references/GOTCHAS.md +0 -390
- package/template/.claude/skills/keystone-dev/references/PATTERNS.md +0 -605
- package/template/.claude/skills/keystone-dev/references/TEMPLATES.md +0 -2710
- package/template/.claude/skills/keystone-dev/references/TESTING.md +0 -44
- package/template/.codex/skills/keystone-dev/SKILL.md +0 -90
- package/template/.codex/skills/keystone-dev/references/ADVANCED_PATTERNS.md +0 -716
- package/template/.codex/skills/keystone-dev/references/APPROVAL.md +0 -121
- package/template/.codex/skills/keystone-dev/references/CAPABILITIES.md +0 -261
- package/template/.codex/skills/keystone-dev/references/CHECKLIST.md +0 -285
- package/template/.codex/skills/keystone-dev/references/GOTCHAS.md +0 -390
- package/template/.codex/skills/keystone-dev/references/PATTERNS.md +0 -605
- package/template/.codex/skills/keystone-dev/references/TEMPLATES.md +0 -2710
- package/template/.codex/skills/keystone-dev/references/TESTING.md +0 -44
- package/template/apps/server/internal/app/routes/module_routes.go +0 -16
- package/template/apps/server/internal/app/routes/routes.go +0 -226
- package/template/apps/server/internal/app/startup/startup.go +0 -74
- package/template/apps/server/internal/frontend/handler.go +0 -122
- package/template/apps/server/internal/modules/registry.go +0 -145
- package/template/apps/web/src/modules/example/help/faq.md +0 -23
- package/template/apps/web/src/modules/example/help/items.md +0 -26
- package/template/apps/web/src/modules/example/help/overview.md +0 -25
|
@@ -1,97 +1,171 @@
|
|
|
1
|
-
package example
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"github.com/gin-gonic/gin"
|
|
5
|
-
"gorm.io/gorm"
|
|
6
|
-
|
|
7
|
-
"github.com/robsuncn/keystone/domain/
|
|
8
|
-
"github.com/robsuncn/keystone/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
1
|
+
package example
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"github.com/gin-gonic/gin"
|
|
5
|
+
"gorm.io/gorm"
|
|
6
|
+
|
|
7
|
+
approvalRepo "github.com/robsuncn/keystone/domain/approval/repository"
|
|
8
|
+
approvalSvc "github.com/robsuncn/keystone/domain/approval/service"
|
|
9
|
+
"github.com/robsuncn/keystone/domain/permissions"
|
|
10
|
+
"github.com/robsuncn/keystone/domain/service"
|
|
11
|
+
"github.com/robsuncn/keystone/infra/exporter"
|
|
12
|
+
"github.com/robsuncn/keystone/infra/importer"
|
|
13
|
+
"github.com/robsuncn/keystone/infra/repository"
|
|
14
|
+
"github.com/robsuncn/keystone/infra/scheduler"
|
|
15
|
+
|
|
16
|
+
examplehandler "__APP_NAME__/apps/server/internal/modules/example/api/handler"
|
|
17
|
+
examplemigrations "__APP_NAME__/apps/server/internal/modules/example/bootstrap/migrations"
|
|
18
|
+
exampleseeds "__APP_NAME__/apps/server/internal/modules/example/bootstrap/seeds"
|
|
19
|
+
examplemodels "__APP_NAME__/apps/server/internal/modules/example/domain/models"
|
|
20
|
+
exampleservice "__APP_NAME__/apps/server/internal/modules/example/domain/service"
|
|
21
|
+
examplei18n "__APP_NAME__/apps/server/internal/modules/example/i18n"
|
|
22
|
+
exampleexporter "__APP_NAME__/apps/server/internal/modules/example/infra/exporter"
|
|
23
|
+
exampleimporter "__APP_NAME__/apps/server/internal/modules/example/infra/importer"
|
|
24
|
+
examplerepository "__APP_NAME__/apps/server/internal/modules/example/infra/repository"
|
|
25
|
+
servermodules "github.com/robsuncn/keystone/server/modules"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
type Module struct {
|
|
29
|
+
db *gorm.DB
|
|
30
|
+
items *exampleservice.ItemService
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
func NewModule() *Module {
|
|
34
|
+
return &Module{}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func (m *Module) Name() string {
|
|
38
|
+
return "example"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
func (m *Module) RegisterRoutes(rg *gin.RouterGroup, deps servermodules.RouteDeps) {
|
|
42
|
+
if rg == nil || m == nil {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
handler := examplehandler.NewItemHandler(m.items)
|
|
46
|
+
if handler == nil {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
middlewares := make([]gin.HandlerFunc, 0, 1+len(deps.TenantGuards))
|
|
50
|
+
if deps.Auth != nil {
|
|
51
|
+
middlewares = append(middlewares, deps.Auth)
|
|
52
|
+
}
|
|
53
|
+
if len(deps.TenantGuards) > 0 {
|
|
54
|
+
middlewares = append(middlewares, deps.TenantGuards...)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
group := rg.Group("/example", middlewares...)
|
|
58
|
+
viewGuard := permissionGuard(deps.RBAC, "example:item:view")
|
|
59
|
+
manageGuard := permissionGuard(deps.RBAC, "example:item:manage")
|
|
60
|
+
|
|
61
|
+
group.GET("/items", viewGuard, handler.List)
|
|
62
|
+
group.GET("/items/export/pdf", viewGuard, handler.ExportPDF)
|
|
63
|
+
group.GET("/items/import-template", manageGuard, handler.DownloadImportTemplate)
|
|
64
|
+
group.GET("/items/:id", viewGuard, handler.Get)
|
|
65
|
+
group.POST("/items", manageGuard, handler.Create)
|
|
66
|
+
group.PATCH("/items/:id", manageGuard, handler.Update)
|
|
67
|
+
group.DELETE("/items/:id", manageGuard, handler.Delete)
|
|
68
|
+
group.POST("/items/:id/submit", manageGuard, handler.Submit)
|
|
69
|
+
group.POST("/items/:id/cancel", manageGuard, handler.Cancel)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
func (m *Module) RegisterModels() []interface{} {
|
|
73
|
+
return []interface{}{&examplemodels.ExampleItem{}}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
func (m *Module) RegisterPermissions(reg *permissions.Registry) error {
|
|
77
|
+
if reg == nil {
|
|
78
|
+
return nil
|
|
79
|
+
}
|
|
80
|
+
// Use NameKey for i18n support
|
|
81
|
+
if err := reg.CreateMenuI18n("example:item", "Example Items", "permission.example.item", "example", 10); err != nil {
|
|
82
|
+
return err
|
|
83
|
+
}
|
|
84
|
+
if err := reg.CreateActionI18n("example:item:view", "View Items", "permission.example.item.view", "example", "example:item"); err != nil {
|
|
85
|
+
return err
|
|
86
|
+
}
|
|
87
|
+
if err := reg.CreateActionI18n("example:item:manage", "Manage Items", "permission.example.item.manage", "example", "example:item"); err != nil {
|
|
88
|
+
return err
|
|
89
|
+
}
|
|
90
|
+
return nil
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
func (m *Module) RegisterI18n() error {
|
|
94
|
+
return examplei18n.RegisterLocales()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
func (m *Module) RegisterTasks(_ *scheduler.Registry) error {
|
|
98
|
+
return nil
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
func (m *Module) RegisterImporters(reg *importer.Service) error {
|
|
102
|
+
if reg == nil {
|
|
103
|
+
return nil
|
|
104
|
+
}
|
|
105
|
+
if m.items == nil && m.db != nil {
|
|
106
|
+
m.ensureServices(m.db)
|
|
107
|
+
}
|
|
108
|
+
return exampleimporter.RegisterItemImporter(reg, m.items)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
func (m *Module) RegisterExporters(reg *exporter.Service) error {
|
|
112
|
+
if reg == nil {
|
|
113
|
+
return nil
|
|
114
|
+
}
|
|
115
|
+
if m.items == nil && m.db != nil {
|
|
116
|
+
m.ensureServices(m.db)
|
|
117
|
+
}
|
|
118
|
+
return exampleexporter.RegisterItemExporter(reg, m.items)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func (m *Module) Migrate(db *gorm.DB) error {
|
|
122
|
+
if db == nil {
|
|
123
|
+
return nil
|
|
124
|
+
}
|
|
125
|
+
m.ensureServices(db)
|
|
126
|
+
return examplemigrations.Migrate(db)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
func (m *Module) Seed(db *gorm.DB) error {
|
|
130
|
+
if db == nil {
|
|
131
|
+
return nil
|
|
132
|
+
}
|
|
133
|
+
m.ensureServices(db)
|
|
134
|
+
return exampleseeds.Seed(db)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
func (m *Module) ensureServices(db *gorm.DB) {
|
|
138
|
+
if m == nil || db == nil || m.items != nil {
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
m.db = db
|
|
142
|
+
repo := examplerepository.NewItemRepository(db)
|
|
143
|
+
|
|
144
|
+
permRepo := repository.NewPermissionRepository(db)
|
|
145
|
+
userRepo := repository.NewUserRepository(db)
|
|
146
|
+
permSvc := service.NewPermissionService(permRepo, userRepo)
|
|
147
|
+
|
|
148
|
+
flowRepo := approvalRepo.NewFlowRepository(db)
|
|
149
|
+
nodeRepo := approvalRepo.NewNodeRepository(db)
|
|
150
|
+
instanceRepo := approvalRepo.NewInstanceRepository(db)
|
|
151
|
+
recordRepo := approvalRepo.NewRecordRepository(db)
|
|
152
|
+
approvalService := approvalSvc.NewService(db, instanceRepo, flowRepo, nodeRepo, recordRepo, userRepo, permSvc, approvalSvc.DefaultCallbackRegistry)
|
|
153
|
+
flowMatcher := approvalSvc.NewFlowMatcher(flowRepo)
|
|
154
|
+
|
|
155
|
+
notificationRepo := repository.NewNotificationRepository(db)
|
|
156
|
+
notificationSvc := service.NewNotificationService(db, notificationRepo)
|
|
157
|
+
|
|
158
|
+
callback := exampleservice.NewApprovalCallback(repo, notificationSvc)
|
|
159
|
+
approvalSvc.DefaultCallbackRegistry.Register(string(exampleservice.ApprovalBusinessType), callback)
|
|
160
|
+
|
|
161
|
+
m.items = exampleservice.NewItemService(repo, approvalService, flowMatcher, notificationSvc)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
func permissionGuard(rbac servermodules.PermissionGuard, code string) gin.HandlerFunc {
|
|
165
|
+
if rbac == nil {
|
|
166
|
+
return func(c *gin.Context) {
|
|
167
|
+
c.Next()
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return rbac.Require(code)
|
|
171
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
package modules
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
example "__APP_NAME__/apps/server/internal/modules/example"
|
|
5
|
-
)
|
|
3
|
+
import servermodules "github.com/robsuncn/keystone/server/modules"
|
|
6
4
|
|
|
7
|
-
//
|
|
8
|
-
func
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
// Register wires application modules into the shared registry.
|
|
6
|
+
func Register(registry *servermodules.Registry) {
|
|
7
|
+
if registry == nil {
|
|
8
|
+
return
|
|
9
|
+
}
|
|
10
|
+
registry.Register(servermodules.NewCoreModule())
|
|
11
11
|
}
|
|
@@ -8,20 +8,22 @@
|
|
|
8
8
|
- `src/main.tsx`:应用入口。
|
|
9
9
|
- `src/app.config.ts`:品牌与模块启用配置。
|
|
10
10
|
- `src/modules/<module>/index.ts`:模块注册入口。
|
|
11
|
+
- `src/modules/index.ts`:应用模块聚合入口。
|
|
11
12
|
- `apps/web/.env.example`:前端环境变量模板(Vite 读取)。
|
|
12
13
|
|
|
13
14
|
## 新建模块
|
|
14
15
|
1) 创建目录:`src/modules/<module>`。
|
|
15
16
|
2) 在 `index.ts` 调用 `registerModule` 注册路由。
|
|
16
17
|
3) 在 `routes.tsx` 配置菜单、权限、帮助文档。
|
|
17
|
-
4) 在 `
|
|
18
|
+
4) 在 `src/modules/index.ts` 引入模块。
|
|
19
|
+
5) 在 `app.config.ts` 的 `modules.enabled` 启用模块。
|
|
18
20
|
|
|
19
21
|
## 帮助文档
|
|
20
22
|
- 放在 `src/modules/<module>/help/**`。
|
|
21
23
|
- `helpKey` 与路由 `handle.helpKey` 保持一致。
|
|
22
24
|
|
|
23
25
|
## 常用命令
|
|
24
|
-
- 开发:`pnpm web
|
|
26
|
+
- 开发:`pnpm dev`(前后端一起)/ `pnpm -C apps/web dev`(仅前端)
|
|
25
27
|
- Lint:`pnpm -C apps/web lint`
|
|
26
28
|
- 测试:`pnpm -C apps/web test`
|
|
27
29
|
|
|
@@ -7,12 +7,14 @@ export const appConfig: Partial<KeystoneWebConfig> = {
|
|
|
7
7
|
appName: 'Keystone',
|
|
8
8
|
platformName: 'Keystone Platform',
|
|
9
9
|
},
|
|
10
|
-
modules: {
|
|
11
|
-
enabled: ['keystone'
|
|
12
|
-
},
|
|
13
|
-
approval: {
|
|
14
|
-
businessTypes: [
|
|
15
|
-
|
|
10
|
+
modules: {
|
|
11
|
+
enabled: ['keystone'],
|
|
12
|
+
},
|
|
13
|
+
approval: {
|
|
14
|
+
businessTypes: [
|
|
15
|
+
{ value: 'general', label: 'General Flow' },
|
|
16
|
+
],
|
|
17
|
+
},
|
|
16
18
|
ui: {
|
|
17
19
|
i18n: {
|
|
18
20
|
enabled: true,
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { StrictMode } from 'react'
|
|
2
2
|
import { createRoot } from 'react-dom/client'
|
|
3
|
-
import
|
|
4
|
-
import { KeystoneApp, getKeystoneConfig, setKeystoneConfig } from '@robsun/keystone-web-core'
|
|
3
|
+
import { KeystoneApp, setKeystoneConfig } from '@robsun/keystone-web-core'
|
|
5
4
|
import { appConfig } from './app.config'
|
|
6
5
|
import '@robsun/keystone-web-core/styles/keystone.css'
|
|
7
6
|
import './index.css'
|
|
8
|
-
import './modules
|
|
7
|
+
import './modules'
|
|
9
8
|
|
|
10
9
|
setKeystoneConfig(appConfig)
|
|
11
|
-
const dayjsLocale = getKeystoneConfig().ui?.locale?.dayjs ?? 'en'
|
|
12
|
-
dayjs.locale(dayjsLocale)
|
|
13
10
|
|
|
14
11
|
createRoot(document.getElementById('root')!).render(
|
|
15
12
|
<StrictMode>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
helpKey: "example/faq"
|
|
3
|
+
title: "Example Module FAQ"
|
|
4
|
+
description: "Common questions for the Example module."
|
|
5
|
+
category: "example"
|
|
6
|
+
tags: ["example", "faq"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# FAQ
|
|
10
|
+
|
|
11
|
+
## Why is the list empty?
|
|
12
|
+
- Confirm migrations and seed data have run (first launch runs them automatically).
|
|
13
|
+
- Check the current user has the `example:item:view` permission.
|
|
14
|
+
- Ensure `example` is enabled in `modules.enabled`.
|
|
15
|
+
|
|
16
|
+
## Why does approval submission fail?
|
|
17
|
+
- Confirm an approval flow exists and is enabled (a sample flow is created by default).
|
|
18
|
+
- Check the current user is logged in and has submit permissions.
|
|
19
|
+
- Status must be `draft` / `rejected` / `cancelled`.
|
|
20
|
+
|
|
21
|
+
## Why can I not edit or delete?
|
|
22
|
+
- `pending` status cannot be edited or deleted.
|
|
23
|
+
- Approved records are read-only.
|
|
24
|
+
|
|
25
|
+
## What if import fails?
|
|
26
|
+
- Ensure import fields include `title`.
|
|
27
|
+
- Category must be `general` / `operations` / `finance` / `growth`.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
helpKey: "example/items"
|
|
3
|
+
title: "Example Items"
|
|
4
|
+
description: "Manage example items with CRUD, approval, import/export, and attachments."
|
|
5
|
+
category: "example"
|
|
6
|
+
tags: ["example", "items", "approval", "import", "export"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Example Items
|
|
10
|
+
This page demonstrates the full lifecycle of example items, including creation, approval, import/export, and attachments.
|
|
11
|
+
|
|
12
|
+
## Field reference
|
|
13
|
+
- **Title**: required, item title.
|
|
14
|
+
- **Description**: optional, item description.
|
|
15
|
+
- **Category**: business category used for filters and approval conditions.
|
|
16
|
+
- **Amount**: amount used for approval conditions and export.
|
|
17
|
+
- **Status**: `draft` / `pending` / `approved` / `rejected` / `cancelled`.
|
|
18
|
+
- **Attachment**: uploaded file stored in the file service.
|
|
19
|
+
|
|
20
|
+
## Approval workflow
|
|
21
|
+
- After submission, status becomes `pending` and is approved by the admin role.
|
|
22
|
+
- Cancellation is supported; status becomes `cancelled` after cancel.
|
|
23
|
+
|
|
24
|
+
## Import/Export
|
|
25
|
+
- Import fields: `title`, `description`, `category`, `amount`, `status`.
|
|
26
|
+
- Export includes ID, amount, approval status, and other fields.
|
|
27
|
+
|
|
28
|
+
## Permissions
|
|
29
|
+
- `example:item:view`: view list and details.
|
|
30
|
+
- `example:item:manage`: create, edit, delete, submit/cancel approval.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
helpKey: "example/overview"
|
|
3
|
+
title: "Example Module Overview"
|
|
4
|
+
description: "Overview of the Example module and the platform integrations it demonstrates."
|
|
5
|
+
category: "example"
|
|
6
|
+
tags: ["example", "items", "approval", "import", "export", "file"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Example Module
|
|
10
|
+
The Example module demonstrates how a business module integrates platform capabilities and serves as a reference template for new module development.
|
|
11
|
+
|
|
12
|
+
## Capabilities covered
|
|
13
|
+
- CRUD with pagination and filters
|
|
14
|
+
- RBAC permissions and menu registration
|
|
15
|
+
- Approval workflow (submit, cancel, approval records)
|
|
16
|
+
- Import/Export (Excel)
|
|
17
|
+
- File upload and attachment storage
|
|
18
|
+
- Notifications
|
|
19
|
+
- i18n and Help docs
|
|
20
|
+
|
|
21
|
+
## Key paths
|
|
22
|
+
- Frontend: `apps/web/src/modules/example/`
|
|
23
|
+
- Backend: `apps/server/internal/modules/example/`
|
|
24
|
+
|
|
25
|
+
## Related APIs
|
|
26
|
+
- `GET /api/v1/example/items`
|
|
27
|
+
- `POST /api/v1/example/items`
|
|
28
|
+
- `PATCH /api/v1/example/items/:id`
|
|
29
|
+
- `DELETE /api/v1/example/items/:id`
|
|
30
|
+
- `POST /api/v1/example/items/:id/submit`
|
|
31
|
+
- `POST /api/v1/example/items/:id/cancel`
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
helpKey: "example/faq"
|
|
3
|
+
title: "Example Module FAQ"
|
|
4
|
+
description: "Common questions for the Example module."
|
|
5
|
+
category: "example"
|
|
6
|
+
tags: ["example", "faq"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# FAQ
|
|
10
|
+
|
|
11
|
+
## 为什么列表为空?
|
|
12
|
+
- 确认已执行迁移与种子数据(首次启动会自动执行)。
|
|
13
|
+
- 检查当前用户是否有 `example:item:view` 权限。
|
|
14
|
+
- 确认 `modules.enabled` 中已启用 `example`。
|
|
15
|
+
|
|
16
|
+
## 为什么提交审批失败?
|
|
17
|
+
- 确认审批流程已创建并启用(默认会创建示例流程)。
|
|
18
|
+
- 检查当前用户是否已登录且具备提交权限。
|
|
19
|
+
- 状态需为 `draft` / `rejected` / `cancelled`。
|
|
20
|
+
|
|
21
|
+
## 为什么无法编辑或删除?
|
|
22
|
+
- `pending` 状态下禁止编辑或删除。
|
|
23
|
+
- 已审批通过的记录仅可查看。
|
|
24
|
+
|
|
25
|
+
## 导入失败怎么办?
|
|
26
|
+
- 检查导入字段是否包含 `title`。
|
|
27
|
+
- 类别需为 `general` / `operations` / `finance` / `growth`。
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
helpKey: "example/items"
|
|
3
|
+
title: "Example Items"
|
|
4
|
+
description: "Manage example items with CRUD, approval, import/export, and attachments."
|
|
5
|
+
category: "example"
|
|
6
|
+
tags: ["example", "items", "approval", "import", "export"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Example Items
|
|
10
|
+
|
|
11
|
+
本页展示示例事项的完整流程,覆盖创建、审批、导入/导出与附件。
|
|
12
|
+
|
|
13
|
+
## 字段说明
|
|
14
|
+
- **Title**:必填,事项标题。
|
|
15
|
+
- **Description**:可选,事项描述。
|
|
16
|
+
- **Category**:业务分类,用于筛选与审批条件。
|
|
17
|
+
- **Amount**:金额,用于审批条件与导出。
|
|
18
|
+
- **Status**:`draft` / `pending` / `approved` / `rejected` / `cancelled`。
|
|
19
|
+
- **Attachment**:上传文件,存储在文件服务中。
|
|
20
|
+
|
|
21
|
+
## 审批流程
|
|
22
|
+
- 提交后进入 `pending` 状态,由管理员角色审批。
|
|
23
|
+
- 支持撤销审批,撤销后状态为 `cancelled`。
|
|
24
|
+
|
|
25
|
+
## 导入/导出
|
|
26
|
+
- 导入字段:`title`, `description`, `category`, `amount`, `status`。
|
|
27
|
+
- 导出包含编号、金额、审批状态等字段。
|
|
28
|
+
|
|
29
|
+
## 权限
|
|
30
|
+
- `example:item:view`:查看列表和详情。
|
|
31
|
+
- `example:item:manage`:新建、编辑、删除、提交/撤销审批。
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
helpKey: "example/overview"
|
|
3
|
+
title: "Example Module Overview"
|
|
4
|
+
description: "Overview of the Example module and the platform integrations it demonstrates."
|
|
5
|
+
category: "example"
|
|
6
|
+
tags: ["example", "items", "approval", "import", "export", "file"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Example Module
|
|
10
|
+
|
|
11
|
+
Example 模块用于演示业务模块如何接入平台能力,适合作为新模块开发的参考模板。
|
|
12
|
+
|
|
13
|
+
## 覆盖能力
|
|
14
|
+
- CRUD + 分页检索与筛选
|
|
15
|
+
- RBAC 权限与菜单注册
|
|
16
|
+
- 审批流程(提交、撤销、审批记录)
|
|
17
|
+
- 导入/导出(Excel)
|
|
18
|
+
- 文件上传与附件存储
|
|
19
|
+
- 通知消息
|
|
20
|
+
- i18n 与 Help 文档
|
|
21
|
+
|
|
22
|
+
## 关键路径
|
|
23
|
+
- 前端:`apps/web/src/modules/example/`
|
|
24
|
+
- 后端:`apps/server/internal/modules/example/`
|
|
25
|
+
|
|
26
|
+
## 相关 API
|
|
27
|
+
- `GET /api/v1/example/items`
|
|
28
|
+
- `POST /api/v1/example/items`
|
|
29
|
+
- `PATCH /api/v1/example/items/:id`
|
|
30
|
+
- `DELETE /api/v1/example/items/:id`
|
|
31
|
+
- `POST /api/v1/example/items/:id/submit`
|
|
32
|
+
- `POST /api/v1/example/items/:id/cancel`
|