crabatool 1.0.410 → 1.0.414

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/apis/data.js CHANGED
@@ -10,13 +10,15 @@ class data {
10
10
  constructor() {
11
11
  this.dslMap = {};
12
12
  this.pagesDataChanged = {};
13
+ this.dsl = {};
14
+ this.dataRefs = [];
13
15
  }
14
16
 
15
17
  _init(req) {
16
18
  if (req.app.jsoncrud) { // 每个server只创建1个实例
17
19
  return;
18
20
  }
19
- req.app.jsoncrud = new JSONCRUD({ storagePath: path.join(req.app.webPath, '../data/data.json') });
21
+ req.app.jsoncrud = new JSONCRUD({ storagePath: path.join(req.app.webPath, '../data/entities'), separateFiles: true });
20
22
 
21
23
  //读取dsl数据
22
24
  var dslData = fs.readFileSync(path.join(req.app.webPath, '../data/dslData.json'));
@@ -25,9 +27,9 @@ class data {
25
27
  } else {
26
28
  dslData = JSON.parse(dslData)
27
29
  }
28
- var dsl = dslData.dsl;
30
+ this.dsl = dslData.dsl;
29
31
  var _this = this;
30
- dsl && dsl.forEach(item => {
32
+ _this.dsl && _this.dsl.forEach(item => {
31
33
  _this.dslMap[crabatool.stringUtils.getFullPinyinCode(item.name)] = JSON.parse(JSON.stringify(item));
32
34
  });
33
35
  var dataRefs = dslData.dataRefs;
@@ -56,7 +58,6 @@ class data {
56
58
  async get(req, res) {
57
59
  var body = utils.getReqBody(req);
58
60
  var that = this;
59
-
60
61
  var queryParams = body.queryParams;
61
62
  var filterParams = body.filter;
62
63
  var items = null;
@@ -84,8 +85,8 @@ class data {
84
85
  items.push({ dataField: key, type: 0, value: queryParams[key] });
85
86
  });
86
87
  }
87
-
88
- var info = await this._getDb(req).find(body.name, {
88
+ var db = this._getDb(req);
89
+ var info = await db.find(body.name, {
89
90
  page: body.pageIndex,
90
91
  pageSize: body.pageSize,
91
92
  filterFunc: function (item) {
@@ -95,7 +96,7 @@ class data {
95
96
  return true;
96
97
  }
97
98
  });
98
-
99
+ await this.fillData(body.name, info.data, db, true);
99
100
  crabatool.utils.end(res, {
100
101
  code: 200,
101
102
  msg: '操作成功',
@@ -104,6 +105,62 @@ class data {
104
105
  });
105
106
  }
106
107
 
108
+ async fillData(name, rows, db, searchDataRef) {
109
+ if (this.dslMap[name]) {
110
+ if (rows) {
111
+ for (var i = 0; i < rows.length; i++) {
112
+ var row = rows[i];
113
+ var dsl = this.dslMap[name];
114
+ for (var j = 0; j < dsl.fields.length; j++) { //join扩展表数据
115
+ var field = dsl.fields[j];
116
+ if (field.type != 'table') {
117
+ continue;
118
+ }
119
+ var temp = await db.getByField(crabatool.stringUtils.getFullPinyinCode(field.ref), crabatool.stringUtils.getFullPinyinCode(field.refField), row[crabatool.stringUtils.getFullPinyinCode(field.name)]);
120
+ if (!temp) {
121
+ continue;
122
+ }
123
+ var str = crabatool.stringUtils.getFullPinyinCode(field.refShowField ? field.refShowField : field.refField);
124
+ row[str] = temp[str];
125
+ }
126
+
127
+ if (searchDataRef) {
128
+ //查询关联明细数据
129
+ var dataRefs = this.dslMap[name].dataRefs;
130
+ if (dataRefs) {
131
+ for (var m = 0; m < dataRefs.length; m++) {
132
+ var dataRef = dataRefs[m];
133
+ var detailPy = crabatool.stringUtils.getFullPinyinCode(dataRef.detail);
134
+ var masterFieldPy = crabatool.stringUtils.getFullPinyinCode(dataRef.masterField);
135
+ var obj = row[masterFieldPy];
136
+ var detailFieldPy = crabatool.stringUtils.getFullPinyinCode(dataRef.detailField);
137
+ var size = 100;
138
+ var rtSize = 0;
139
+ var array = [];
140
+ do {
141
+ //循环取外表数据
142
+ var page = 1;
143
+ var t = await db.find(detailPy, {
144
+ page: page,
145
+ pageSize: size,
146
+ filterFunc: function (row) {
147
+ return obj && obj === row[detailFieldPy];
148
+ }
149
+ });
150
+ page++;
151
+ rtSize = t.pageData.count;
152
+ array = array.concat(t.data);
153
+ } while (rtSize == size);
154
+ row[detailPy] = array;
155
+ await this.fillData(detailPy, row[detailPy], db, false);//只查一级
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+
107
164
  async reverseData(req, pageName, body) {
108
165
  var oldEntity = await this._getDb(req).get(body.name, body.data.id);
109
166
  if (!oldEntity) {
@@ -125,6 +182,8 @@ class data {
125
182
 
126
183
  var newData;
127
184
  var pageName = body.pageName;
185
+ var db = this._getDb(req);
186
+ var rtData = JSON.parse(JSON.stringify(body.data));
128
187
  if (body.data.id) {
129
188
  var oldData = await this.reverseData(req, pageName, body);
130
189
  if (!oldData) {
@@ -133,23 +192,46 @@ class data {
133
192
  await this.buildDataPrimaryAndForeignKey(body.name, body.data, true);
134
193
  //更新联动新数据
135
194
  await this.pageSaveToDataLinkage(req, body.name, pageName, body.data, oldData);
136
- await this._getDb(req).update(body.name, body.data.id, body.data);
195
+ var name = body.name;
196
+ await this._saveRefData(name, body.data, rtData, db);
197
+ await db.update(body.name, body.data.id, body.data);
137
198
  newData = body.data;
138
199
  } else {
139
200
  //提前制定ID
140
201
  body.data.id = cuid.newCuidString()
141
202
  await this.buildDataPrimaryAndForeignKey(body.name, body.data);
142
203
  await this.pageSaveToDataLinkage(req, body.name, pageName, body.data)
143
- newData = await this._getDb(req).create(body.name, body.data);
204
+ await this._saveRefData(name, body.data, rtData, db);
205
+ newData = await db.create(body.name, body.data);
144
206
  }
145
207
 
146
208
  crabatool.utils.end(res, {
147
209
  code: 200,
148
210
  msg: '操作成功',
149
- data: newData
211
+ data: rtData
150
212
  });
151
213
  }
152
214
 
215
+ async _saveRefData(name, data, rtData, db) {
216
+ var dataRefs = this.dslMap[name].dataRefs;
217
+ for (var i = 0; dataRefs && i < dataRefs.length; i++) {
218
+ var dataRef = dataRefs[i];
219
+ var detailPy = crabatool.stringUtils.getFullPinyinCode(dataRef.detail)
220
+ var details = data[detailPy] ? data[detailPy] : [];
221
+ delete data[detailPy];
222
+ for (var j = 0; j < details.length; j++) {
223
+ var detail = details[j];
224
+ if (detail.id) {
225
+ await db.update(detailPy, detail.id, detail)
226
+ } else {
227
+ await db.create(detailPy, detail)
228
+ rtData[detailPy][j].id = detail.id;//补充新增行的ID
229
+ }
230
+ await this._saveRefData(detailPy, detail, rtData[detailPy][j], db);
231
+ }
232
+ }
233
+ }
234
+
153
235
  findLayerData(data, items, layer) {
154
236
  if (!data) {
155
237
  return null;
@@ -205,9 +287,9 @@ class data {
205
287
  }
206
288
  //查找涉及的所有实体
207
289
  var _this = this;
208
- for(var i = 0 ; i < actions.length; i++){
290
+ for (var i = 0; i < actions.length; i++) {
209
291
  var action = actions[i];
210
- for(var j = 0 ; j < action.length ; j++){
292
+ for (var j = 0; j < action.length; j++) {
211
293
  var item = action[j];
212
294
  if (item.type == 'external') {//外表处理
213
295
  await _this.externalDataLinkage(req, name, data, item, reverseNumber);
@@ -232,17 +314,17 @@ class data {
232
314
  //根据refData和sourceData计算结果
233
315
  var refNamePy = crabatool.stringUtils.getFullPinyinCode(item.ref);
234
316
  var fieldNamePy = crabatool.stringUtils.getFullPinyinCode(item.field);
235
- Object.keys(refData).forEach(key => {
317
+ refData && Object.keys(refData).forEach(key => {
236
318
  var target = refData[key][0];
237
319
  //目标值为单一对象
238
320
  if (!target[refNamePy]) {
239
321
  return;
240
322
  }
241
323
  if (oldData) {
242
- if(name != refNamePy){
324
+ if (name != refNamePy) {
243
325
  //传入了老数据,当前计算的值可以直接取老数据的对应值,因为它已经排除本单
244
326
  var oldDataTemp = oldData[name][refNamePy];
245
- if(oldDataTemp instanceof Array){
327
+ if (oldDataTemp instanceof Array) {
246
328
  target[refNamePy][fieldNamePy] = oldDataTemp[0][fieldNamePy];//强制取第一行
247
329
  } else {
248
330
  target[refNamePy][fieldNamePy] = oldDataTemp[fieldNamePy] ? oldDataTemp[fieldNamePy] : 0;
@@ -271,10 +353,10 @@ class data {
271
353
  if (refNamePy != name) {
272
354
  targetObj = data[refNamePy];
273
355
  }
274
- if(targetObj instanceof Array){
275
- targetObj.forEach(titem => {
356
+ if (targetObj instanceof Array) {
357
+ targetObj.forEach(titem => {
276
358
  var primaryKey = titem[targetArray[1]];
277
- if(!refData[primaryKey]){//没找到对应行,直接返回
359
+ if (!refData[primaryKey]) {//没找到对应行,直接返回
278
360
  return;
279
361
  }
280
362
  var refDataTemp = refData[primaryKey][0][refNamePy];
@@ -289,7 +371,7 @@ class data {
289
371
  }
290
372
  //将结果赋值给实体对象
291
373
  var t = targetValue[refNamePy];
292
- Object.keys(t).forEach(key => {
374
+ t && Object.keys(t).forEach(key => {
293
375
  targetObj[key] = t[key];
294
376
  });
295
377
  }
@@ -324,7 +406,7 @@ class data {
324
406
  page: page,
325
407
  pageSize: size,
326
408
  filterFunc: function (row) {
327
- if (filterValue[row[refFieldPy]]) {
409
+ if (filterValue && filterValue[row[refFieldPy]]) {
328
410
  changeRefData.push({
329
411
  ref: row,
330
412
  formateValue: filterValue[row[refFieldPy]]
@@ -496,9 +578,9 @@ class data {
496
578
  }
497
579
  data[detailName].forEach(detail => {
498
580
  detail[crabatool.stringUtils.getFullPinyinCode(item.detailField)] = data[crabatool.stringUtils.getFullPinyinCode(item.masterField)];
499
- if (!detail.id) {//明细行ID为空时需要生成新值
500
- detail.id = cuid.newCuidString()
501
- }
581
+ // if (!detail.id) {//明细行ID为空时需要生成新值
582
+ // detail.id = cuid.newCuidString()
583
+ // }
502
584
  //嵌套处理明细中关联的主键和外键
503
585
  _this.buildDataPrimaryAndForeignKey(detailName, detail)
504
586
  });
package/lib/jsoncrud.js CHANGED
@@ -7,6 +7,7 @@ class JSONCRUD {
7
7
  * @param {Object} config - 配置项
8
8
  * @param {string} [config.storagePath] - 文件存储路径
9
9
  * @param {boolean} [config.useMemory] - 是否使用内存存储
10
+ * @param {boolean} [config.separateFiles] - 按实体分文件存储
10
11
  */
11
12
  constructor(config = {}) {
12
13
  this.config = config
@@ -33,29 +34,54 @@ class JSONCRUD {
33
34
  }
34
35
 
35
36
  // 保存到文件
36
- async saveToFile() {
37
+ async saveToFile(entityName) {
37
38
  if (!this.useMemory) {
38
- // 构建包含所有实体的存储对象
39
- const dataToSave = Object.entries(this.entities).reduce((acc, [entityName, entityData]) => {
40
- acc[entityName] = entityData.data
41
- return acc
42
- }, {})
39
+ var data = Object.entries(this.entities);
40
+ var tempStorageFile = this.storageFile;
41
+ var dataToSave = null;
42
+ if (this.config.separateFiles) {
43
+ //按文件拆分存储
44
+ data = entityName && this.entities[entityName] ? this.entities[entityName].data : {};
45
+ dataToSave = data;
46
+ tempStorageFile = path.join(tempStorageFile, entityName + '.json');
47
+ } else {
48
+ // 构建包含所有实体的存储对象
49
+ dataToSave = data.reduce((acc, [entityName, entityData]) => {
50
+ acc[entityName] = entityData.data
51
+ return acc
52
+ }, {})
53
+ }
43
54
 
44
55
  // 创建存储目录(如果不存在)
45
- await fs.mkdir(path.dirname(this.storageFile), { recursive: true })
56
+ await fs.mkdir(path.dirname(tempStorageFile), { recursive: true })
46
57
 
47
58
  // 原子化写入(避免写入过程中崩溃导致数据丢失)
48
- const tmpFile = `${this.storageFile}.tmp`
49
- try{
59
+ const tmpFile = `${tempStorageFile}.tmp`
60
+ try {
50
61
  //频繁写入时会导致数据错误
51
62
  await fs.writeFile(tmpFile, JSON.stringify(dataToSave, null, 2))
52
- await fs.rename(tmpFile, this.storageFile)
53
- }catch(e){
63
+ await fs.rename(tmpFile, tempStorageFile)
64
+ } catch (e) {
54
65
  console.log(e);
55
66
  }
56
67
  }
57
68
  }
58
69
 
70
+ async batchCreate(entityName, items) {
71
+ await this.ready()
72
+ this.verifyEntityExists(entityName)
73
+ var _this = this;
74
+ items.forEach(item=>{
75
+ const newItem = {
76
+ id: cuid.newCuidString(),//允许外部提前制定ID
77
+ ...item,
78
+ createdAt: new Date().toISOString()
79
+ }
80
+ _this.entities[entityName].data.push(newItem)
81
+ })
82
+ await this.persist(entityName)
83
+ }
84
+
59
85
  // 核心CRUD方法
60
86
  async create(entityName, item) {
61
87
  await this.ready()
@@ -67,7 +93,7 @@ class JSONCRUD {
67
93
  createdAt: new Date().toISOString()
68
94
  }
69
95
  this.entities[entityName].data.push(newItem)
70
- await this.persist()
96
+ await this.persist(entityName)
71
97
  return newItem
72
98
  }
73
99
 
@@ -135,6 +161,15 @@ class JSONCRUD {
135
161
  return this.entities[entityName].data[index]
136
162
  }
137
163
 
164
+ async getByField(entityName, field, value) {
165
+ await this.ready()
166
+ this.verifyEntityExists(entityName)
167
+
168
+ const index = this.entities[entityName].data.findIndex(item => item[field] === value)
169
+ if (index === -1) return null
170
+ return this.entities[entityName].data[index]
171
+ }
172
+
138
173
  async update(entityName, id, updates) {
139
174
  await this.ready()
140
175
  this.verifyEntityExists(entityName)
@@ -147,15 +182,15 @@ class JSONCRUD {
147
182
  ...updates,
148
183
  updatedAt: new Date().toISOString()
149
184
  }
150
- await this.persist()
185
+ await this.persist(entityName)
151
186
  return this.entities[entityName].data[index]
152
187
  }
153
188
 
154
- async batchUpdate(entityName, items){
189
+ async batchUpdate(entityName, items) {
155
190
  await this.ready()
156
191
  this.verifyEntityExists(entityName)
157
192
 
158
- items.forEach(entity =>{
193
+ items.forEach(entity => {
159
194
  const index = this.entities[entityName].data.findIndex(item => item.id === entity.id)
160
195
  if (index === -1) return null
161
196
 
@@ -165,7 +200,7 @@ class JSONCRUD {
165
200
  updatedAt: new Date().toISOString()
166
201
  }
167
202
  })
168
- await this.persist()
203
+ await this.persist(entityName)
169
204
  }
170
205
 
171
206
  async delete(entityName, id) {
@@ -177,7 +212,7 @@ class JSONCRUD {
177
212
  item => item.id !== id
178
213
  )
179
214
  const success = this.entities[entityName].data.length < initialLength
180
- if (success) await this.persist()
215
+ if (success) await this.persist(entityName)
181
216
  return success
182
217
  }
183
218
 
@@ -194,14 +229,40 @@ class JSONCRUD {
194
229
  await new Promise(resolve => setTimeout(resolve, 50))
195
230
  }
196
231
  }
232
+ async readAllFilesInDirectory(dirPath) {
233
+ try {
234
+ var fileContent = {};
235
+ const files = await fs.readdir(dirPath);
236
+ for (const file of files) {
237
+ const filePath = path.join(dirPath, file);
238
+ var stats = await fs.stat(filePath);
239
+ if (stats.isFile()) {
240
+ var entityName = file.substring(0, file.lastIndexOf('.'));
241
+ var temp = await fs.readFile(filePath, 'utf-8')
242
+ fileContent[entityName] = temp?JSON.parse(temp):{};
243
+ } else if (stats.isDirectory()) {
244
+ // 如果需要递归处理子目录,可以在这里调用readAllFilesInDirectory(filePath)
245
+ }
246
+ }
247
+ return fileContent;
248
+ } catch (err) {
249
+ return {};
250
+ }
251
+ }
197
252
 
198
253
  // 初始化文件存储
199
254
  async initFileStorage() {
200
255
  try {
201
- // 1. 读取存储文件内容
202
- const fileContent = await fs.readFile(this.storageFile, 'utf-8')
203
- const storedData = JSON.parse(fileContent || '{}')
204
-
256
+ var fileContent = null;
257
+ var storedData = {};
258
+ if (this.config.separateFiles) {
259
+ var dir = this.storageFile;
260
+ storedData = await this.readAllFilesInDirectory(dir);//读取文件夹中的所有文件
261
+ } else {
262
+ // 1. 读取存储文件内容
263
+ fileContent = await fs.readFile(this.storageFile, 'utf-8')
264
+ storedData = JSON.parse(fileContent || '{}')
265
+ }
205
266
  // 2. 自动创建存储中的实体(如果尚未定义)
206
267
  Object.keys(storedData).forEach(entityName => {
207
268
  if (!this.entities[entityName]) {
@@ -221,7 +282,6 @@ class JSONCRUD {
221
282
  }))
222
283
  }
223
284
  })
224
-
225
285
  } catch (err) {
226
286
  if (err.code === 'ENOENT') {
227
287
  // 4. 文件不存在时初始化空文件
@@ -240,9 +300,9 @@ class JSONCRUD {
240
300
  }
241
301
 
242
302
  // 通用保存方法
243
- async persist() {
303
+ async persist(entityName) {
244
304
  if (this.useMemory) return
245
- await this.saveToFile()
305
+ await this.saveToFile(entityName)
246
306
  }
247
307
 
248
308
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crabatool",
3
- "version": "1.0.410",
3
+ "version": "1.0.414",
4
4
  "description": "crabatool",
5
5
  "main": "index.js",
6
6
  "bin": {
package/tool/checkjs.js CHANGED
@@ -250,7 +250,8 @@ module.exports.start = async function() {
250
250
  }
251
251
 
252
252
  reportData.data = {
253
- errorCount: errKeys.length + undefKeys.length,
253
+ errorCount: errKeys.length,
254
+ undefCount: undefKeys.length, // 未定义总数
254
255
  warnCount: warnKeys.length,
255
256
  tipCount: infoKeys.length,
256
257
  fileSize: fileSize,
@@ -281,7 +282,7 @@ module.exports.start = async function() {
281
282
  webhookList.push(`1. js语法undefined:${undefKeys.length}个,占比${calc(undefKeys.length, jsFiles.length)}`);
282
283
 
283
284
  // 随机显示5个异常文件到钉钉消息
284
- var errCount = reportData.data.errCount;
285
+ var errCount = reportData.data.errCount + reportData.data.undefCount;
285
286
  /*
286
287
  if (errCount > 0) {
287
288
  var list0 = [];
package/tool/compress.js CHANGED
@@ -88,6 +88,11 @@ function doCompress() {
88
88
  inNames = ['grid.js', 'controlsEx.js', 'treeView.js', 'print.js', 'workflow.js', '../../Carpa.Dress/Dress.js', 'htmlEditor.js'];
89
89
  compressCrabaJs(inNames, 'crabaEx.min.js');
90
90
 
91
+ // workflow流程图
92
+ //inNames = ['workflow.js'];
93
+ //compressCrabaJs(inNames, 'workflow.js');
94
+
95
+
91
96
  // echarts
92
97
  inNames = ['echarts4-all.js'];
93
98
  compressCrabaJs(inNames, 'echarts-all.js');
package/tool/gspxHash.js DELETED
@@ -1,90 +0,0 @@
1
-
2
- var config = require('../lib/config.js');
3
- var path = require('path');
4
- var fs = require('fs');
5
- var utils = require('../lib/utils.js');
6
- var os = require('os');
7
- const crypto = require('crypto');
8
- var requestSync = require('sync-request');
9
-
10
-
11
- module.exports.start = function() {
12
- if (!config.hashName) {
13
- config.hashName = 'sha384';
14
- }
15
-
16
- if (!config.files) {
17
- config.files = [];
18
- }
19
-
20
- var results = {};
21
- buildFiles(results, config.files);
22
-
23
- utils.mkdirsSync(config.outJson);
24
- fs.writeFileSync(config.outJson, JSON.stringify(results));
25
- }
26
-
27
- function buildFiles(results, files) {
28
- files.forEach(function(f) {
29
- console.log(f);
30
-
31
- var content;
32
- var isHttp = f.startsWith('http');
33
- if (isHttp) {
34
- var res = requestSync("GET", f);
35
- content = res.getBody();
36
- } else if (fs.existsSync(f)) {
37
-
38
- // 磁盘目录
39
- var statFs = fs.statSync(f);
40
- if (!statFs.isFile()) {
41
- var files2 = fs.readdirSync(f);
42
- files2 = files2.map(function(s) {
43
- return utils.join(f, s);
44
- });
45
- buildFiles(results, files2);
46
- return;
47
- }
48
-
49
- if (config.exts && config.exts.length > 0) {
50
- var ext = path.extname(f).toLowerCase();
51
- if (!config.exts.includes(ext)) {
52
- return;
53
- }
54
- }
55
-
56
- content = fs.readFileSync(f);
57
- } else {
58
- console.error('文件不存在:' + f);
59
- return;
60
- }
61
-
62
- var index = f.indexOf('?');
63
- if (index > 0) {
64
- f = f.substr(0, index);
65
- }
66
-
67
- // 转为相对webPath的路径
68
- if (!isHttp) {
69
- f = path.resolve(f);
70
- var webPath = path.resolve(config.webPath);
71
- f = f.replace(webPath, '');
72
- if (config.modName) {
73
- f = path.join(config.modName, f);
74
- }
75
- f = f.replace(/\\/g, '/');
76
- }
77
-
78
- // SRI Hash Generator
79
- // https://www.srihash.org/
80
-
81
- var base64 = makeHash(content, config.hashName); // 将文件内容进行hash计算
82
- results[f] = config.hashName + '-' + base64; // 使用 base64 编码 sha384 算法计算出摘要后的 integrity 值的示例
83
- });
84
- }
85
-
86
- function makeHash(str, name) {
87
- const hash = crypto.createHash(name);
88
- hash.update(str);
89
- return hash.digest('base64');
90
- }