chanjs 1.2.5 → 2.0.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.
@@ -0,0 +1,54 @@
1
+ import path from "path";
2
+ import fs from "fs";
3
+ import { pathToFileURL } from 'url'; // 新增顶部导入
4
+ const ROOT_PATH = process.cwd();
5
+ const APP_PATH = path.join(ROOT_PATH, "app");
6
+ const CONFIG_PATH = path.join(APP_PATH, "config");
7
+ const EXTEND_PATH = path.join(APP_PATH, "extend");
8
+ const PUBLIC_PATH = path.join(APP_PATH, "public");
9
+ const MODULES_PATH = path.join(APP_PATH, "modules");
10
+ // 兼容低版本node common包
11
+ import { createRequire } from "module";
12
+ const requirejs = createRequire(import.meta.url);
13
+
14
+ //let user = getFilePath('app/controller/user.js')
15
+
16
+ //实现dirname
17
+ global.__dirname = path.dirname(new URL(import.meta.url).pathname);
18
+ //实现__filename
19
+ global.__filename = new URL(import.meta.url).pathname;
20
+
21
+ // app
22
+ global.APP_PATH = APP_PATH;
23
+ // config
24
+ global.CONFIG_PATH = CONFIG_PATH;
25
+ // run root path
26
+ global.ROOT_PATH = ROOT_PATH;
27
+ // extend
28
+ global.EXTEND_PATH = EXTEND_PATH;
29
+ // public
30
+ global.PUBLIC_PATH = PUBLIC_PATH;
31
+ // modules
32
+ global.MODULES_PATH = MODULES_PATH;
33
+ // require 兼容低版本node common包
34
+ global.requirejs = requirejs;
35
+ //解决多重...问题
36
+ const importRootFile = async (str) => {
37
+ let filepath = path.join(global.ROOT_PATH, str);
38
+ if (fs.existsSync(filepath)) {
39
+ const fileUrl = pathToFileURL(filepath).href; // 新增转换
40
+ const module = await import(fileUrl);
41
+ return module.default || module;
42
+ }
43
+ };
44
+
45
+ const importFile = async (filepath) => {
46
+ if (fs.existsSync(filepath)) {
47
+ const fileUrl = pathToFileURL(filepath).href; // 新增转换
48
+ const module = await import(fileUrl);
49
+ return module.default || module;
50
+ }
51
+ };
52
+
53
+ global.importFile = importFile;
54
+ global.importRootFile = importRootFile;
@@ -0,0 +1,29 @@
1
+ export default class Controller {
2
+ constructor() {}
3
+ success(data) {
4
+ return {
5
+ success: true,
6
+ msg: "操作成功",
7
+ code: 200,
8
+ data,
9
+ };
10
+ }
11
+
12
+ fail(data, code = 201) {
13
+ return {
14
+ success: false,
15
+ msg: "操作失败",
16
+ code,
17
+ data,
18
+ };
19
+ }
20
+
21
+ err(data = {}, code = 500) {
22
+ return {
23
+ success: false,
24
+ msg: "系统异常",
25
+ code,
26
+ data,
27
+ };
28
+ }
29
+ }
package/core/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import Controller from "./controller.js";
2
+ import Service from "./service.js";
3
+ export {Controller, Service};
@@ -0,0 +1,297 @@
1
+ // ====================== 模块级别工具函数 (只初始化一次) ======================
2
+ const errCode = {
3
+ "ECONNREFUSED": "数据库连接被拒绝,请检查数据库服务是否正常运行。",
4
+ "ER_ACCESS_DENIED_ERROR": "无权限访问,账号或密码错误。",
5
+ "ER_ROW_IS_REFERENCED_2": "无法删除或更新记录,存在关联数据。",
6
+ "ER_BAD_FIELD_ERROR": "SQL语句中包含无效字段,请检查查询条件或列名。",
7
+ "ER_DUP_ENTRY": "插入失败:数据重复,违反唯一性约束。",
8
+ "ER_NO_SUCH_TABLE": "操作失败:目标表不存在。",
9
+ "ETIMEOUT": "数据库操作超时,请稍后再试。"
10
+ };
11
+
12
+ const getDefaultErrorMessage = (error) => {
13
+ if (error.message.includes('syntax') || error.message.includes('SQL')) {
14
+ return '数据库语法错误,请检查您的查询语句。';
15
+ } else if (error.message.includes('Connection closed')) {
16
+ return '数据库连接已关闭,请重试。';
17
+ } else if (error.message.includes('permission')) {
18
+ return '数据库权限不足,请检查配置。';
19
+ }
20
+ return '数据库发生未知错误,请稍后重试。';
21
+ };
22
+
23
+ const errorResponse = (err) => {
24
+ console.error('DB Error:', err);
25
+ const message = errCode[err.code] || getDefaultErrorMessage(err);
26
+ return {
27
+ success: false,
28
+ msg: message,
29
+ code: 500,
30
+ data: {
31
+ sql: err.sql,
32
+ sqlMessage: err.sqlMessage
33
+ }
34
+ };
35
+ };
36
+
37
+ const failResponse = (msg = "操作失败", data = {}) => {
38
+ console.warn('Operation failed:', msg);
39
+ return {
40
+ success: false,
41
+ msg,
42
+ code: 201,
43
+ data
44
+ };
45
+ };
46
+
47
+ const successResponse = (data = {}, msg = "操作成功") => ({
48
+ success: true,
49
+ msg,
50
+ code: 200,
51
+ data
52
+ });
53
+
54
+ // ====================== 共享数据库方法 (只创建一次) ======================
55
+ const databaseMethods = {
56
+ /**
57
+ * 查询表所有记录(慎用)
58
+ * @param {Object} query - 查询条件
59
+ * @returns {Promise} 查询结果
60
+ */
61
+ async all(query = {}) {
62
+ try {
63
+ let dbQuery = this.knex(this.model);
64
+ if (Object.keys(query).length > 0) {
65
+ dbQuery = dbQuery.where(query);
66
+ }
67
+ const res = await dbQuery.select();
68
+ return successResponse(res);
69
+ } catch (err) {
70
+ return errorResponse(err);
71
+ }
72
+ },
73
+
74
+ /**
75
+ * 获取单个记录
76
+ * @param {Object} query - 查询条件
77
+ * @returns {Promise} 查询结果
78
+ *
79
+ * */
80
+
81
+ async one(query = {}) {
82
+ try {
83
+ let dbQuery = this.knex(this.model);
84
+ if (Object.keys(query).length > 0) {
85
+ dbQuery = dbQuery.where(query);
86
+ }
87
+ const res = await dbQuery.first();
88
+ return successResponse(res);
89
+ } catch (err) {
90
+ return errorResponse(err);
91
+ }
92
+ },
93
+
94
+ /**
95
+ * 根据ID查询记录
96
+ * @param {Object} options - 查询选项
97
+ * @param {Object} options.query - 查询条件
98
+ * @param {Array} options.field - 返回字段
99
+ * @param {number} options.len - 返回数量
100
+ */
101
+ async findById({ query, field = [], len = 1 }) {
102
+ try {
103
+ let dataQuery = this.knex(this.model).where(query);
104
+ if (field.length > 0) dataQuery = dataQuery.select(field);
105
+ if (len === 1) dataQuery = dataQuery.first();
106
+ else if (len > 1) dataQuery = dataQuery.limit(len);
107
+
108
+ const res = await dataQuery;
109
+ return successResponse(res || (len === 1 ? {} : []));
110
+ } catch (err) {
111
+ return errorResponse(err);
112
+ }
113
+ },
114
+
115
+ /**
116
+ * 创建新记录
117
+ * @param {Object} data - 包含要插入的数据对象
118
+ * @returns {Promise} 操作结果
119
+ */
120
+ async insert(data = {}) {
121
+ try {
122
+ if (Object.keys(data).length === 0) {
123
+ return failResponse('插入数据不能为空');
124
+ }
125
+ const result = await this.knex(this.model).insert(data);
126
+ return successResponse(result?.length > 0 || !!result);
127
+ } catch (err) {
128
+ return errorResponse(err);
129
+ }
130
+ },
131
+
132
+ /**
133
+ * 插入多条记录
134
+ * @param {Array} records - 包含要插入的数据对象数组
135
+ * @returns {Promise} 操作结果
136
+ */
137
+ async insertMany(records = []) {
138
+ try {
139
+ if (records.length === 0) {
140
+ return failResponse('插入数据不能为空');
141
+ }
142
+ const result = await this.knex(this.model).insert(records);
143
+ return successResponse(result);
144
+ } catch (err) {
145
+ return errorResponse(err);
146
+ }
147
+ },
148
+
149
+ /**
150
+ * 根据指定条件删除记录
151
+ * @param {Object} query - 包含查询条件的对象
152
+ * @returns {Promise} 操作结果
153
+ */
154
+ async delete(query = {}) {
155
+ try {
156
+ if (Object.keys(query).length === 0) {
157
+ return failResponse("请指定删除条件");
158
+ }
159
+ const affectedRows = await this.knex(this.model).where(query).del();
160
+ return successResponse(affectedRows > 0);
161
+ } catch (err) {
162
+ return errorResponse(err);
163
+ }
164
+ },
165
+
166
+ /**
167
+ * 根据指定条件更新记录
168
+ * @param {Object} options - 更新选项
169
+ * @param {Object} options.query - 查询条件
170
+ * @param {Object} options.params - 更新数据
171
+ * @returns {Promise} 操作结果
172
+ */
173
+ async update({ query, params } = {}) {
174
+ try {
175
+ if (!query || !params || Object.keys(query).length === 0) {
176
+ return failResponse("参数错误");
177
+ }
178
+ const result = await this.knex(this.model).where(query).update(params);
179
+ return successResponse(!!result);
180
+ } catch (err) {
181
+ return errorResponse(err);
182
+ }
183
+ },
184
+
185
+ /**
186
+ * 批量更新多条记录
187
+ * @param {Array} updates - 更新操作数组
188
+ * @returns {Promise} 操作结果
189
+ */
190
+ async updateMany(updates = []) {
191
+ if (!Array.isArray(updates) || updates.length === 0) {
192
+ return failResponse('更新数据不能为空');
193
+ }
194
+
195
+ const trx = await this.knex.transaction();
196
+ try {
197
+ for (const { query, params } of updates) {
198
+ const result = await trx(this.model).where(query).update(params);
199
+ if (result === 0) {
200
+ await trx.rollback();
201
+ return failResponse(`更新失败: ${JSON.stringify(query)}`);
202
+ }
203
+ }
204
+ await trx.commit();
205
+ return successResponse(true);
206
+ } catch (err) {
207
+ await trx.rollback();
208
+ return errorResponse(err);
209
+ }
210
+ },
211
+
212
+ /**
213
+ * 分页查询
214
+ * @param {Object} options - 查询选项
215
+ * @param {number} options.current - 当前页码
216
+ * @param {number} options.pageSize - 每页大小
217
+ * @param {Object} options.query - 查询条件
218
+ * @param {Array} options.field - 返回字段
219
+ * @returns {Promise} 查询结果
220
+ */
221
+ async query({ current = 1, pageSize = 10, query = {}, field = [] }) {
222
+ try {
223
+ const offset = (current - 1) * pageSize;
224
+ let countQuery = this.knex(this.model).count("* as total");
225
+ let dataQuery = this.knex(this.model);
226
+
227
+ if (Object.keys(query).length > 0) {
228
+ Object.entries(query).forEach(([key, value]) => {
229
+ countQuery = countQuery.where(key, value);
230
+ dataQuery = dataQuery.where(key, value);
231
+ });
232
+ }
233
+
234
+ if (field.length > 0) dataQuery = dataQuery.select(field);
235
+
236
+ const [totalResult, list] = await Promise.all([
237
+ countQuery.first(),
238
+ dataQuery.offset(offset).limit(pageSize)
239
+ ]);
240
+
241
+ const total = totalResult?.total || 0;
242
+ return successResponse({ list, total, current, pageSize });
243
+ } catch (err) {
244
+ return errorResponse(err);
245
+ }
246
+ },
247
+
248
+ /**
249
+ * 计数查询
250
+ * @param {Array} query - 查询条件数组
251
+ * @returns {Promise} 查询结果
252
+ */
253
+ async count(query = []) {
254
+ try {
255
+ let dataQuery = this.knex(this.model);
256
+ if (query.length > 0) {
257
+ query.forEach(condition => dataQuery = dataQuery.where(condition));
258
+ }
259
+ const result = await dataQuery.count("* as total").first();
260
+ return successResponse(Number(result?.total) || 0);
261
+ } catch (err) {
262
+ return errorResponse(err);
263
+ }
264
+ }
265
+ };
266
+
267
+ // ====================== 工厂函数 (轻量创建实例) ======================
268
+ /**
269
+ * 创建数据库服务实例
270
+ * @param {Object} knex - Knex实例
271
+ * @param {string} model - 表名/模型名
272
+ * @returns {Object} 数据库服务实例
273
+ */
274
+ export default function Service(knex, model) {
275
+ if (!knex || !model) {
276
+ throw new Error('createDBService: knex instance and model name are required');
277
+ }
278
+
279
+ // 创建继承数据库方法的轻量对象
280
+ const service = Object.create(databaseMethods);
281
+
282
+ // 设置实例专属状态(不可写)
283
+ Object.defineProperties(service, {
284
+ knex: {
285
+ value: knex,
286
+ writable: false,
287
+ enumerable: true
288
+ },
289
+ model: {
290
+ value: model,
291
+ writable: false,
292
+ enumerable: true
293
+ }
294
+ });
295
+
296
+ return service;
297
+ }
@@ -0,0 +1,28 @@
1
+ const template = requirejs("art-template");
2
+ import dayjs from 'dayjs';
3
+ // 注册 dateFormat 函数
4
+ template.defaults.imports.dateFormat = function (date, format) {
5
+ if (!date) {
6
+ return "";
7
+ }
8
+ // 如果传入的是一个 Date 对象,转换为 dayjs 对象
9
+ if (
10
+ date instanceof Date ||
11
+ typeof date === "string" ||
12
+ typeof date === "number"
13
+ ) {
14
+ date = dayjs(date);
15
+ } else {
16
+ return "";
17
+ }
18
+ return date.format(format);
19
+ };
20
+
21
+ template.defaults.imports.truncate = (str, length = 10) => {
22
+ return str.length > length ? str.slice(0, length) + "..." : str;
23
+ };
24
+
25
+ // 注册安全序列化方法
26
+ template.defaults.imports.safeStringify = (obj) => {
27
+ return JSON.stringify(obj, null, 2);
28
+ };
@@ -0,0 +1,6 @@
1
+ import express from "express";
2
+
3
+ import { z } from 'zod';
4
+
5
+
6
+ export { express, z };