midway-fatcms 0.0.11 → 0.0.13

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 (68) hide show
  1. package/dist/configuration.d.ts +0 -2
  2. package/dist/configuration.js +14 -12
  3. package/dist/controller/gateway/CrudMtdGatewayController.js +2 -1
  4. package/dist/controller/gateway/DocGatewayController.js +7 -5
  5. package/dist/controller/gateway/PublicApiController.js +32 -3
  6. package/dist/controller/gateway/StaticController.d.ts +0 -2
  7. package/dist/controller/gateway/StaticController.js +4 -39
  8. package/dist/controller/home.controller.js +2 -1
  9. package/dist/controller/manage/AccountRoleManageApi.d.ts +2 -1
  10. package/dist/controller/manage/AccountRoleManageApi.js +34 -0
  11. package/dist/controller/manage/DataDictManageApi.d.ts +2 -0
  12. package/dist/controller/manage/DataDictManageApi.js +41 -9
  13. package/dist/controller/manage/DocManageApi.js +2 -2
  14. package/dist/controller/manage/UserAccountManageApi.js +4 -3
  15. package/dist/controller/render/AppRenderController.js +7 -6
  16. package/dist/libs/crud-pro/CrudPro.d.ts +0 -1
  17. package/dist/libs/crud-pro/CrudPro.js +2 -11
  18. package/dist/libs/crud-pro/exceptions.d.ts +6 -0
  19. package/dist/libs/crud-pro/exceptions.js +6 -0
  20. package/dist/libs/crud-pro/models/keys.d.ts +1 -0
  21. package/dist/libs/crud-pro/models/keys.js +1 -0
  22. package/dist/libs/crud-pro/services/CrudProExecuteFuncService.js +2 -2
  23. package/dist/libs/crud-pro/services/CrudProFieldUpdateService.js +3 -0
  24. package/dist/libs/crud-pro/services/CrudProTableMetaService.js +2 -2
  25. package/dist/libs/crud-pro/utils/DatabaseName.js +11 -0
  26. package/dist/libs/crud-pro/utils/DateTimeUtils.js +1 -1
  27. package/dist/libs/crud-pro/utils/SqlErrorParseUtils.d.ts +22 -0
  28. package/dist/libs/crud-pro/utils/SqlErrorParseUtils.js +219 -0
  29. package/dist/libs/utils/functions.d.ts +8 -1
  30. package/dist/libs/utils/functions.js +29 -1
  31. package/dist/service/AuthService.js +1 -1
  32. package/dist/service/anyapi/AnyApiService.js +1 -1
  33. package/dist/service/crudstd/CrudStdService.js +8 -3
  34. package/dist/service/curd/CurdMixByDictService.js +1 -1
  35. package/dist/service/curd/CurdMixBySysConfigService.js +1 -1
  36. package/dist/service/curd/CurdMixByWorkbenchService.js +1 -1
  37. package/dist/service/curd/fixCfgModel.js +3 -1
  38. package/dist/service/proxyapi/ProxyApiLoadService.js +3 -0
  39. package/package.json +1 -1
  40. package/src/configuration.ts +18 -11
  41. package/src/controller/gateway/CrudMtdGatewayController.ts +2 -1
  42. package/src/controller/gateway/DocGatewayController.ts +9 -5
  43. package/src/controller/gateway/PublicApiController.ts +39 -4
  44. package/src/controller/gateway/StaticController.ts +11 -40
  45. package/src/controller/home.controller.ts +3 -1
  46. package/src/controller/manage/AccountRoleManageApi.ts +38 -0
  47. package/src/controller/manage/DataDictManageApi.ts +48 -11
  48. package/src/controller/manage/DocManageApi.ts +2 -2
  49. package/src/controller/manage/UserAccountManageApi.ts +4 -3
  50. package/src/controller/render/AppRenderController.ts +9 -7
  51. package/src/libs/crud-pro/CrudPro.ts +2 -12
  52. package/src/libs/crud-pro/exceptions.ts +6 -0
  53. package/src/libs/crud-pro/models/keys.ts +1 -0
  54. package/src/libs/crud-pro/services/CrudProExecuteFuncService.ts +3 -2
  55. package/src/libs/crud-pro/services/CrudProFieldUpdateService.ts +5 -0
  56. package/src/libs/crud-pro/services/CrudProTableMetaService.ts +2 -2
  57. package/src/libs/crud-pro/utils/DatabaseName.ts +12 -0
  58. package/src/libs/crud-pro/utils/DateTimeUtils.ts +1 -1
  59. package/src/libs/crud-pro/utils/SqlErrorParseUtils.ts +236 -0
  60. package/src/libs/utils/functions.ts +37 -2
  61. package/src/service/AuthService.ts +2 -2
  62. package/src/service/anyapi/AnyApiService.ts +2 -2
  63. package/src/service/crudstd/CrudStdService.ts +9 -4
  64. package/src/service/curd/CurdMixByDictService.ts +1 -1
  65. package/src/service/curd/CurdMixBySysConfigService.ts +1 -1
  66. package/src/service/curd/CurdMixByWorkbenchService.ts +1 -1
  67. package/src/service/curd/fixCfgModel.ts +3 -1
  68. package/src/service/proxyapi/ProxyApiLoadService.ts +4 -1
