chanjs 2.1.0 → 2.3.0

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 (61) hide show
  1. package/App.js +387 -0
  2. package/base/Context.js +78 -0
  3. package/base/Controller.js +137 -0
  4. package/base/Database.js +314 -0
  5. package/base/Service.js +539 -0
  6. package/common/api.js +25 -0
  7. package/common/category.js +22 -0
  8. package/common/code.js +42 -0
  9. package/common/email.js +110 -0
  10. package/common/index.js +7 -0
  11. package/common/pages.js +86 -0
  12. package/common/sms.js +104 -0
  13. package/common/utils.js +73 -0
  14. package/config/code.js +110 -52
  15. package/config/index.js +10 -0
  16. package/config/paths.js +60 -0
  17. package/extend/art-template.js +46 -28
  18. package/extend/index.js +6 -0
  19. package/global/env.js +11 -5
  20. package/global/global.js +63 -39
  21. package/global/import.js +43 -39
  22. package/global/index.js +8 -3
  23. package/helper/cache.js +182 -0
  24. package/helper/data-parse.js +121 -37
  25. package/helper/db.js +71 -83
  26. package/helper/file.js +158 -208
  27. package/helper/filter.js +34 -0
  28. package/helper/html.js +30 -47
  29. package/helper/index.js +29 -5
  30. package/helper/ip.js +48 -31
  31. package/helper/jwt.js +78 -11
  32. package/helper/loader.js +93 -50
  33. package/helper/request.js +41 -144
  34. package/helper/sign.js +96 -33
  35. package/helper/time.js +89 -74
  36. package/helper/tree.js +77 -0
  37. package/index.js +15 -181
  38. package/middleware/cookie.js +20 -4
  39. package/middleware/cors.js +20 -0
  40. package/middleware/favicon.js +21 -5
  41. package/middleware/header.js +26 -9
  42. package/middleware/index.js +14 -23
  43. package/middleware/preventRetry.js +30 -0
  44. package/middleware/setBody.js +24 -10
  45. package/middleware/static.js +31 -10
  46. package/middleware/template.js +34 -14
  47. package/middleware/validator.js +43 -23
  48. package/middleware/waf.js +147 -287
  49. package/package.json +1 -1
  50. package/utils/checker.js +68 -0
  51. package/utils/error-handler.js +115 -0
  52. package/utils/error.js +81 -0
  53. package/utils/index.js +6 -0
  54. package/utils/keywords.js +126 -0
  55. package/utils/rate-limit.js +116 -0
  56. package/utils/response.js +103 -64
  57. package/utils/xss-filter.js +42 -0
  58. package/core/controller.js +0 -33
  59. package/core/index.js +0 -3
  60. package/core/service.js +0 -296
  61. package/middleware/log.js +0 -21
