befly-tpl 3.0.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.
Files changed (142) hide show
  1. package/.env.development +83 -0
  2. package/LICENSE +201 -0
  3. package/README.md +20 -0
  4. package/README.ts.md +175 -0
  5. package/addon-loader.example.ts +99 -0
  6. package/addons/_template/README.md +123 -0
  7. package/addons/_template/addon.config.json +17 -0
  8. package/addons/_template/apis/example.ts +33 -0
  9. package/addons/_template/checks/example.ts +23 -0
  10. package/addons/_template/config/default.ts +12 -0
  11. package/addons/_template/plugins/example.ts +39 -0
  12. package/addons/_template/tables/example.json +7 -0
  13. package/addons/_template/types/index.d.ts +21 -0
  14. package/addons/admin/README.md +179 -0
  15. package/addons/admin/addon.config.json +13 -0
  16. package/addons/admin/apis/adminDel.ts +37 -0
  17. package/addons/admin/apis/adminInfo.ts +50 -0
  18. package/addons/admin/apis/adminIns.ts +70 -0
  19. package/addons/admin/apis/adminList.ts +24 -0
  20. package/addons/admin/apis/adminRoleDetail.ts +38 -0
  21. package/addons/admin/apis/adminRoleSave.ts +40 -0
  22. package/addons/admin/apis/adminUpd.ts +54 -0
  23. package/addons/admin/apis/apiAll.ts +38 -0
  24. package/addons/admin/apis/cacheRefresh.ts +36 -0
  25. package/addons/admin/apis/dashboardAddonList.ts +16 -0
  26. package/addons/admin/apis/dashboardChangelog.ts +41 -0
  27. package/addons/admin/apis/dashboardConfigStatus.ts +56 -0
  28. package/addons/admin/apis/dashboardEnvironmentInfo.ts +48 -0
  29. package/addons/admin/apis/dashboardPerformanceMetrics.ts +25 -0
  30. package/addons/admin/apis/dashboardPermissionStats.ts +33 -0
  31. package/addons/admin/apis/dashboardServiceStatus.ts +84 -0
  32. package/addons/admin/apis/dashboardSystemInfo.ts +34 -0
  33. package/addons/admin/apis/dashboardSystemOverview.ts +34 -0
  34. package/addons/admin/apis/dashboardSystemResources.ts +119 -0
  35. package/addons/admin/apis/dictAll.ts +26 -0
  36. package/addons/admin/apis/dictDel.ts +27 -0
  37. package/addons/admin/apis/dictDetail.ts +28 -0
  38. package/addons/admin/apis/dictIns.ts +38 -0
  39. package/addons/admin/apis/dictList.ts +27 -0
  40. package/addons/admin/apis/dictUpd.ts +44 -0
  41. package/addons/admin/apis/login.ts +123 -0
  42. package/addons/admin/apis/logout.ts +23 -0
  43. package/addons/admin/apis/menuAll.ts +70 -0
  44. package/addons/admin/apis/menuDel.ts +40 -0
  45. package/addons/admin/apis/menuIns.ts +31 -0
  46. package/addons/admin/apis/menuList.ts +26 -0
  47. package/addons/admin/apis/menuUpd.ts +41 -0
  48. package/addons/admin/apis/register.ts +50 -0
  49. package/addons/admin/apis/roleApiDetail.ts +34 -0
  50. package/addons/admin/apis/roleApiSave.ts +44 -0
  51. package/addons/admin/apis/roleDel.ts +48 -0
  52. package/addons/admin/apis/roleDetail.ts +28 -0
  53. package/addons/admin/apis/roleIns.ts +40 -0
  54. package/addons/admin/apis/roleList.ts +18 -0
  55. package/addons/admin/apis/roleMenuDetail.ts +33 -0
  56. package/addons/admin/apis/roleMenuSave.ts +39 -0
  57. package/addons/admin/apis/roleSave.ts +45 -0
  58. package/addons/admin/apis/roleUpd.ts +53 -0
  59. package/addons/admin/apis/sendSmsCode.ts +36 -0
  60. package/addons/admin/checks/admin.ts +36 -0
  61. package/addons/admin/config/index.ts +45 -0
  62. package/addons/admin/config/menu.json +44 -0
  63. package/addons/admin/scripts/syncApi.ts +285 -0
  64. package/addons/admin/scripts/syncDev.ts +203 -0
  65. package/addons/admin/scripts/syncMenu.ts +210 -0
  66. package/addons/admin/tables/admin.json +14 -0
  67. package/addons/admin/tables/api.json +8 -0
  68. package/addons/admin/tables/dict.json +8 -0
  69. package/addons/admin/tables/menu.json +8 -0
  70. package/addons/admin/tables/role.json +8 -0
  71. package/addons/admin/types/index.ts +44 -0
  72. package/addons/admin/util.ts +266 -0
  73. package/addons/befly/addon.config.json +13 -0
  74. package/addons/befly/apis/health/info.ts +77 -0
  75. package/addons/befly/apis/tool/tokenCheck.ts +52 -0
  76. package/addons/demo/README.md +62 -0
  77. package/addons/demo/addon.config.json +13 -0
  78. package/addons/demo/apis/demoIns.ts +36 -0
  79. package/addons/demo/apis/demoList.ts +36 -0
  80. package/addons/demo/checks/demo.ts +30 -0
  81. package/addons/demo/config/default.ts +17 -0
  82. package/addons/demo/plugins/tool.ts +61 -0
  83. package/addons/demo/tables/todo.json +6 -0
  84. package/addons/demo/types/index.d.ts +56 -0
  85. package/apis/article/articleDel.ts +33 -0
  86. package/apis/article/articleDetail.ts +26 -0
  87. package/apis/article/articleIns.ts +47 -0
  88. package/apis/article/articleList.ts +47 -0
  89. package/apis/article/articleUpd.ts +55 -0
  90. package/apis/article/increment.ts +37 -0
  91. package/apis/test/hi.ts +9 -0
  92. package/apis/user/login.ts +56 -0
  93. package/apis/user/userList.ts +40 -0
  94. package/bun.lock +140 -0
  95. package/checks/demo.ts +25 -0
  96. package/logs/2025-08-22.0.log +197 -0
  97. package/logs/2025-08-23.0.log +151 -0
  98. package/logs/2025-08-24.0.log +296 -0
  99. package/logs/2025-08-25.0.log +162 -0
  100. package/logs/2025-08-26.0.log +19 -0
  101. package/logs/2025-08-27.0.log +63 -0
  102. package/logs/2025-08-28.0.log +286 -0
  103. package/logs/2025-08-30.0.log +1 -0
  104. package/logs/2025-09-01.0.log +296 -0
  105. package/logs/2025-09-02.0.log +298 -0
  106. package/logs/2025-10-11.0.log +2718 -0
  107. package/logs/2025-10-12.0.log +4374 -0
  108. package/logs/2025-10-13.0.log +759 -0
  109. package/logs/2025-10-14.0.log +2350 -0
  110. package/logs/2025-10-15.0.log +2386 -0
  111. package/logs/2025-10-16.0.log +2807 -0
  112. package/logs/2025-10-17.0.log +1143 -0
  113. package/logs/2025-10-18.0.log +1292 -0
  114. package/logs/2025-10-19.0.log +1752 -0
  115. package/logs/2025-10-20.0.log +722 -0
  116. package/logs/2025-10-21.0.log +1075 -0
  117. package/logs/2025-10-23.0.log +3291 -0
  118. package/logs/2025-10-24.0.log +2341 -0
  119. package/logs/2025-10-25.0.log +1367 -0
  120. package/logs/debug.0.log +25174 -0
  121. package/main.ts +9 -0
  122. package/package.json +29 -0
  123. package/pm2.config.cjs +85 -0
  124. package/tables/article.json +11 -0
  125. package/tables/user.json +8 -0
  126. package/temp/addon-route-prefix-migration.md +400 -0
  127. package/temp/api-route-conflict-analysis.md +441 -0
  128. package/temp/interactive-cli-guide.md +199 -0
  129. package/temp/missing-apis-fix.md +362 -0
  130. package/temp/remove-status-field.md +239 -0
  131. package/temp/roleid-to-rolecode-optimization.md +321 -0
  132. package/temp/status-to-state-migration-complete.md +176 -0
  133. package/temp/syncMenu-guide.md +235 -0
  134. package/temp/test-admin-menus-cache.ts +125 -0
  135. package/temp/test-admin-menus.ts +110 -0
  136. package/temp/test-interactive-cli.ps1 +14 -0
  137. package/tests/core.test.ts +13 -0
  138. package/tsconfig.json +23 -0
  139. package/types/api.ts +128 -0
  140. package/types/index.ts +6 -0
  141. package/types/models.example.ts +267 -0
  142. package/types/models.ts +67 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * 删除角色