@@ -4,7 +4,7 @@ import * as _ from 'lodash';
4
4
  import { BaseApiController } from '../base/BaseApiController';
5
5
  import { EnumInfoService } from '@/service/EnumInfoService';
6
6
  import { CommonResult } from '@/libs/utils/common-dto';
7
- import { parseJsonObject } from '@/libs/utils/functions';
7
+ import { isEntityOK, parseJsonObject } from '@/libs/utils/functions';
8
8
  import { WorkbenchService } from '@/service/WorkbenchService';
9
9
  import { SystemRoleCode } from '@/models/SystemPerm';
10
10
  import { KeysOfAuthType } from '@/libs/crud-pro/models/keys';
@@ -71,10 +71,33 @@ export class PublicApiController extends BaseApiController {
71
71
  const allMenuList = await this.sysMenuService.getCachedMenusList();
72
72
 
73
73
  const menuList = allMenuList.filter(e => {
74
- return workbenchMenuCodeSet.has(e.menu_code) && e.status === 1;
74
+ return workbenchMenuCodeSet.has(e.menu_code) && isEntityOK(e);
75
75
  });
76
76
 
77
77
 
78
+ const addPermissionInfo = (menu_list: any[], level: number) => {
79
+ if (!Array.isArray(menu_list)) {
80
+ return [];
81
+ }
82
+ if (level > 10) {
83
+ return menu_list;
84
+ }
85
+ return menu_list.map(e => {
86
+ if (Array.isArray(e.children)) {
87
+ e.children = addPermissionInfo(e.children, level + 1);
88
+ }
89
+ const view_auth_config = e.view_auth_config;
90
+ const view_auth_type: KeysOfAuthType = e.view_auth_type || KeysOfAuthType.byFuncCode;
91
+ if (!view_auth_config) {
92
+ return { ...e, hasPermission: true };
93
+ }
94
+ const hasPermission = this.ctx.userSession.isAuthPass(view_auth_type, view_auth_config);
95
+ return { ...e, hasPermission };
96
+ });
97
+ };
98
+
99
+
100
+
78
101
  const mapResult: any = {};
79
102
  for (let i = 0; i < menuList.length; i++) {
80
103
  const rowElement = cloneObject(menuList[i]);
@@ -86,7 +109,8 @@ export class PublicApiController extends BaseApiController {
86
109
 
87
110
  const menu_config_content = rowElement.menu_config_content;
88
111
  delete rowElement.menu_config_content;
89
- const menu_list = parseJsonObject(menu_config_content) || [];
112
+ let menu_list = parseJsonObject(menu_config_content) || [];
113
+ menu_list = addPermissionInfo(menu_list, 0);
90
114
  mapResult[menu_code] = { ...rowElement, menu_list, hasPermission };
91
115
  }
92
116
 
@@ -121,10 +145,21 @@ export class PublicApiController extends BaseApiController {
121
145
  }
122
146
 
123
147
  if (pathname && workbenchCode) {
124
- resultData.pageData = await this.sysAppService.getSysAppPageOne({
148
+
149
+ const pageData = await this.sysAppService.getSysAppPageOne({
125
150
  page_path: pathname,
126
151
  workbench_code: workbenchCode
127
152
  });
153
+
154
+ if (pageData) {
155
+ const clonePageInfo = { ...pageData };
156
+ const view_auth_config = clonePageInfo.view_auth_config;
157
+ const view_auth_type: KeysOfAuthType = clonePageInfo.view_auth_type;
158
+ const hasPermission = this.ctx.userSession.isAuthPass(view_auth_type, view_auth_config);
159
+ clonePageInfo.hasPermission = hasPermission;
160
+ resultData.pageData = clonePageInfo;
161
+ }
162
+
128
163
  }
129
164
 
130
165
  return CommonResult.successRes(resultData);
@@ -31,9 +31,8 @@ function getPathConfig(ossName: string) {
31
31
  };
32
32
  }
33
33
 
34
- // 404列表缓存
34
+ // 404列表缓存: 只再内存中记录。重启后继续
35
35
  let notFoundList = new Set();
36
- let notFoundListIsInit = false;
37
36
 
38
37
  /**
39
38
  * 静态文件代理功能
@@ -47,33 +46,11 @@ export class StaticController extends BaseApiController {
47
46
  const app = ANONYMOUS_CONTEXT.getApp();
48
47
  const appDir = app.getAppDir();
49
48
  const localDir = path.join(appDir, './public/static'); // 本地文件存储目录
50
- const notFoundListFile = path.join(localDir, '__404__list.json'); // 404列表文件
51
49
  return {
52
50
  localDir,
53
- notFoundListFile,
54
51
  };
55
52
  }
56
53
 
57
- private async initNotFoundList() {
58
- if (notFoundListIsInit) {
59
- return;
60
- }
61
- notFoundListIsInit = true;
62
-
63
- const { localDir, notFoundListFile } = this.getLocalPaths();
64
- try {
65
- // 确保本地存储目录存在
66
- await fs.mkdir(localDir, { recursive: true });
67
- const data = await fs.readFile(notFoundListFile, 'utf8');
68
-
69
- notFoundList = new Set(JSON.parse(data));
70
- console.log(`已加载${notFoundList.size}个404记录`);
71
- } catch (error) {
72
- if (error.code !== 'ENOENT') {
73
- console.error('读取404列表失败:', error);
74
- }
75
- }
76
- }
77
54
 
78
55
  private async responseLocalFile(localFilePath: string, localHeaderPath: string, relativePath: string): Promise<boolean> {
79
56
  const headers = {
@@ -87,13 +64,18 @@ export class StaticController extends BaseApiController {
87
64
  if (stats.isFile()) {
88
65
  const headerDataStr = await fs.readFile(localHeaderPath, 'utf8');
89
66
  const headerData = parseJsonObject(headerDataStr);
90
- if (headerData) {
67
+
68
+ if (headerData && headerData['last-modified']) {
91
69
  headers['last-modified'] = headerData['last-modified'];
70
+ }
71
+
72
+ if (headerData && headerData['etag']) {
92
73
  headers['etag'] = headerData['etag'];
93
74
  }
75
+
94
76
  }
95
77
  } catch (error) {
96
- this.logDebug('[StaticController]responseLocalFile not found header file => ' + localHeaderPath );
78
+ this.logDebug('[StaticController]responseLocalFile not found header file => ' + localHeaderPath);
97
79
  }
98
80
 
99
81
  try {
@@ -125,7 +107,7 @@ export class StaticController extends BaseApiController {
125
107
 
126
108
  @All('/:ossName/:relativePath+')
127
109
  async proxyStaticFile(@Param('ossName') ossName: string, @Param('relativePath') relativePath: string) {
128
- await this.initNotFoundList();
110
+
129
111
  const { localDir } = this.getLocalPaths();
130
112
  const PATH_CONFIG = getPathConfig(ossName);
131
113
 
@@ -161,9 +143,10 @@ export class StaticController extends BaseApiController {
161
143
  return;
162
144
  }
163
145
  } else if (remoteRes.statusCode === 404) {
146
+
164
147
  // 记录404并返回
165
148
  notFoundList.add(relativePath);
166
- await this.saveNotFoundList();
149
+
167
150
  this.logInfo(`[StaticController]远程文件不存在,已记录404: ${relativePath}`);
168
151
  this.ctx.status = 404;
169
152
  return this.ctx.render('500', { errorMsg: ' 远程文件不存在,已记录404' });
@@ -185,19 +168,7 @@ export class StaticController extends BaseApiController {
185
168
  return this.ctx.render('500', { errorMsg: '未知异常' });
186
169
  }
187
170
 
188
- // 保存404列表
189
- async saveNotFoundList() {
190
- const { notFoundListFile } = this.getLocalPaths();
191
- try {
192
- // 确保存储404列表的目录存在
193
- const dir = path.dirname(notFoundListFile);
194
- await fs.mkdir(dir, { recursive: true });
195
171
 
196
- await fs.writeFile(notFoundListFile, JSON.stringify(Array.from(notFoundList), null), 'utf8');
197
- } catch (error) {
198
- this.logError('[StaticController]保存404列表失败:', error);
199
- }
200
- }
201
172
 
202
173
  // 封装https请求为异步函数
203
174
  async httpsGet(url: string): Promise<HttpGetRes> {
@@ -6,6 +6,7 @@ import { createRenderUtils } from '@/libs/utils/render-utils';
6
6
  import { privateAES } from '@/libs/utils/crypto-utils';
7
7
  import { AuthService } from '@/service/AuthService';
8
8
  import { ISessionInfo } from '@/models/userSession';
9
+ import { isEntityOK } from '@/libs/utils/functions';
9
10
 
10
11
  @Controller('/')
11
12
  export class HomeController extends BaseApiController {
@@ -25,7 +26,7 @@ export class HomeController extends BaseApiController {
25
26
 
26
27
  const workbenchInfo = await this.workbenchService.getCurrentHostWorkbenchInfo();
27
28
 
28
- if (!workbenchInfo || workbenchInfo.status !== 1) {
29
+ if (!isEntityOK(workbenchInfo)) {
29
30
  this.logInfo(`域名不存在:hostname = ${hostname}, host=${host}`);
30
31
  const infos = {
31
32
  host,
@@ -35,6 +36,7 @@ export class HomeController extends BaseApiController {
35
36
  return this.ctx.render('404_workbench', infos);
36
37
  }
37
38
 
39
+
38
40
  const html_content = workbenchInfo.html_content || '未配置HTML模版';
39
41
 
40
42
  const userInfo = await this.getUserAndRefreshSessionInfo();
@@ -7,6 +7,9 @@ import { refreshCache } from '@/middleware/cacherefresh.middleware';
7
7
  import { CacheNameEnum } from '@/models/bizmodels';
8
8
  import { SystemFuncCode } from '@/models/SystemPerm';
9
9
  import { RelatedType } from '@/service/curd/CurdMixUtils';
10
+ import { SystemTables } from '@/models/SystemTables';
11
+ import { GLOBAL_STATIC_CONFIG } from '@/libs/global-config/global-config';
12
+ import { CommonResult } from '@/libs/utils/common-dto';
10
13
 
11
14
  @Controller('/ns/api/manage/accountRole', { middleware: [checkPermission(SystemFuncCode.AccountRoleManageRead)] })
12
15
  export class AccountRoleManageApi extends BaseApiController {
@@ -39,6 +42,41 @@ export class AccountRoleManageApi extends BaseApiController {
39
42
 
40
43
  @Post('/createAccountRole', { middleware: [checkPermission(SystemFuncCode.AccountRoleManageWrite), refreshCache(CacheNameEnum.CurdMixByAccount)] })
41
44
  async createAccountRole() {
45
+ const { SystemDbName, SystemDbType } = GLOBAL_STATIC_CONFIG.getConfig();
46
+ const body = this.ctx.request.body as any;
47
+ const accountId = body.data?.account_id;
48
+ const roleCode = body.data?.role_code;
49
+
50
+ // 校验 account_id 是否存在
51
+ if (accountId) {
52
+ const accountInfoRes = await this.curdMixService.getQuickCrud({
53
+ sqlDatabase: SystemDbName,
54
+ sqlDbType: SystemDbType,
55
+ sqlTable: SystemTables.sys_user_account,
56
+ }).isExist({
57
+ condition: { account_id: accountId }
58
+ });
59
+
60
+ if (!accountInfoRes.exists) {
61
+ return CommonResult.errorRes(`账户ID '${accountId}' 不存在`);
62
+ }
63
+ }
64
+
65
+ // 校验 role_code 是否存在
66
+ if (roleCode) {
67
+ const roleInfoRes = await this.curdMixService.getQuickCrud({
68
+ sqlDatabase: SystemDbName,
69
+ sqlDbType: SystemDbType,
70
+ sqlTable: SystemTables.sys_perm_role,
71
+ }).isExist({
72
+ condition: { role_code: roleCode }
73
+ });
74
+
75
+ if (!roleInfoRes.exists) {
76
+ return CommonResult.errorRes(`角色编码 '${roleCode}' 不存在`);
77
+ }
78
+ }
79
+
42
80
  return this.executeSysSimpleSQL('sys_perm_user_role', KeysOfSimpleSQL.SIMPLE_INSERT, {
43
81
  validateCfg: {
44
82
  'data.account_id': [KeysOfValidators.REQUIRED, KeysOfValidators.STRING],
@@ -6,7 +6,9 @@ import { checkPermission } from '@/middleware/permission.middleware';
6
6
  import { refreshCache } from '@/middleware/cacherefresh.middleware';
7
7
  import { CacheNameEnum } from '@/models/bizmodels';
8
8
  import { SystemFuncCode } from '@/models/SystemPerm';
9
- import {CommonResult} from "@/libs/utils/common-dto";
9
+ import { CommonResult } from "@/libs/utils/common-dto";
10
+ import { CommonException, Exceptions } from '@/libs/crud-pro/exceptions';
11
+ import { GLOBAL_STATIC_CONFIG } from '@/libs/global-config/global-config';
10
12
 
11
13
  @Controller('/ns/api/manage/dataDict', { middleware: [checkPermission(SystemFuncCode.DataDictMangeRead)] })
12
14
  export class DataDictManageApi extends BaseApiController {
@@ -29,12 +31,47 @@ export class DataDictManageApi extends BaseApiController {
29
31
 
30
32
  @Post('/createDataDict', { middleware: [checkPermission(SystemFuncCode.DataDictMangeWrite), refreshCache(CacheNameEnum.GetDataDictItemsByDictCode)] })
31
33
  async createDataDict() {
32
- return this.executeSysSimpleSQL('sys_data_dict', KeysOfSimpleSQL.SIMPLE_INSERT, {
33
- enableSoftDelete: true,
34
- validateCfg: {
35
- 'data.dict_code': [KeysOfValidators.REQUIRED],
36
- },
37
- });
34
+ const body = this.ctx.request.body as any;
35
+ const dict_code = body?.data?.dict_code;
36
+ try {
37
+ return await this.executeSysSimpleSQL('sys_data_dict', KeysOfSimpleSQL.SIMPLE_INSERT, {
38
+ enableSoftDelete: true,
39
+ validateCfg: {
40
+ 'data.dict_code': [KeysOfValidators.REQUIRED],
41
+ },
42
+ });
43
+ } catch (e) {
44
+ if (e?.code === Exceptions.RUN_SQL_EXCEPTION_ER_DUP_ENTRY && dict_code) {
45
+ const isSoftDeleted = await this.isSoftDeletedDictCode(dict_code);
46
+ if (isSoftDeleted) {
47
+ throw new CommonException(
48
+ Exceptions.RUN_SQL_EXCEPTION_ER_DUP_ENTRY,
49
+ '该 dict_code 对应的数据曾被软删除,无法直接创建。请联系 DBA 处理,或更换 dict_code 后重试。'
50
+ );
51
+ }
52
+ }
53
+ throw e;
54
+ }
55
+ }
56
+
57
+ /** 查询 dict_code 是否仅被软删除记录占用(不含 deleted_at=0 的活跃记录) */
58
+ private async isSoftDeletedDictCode(dict_code: string): Promise<boolean> {
59
+ const { SystemDbName, SystemDbType } = GLOBAL_STATIC_CONFIG.getConfig();
60
+ const result = await this.curdMixService.executeCrudByCfg(
61
+ { condition: { dict_code } },
62
+ {
63
+ sqlTable: 'sys_data_dict',
64
+ sqlSimpleName: KeysOfSimpleSQL.SIMPLE_QUERY_ONE,
65
+ sqlDatabase: SystemDbName,
66
+ sqlDbType: SystemDbType,
67
+ enableSoftDelete: false,
68
+ }
69
+ );
70
+ const row = result.getOneObj();
71
+ if (!row) {
72
+ return false;
73
+ }
74
+ return Number(row.deleted_at) !== 0;
38
75
  }
39
76
 
40
77
  @Post('/updateDataDict', { middleware: [checkPermission(SystemFuncCode.DataDictMangeWrite), refreshCache(CacheNameEnum.GetDataDictItemsByDictCode)] })
@@ -42,7 +79,7 @@ export class DataDictManageApi extends BaseApiController {
42
79
  return this.executeSysSimpleSQL('sys_data_dict', KeysOfSimpleSQL.SIMPLE_UPDATE, {
43
80
  enableSoftDelete: true,
44
81
  validateCfg: {
45
- 'condition.id': [KeysOfValidators.REQUIRED, KeysOfValidators.NUMERIC],
82
+ 'condition.id': [KeysOfValidators.REQUIRED],
46
83
  },
47
84
  });
48
85
  }
@@ -57,7 +94,7 @@ export class DataDictManageApi extends BaseApiController {
57
94
  return this.executeSysSimpleSQL('sys_data_dict', KeysOfSimpleSQL.SIMPLE_DELETE, {
58
95
  enableSoftDelete: true,
59
96
  validateCfg: {
60
- 'condition.id': [KeysOfValidators.REQUIRED, KeysOfValidators.NUMERIC],
97
+ 'condition.id': [KeysOfValidators.REQUIRED],
61
98
  'condition.dict_code': [KeysOfValidators.REQUIRED],
62
99
  },
63
100
  });
@@ -94,7 +131,7 @@ export class DataDictManageApi extends BaseApiController {
94
131
  return this.executeSysSimpleSQL('sys_data_dict_item', KeysOfSimpleSQL.SIMPLE_UPDATE, {
95
132
  enableSoftDelete: true,
96
133
  validateCfg: {
97
- 'condition.id': [KeysOfValidators.REQUIRED, KeysOfValidators.NUMERIC],
134
+ 'condition.id': [KeysOfValidators.REQUIRED],
98
135
  },
99
136
  });
100
137
  }
@@ -104,7 +141,7 @@ export class DataDictManageApi extends BaseApiController {
104
141
  return this.executeSysSimpleSQL('sys_data_dict_item', KeysOfSimpleSQL.SIMPLE_DELETE, {
105
142
  enableSoftDelete: true,
106
143
  validateCfg: {
107
- 'condition.id': [KeysOfValidators.REQUIRED, KeysOfValidators.NUMERIC],
144
+ 'condition.id': [KeysOfValidators.REQUIRED],
108
145
  'condition.dict_code': [KeysOfValidators.REQUIRED],
109
146
  },
110
147
  });
@@ -80,7 +80,7 @@ export class DocManageApi extends BaseApiController {
80
80
  return this.executeSysSimpleSQL('sys_doc', KeysOfSimpleSQL.SIMPLE_UPDATE, {
81
81
  enableSoftDelete: true,
82
82
  validateCfg: {
83
- 'condition.id': [KeysOfValidators.REQUIRED, KeysOfValidators.NUMERIC],
83
+ 'condition.id': [KeysOfValidators.REQUIRED],
84
84
  },
85
85
  updateCfg: {
86
86
  ...updateCfg,
@@ -94,7 +94,7 @@ export class DocManageApi extends BaseApiController {
94
94
  return this.executeSysSimpleSQL('sys_doc', KeysOfSimpleSQL.SIMPLE_DELETE, {
95
95
  enableSoftDelete: true,
96
96
  validateCfg: {
97
- 'condition.id': [KeysOfValidators.REQUIRED, KeysOfValidators.NUMERIC],
97
+ 'condition.id': [KeysOfValidators.REQUIRED],
98
98
  },
99
99
  updateCfg: {
100
100
  'condition.workbench_code': { contextAsString: CTX_WORKBENCH_CODE },
@@ -2,13 +2,13 @@ import { Controller, Inject, Post } from '@midwayjs/core';
2
2
  import { Context } from '@midwayjs/koa';
3
3
  import { KeysOfSimpleSQL, KeysOfValidators } from '../../libs/crud-pro/models/keys';
4
4
  import { BaseApiController } from '../base/BaseApiController';
5
- import { createUniqueId } from '../../libs/utils/functions';
6
5
  import { checkPermission } from '../../middleware/permission.middleware';
7
6
  import { SystemFuncCode } from '../../models/SystemPerm';
8
7
  import { CommonException, Exceptions } from '../../libs/crud-pro/exceptions';
9
8
  import { SystemTables } from '../../models/SystemTables';
10
9
  import { GLOBAL_STATIC_CONFIG } from '@/libs/global-config/global-config';
11
10
  import { CommonResult } from "@/libs/utils/common-dto";
11
+ import { MixinUtils } from '@/libs/crud-pro/utils/MixinUtils';
12
12
 
13
13
  const accountNameBlacklist = new Set(['sa', 'root', 'admin', 'superadmin', 'administrator', 'sys', 'sysop', 'schedule_user']);
14
14
  function checkAccountCreateBlacklist(value: string) {
@@ -80,23 +80,24 @@ export class UserAccountManageApi extends BaseApiController {
80
80
  @Post('/createUserAccount', { middleware: [checkPermission(SystemFuncCode.UserAccountMangeWrite)] })
81
81
  async createUserAccount() {
82
82
  const body = this.ctx.request.body as any;
83
- body.data.account_id = createUniqueId();
84
83
 
85
84
  const { generateUserAccountId } = GLOBAL_STATIC_CONFIG.getConfig();
86
85
  if (typeof generateUserAccountId === 'function') {
87
86
  body.data.account_id = await generateUserAccountId(body.data);
87
+ } else {
88
+ body.data.account_id = MixinUtils.generateSnowflakeId();
88
89
  }
89
90
 
90
91
  const result = await this.executeSysSimpleSQL(SystemTables.sys_user_account, KeysOfSimpleSQL.SIMPLE_INSERT, {
91
92
  validateCfg: {
92
93
  'data.login_name': LOGIN_NAME_VALIDATE,
93
94
  'data.nick_name': [KeysOfValidators.REQUIRED, KeysOfValidators.STRING, 'length:2,20', checkAccountCreateBlacklist],
94
- 'data.avatar': [KeysOfValidators.REQUIRED, KeysOfValidators.STRING],
95
95
  },
96
96
  });
97
97
  return result;
98
98
  }
99
99
 
100
+
100
101
  @Post('/deleteUserAccount', { middleware: [checkPermission(SystemFuncCode.UserAccountMangeWrite)] })
101
102
  async deleteUserAccount() {
102
103
  const result = await this.executeSysSimpleSQL(SystemTables.sys_user_account, KeysOfSimpleSQL.SIMPLE_DELETE, {
@@ -7,6 +7,7 @@ import { privateAES } from '@/libs/utils/crypto-utils';
7
7
  import { SysAppService } from "@/service/SysAppService";
8
8
  import { ISessionInfo } from '@/models/userSession';
9
9
  import { AuthService } from '@/service/AuthService';
10
+ import { isEntityOK } from '@/libs/utils/functions';
10
11
 
11
12
  /**
12
13
  * 渲染独立外部应用
@@ -33,14 +34,9 @@ export class AppRenderController extends BaseApiController {
33
34
 
34
35
  const appInfo = await this.sysAppService.getSysAppOne(appCode);
35
36
 
36
- if (!appInfo) {
37
+ if (!isEntityOK(appInfo)) {
37
38
  this.ctx.status = 404;
38
- return this.ctx.render('404_app', { appCode, errorMsg: ' 应用不存在' });
39
- }
40
-
41
- if (appInfo.status !== 1) {
42
- this.ctx.status = 404;
43
- return this.ctx.render('404_app', { appCode, errorMsg: ' 应用已下线' });
39
+ return this.ctx.render('404_app', { appCode, errorMsg: '应用不存在或已下线' });
44
40
  }
45
41
 
46
42
  const isSupportWorkbench = await this.isSupportCurrentWorkbench(appInfo);
@@ -51,6 +47,12 @@ export class AppRenderController extends BaseApiController {
51
47
 
52
48
  const workbenchInfo = await this.workbenchService.getCurrentHostWorkbenchInfo();
53
49
 
50
+ if (!isEntityOK(workbenchInfo)) {
51
+ this.ctx.status = 404;
52
+ return this.ctx.render('404_app', { appCode, errorMsg: '站点不存在或已下线' });
53
+ }
54
+
55
+
54
56
  const html_content = appInfo.html_content || '<b style="color: red">错误:未配置HTML模版,请检查!!</b>';
55
57
  const userInfo = await this.getUserAndRefreshSessionInfo();
56
58
 
@@ -5,6 +5,7 @@ import { CurdProServiceHub } from './services/CurdProServiceHub';
5
5
  import { CommonException, Exceptions } from './exceptions';
6
6
  import { RequestCfgModel } from './models/RequestCfgModel';
7
7
  import { MixinUtils } from './utils/MixinUtils';
8
+ import { SqlErrorParseUtils } from './utils/SqlErrorParseUtils';
8
9
  import { Transaction } from './models/Transaction';
9
10
  import { IExecuteContextFunc } from './models/ExecuteContextFunc';
10
11
  import { KeysOfSimpleSQL } from './models/keys';
@@ -417,21 +418,10 @@ class CrudPro {
417
418
  const message = MixinUtils.getErrorMessage(e);
418
419
  const logger = this.executeContext.getLogger();
419
420
  logger.error('RUN_SQL_EXCEPTION', message);
420
- throw this.parseRunSqlException(e || {});
421
+ throw SqlErrorParseUtils.parseRunSqlException(e || {});
421
422
  }
422
423
  }
423
424
 
424
- private parseRunSqlException(e: any): CommonException {
425
- const sqlMessage = '' + e.sqlMessage;
426
- if (e.code === 'ER_DUP_ENTRY' && sqlMessage.startsWith('Duplicate entry')) {
427
- return new CommonException(Exceptions.RUN_SQL_EXCEPTION_ER_DUP_ENTRY, '此对象实体已存在,不能创建重复对象');
428
- }
429
- if (e.code === 'ER_NO_SUCH_TABLE') {
430
- return new CommonException(Exceptions.RUN_SQL_EXCEPTION_ER_NO_SUCH_TABLE, '查询的表不存在:' + sqlMessage);
431
- }
432
- return e;
433
- }
434
-
435
425
  private async afterExecuteSQLList() {
436
426
  return this.executeContext.contextFunc.afterExecuteSQLList();
437
427
  }
@@ -86,6 +86,12 @@ export enum Exceptions {
86
86
  RUN_SQL_EXCEPTION = 'RUN_SQL_EXCEPTION',
87
87
  RUN_SQL_EXCEPTION_ER_DUP_ENTRY = 'RUN_SQL_EXCEPTION_ER_DUP_ENTRY',
88
88
  RUN_SQL_EXCEPTION_ER_NO_SUCH_TABLE = 'RUN_SQL_EXCEPTION_ER_NO_SUCH_TABLE',
89
+ RUN_SQL_EXCEPTION_ER_FK_PARENT_REFERENCED = 'RUN_SQL_EXCEPTION_ER_FK_PARENT_REFERENCED',
90
+ RUN_SQL_EXCEPTION_ER_FK_PARENT_NOT_FOUND = 'RUN_SQL_EXCEPTION_ER_FK_PARENT_NOT_FOUND',
91
+ RUN_SQL_EXCEPTION_ER_NOT_NULL = 'RUN_SQL_EXCEPTION_ER_NOT_NULL',
92
+ RUN_SQL_EXCEPTION_ER_DATA_TOO_LONG = 'RUN_SQL_EXCEPTION_ER_DATA_TOO_LONG',
93
+ RUN_SQL_EXCEPTION_ER_BAD_FIELD = 'RUN_SQL_EXCEPTION_ER_BAD_FIELD',
94
+ RUN_SQL_EXCEPTION_ER_DEADLOCK = 'RUN_SQL_EXCEPTION_ER_DEADLOCK',
89
95
  RUN_IS_NEED_EXECUTE_ERR = 'RUN_IS_NEED_EXECUTE_ERR',
90
96
  RUN_PICK_ERR_VISITOR_NULL = 'RUN_PICK_ERR_VISITOR_NULL',
91
97
  RUN_PICK_ERR_VISITOR_FIELD = 'RUN_PICK_ERR_VISITOR_FIELD',
@@ -9,6 +9,7 @@ export enum KeysOfFunCtx {
9
9
  CURRENT_VALUE = '$current',
10
10
  VISITOR = 'visitor',
11
11
  VISITOR_ATTR = 'visitor.',
12
+ VISITOR_AVATAR = 'visitor.avatar',
12
13
  REQUEST = 'req.',
13
14
  RESULT = 'res.',
14
15
  }
@@ -95,8 +95,9 @@ class CrudProExecuteFuncService extends CrudProServiceBase {
95
95
  if (pickString.startsWith(KeysOfFunCtx.VISITOR_ATTR)) {
96
96
  const reqModel = funcCtx?.reqModel;
97
97
  const attrValue = _.get(reqModel, pickString); // visitor.nickName
98
- if (isNil(attrValue)) {
99
- throw new CommonException(Exceptions.RUN_PICK_ERR_VISITOR_NULL, '获取用户ID失败, 可能用户没有登陆');
98
+
99
+ if (isNil(attrValue) && ![`${KeysOfFunCtx.VISITOR_AVATAR}`].includes(pickString)) {
100
+ throw new CommonException(Exceptions.RUN_PICK_ERR_VISITOR_NULL, '获取用户字段${pickString}失败, 可能用户没有登陆');
100
101
  }
101
102
  return attrValue;
102
103
  }
@@ -49,7 +49,12 @@ class CrudProFieldUpdateService extends CrudProServiceBase {
49
49
 
50
50
  result = this.serviceHub.executeFuncCfg(updateCfg, exeFunCtx);
51
51
  } catch (e) {
52
+
52
53
  this.logger.error('getUpdateNewValueByCfg->executeFuncCfg', e);
54
+ if (e instanceof CommonException) {
55
+ throw e;
56
+ }
57
+
53
58
  throw new CommonException(Exceptions.UPDATE_EXCEPTION, key + '.' + e);
54
59
  }
55
60
 
@@ -166,12 +166,12 @@ class CrudProTableMetaService extends CrudProServiceBase {
166
166
  const dbUtil = { sqlDatabase: query.sqlDatabase, sqlDbType: query.sqlDbType } as IExecuteUnsafeQueryCtx;
167
167
 
168
168
  // 获取物理表
169
- const tableSql = `SHOW TABLES FROM ${query.sqlDatabase}`;
169
+ const tableSql = `SHOW TABLES`;
170
170
  const tableRes = await this.executeUnsafeQuery(dbUtil, tableSql);
171
171
  const tableNames: string[] = (tableRes.rows || []).map((row: any) => Object.values(row)[0] as string);
172
172
 
173
173
  // 获取视图
174
- const viewSql = `SHOW FULL TABLES FROM ${query.sqlDatabase} WHERE Table_type = 'VIEW'`;
174
+ const viewSql = `SHOW FULL TABLES WHERE Table_type = 'VIEW'`;
175
175
  const viewRes = await this.executeUnsafeQuery(dbUtil, viewSql);
176
176
  const viewNames: string[] = (viewRes.rows || []).map((row: any) => Object.values(row)[0] as string);
177
177
 
@@ -1,4 +1,5 @@
1
1
  import { SqlDbType } from '../models/keys';
2
+ import { GLOBAL_STATIC_CONFIG } from '../../global-config/global-config'
2
3
 
3
4
  interface IDbTypeAndName {
4
5
  dbType: SqlDbType;
@@ -35,6 +36,17 @@ function parseDatabaseName(databaseName: string): IDbTypeAndName {
35
36
  };
36
37
  }
37
38
 
39
+ const gConfig = GLOBAL_STATIC_CONFIG.getConfig();
40
+ // 访问系统库
41
+ if (databaseName === 'fatcms' || databaseName === gConfig.SystemDbName) {
42
+ if (dbNameArr.length === 1) {
43
+ return {
44
+ dbType: gConfig.SystemDbType,
45
+ dbName: dbNameArr[0],
46
+ };
47
+ }
48
+ }
49
+
38
50
  if (dbNameArr.length === 1) {
39
51
  return {
40
52
  dbType: SqlDbType.mysql, // 默认
@@ -6,7 +6,7 @@ const DateTimeUtils = {
6
6
  return Date.now();
7
7
  },
8
8
  getCurrentTimeString(): string {
9
- return moment().format('YYYY-MM-DD HH:mm:ss');
9
+ return moment().format('YYYY-MM-DD HH:mm:ss.SSS');
10
10
  },
11
11
  // 以秒为单位的时间戳
12
12
  getCurrentTimeStampSecond(): number {