@@ -0,0 +1,539 @@
1
+ /**
2
+ * 数据库服务基类
3
+ * 提供常用的数据库操作方法,包括增删改查、分页查询、事务等
4
+ */
5
+ import { formatTime, formatDateFields } from "../helper/time.js";
6
+
7
+ class Service {
8
+ /**
9
+ * 构造函数
10
+ * @param {Object} knex - Knex数据库实例
11
+ * @param {string} tableName - 表名
12
+ */
13
+ constructor(knex = null, tableName = null) {
14
+ if (knex && tableName) {
15
+ this.db = knex;
16
+ this.tableName = tableName;
17
+ this._config = Chan.config || {};
18
+ } else if (global.appContext) {
19
+ this.context = global.appContext;
20
+ } else {
21
+ this.context = { get: () => null, set: () => null };
22
+ }
23
+
24
+ this._dateFields = ['created_at', 'updated_at', 'deleted_at', 'publish_time', 'start_time', 'end_time', 'login_time', 'created_date', 'updated_date', 'createdAt', 'updatedAt', 'deletedAt', 'publishTime', 'startTime', 'endTime', 'loginTime', 'createdDate', 'updatedDate'];
25
+ }
26
+
27
+ /**
28
+ * 获取每页大小配置
29
+ * @returns {number} 每页记录数,默认20
30
+ */
31
+ get pageSize() {
32
+ return this._config.PAGE_SIZE || 20;
33
+ }
34
+
35
+ /**
36
+ * 获取最大限制配置
37
+ * @returns {number} 最大记录数,默认300
38
+ */
39
+ get limit() {
40
+ return this._config.LIMIT_MAX || 300;
41
+ }
42
+
43
+ /**
44
+ * 获取模型实例
45
+ * @param {string} name - 模型名称
46
+ * @returns {Object} 模型实例
47
+ */
48
+ getModel(name) {
49
+ return this.context.getModel(name);
50
+ }
51
+
52
+ /**
53
+ * 获取数据库连接
54
+ * @param {string} name - 数据库名称
55
+ * @returns {Object} 数据库实例
56
+ */
57
+ getDB(name) {
58
+ return this.context.get(`db:${name}`);
59
+ }
60
+
61
+ /**
62
+ * 执行事务
63
+ * @param {Function} callback - 事务回调函数
64
+ * @returns {Promise} 事务执行结果
65
+ */
66
+ async withTransaction(callback) {
67
+ const db = this.getDB("default") || Chan.db;
68
+ return db.transaction(callback);
69
+ }
70
+
71
+ /**
72
+ * 检查数据库连接是否可用
73
+ * @private
74
+ * @throws {Error} 数据库连接不可用时抛出异常
75
+ */
76
+ _checkDB() {
77
+ if (!this.db) {
78
+ throw new Error("Database connection not available");
79
+ }
80
+ }
81
+
82
+ /**
83
+ * 格式化日期字段
84
+ * @private
85
+ * @param {Object} data - 要格式化的数据对象
86
+ * @returns {Object} 格式化后的数据
87
+ * @description 自动将日期字符串转换为数据库可识别的格式
88
+ */
89
+ _formatDateFields(data) {
90
+ if (!data || typeof data !== 'object') return data;
91
+
92
+ const result = { ...data };
93
+ for (const field of this._dateFields) {
94
+ if (result[field] && typeof result[field] === 'string') {
95
+ try {
96
+ const date = new Date(result[field]);
97
+ if (!isNaN(date.getTime())) {
98
+ result[field] = date;
99
+ }
100
+ } catch (error) {
101
+ console.error(`[Service._formatDateFields] 日期字段 ${field} 格式化失败:`, {
102
+ value: result[field],
103
+ error: error.message
104
+ });
105
+ }
106
+ }
107
+ }
108
+ return result;
109
+ }
110
+
111
+ /**
112
+ * 构建基础查询
113
+ * @private
114
+ * @param {Object} options - 查询选项
115
+ * @param {Object} options.query - 查询条件
116
+ * @param {Object} options.sort - 排序条件
117
+ * @param {Array} options.fields - 查询字段
118
+ * @returns {Object} Knex查询构建器
119
+ */
120
+ _buildBaseQuery({ query = {}, sort = {}, fields = [] } = {}) {
121
+ this._checkDB();
122
+
123
+ let dbQuery = this.db(this.tableName);
124
+
125
+ if (Object.keys(query).length) dbQuery = dbQuery.where(query);
126
+ if (fields.length) dbQuery = dbQuery.select(fields);
127
+
128
+ if (sort && typeof sort === 'object') {
129
+ for (const [field, dir] of Object.entries(sort)) {
130
+ const direction = ['asc', 'desc'].includes(dir.toLowerCase()) ? dir.toLowerCase() : 'asc';
131
+ dbQuery = dbQuery.orderBy(field, direction);
132
+ }
133
+ }
134
+
135
+ return dbQuery;
136
+ }
137
+
138
+ /**
139
+ * 查询所有记录
140
+ * @param {Object} options - 查询选项
141
+ * @param {Object} options.query - 查询条件
142
+ * @param {Object} options.sort - 排序条件
143
+ * @param {Array} options.fields - 查询字段
144
+ * @returns {Promise<Array>} 查询结果数组
145
+ */
146
+ async all({ query = {}, sort = {}, fields = [] } = {}) {
147
+ const _query = this._buildBaseQuery({ query, sort, fields });
148
+ const res = await _query.select();
149
+ return formatDateFields(res, this._dateFields);
150
+ }
151
+
152
+ /**
153
+ * 分页查询记录
154
+ * @param {Object} options - 查询选项
155
+ * @param {Object} options.query - 查询条件
156
+ * @param {Object} options.sort - 排序条件
157
+ * @param {Array} options.fields - 查询字段
158
+ * @param {number} options.limit - 限制条数
159
+ * @param {number} options.offset - 偏移量
160
+ * @returns {Promise<Object>} 查询结果,包含data字段
161
+ */
162
+ async find({ query = {}, sort = {}, fields = [], limit, offset } = {}) {
163
+ let _query = this._buildBaseQuery({ query, sort, fields });
164
+
165
+ if (typeof offset === 'number') {
166
+ _query = _query.offset(offset);
167
+ }
168
+ if (typeof limit === 'number') {
169
+ _query = _query.limit(limit);
170
+ }
171
+
172
+ const res = await _query.select();
173
+ return { success: true, code: 200, msg: '查询成功', data: formatDateFields(res, this._dateFields) };
174
+ }
175
+
176
+ /**
177
+ * 查询单条记录
178
+ * @param {Object} options - 查询选项
179
+ * @param {Object} options.query - 查询条件
180
+ * @param {Array} options.fields - 查询字段
181
+ * @returns {Promise<Object>} 查询结果,包含data字段
182
+ */
183
+ async findOne({ query = {}, fields = [] } = {}) {
184
+ this._checkDB();
185
+
186
+ let dbQuery = this.db(this.tableName);
187
+ if (Object.keys(query).length) dbQuery = dbQuery.where(query);
188
+ if (fields.length) dbQuery = dbQuery.select(fields);
189
+ const res = await dbQuery.first();
190
+
191
+ if (!res) {
192
+ return { success: false, code: 404, msg: '记录不存在', data: null };
193
+ }
194
+
195
+ return { success: true, code: 200, msg: '查询成功', data: formatDateFields(res, this._dateFields) };
196
+ }
197
+
198
+ /**
199
+ * 根据ID查询单条记录
200
+ * @param {number|string} id - 记录ID
201
+ * @param {Object} options - 查询选项
202
+ * @param {Array} options.fields - 查询字段
203
+ * @returns {Promise<Object>} 查询结果,包含data字段
204
+ */
205
+ async findById(id, { fields = [] } = {}) {
206
+ this._checkDB();
207
+
208
+ let _query = this.db(this.tableName).where({ id });
209
+ if (fields.length) _query = _query.select(fields);
210
+ const res = await _query.first();
211
+
212
+ if (!res) {
213
+ return { success: false, code: 404, msg: '记录不存在', data: null };
214
+ }
215
+
216
+ return { success: true, code: 200, msg: '查询成功', data: formatDateFields(res, this._dateFields) };
217
+ }
218
+
219
+ /**
220
+ * 插入单条记录
221
+ * @param {Object} data - 要插入的数据
222
+ * @returns {Promise<Object>} 插入结果,包含insertId和affectedRows
223
+ */
224
+ async insert(data = {}) {
225
+ this._checkDB();
226
+
227
+ if (!Object.keys(data).length) return { success: false, code: 400, msg: '参数缺失', data: {} };
228
+ const formattedData = this._formatDateFields(data);
229
+ const result = await this.db(this.tableName).insert(formattedData);
230
+ return { success: true, code: 200, msg: '插入成功', data: { insertId: result[0], affectedRows: result.length } };
231
+ }
232
+
233
+ /**
234
+ * 批量插入记录
235
+ * @param {Array} records - 要插入的记录数组
236
+ * @returns {Promise<Object>} 插入结果,包含insertIds和affectedRows
237
+ */
238
+ async insertMany(records = []) {
239
+ this._checkDB();
240
+
241
+ if (!records.length) return { success: false, code: 400, msg: '参数缺失', data: {} };
242
+ const formattedRecords = records.map(record => this._formatDateFields(record));
243
+ const result = await this.db(this.tableName).insert(formattedRecords);
244
+ return { success: true, code: 200, msg: '批量插入成功', data: { insertIds: result, affectedRows: result.length } };
245
+ }
246
+
247
+ /**
248
+ * 根据条件删除记录
249
+ * @param {Object} query - 删除条件
250
+ * @returns {Promise<Object>} 删除结果,包含affectedRows
251
+ */
252
+ async delete(query = {}) {
253
+ this._checkDB();
254
+
255
+ if (!Object.keys(query).length) return { success: false, code: 400, msg: '参数缺失', data: {} };
256
+ const affectedRows = await this.db(this.tableName).where(query).del();
257
+ return { success: true, code: 200, msg: '删除成功', data: { affectedRows } };
258
+ }
259
+
260
+ /**
261
+ * 根据ID删除记录
262
+ * @param {number|string} id - 记录ID
263
+ * @returns {Promise<Object>} 删除结果,包含affectedRows
264
+ */
265
+ async deleteById(id) {
266
+ this._checkDB();
267
+
268
+ if (!id) return { success: false, code: 400, msg: '参数缺失', data: {} };
269
+ const affectedRows = await this.db(this.tableName).where({ id }).del();
270
+ return { success: true, code: 200, msg: '删除成功', data: { affectedRows } };
271
+ }
272
+
273
+ /**
274
+ * 根据条件更新记录
275
+ * @param {Object} options - 更新选项
276
+ * @param {Object} options.query - 更新条件
277
+ * @param {Object} options.data - 更新数据
278
+ * @returns {Promise<Object>} 更新结果,包含affectedRows
279
+ */
280
+ async updateByQuery({ query, data } = {}) {
281
+ this._checkDB();
282
+
283
+ if (!query || !data || !Object.keys(query).length || !Object.keys(data).length) {
284
+ return { success: false, code: 400, msg: '参数无效', data: {} };
285
+ }
286
+ const formattedData = this._formatDateFields(data);
287
+ const affectedRows = await this.db(this.tableName).where(query).update(formattedData);
288
+ return { success: true, code: 200, msg: '更新成功', data: { affectedRows } };
289
+ }
290
+
291
+ /**
292
+ * 根据ID更新记录
293
+ * @param {number|string} id - 记录ID
294
+ * @param {Object} data - 更新数据
295
+ * @returns {Promise<Object>} 更新结果,包含affectedRows
296
+ */
297
+ async updateById(id, data = {}) {
298
+ this._checkDB();
299
+
300
+ if (!id || !Object.keys(data).length) {
301
+ return { success: false, code: 400, msg: '参数无效', data: {} };
302
+ }
303
+ const formattedData = this._formatDateFields(data);
304
+ const affectedRows = await this.db(this.tableName).where({ id }).update(formattedData);
305
+ const updatedRecord = await this.findById(id);
306
+ return { success: true, code: 200, msg: '更新成功', data: updatedRecord.data };
307
+ }
308
+
309
+ /**
310
+ * 批量更新记录(事务)
311
+ * @param {Array} updates - 更新数组,每项包含query和data
312
+ * @returns {Promise<Object>} 更新结果,包含affectedRows
313
+ */
314
+ async updateMany(updates = []) {
315
+ this._checkDB();
316
+
317
+ if (!Array.isArray(updates) || !updates.length) {
318
+ return { success: false, code: 400, msg: '参数缺失', data: {} };
319
+ }
320
+
321
+ const trx = await this.db.transaction();
322
+ let totalAffected = 0;
323
+ for (const { query, data } of updates) {
324
+ if (!query || !Object.keys(query).length) {
325
+ await trx.rollback().catch(rollbackErr => {
326
+ console.error('[updateMany] 回滚失败:', rollbackErr.message);
327
+ });
328
+ return { success: false, code: 400, msg: '参数无效:批量更新不允许空条件', data: {} };
329
+ }
330
+ const result = await trx(this.tableName).where(query).update(data);
331
+ if (result === 0) {
332
+ console.log('[updateMany] 未匹配到行, query=%j', query);
333
+ }
334
+ totalAffected += result;
335
+ }
336
+ await trx.commit();
337
+ return { success: true, code: 200, msg: '批量更新成功', data: { affectedRows: totalAffected } };
338
+ }
339
+
340
+ /**
341
+ * 分页查询
342
+ * @param {Object} options - 查询选项
343
+ * @param {number} options.current - 当前页码,默认1
344
+ * @param {number} options.pageSize - 每页大小,默认10
345
+ * @param {Object} options.query - 查询条件
346
+ * @param {Object} options.sort - 排序条件
347
+ * @param {Array} options.field - 查询字段
348
+ * @returns {Promise<Object>} 分页结果,包含list、total、current、pageSize、totalPages
349
+ */
350
+ async query({ current = 1, pageSize = 10, query = {}, sort = {}, field = [] }) {
351
+ this._checkDB();
352
+
353
+ const size = Math.min(Math.max(pageSize, 1), this.limit);
354
+ const offset = (current - 1) * size;
355
+
356
+ let countQuery = this.db(this.tableName).count("* as total");
357
+ let dataQuery = this._buildBaseQuery({ query, sort, fields: field });
358
+
359
+ const [totalResult, list] = await Promise.all([
360
+ countQuery.first(),
361
+ dataQuery.offset(offset).limit(size),
362
+ ]);
363
+
364
+ const total = Number(totalResult?.total ?? 0);
365
+ const totalPages = Math.ceil(total / size);
366
+
367
+ return { success: true, code: 200, msg: '查询成功', data: { list: formatDateFields(list, this._dateFields), total, current, pageSize: size, totalPages } };
368
+ }
369
+
370
+ /**
371
+ * 统计记录数
372
+ * @param {Object} query - 查询条件
373
+ * @returns {Promise<Object>} 统计结果,包含count
374
+ */
375
+ async count(query = {}) {
376
+ this._checkDB();
377
+
378
+ let dataQuery = this.db(this.tableName);
379
+ if (Object.keys(query).length) dataQuery = dataQuery.where(query);
380
+ const result = await dataQuery.count("* as total").first();
381
+ return { success: true, code: 200, msg: '统计成功', data: { count: Number(result?.total ?? 0) } };
382
+ }
383
+
384
+ /**
385
+ * 检查记录是否存在
386
+ * @param {Object} query - 查询条件
387
+ * @returns {Promise<Object>} 存在性结果,包含exists布尔值
388
+ */
389
+ async exists(query = {}) {
390
+ this._checkDB();
391
+
392
+ let dataQuery = this.db(this.tableName);
393
+ if (Object.keys(query).length) dataQuery = dataQuery.where(query);
394
+ const result = await dataQuery.first();
395
+ return { success: true, code: 200, msg: '检查成功', data: { exists: !!result } };
396
+ }
397
+
398
+ /**
399
+ * 关联查询
400
+ * @param {Object} options - 查询选项
401
+ * @param {string} options.joinTable - 关联表名
402
+ * @param {string} options.localField - 本地表字段
403
+ * @param {string} options.foreignField - 关联表字段
404
+ * @param {Array} options.fields - 查询字段,默认["*"]
405
+ * @param {Object} options.query - 查询条件
406
+ * @param {Object} options.sort - 排序条件
407
+ * @returns {Promise<Array>} 查询结果数组
408
+ */
409
+ async join({ joinTable, localField, foreignField, fields = ["*"], query = {}, sort = {} }) {
410
+ this._checkDB();
411
+
412
+ let _query = this.db(this.tableName)
413
+ .join(
414
+ joinTable,
415
+ `${this.tableName}.${localField}`,
416
+ "=",
417
+ `${joinTable}.${foreignField}`
418
+ )
419
+ .select(fields);
420
+
421
+ if (Object.keys(query).length) _query = _query.where(query);
422
+ if (sort && typeof sort === 'object') {
423
+ for (const [field, dir] of Object.entries(sort)) {
424
+ const direction = ['asc', 'desc'].includes(dir.toLowerCase()) ? dir.toLowerCase() : 'asc';
425
+ _query = _query.orderBy(field, direction);
426
+ }
427
+ }
428
+
429
+ const res = await _query;
430
+ return { success: true, code: 200, msg: '查询成功', data: formatDateFields(res, this._dateFields) };
431
+ }
432
+
433
+ /**
434
+ * 批量删除记录(根据ID数组)
435
+ * @param {Array} ids - ID数组
436
+ * @returns {Promise<Object>} 删除结果,包含affectedRows
437
+ */
438
+ async deleteMany(ids = []) {
439
+ this._checkDB();
440
+
441
+ if (!ids.length) return { success: false, code: 400, msg: '参数缺失', data: {} };
442
+ const affectedRows = await this.db(this.tableName).whereIn('id', ids).del();
443
+ return { success: true, code: 200, msg: '删除成功', data: { affectedRows } };
444
+ }
445
+
446
+ /**
447
+ * 软删除(设置deleted_at字段)
448
+ * @param {number|string} id - 记录ID
449
+ * @returns {Promise<Object>} 删除结果,包含affectedRows
450
+ */
451
+ async softDelete(id) {
452
+ this._checkDB();
453
+
454
+ if (!id) return { msg: '参数缺失' };
455
+ const affectedRows = await this.db(this.tableName)
456
+ .where({ id })
457
+ .update({ deleted_at: new Date() });
458
+ return { affectedRows };
459
+ }
460
+
461
+ /**
462
+ * 恢复软删除的记录
463
+ * @param {number|string} id - 记录ID
464
+ * @returns {Promise<Object>} 恢复结果,包含affectedRows
465
+ */
466
+ async restore(id) {
467
+ this._checkDB();
468
+
469
+ if (!id) return { msg: '参数缺失' };
470
+ const affectedRows = await this.db(this.tableName)
471
+ .where({ id })
472
+ .update({ deleted_at: null });
473
+ return { affectedRows };
474
+ }
475
+
476
+ /**
477
+ * 查询已软删除的记录
478
+ * @param {Object} options - 查询选项
479
+ * @param {Object} options.query - 查询条件
480
+ * @param {Array} options.fields - 查询字段
481
+ * @param {number} options.limit - 限制条数,默认20
482
+ * @param {number} options.offset - 偏移量,默认0
483
+ * @returns {Promise<Array>} 查询结果数组
484
+ */
485
+ async findTrashed({ query = {}, fields = [], limit = 20, offset = 0 } = {}) {
486
+ this._checkDB();
487
+
488
+ let _query = this.db(this.tableName).whereNotNull('deleted_at');
489
+
490
+ if (Object.keys(query).length) _query = _query.where(query);
491
+ if (fields.length) _query = _query.select(fields);
492
+
493
+ const res = await _query.limit(limit).offset(offset).orderBy('deleted_at', 'desc');
494
+ return res;
495
+ }
496
+
497
+ /**
498
+ * 强制删除指定天数前的软删除记录
499
+ * @param {number} days - 天数,默认30天
500
+ * @returns {Promise<Object>} 删除结果,包含affectedRows
501
+ */
502
+ async forceDelete(days = 30) {
503
+ this._checkDB();
504
+
505
+ const date = new Date();
506
+ date.setDate(date.getDate() - days);
507
+
508
+ const affectedRows = await this.db(this.tableName)
509
+ .whereNotNull('deleted_at')
510
+ .where('deleted_at', '<', date)
511
+ .del();
512
+
513
+ return { affectedRows };
514
+ }
515
+
516
+ /**
517
+ * 统计数据(总数和今日新增)
518
+ * @returns {Promise<Object>} 统计结果,包含total和today
519
+ */
520
+ async stats() {
521
+ this._checkDB();
522
+
523
+ const total = await this.db(this.tableName).count('* as count').first();
524
+ const today = new Date();
525
+ today.setHours(0, 0, 0, 0);
526
+
527
+ const todayCount = await this.db(this.tableName)
528
+ .where('created_at', '>=', today)
529
+ .count('* as count')
530
+ .first();
531
+
532
+ return {
533
+ total: Number(total?.count || 0),
534
+ today: Number(todayCount?.count || 0)
535
+ };
536
+ }
537
+ }
538
+
539
+ export default Service;
package/common/api.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * API响应常量定义
3
+ * 提供统一的响应状态码和消息
4
+ */
5
+
6
+ export const success = {
7
+ code: 200,
8
+ msg: "success",
9
+ };
10
+
11
+ export const fail = {
12
+ code: 201,
13
+ msg: "error",
14
+ };
15
+
16
+ export const error = {
17
+ code: 500,
18
+ msg: "error",
19
+ };
20
+
21
+ export default {
22
+ success,
23
+ fail,
24
+ error,
25
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 分类工具函数
3
+ * 提供分类相关的辅助方法
4
+ */
5
+
6
+ /**
7
+ * 根据拼音或ID获取分类信息
8
+ * @param {string|number} py - 拼音或ID
9
+ * @param {Array} source - 分类数据源
10
+ * @returns {Object} 包含分类对象和ID的对象
11
+ */
12
+ export function getChildrenId(py, source) {
13
+ let cate = {};
14
+ let id = "";
15
+ source.forEach((item) => {
16
+ if (item.pinyin == py || item.id == py) {
17
+ cate = item;
18
+ id = item.id;
19
+ }
20
+ });
21
+ return { cate, id };
22
+ }
package/common/code.js ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 响应状态码常量定义
3
+ * 提供标准的状态码和对应消息
4
+ */
5
+
6
+ export const CODE = {
7
+ /**
8
+ * 操作成功
9
+ */
10
+ SUCCESS: {
11
+ code: 200,
12
+ message: "操作成功",
13
+ },
14
+ /**
15
+ * 操作失败
16
+ */
17
+ FAIL: {
18
+ code: 201,
19
+ message: "操作失败",
20
+ },
21
+ /**
22
+ * 服务器错误
23
+ */
24
+ ERROR: {
25
+ code: 500,
26
+ message: "服务器错误",
27
+ },
28
+ /**
29
+ * 未授权
30
+ */
31
+ UNAUTHORIZED: {
32
+ code: 401,
33
+ message: "未授权",
34
+ },
35
+ /**
36
+ * 禁止访问
37
+ */
38
+ FORBIDDEN: {
39
+ code: 403,
40
+ message: "禁止访问",
41
+ },
42
+ };