3
+ */
4
+
5
+ import { Yes, No, Fields } from 'befly';
6
+ import { deleteRolePermissions } from '../util';
7
+
8
+ export default {
9
+ name: '删除角色',
10
+ fields: {
11
+ id: Fields._id
12
+ },
13
+ handler: async (befly, ctx) => {
14
+ try {
15
+ // 检查是否有用户使用此角色(使用 getList 代替 getAll)
16
+ const adminList = await befly.db.getList({
17
+ table: 'addon_admin_admin',
18
+ where: { roleId: ctx.body.id }
19
+ });
20
+
21
+ if (adminList.total > 0) {
22
+ return No('该角色已分配给用户,无法删除');
23
+ }
24
+
25
+ // 获取角色信息(用于删除缓存)
26
+ const role = await befly.db.getDetail({
27
+ table: 'addon_admin_role',
28
+ where: { id: ctx.body.id }
29
+ });
30
+
31
+ // 删除角色
32
+ await befly.db.delData({
33
+ table: 'addon_admin_role',
34
+ where: { id: ctx.body.id }
35
+ });
36
+
37
+ // 删除角色权限缓存
38
+ if (role?.code) {
39
+ await deleteRolePermissions(befly, role.code);
40
+ }
41
+
42
+ return Yes('操作成功');
43
+ } catch (error) {
44
+ befly.logger.error('删除角色失败:', error);
45
+ return No('操作失败');
46
+ }
47
+ }
48
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 获取用户的角色(单角色模式)
3
+ */
4
+
5
+ import { Yes, No, Fields } from 'befly';
6
+
7
+ export default {
8
+ name: '获取用户角色',
9
+ auth: true, // 需要登录(权限由角色接口列表控制)
10
+ fields: {
11
+ id: Fields._id
12
+ },
13
+ handler: async (befly, ctx) => {
14
+ let roleInfo = null;
15
+ if (ctx.body.id && ctx.user.roleType === 'admin') {
16
+ roleInfo = await befly.db.getOne({
17
+ table: 'addon_admin_role',
18
+ where: { code: ctx.body.id }
19
+ });
20
+ }
21
+
22
+ return Yes('操作成功', {
23
+ roleId: ctx.body.id,
24
+ roleCode: ctx.body.id,
25
+ role: roleInfo
26
+ });
27
+ }
28
+ };
@@ -0,0 +1,40 @@
1
+ import { Yes, No } from 'befly';
2
+ import adminRoleTable from '../tables/role.json';
3
+ import { cacheRolePermissions } from '../util';
4
+
5
+ /**
6
+ * 创建角色
7
+ */
8
+ export default {
9
+ name: '创建角色',
10
+ fields: adminRoleTable,
11
+ handler: async (befly, ctx) => {
12
+ // 检查角色代码是否已存在
13
+ const existing = await befly.db.getOne({
14
+ table: 'addon_admin_role',
15
+ where: { code: ctx.body.code }
16
+ });
17
+
18
+ if (existing) {
19
+ return No('角色代码已存在');
20
+ }
21
+
22
+ const roleId = await befly.db.insData({
23
+ table: 'addon_admin_role',
24
+ data: {
25
+ name: ctx.body.name,
26
+ code: ctx.body.code,
27
+ description: ctx.body.description,
28
+ menus: ctx.body.menus || '',
29
+ apis: ctx.body.apis || '',
30
+ sort: ctx.body.sort
31
+ // state 由框架自动设置为 1
32
+ }
33
+ });
34
+
35
+ // 增量缓存角色权限到 Redis Set
36
+ await cacheRolePermissions(befly, ctx.body.code, ctx.body.apis || '');
37
+
38
+ return Yes('操作成功', { id: roleId });
39
+ }
40
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * 获取角色列表
3
+ */
4
+
5
+ import { Yes } from 'befly';
6
+
7
+ export default {
8
+ name: '获取角色列表',
9
+ handler: async (befly, ctx) => {
10
+ const roles = await befly.db.getList({
11
+ limit: 30,
12
+ table: 'addon_admin_role',
13
+ orderBy: ['sort#ASC', 'id#ASC']
14
+ });
15
+
16
+ return Yes('操作成功', roles);
17
+ }
18
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * 获取角色的菜单权限
3
+ */
4
+
5
+ import { Yes, No, Fields } from 'befly';
6
+
7
+ export default {
8
+ name: '获取角色菜单权限',
9
+ fields: {
10
+ roleId: Fields._id
11
+ },
12
+ handler: async (befly, ctx) => {
13
+ // 查询角色信息
14
+ const role = await befly.db.getOne({
15
+ table: 'addon_admin_role',
16
+ where: { id: ctx.body.roleId }
17
+ });
18
+
19
+ if (!role) {
20
+ return No('角色不存在');
21
+ }
22
+
23
+ // 解析菜单ID列表(逗号分隔的字符串转为数组)
24
+ const menuIds = role.menus
25
+ ? role.menus
26
+ .split(',')
27
+ .map((id: string) => parseInt(id.trim()))
28
+ .filter((id: number) => !isNaN(id))
29
+ : [];
30
+
31
+ return Yes('操作成功', menuIds);
32
+ }
33
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * 保存角色的菜单权限
3
+ */
4
+
5
+ import { Yes, No, Fields } from 'befly';
6
+ import adminRoleTable from '../tables/role.json';
7
+
8
+ export default {
9
+ name: '保存角色菜单权限',
10
+ fields: {
11
+ roleId: Fields._id,
12
+ menuIds: adminRoleTable.menus
13
+ },
14
+ handler: async (befly, ctx) => {
15
+ // 查询角色是否存在
16
+ const role = await befly.db.getOne({
17
+ table: 'addon_admin_role',
18
+ where: { id: ctx.body.roleId }
19
+ });
20
+
21
+ if (!role) {
22
+ return No('角色不存在');
23
+ }
24
+
25
+ // 将数组转为逗号分隔的字符串存储
26
+ const menuIdsStr = Array.isArray(ctx.body.menuIds) ? ctx.body.menuIds.join(',') : '';
27
+
28
+ // 更新角色的菜单权限
29
+ await befly.db.updData({
30
+ table: 'addon_admin_role',
31
+ where: { id: ctx.body.roleId },
32
+ data: {
33
+ menus: menuIdsStr
34
+ }
35
+ });
36
+
37
+ return Yes('操作成功');
38
+ }
39
+ };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * 保存用户的角色(单角色模式)
3
+ */
4
+
5
+ import { Yes, No, Fields } from 'befly';
6
+
7
+ export default {
8
+ name: '保存用户角色',
9
+ fields: {
10
+ adminId: Fields._id,
11
+ roleCode: '角色编码|string|2|50|null|1|^[a-zA-Z0-9_]+$'
12
+ },
13
+ handler: async (befly, ctx) => {
14
+ try {
15
+ // 查询角色是否存在(使用 roleCode 而非 roleId)
16
+ const role = await befly.db.getOne({
17
+ table: 'addon_admin_role',
18
+ where: { code: ctx.body.roleCode }
19
+ });
20
+
21
+ if (!role) {
22
+ return No('角色不存在');
23
+ }
24
+
25
+ // 根据角色编码判断角色类型(硬编码规则)
26
+ const roleType = role.code === 'dev' || role.code === 'admin' ? 'admin' : 'user';
27
+
28
+ // 更新管理员的角色ID、角色编码和角色类型
29
+ await befly.db.updData({
30
+ table: 'addon_admin_admin',
31
+ where: { id: ctx.body.adminId },
32
+ data: {
33
+ roleId: role.id,
34
+ roleCode: role.code,
35
+ roleType: roleType
36
+ }
37
+ });
38
+
39
+ return Yes('操作成功');
40
+ } catch (error) {
41
+ befly.logger.error('保存用户角色失败:', error);
42
+ return No('操作失败');
43
+ }
44
+ }
45
+ };
@@ -0,0 +1,53 @@
1
+ import { Yes, No, Fields } from 'befly';
2
+ import adminRoleTable from '../tables/role.json';
3
+ import { cacheRolePermissions } from '../util';
4
+
5
+ /**
6
+ * 更新角色
7
+ */
8
+ export default {
9
+ name: '更新角色',
10
+ fields: {
11
+ id: Fields._id,
12
+ name: adminRoleTable.name,
13
+ code: adminRoleTable.code,
14
+ description: adminRoleTable.description,
15
+ menus: adminRoleTable.menus,
16
+ apis: adminRoleTable.apis,
17
+ sort: adminRoleTable.sort
18
+ // state 需要禁用时传 2,启用时传 1
19
+ },
20
+ handler: async (befly, ctx) => {
21
+ // 检查角色代码是否被其他角色占用
22
+ const existing = await befly.db.getList({
23
+ table: 'addon_admin_role',
24
+ where: {
25
+ code: ctx.body.code,
26
+ id$ne: ctx.body.id
27
+ }
28
+ });
29
+
30
+ if (existing.total > 0) {
31
+ return No('角色代码已被其他角色使用');
32
+ }
33
+
34
+ await befly.db.updData({
35
+ table: 'addon_admin_role',
36
+ where: { id: ctx.body.id },
37
+ data: {
38
+ name: ctx.body.name,
39
+ code: ctx.body.code,
40
+ description: ctx.body.description,
41
+ menus: ctx.body.menus || '',
42
+ apis: ctx.body.apis || '',
43
+ sort: ctx.body.sort
44
+ // state 字段不在此处更新,需要禁用/启用时单独处理
45
+ }
46
+ });
47
+
48
+ // 增量更新角色权限缓存(先删除再重建)
49
+ await cacheRolePermissions(befly, ctx.body.code, ctx.body.apis || '');
50
+
51
+ return Yes('操作成功');
52
+ }
53
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * 发送短信验证码接口
3
+ */
4
+
5
+ import { Yes } from 'befly';
6
+
7
+ import adminTable from '../tables/admin.json';
8
+
9
+ export default {
10
+ name: '发送短信验证码',
11
+ auth: false,
12
+ fields: {
13
+ phone: adminTable.phone
14
+ },
15
+ required: ['phone'],
16
+ handler: async (befly, ctx) => {
17
+ // 生成6位数验证码
18
+ const code = Math.floor(100000 + Math.random() * 900000).toString();
19
+
20
+ // TODO: 调用短信服务发送验证码
21
+ // 这里需要集成实际的短信服务提供商(如阿里云、腾讯云等)
22
+ // await smsService.send(phone, code);
23
+
24
+ // 将验证码存储到 Redis 中,有效期5分钟
25
+ // 如果项目没有 Redis,也可以存储到数据库中
26
+ if (befly.redis) {
27
+ const key = `sms_code:${ctx.body.phone}`;
28
+ await befly.redis.set(key, code, 'EX', 300); // 5分钟过期
29
+ }
30
+
31
+ // 开发环境下返回验证码(生产环境应该删除)
32
+ const isDev = process.env.NODE_ENV === 'development';
33
+
34
+ return Yes('验证码已发送', isDev ? { code } : null);
35
+ }
36
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Admin Addon 启动检查
3
+ * 验证组件配置和依赖
4
+ */
5
+
6
+ import { Logger } from 'befly';
7
+
8
+ export default async function (): Promise<boolean> {
9
+ try {
10
+ // 检查组件是否启用
11
+ const adminEnable = process.env.ADMIN_ENABLE;
12
+
13
+ if (adminEnable === 'false') {
14
+ Logger.info('[Admin] 组件已禁用');
15
+ return true;
16
+ }
17
+
18
+ // 检查 JWT 密钥配置
19
+ const jwtSecret = process.env.JWT_SECRET;
20
+ if (!jwtSecret) {
21
+ Logger.warn('[Admin] 未配置 JWT_SECRET 环境变量,将使用默认密钥(不建议用于生产环境)');
22
+ }
23
+
24
+ // 检查短信服务配置
25
+ const smsProvider = process.env.SMS_PROVIDER;
26
+ if (!smsProvider) {
27
+ Logger.info('[Admin] 未配置短信服务,手机登录功能将使用测试验证码');
28
+ }
29
+
30
+ Logger.info('[Admin] 组件检查通过');
31
+ return true;
32
+ } catch (error: any) {
33
+ Logger.error('[Admin] 组件检查失败:', error);
34
+ return false;
35
+ }
36
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Admin 插件配置
3
+ */
4
+
5
+ export default {
6
+ // 插件名称
7
+ name: 'admin',
8
+
9
+ // 插件描述
10
+ description: '管理后台基础功能',
11
+
12
+ // 插件版本
13
+ version: '1.0.0',
14
+
15
+ // 是否启用
16
+ enabled: true,
17
+
18
+ // 配置选项
19
+ config: {
20
+ // JWT 密钥(建议从环境变量读取)
21
+ jwtSecret: process.env.JWT_SECRET || 'your-secret-key',
22
+
23
+ // Token 有效期(天)
24
+ tokenExpireDays: 7,
25
+
26
+ // 验证码有效期(秒)
27
+ smsCodeExpire: 300,
28
+
29
+ // 短信服务配置(需要根据实际使用的服务商配置)
30
+ sms: {
31
+ // 服务商: aliyun, tencent, etc.
32
+ provider: 'aliyun',
33
+
34
+ // 访问密钥
35
+ accessKeyId: process.env.SMS_ACCESS_KEY_ID || '',
36
+ accessKeySecret: process.env.SMS_ACCESS_KEY_SECRET || '',
37
+
38
+ // 短信签名
39
+ signName: '您的签名',
40
+
41
+ // 模板代码
42
+ templateCode: 'SMS_123456789'
43
+ }
44
+ }
45
+ };
@@ -0,0 +1,44 @@
1
+ [
2
+ {
3
+ "name": "首页",
4
+ "path": "/",
5
+ "icon": "Home",
6
+ "sort": 1,
7
+ "type": 1
8
+ },
9
+ {
10
+ "name": "管理员管理",
11
+ "path": "/admin",
12
+ "icon": "Users",
13
+ "sort": 2,
14
+ "type": 1
15
+ },
16
+ {
17
+ "name": "新闻管理",
18
+ "path": "/news",
19
+ "icon": "Newspaper",
20
+ "sort": 3,
21
+ "type": 1
22
+ },
23
+ {
24
+ "name": "菜单管理",
25
+ "path": "/menu",
26
+ "icon": "Menu",
27
+ "sort": 4,
28
+ "type": 1
29
+ },
30
+ {
31
+ "name": "角色管理",
32
+ "path": "/role",
33
+ "icon": "Users",
34
+ "sort": 5,
35
+ "type": 1
36
+ },
37
+ {
38
+ "name": "字典管理",
39
+ "path": "/dict",
40
+ "icon": "BookOpen",
41
+ "sort": 6,
42
+ "type": 1
43
+ }
44
+ ]