crabatool 1.0.410 → 1.0.415
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 +117 -26
- package/lib/jsoncrud.js +87 -27
- package/lib/server.js +6 -1
- package/lib/utils.js +37 -0
- package/package.json +5 -2
- package/res/Login.gspx +34 -0
- package/res/Login.js +155 -0
- package/res/login.html +102 -0
- package/tool/checkjs.js +3 -2
- package/tool/compress.js +5 -0
- package/tool/start.js +2 -0
- package/tool/gspxHash.js +0 -90
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/
|
|
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
|
-
|
|
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
|
|
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,8 +105,65 @@ 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
|
-
var
|
|
165
|
+
var db = this._getDb(req);
|
|
166
|
+
var oldEntity = await db.get(body.name, body.data.id);
|
|
109
167
|
if (!oldEntity) {
|
|
110
168
|
crabatool.utils.end(res, {
|
|
111
169
|
code: 404,
|
|
@@ -113,6 +171,8 @@ class data {
|
|
|
113
171
|
});
|
|
114
172
|
return;
|
|
115
173
|
}
|
|
174
|
+
|
|
175
|
+
await this.fillData(body.name, [oldEntity], db, true);
|
|
116
176
|
//退回联动老数据
|
|
117
177
|
var rt = await this.pageSaveToDataLinkage(req, body.name, pageName, oldEntity, null, true);
|
|
118
178
|
return {
|
|
@@ -125,6 +185,8 @@ class data {
|
|
|
125
185
|
|
|
126
186
|
var newData;
|
|
127
187
|
var pageName = body.pageName;
|
|
188
|
+
var db = this._getDb(req);
|
|
189
|
+
var rtData = JSON.parse(JSON.stringify(body.data));
|
|
128
190
|
if (body.data.id) {
|
|
129
191
|
var oldData = await this.reverseData(req, pageName, body);
|
|
130
192
|
if (!oldData) {
|
|
@@ -133,23 +195,46 @@ class data {
|
|
|
133
195
|
await this.buildDataPrimaryAndForeignKey(body.name, body.data, true);
|
|
134
196
|
//更新联动新数据
|
|
135
197
|
await this.pageSaveToDataLinkage(req, body.name, pageName, body.data, oldData);
|
|
136
|
-
|
|
198
|
+
var name = body.name;
|
|
199
|
+
await this._saveRefData(name, body.data, rtData, db);
|
|
200
|
+
await db.update(body.name, body.data.id, body.data);
|
|
137
201
|
newData = body.data;
|
|
138
202
|
} else {
|
|
139
203
|
//提前制定ID
|
|
140
204
|
body.data.id = cuid.newCuidString()
|
|
141
205
|
await this.buildDataPrimaryAndForeignKey(body.name, body.data);
|
|
142
206
|
await this.pageSaveToDataLinkage(req, body.name, pageName, body.data)
|
|
143
|
-
|
|
207
|
+
await this._saveRefData(name, body.data, rtData, db);
|
|
208
|
+
newData = await db.create(body.name, body.data);
|
|
144
209
|
}
|
|
145
210
|
|
|
146
211
|
crabatool.utils.end(res, {
|
|
147
212
|
code: 200,
|
|
148
213
|
msg: '操作成功',
|
|
149
|
-
data:
|
|
214
|
+
data: rtData
|
|
150
215
|
});
|
|
151
216
|
}
|
|
152
217
|
|
|
218
|
+
async _saveRefData(name, data, rtData, db) {
|
|
219
|
+
var dataRefs = this.dslMap[name].dataRefs;
|
|
220
|
+
for (var i = 0; dataRefs && i < dataRefs.length; i++) {
|
|
221
|
+
var dataRef = dataRefs[i];
|
|
222
|
+
var detailPy = crabatool.stringUtils.getFullPinyinCode(dataRef.detail)
|
|
223
|
+
var details = data[detailPy] ? data[detailPy] : [];
|
|
224
|
+
delete data[detailPy];
|
|
225
|
+
for (var j = 0; j < details.length; j++) {
|
|
226
|
+
var detail = details[j];
|
|
227
|
+
if (detail.id) {
|
|
228
|
+
await db.update(detailPy, detail.id, detail)
|
|
229
|
+
} else {
|
|
230
|
+
await db.create(detailPy, detail)
|
|
231
|
+
rtData[detailPy][j].id = detail.id;//补充新增行的ID
|
|
232
|
+
}
|
|
233
|
+
await this._saveRefData(detailPy, detail, rtData[detailPy][j], db);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
153
238
|
findLayerData(data, items, layer) {
|
|
154
239
|
if (!data) {
|
|
155
240
|
return null;
|
|
@@ -205,9 +290,9 @@ class data {
|
|
|
205
290
|
}
|
|
206
291
|
//查找涉及的所有实体
|
|
207
292
|
var _this = this;
|
|
208
|
-
for(var i = 0
|
|
293
|
+
for (var i = 0; i < actions.length; i++) {
|
|
209
294
|
var action = actions[i];
|
|
210
|
-
for(var j = 0
|
|
295
|
+
for (var j = 0; j < action.length; j++) {
|
|
211
296
|
var item = action[j];
|
|
212
297
|
if (item.type == 'external') {//外表处理
|
|
213
298
|
await _this.externalDataLinkage(req, name, data, item, reverseNumber);
|
|
@@ -215,7 +300,7 @@ class data {
|
|
|
215
300
|
//从原始数据中获取对应字段的数据
|
|
216
301
|
var targetRef = _this.findFormateItem(item.filter.refField)
|
|
217
302
|
var targetRefField = _this.findFormateItem(`#[${item.ref}.${item.field}]`)
|
|
218
|
-
var targetValue = _this.findItemMapData(name, crabatool.stringUtils.getFullPinyinCode(item.ref), data, new Set([...targetRef, ...targetRefField]));
|
|
303
|
+
var targetValue = _this.findItemMapData(name, crabatool.stringUtils.getFullPinyinCode(item.ref), data, new Set([...targetRef, ...targetRefField, `${item.ref}.id`]));
|
|
219
304
|
var refFieldName = this.matchFields(item.filter.refField)[0];
|
|
220
305
|
var refFieldNamePy = crabatool.stringUtils.getFullPinyinCode(refFieldName);
|
|
221
306
|
var targetArray = refFieldNamePy.split('.')
|
|
@@ -232,18 +317,24 @@ class data {
|
|
|
232
317
|
//根据refData和sourceData计算结果
|
|
233
318
|
var refNamePy = crabatool.stringUtils.getFullPinyinCode(item.ref);
|
|
234
319
|
var fieldNamePy = crabatool.stringUtils.getFullPinyinCode(item.field);
|
|
235
|
-
Object.keys(refData).forEach(key => {
|
|
320
|
+
refData && Object.keys(refData).forEach(key => {
|
|
236
321
|
var target = refData[key][0];
|
|
237
322
|
//目标值为单一对象
|
|
238
323
|
if (!target[refNamePy]) {
|
|
239
324
|
return;
|
|
240
325
|
}
|
|
241
326
|
if (oldData) {
|
|
242
|
-
if(name != refNamePy){
|
|
327
|
+
if (name != refNamePy) {
|
|
243
328
|
//传入了老数据,当前计算的值可以直接取老数据的对应值,因为它已经排除本单
|
|
244
329
|
var oldDataTemp = oldData[name][refNamePy];
|
|
245
|
-
if(oldDataTemp instanceof Array){
|
|
246
|
-
target[refNamePy][fieldNamePy] =
|
|
330
|
+
if (oldDataTemp instanceof Array) {
|
|
331
|
+
target[refNamePy][fieldNamePy] = 0;
|
|
332
|
+
for(var m = 0 ; m < oldDataTemp.length; m++){
|
|
333
|
+
if(oldDataTemp[m].id == target[refNamePy].id){
|
|
334
|
+
target[refNamePy][fieldNamePy] = oldDataTemp[m][fieldNamePy];
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
247
338
|
} else {
|
|
248
339
|
target[refNamePy][fieldNamePy] = oldDataTemp[fieldNamePy] ? oldDataTemp[fieldNamePy] : 0;
|
|
249
340
|
}
|
|
@@ -271,10 +362,10 @@ class data {
|
|
|
271
362
|
if (refNamePy != name) {
|
|
272
363
|
targetObj = data[refNamePy];
|
|
273
364
|
}
|
|
274
|
-
if(targetObj instanceof Array){
|
|
275
|
-
targetObj.forEach(titem => {
|
|
365
|
+
if (targetObj instanceof Array) {
|
|
366
|
+
targetObj.forEach(titem => {
|
|
276
367
|
var primaryKey = titem[targetArray[1]];
|
|
277
|
-
if(!refData[primaryKey]){//没找到对应行,直接返回
|
|
368
|
+
if (!refData[primaryKey]) {//没找到对应行,直接返回
|
|
278
369
|
return;
|
|
279
370
|
}
|
|
280
371
|
var refDataTemp = refData[primaryKey][0][refNamePy];
|
|
@@ -289,7 +380,7 @@ class data {
|
|
|
289
380
|
}
|
|
290
381
|
//将结果赋值给实体对象
|
|
291
382
|
var t = targetValue[refNamePy];
|
|
292
|
-
Object.keys(t).forEach(key => {
|
|
383
|
+
t && Object.keys(t).forEach(key => {
|
|
293
384
|
targetObj[key] = t[key];
|
|
294
385
|
});
|
|
295
386
|
}
|
|
@@ -324,7 +415,7 @@ class data {
|
|
|
324
415
|
page: page,
|
|
325
416
|
pageSize: size,
|
|
326
417
|
filterFunc: function (row) {
|
|
327
|
-
if (filterValue[row[refFieldPy]]) {
|
|
418
|
+
if (filterValue && filterValue[row[refFieldPy]]) {
|
|
328
419
|
changeRefData.push({
|
|
329
420
|
ref: row,
|
|
330
421
|
formateValue: filterValue[row[refFieldPy]]
|
|
@@ -496,9 +587,9 @@ class data {
|
|
|
496
587
|
}
|
|
497
588
|
data[detailName].forEach(detail => {
|
|
498
589
|
detail[crabatool.stringUtils.getFullPinyinCode(item.detailField)] = data[crabatool.stringUtils.getFullPinyinCode(item.masterField)];
|
|
499
|
-
if (!detail.id) {//明细行ID为空时需要生成新值
|
|
500
|
-
|
|
501
|
-
}
|
|
590
|
+
// if (!detail.id) {//明细行ID为空时需要生成新值
|
|
591
|
+
// detail.id = cuid.newCuidString()
|
|
592
|
+
// }
|
|
502
593
|
//嵌套处理明细中关联的主键和外键
|
|
503
594
|
_this.buildDataPrimaryAndForeignKey(detailName, detail)
|
|
504
595
|
});
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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(
|
|
56
|
+
await fs.mkdir(path.dirname(tempStorageFile), { recursive: true })
|
|
46
57
|
|
|
47
58
|
// 原子化写入(避免写入过程中崩溃导致数据丢失)
|
|
48
|
-
const tmpFile = `${
|
|
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,
|
|
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
|
|
|
@@ -101,7 +127,7 @@ class JSONCRUD {
|
|
|
101
127
|
const end = start + pageSize
|
|
102
128
|
|
|
103
129
|
return {
|
|
104
|
-
data: sorted.slice(start, end),
|
|
130
|
+
data: JSON.parse(JSON.stringify(sorted.slice(start, end))),
|
|
105
131
|
pageData: {
|
|
106
132
|
count: allData.length,
|
|
107
133
|
page,
|
|
@@ -132,7 +158,16 @@ class JSONCRUD {
|
|
|
132
158
|
|
|
133
159
|
const index = this.entities[entityName].data.findIndex(item => item.id === id)
|
|
134
160
|
if (index === -1) return null
|
|
135
|
-
return this.entities[entityName].data[index]
|
|
161
|
+
return JSON.parse(JSON.stringify(this.entities[entityName].data[index]))
|
|
162
|
+
}
|
|
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 JSON.parse(JSON.stringify(this.entities[entityName].data[index]))
|
|
136
171
|
}
|
|
137
172
|
|
|
138
173
|
async update(entityName, id, updates) {
|
|
@@ -147,15 +182,15 @@ class JSONCRUD {
|
|
|
147
182
|
...updates,
|
|
148
183
|
updatedAt: new Date().toISOString()
|
|
149
184
|
}
|
|
150
|
-
await this.persist()
|
|
151
|
-
return this.entities[entityName].data[index]
|
|
185
|
+
await this.persist(entityName)
|
|
186
|
+
return JSON.parse(JSON.stringify(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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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/lib/server.js
CHANGED
|
@@ -92,6 +92,11 @@ function createServer(app, options) {
|
|
|
92
92
|
app.use(utils.rewriteCrabaJs);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
// 统一拦截login.html
|
|
96
|
+
if (config.modName && !config.localLogin) {
|
|
97
|
+
app.use(utils.rewriteLoginHTML);
|
|
98
|
+
}
|
|
99
|
+
|
|
95
100
|
// 指定静态文件目录
|
|
96
101
|
var webPath = config.webPath;
|
|
97
102
|
if (options) {
|
|
@@ -111,7 +116,7 @@ function createServer(app, options) {
|
|
|
111
116
|
res.setHeader('Content-Type', 'text/html; charset=utf-8'); // 当做文本输出,才能显示到iframe中
|
|
112
117
|
}
|
|
113
118
|
var name = path.basename(pathname);
|
|
114
|
-
if (name == 'index.html') {
|
|
119
|
+
if (name == 'index.html' || name == 'login.html') {
|
|
115
120
|
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
|
116
121
|
res.setHeader('Pragma', 'no-cache');
|
|
117
122
|
res.setHeader('Expires', '0');
|
package/lib/utils.js
CHANGED
|
@@ -527,6 +527,43 @@ class Utils {
|
|
|
527
527
|
res.end(content);
|
|
528
528
|
}
|
|
529
529
|
|
|
530
|
+
|
|
531
|
+
rewriteLoginHTML(req, res, next) {
|
|
532
|
+
var url = req.originalUrl;
|
|
533
|
+
if (url.startsWith('/login.html')) {
|
|
534
|
+
var htmlPath = utils.join(__dirname, '../res/login.html');
|
|
535
|
+
var content = fs.readFileSync(htmlPath).toString();
|
|
536
|
+
content = content.replaceAll('${modName}', config.modName);
|
|
537
|
+
|
|
538
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8'); // 当做文本输出,才能显示到iframe中
|
|
539
|
+
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
|
540
|
+
res.setHeader('Pragma', 'no-cache');
|
|
541
|
+
res.setHeader('Expires', '0');
|
|
542
|
+
res.end(content);
|
|
543
|
+
} else if (url.startsWith('/crabatool/Login.gspx')) {
|
|
544
|
+
var htmlPath = utils.join(__dirname, '../res/Login.gspx');
|
|
545
|
+
var content = fs.readFileSync(htmlPath).toString();
|
|
546
|
+
content = content.replaceAll('${modName}', config.modName);
|
|
547
|
+
|
|
548
|
+
res.setHeader('Content-Type', 'text/plain; charset=utf-8'); // 当做文本输出,才能显示到iframe中
|
|
549
|
+
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
|
550
|
+
res.setHeader('Pragma', 'no-cache');
|
|
551
|
+
res.setHeader('Expires', '0');
|
|
552
|
+
res.end(content);
|
|
553
|
+
} else if (url.startsWith('/crabatool/Login.js')) {
|
|
554
|
+
var htmlPath = utils.join(__dirname, '../res/Login.js');
|
|
555
|
+
var content = fs.readFileSync(htmlPath).toString();
|
|
556
|
+
content = content.replaceAll('${modName}', config.modName);
|
|
557
|
+
|
|
558
|
+
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
|
559
|
+
res.setHeader('Pragma', 'no-cache');
|
|
560
|
+
res.setHeader('Expires', '0');
|
|
561
|
+
res.end(content);
|
|
562
|
+
} else {
|
|
563
|
+
next();
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
530
567
|
getFiles(options, fileList) {
|
|
531
568
|
var exts = options.exts;
|
|
532
569
|
var source = options.source;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "crabatool",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.415",
|
|
4
4
|
"description": "crabatool",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -28,7 +28,10 @@
|
|
|
28
28
|
"makeHash2": "node run.js -makeHash -webPath ./test/ -modName craba -files ./test/ -exts .js -outJson ./hash2.json -hashName sha384",
|
|
29
29
|
"pageHash": "node run.js -pageHash /Test/TestMasterDetail.gspx",
|
|
30
30
|
"addVersion": "node run.js -addVersion -file F:\\basicweb\\www\\index.html -exp AUTOVERSION",
|
|
31
|
-
"gspxHash": "node run.js -gspxHash -webPath F:\\Beefun\\srcs\\Beefun"
|
|
31
|
+
"gspxHash": "node run.js -gspxHash -webPath F:\\Beefun\\srcs\\Beefun",
|
|
32
|
+
"runShell": "node run.js -run -webPath F:\\shell-gerrit\\web\\src\\main\\resources\\static\\shell\\ -port 10000 -modName shell",
|
|
33
|
+
"runShellLocal": "node run.js -run -webPath F:\\shell-gerrit\\web\\src\\main\\resources\\static\\shell\\ -port 10000 -modName shell -localLogin true",
|
|
34
|
+
"runJxc": "node run.js -run -webPath F:\\jxc\\jxc-web\\src\\main\\resources\\static\\jxc\\ -port 10001 -modName jxc"
|
|
32
35
|
},
|
|
33
36
|
"author": "wssf",
|
|
34
37
|
"dependencies": {
|
package/res/Login.gspx
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<Page xmlns="Craba.UI" Title="NGP开发环境统一登录入口" ActionType="crabatool.LoginAction, crabatool/Login.js" DataSource='${formData}'>
|
|
3
|
+
<FlexColumn CssClass='FlexCenter MainBg'>
|
|
4
|
+
<FlowPanel Caption='Ngp模块登录' CssClass='VertItem' LayoutDirection='Vert' ItemLabelWidth='70' ItemCssClass='FlexAuto'>
|
|
5
|
+
<TextEdit Label='公司名称:' DataField='companyName' Required="true" />
|
|
6
|
+
<TextEdit Label='职员名称:' DataField='employeeName' Required="true" />
|
|
7
|
+
<DropDownEdit Label='指定产品:' DataField='productId' DataSource='${formData.products}' DataTextField='name' DataValueField='id' Required="true" OnChange="doChangeProduct" />
|
|
8
|
+
<HBlock Label='服务版本:'>
|
|
9
|
+
<TextEdit DataField='deploy' CssClass='FlexAuto' NullDisplayText='不填写则使用默认账套账本' />
|
|
10
|
+
<DropDownEdit DataField='productDeploy' DataSource="${formData.productDeploys}" DataTextField='deployName' DataValueField='deployName' />
|
|
11
|
+
</HBlock>
|
|
12
|
+
<TextEdit Label='本地端口:' DataField='localPort' Required="true" />
|
|
13
|
+
|
|
14
|
+
<Grid ID='grid' DataField="routes" AutoMaxRowCount="8" AllowConfig='false' ReadOnly='false'>
|
|
15
|
+
<TextColumn Caption="模块名称" DataField="serverName" AllowStretch='true' NullDisplayText='微服务名称' />
|
|
16
|
+
<TextColumn Caption="Ip" DataField="serverIp" AllowStretch='true' NullDisplayText='微服务IP地址' />
|
|
17
|
+
<TextColumn Caption="端口" DataField="serverPort" AllowStretch='true' NullDisplayText='微服务端口号' />
|
|
18
|
+
<RowDeleteColumn Caption="操作" />
|
|
19
|
+
</Grid>
|
|
20
|
+
|
|
21
|
+
<FlexBlock CssClass='BottomBlock FlexRight'>
|
|
22
|
+
<Button Text='添加路由' OnClick='addRoute' />
|
|
23
|
+
<Button Text='登录' CssClass='SpecialButton' OnClick="doLogin" />
|
|
24
|
+
</FlexBlock>
|
|
25
|
+
</FlowPanel>
|
|
26
|
+
</FlexColumn>
|
|
27
|
+
|
|
28
|
+
<Style>
|
|
29
|
+
.MainBg{background-color: #374979;}
|
|
30
|
+
.MainBg .FlowPanel{border-radius:8px;box-shadow:0 0 18px #111;width:600px;}
|
|
31
|
+
.MainBg .FlowPanel .FlowItem{padding:10px 20px;margin:0;}
|
|
32
|
+
.MainBg .GridBlock{margin:10px 20px}
|
|
33
|
+
</Style>
|
|
34
|
+
</Page>
|
package/res/Login.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
Type.registerNamespace('crabatool');
|
|
2
|
+
crabatool.LoginAction = function() {
|
|
3
|
+
crabatool.LoginAction.initializeBase(this);
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
crabatool.LoginAction.prototype = {
|
|
7
|
+
context: function(cb) {
|
|
8
|
+
this.initData(cb);
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
initialize: function LoginAction$initialize() {
|
|
12
|
+
crabatool.LoginAction.callBaseMethod(this, 'initialize');
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
initData: function(cb) {
|
|
16
|
+
var data = {
|
|
17
|
+
companyName: "",
|
|
18
|
+
employeeName: "",
|
|
19
|
+
productId: "0",
|
|
20
|
+
deploy: "",
|
|
21
|
+
localPort: "",
|
|
22
|
+
routes: [],
|
|
23
|
+
products: [],
|
|
24
|
+
deploys: {},
|
|
25
|
+
productDeploys: [],
|
|
26
|
+
productDeploy: ""
|
|
27
|
+
};
|
|
28
|
+
var formData = { formData: data }; // 窗体数据
|
|
29
|
+
|
|
30
|
+
var routes = localStorage.getItem("routes");
|
|
31
|
+
if (routes) {
|
|
32
|
+
routes = JSON.parse(routes);
|
|
33
|
+
data.routes = routes;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
var user = localStorage.getItem("user");
|
|
37
|
+
if (user) {
|
|
38
|
+
user = JSON.parse(user);
|
|
39
|
+
data.companyName = user.companyName;
|
|
40
|
+
data.employeeName = user.employeeName;
|
|
41
|
+
data.productId = user.productId;
|
|
42
|
+
data.deploy = user.deploy;
|
|
43
|
+
data.localPort = user.port || user.localPort || "";
|
|
44
|
+
data.productDeploy = user.productDeploy || "";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
var route = localStorage.getItem("route");
|
|
48
|
+
if (route) {
|
|
49
|
+
route = JSON.parse(route);
|
|
50
|
+
this.setRoute(route, data);
|
|
51
|
+
this.login();
|
|
52
|
+
this.end(); // 不继续处理Login.gspx
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
var that = this;
|
|
57
|
+
$common.ajax({
|
|
58
|
+
url: 'http://172.17.0.237:56789/ngp/auth/init',
|
|
59
|
+
type: 'GET',
|
|
60
|
+
success: function(res) {
|
|
61
|
+
if (res.code != "200") {
|
|
62
|
+
$common.alertError("初始化信息失败");
|
|
63
|
+
that.end();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
data.deploys = res.data.deploys;
|
|
68
|
+
data.products = res.data.products;
|
|
69
|
+
console.log(data.productId);
|
|
70
|
+
data.productDeploys = res.data.deploys[data.productId];
|
|
71
|
+
cb(formData);
|
|
72
|
+
},
|
|
73
|
+
error: function() {
|
|
74
|
+
$common.alertError("网络请求失败");
|
|
75
|
+
that.end();
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
dispose: function() {
|
|
81
|
+
crabatool.LoginAction.callBaseMethod(this, 'dispose');
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
setRoute: function(route, data) {
|
|
85
|
+
route.deploy = data.deploy || (data.productDeploy || route.deploy);
|
|
86
|
+
route.productId = (data.productId == "0") ? route.productId : data.productId;
|
|
87
|
+
var debugMs = {};
|
|
88
|
+
for (var key in route) {
|
|
89
|
+
debugMs[key] = route[key];
|
|
90
|
+
}
|
|
91
|
+
debugMs.aloneDeploy = '${modName}';
|
|
92
|
+
debugMs.gateway = "http://eshop.gateway.ngp.wsgjp.com.cn";
|
|
93
|
+
debugMs.aloneServer = "http://" + location.hostname + ":" + data.localPort;
|
|
94
|
+
$ms.router = {//设置请求路由
|
|
95
|
+
debugMs: debugMs,
|
|
96
|
+
'ngp-authorization': 'jwt',
|
|
97
|
+
'ngp-router': 'ngprt'
|
|
98
|
+
};
|
|
99
|
+
if (data.routes.length > 0) {
|
|
100
|
+
var server = {};
|
|
101
|
+
for (var i = 0; i < data.routes.length; i++) {
|
|
102
|
+
var r = data.routes[i];
|
|
103
|
+
server[r.serverName] = r.serverIp + ":" + r.serverPort;
|
|
104
|
+
}
|
|
105
|
+
$ms.server = server;
|
|
106
|
+
}
|
|
107
|
+
var cookieStr = JSON.stringify(route);
|
|
108
|
+
$common.setCookieNoEscape("ngp-route", cookieStr);
|
|
109
|
+
localStorage.setItem("route", JSON.stringify(route));
|
|
110
|
+
},
|
|
111
|
+
login: function() {
|
|
112
|
+
$common.setCookieNoEscape('ngp-authorization', 'jwt');
|
|
113
|
+
$common.setCookieNoEscape('ngp-router', 'ngprt');
|
|
114
|
+
$common.setCookie('debugMs', JSON.stringify($ms.router.debugMs));
|
|
115
|
+
|
|
116
|
+
location.reload();
|
|
117
|
+
},
|
|
118
|
+
doLogin: function(sender) {
|
|
119
|
+
var user = this.get_form().saveData({clear:true});
|
|
120
|
+
var data = {
|
|
121
|
+
companyName: user.companyName,
|
|
122
|
+
userName: user.employeeName
|
|
123
|
+
};
|
|
124
|
+
localStorage.setItem("user", JSON.stringify(user));
|
|
125
|
+
localStorage.setItem("routes", JSON.stringify(user.routes));
|
|
126
|
+
|
|
127
|
+
var that = this;
|
|
128
|
+
$common.ajax({
|
|
129
|
+
url: "http://172.17.0.237:56789/ngp/auth/login",
|
|
130
|
+
data: data,
|
|
131
|
+
success: function(res) {
|
|
132
|
+
if (res.code != "200") {
|
|
133
|
+
$common.alertError("登录失败,请检查公司名称和职员名称是否正确");
|
|
134
|
+
} else {
|
|
135
|
+
that.setRoute(res.data, user);
|
|
136
|
+
that.login();
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
error: function() {
|
|
140
|
+
$common.alertError("网络请求失败");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
addRoute: function(sender) {
|
|
146
|
+
this.get_form().grid.appendRowData({});
|
|
147
|
+
},
|
|
148
|
+
doChangeProduct: function(sender) {
|
|
149
|
+
var pid = sender.get_value();
|
|
150
|
+
var deploys = this.get_context('formData').deploys;
|
|
151
|
+
var pdeploys = deploys[pid];
|
|
152
|
+
sender.get_form().productDeploy.set_items(pdeploys);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
crabatool.LoginAction.registerClass('crabatool.LoginAction', Sys.UI.PageAction);
|
package/res/login.html
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-cn" translate="no">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<title>NGP开发环境统一登录入口</title>
|
|
6
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />
|
|
7
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
8
|
+
<link rel="shortcut icon" type="image/x-icon" href="${modName}/favicon.ico" />
|
|
9
|
+
</head>
|
|
10
|
+
|
|
11
|
+
<body>
|
|
12
|
+
<script>
|
|
13
|
+
var modeName = '${modName}'; // 按各组的模块名称修改
|
|
14
|
+
|
|
15
|
+
function startPage() { // 供agency内部调用
|
|
16
|
+
var authorization = $common.getCookie('ngp-authorization');
|
|
17
|
+
var ngp_route = $common.getCookie('ngp-route');
|
|
18
|
+
if (authorization && ngp_route) {
|
|
19
|
+
$ms.router = {//设置请求路由
|
|
20
|
+
debugMs: JSON.parse($common.getCookie('debugMs')),
|
|
21
|
+
'ngp-authorization': 'jwt',
|
|
22
|
+
'ngp-router': 'ngprt'
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
var routes = localStorage.getItem("routes");
|
|
26
|
+
if (routes) {
|
|
27
|
+
routes = JSON.parse(routes);
|
|
28
|
+
if (routes.length > 0) {
|
|
29
|
+
var server = {};
|
|
30
|
+
for (var i = 0; i < routes.length; i++) {
|
|
31
|
+
var r = routes[i];
|
|
32
|
+
server[r.serverName] = r.serverIp + ":" + r.serverPort;
|
|
33
|
+
}
|
|
34
|
+
$ms.server = server;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
var srcs = [];
|
|
39
|
+
srcs.push('shell/js/help.plug.js?rv=' + Math.random());
|
|
40
|
+
srcs.push('shell/js/init.js?rv=' + Math.random());
|
|
41
|
+
$common.loadScript(srcs, function() {
|
|
42
|
+
showMainPage();
|
|
43
|
+
});
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
showLoginPage();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function showMainPage() {
|
|
50
|
+
$skin.loadCss(modeName + '/skins/craba.min.css,shell/skins/shell.css', 'login', function() {
|
|
51
|
+
$craba.run(modeName + '/Main.gspx', modeName);
|
|
52
|
+
createLoginBtn();
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function showLoginPage() {
|
|
57
|
+
$skin.loadCss(modeName + '/skins/craba.min.css', 'login', function() {
|
|
58
|
+
$craba.run('crabatool/Login.gspx', modeName);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function createLoginBtn() {
|
|
63
|
+
var btn = $common.createClassDiv('Button');
|
|
64
|
+
btn.innerText = '重新登录';
|
|
65
|
+
btn.style.cssText = 'z-index: 9999;font-weight: bold;background-color:#03abf5;border:none;position:fixed;bottom:5px;right:5px;';
|
|
66
|
+
document.body.appendChild(btn);
|
|
67
|
+
$common.addClickHandler(btn, function() {
|
|
68
|
+
localStorage.removeItem("route");
|
|
69
|
+
$common.removeCookie('ngp-authorization');
|
|
70
|
+
location.reload();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function loadScript(src, cb) {
|
|
75
|
+
var script = document.createElement('script');
|
|
76
|
+
script.type = 'text/javascript';
|
|
77
|
+
script.onload = script.onreadystatechange = function() {
|
|
78
|
+
if (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") {
|
|
79
|
+
script.onload = script.onreadystatechange = script.onerror = null;
|
|
80
|
+
cb();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
script.onerror = function() {
|
|
84
|
+
script.onload = script.onreadystatechange = script.onerror = null;
|
|
85
|
+
cb();
|
|
86
|
+
};
|
|
87
|
+
script.src = src;
|
|
88
|
+
document.getElementsByTagName('HEAD')[0].appendChild(script);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
var agencyUrl = 'js/agency.js?vc=' + (new Date()).getTime(); // 加时间戳防止浏览器缓存
|
|
92
|
+
loadScript(agencyUrl, function() {
|
|
93
|
+
$agency.load(['js/craba.min.js',
|
|
94
|
+
'js/crabaEx.min.js',
|
|
95
|
+
'js/math.min.js',
|
|
96
|
+
'js/crabaNgp.js'
|
|
97
|
+
], {}, startPage); // 这里写死首页脚本,agency内部使用。所有脚本由agency内部版本号防止浏览器缓存
|
|
98
|
+
});
|
|
99
|
+
</script>
|
|
100
|
+
</body>
|
|
101
|
+
|
|
102
|
+
</html>
|
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
|
|
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/start.js
CHANGED
|
@@ -87,6 +87,8 @@ class Start {
|
|
|
87
87
|
{ name: '-abortUrl', type: '' },
|
|
88
88
|
{ name: '-reportHost', type: '' },
|
|
89
89
|
{ name: '-aiHost', type: '' },
|
|
90
|
+
{ name: '-defaultPage', type: '' },
|
|
91
|
+
{ name: '-localLogin', type: 'boolean' },
|
|
90
92
|
|
|
91
93
|
{ name: '-ignoreCheck', type: 'array' },
|
|
92
94
|
{ name: '-childModList', type: 'array' },
|
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
|
-
}
|