q-koa 13.1.7 → 13.1.9
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/core/app.js +16 -54
- package/core/file/plugins/system/controller.js +3 -1
- package/core/file/plugins/system/service.js +18 -44
- package/core/file/plugins/table_setting/config.js +14 -1
- package/core/file/plugins/weixin/service.js +12 -1
- package/core/file/services/weixinMP.js +20 -0
- package/core/file/utils/index.js +123 -0
- package/package.json +1 -1
package/core/app.js
CHANGED
|
@@ -22,7 +22,7 @@ const util = require('util')
|
|
|
22
22
|
const jwt = require('jsonwebtoken')
|
|
23
23
|
const verify = util.promisify(jwt.verify)
|
|
24
24
|
const fsExtra = require('fs-extra')
|
|
25
|
-
const { getObject, getAppConfig } = require('./file/utils')
|
|
25
|
+
const { getObject, getAppConfig, formatLiteralObj } = require('./file/utils')
|
|
26
26
|
|
|
27
27
|
const restc = require('./restc')
|
|
28
28
|
const APP_DIR = 'app'
|
|
@@ -288,6 +288,18 @@ class APP {
|
|
|
288
288
|
)} server is running at http://localhost:${this.port}`
|
|
289
289
|
)
|
|
290
290
|
if (is_dev) {
|
|
291
|
+
const db_name = _.get(this.app[appName], 'sequelize.config.database')
|
|
292
|
+
this.app[appName].model.setting.update(
|
|
293
|
+
{
|
|
294
|
+
value: db_name,
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
where: {
|
|
298
|
+
code: 'db_name',
|
|
299
|
+
},
|
|
300
|
+
}
|
|
301
|
+
)
|
|
302
|
+
|
|
291
303
|
console.log(
|
|
292
304
|
`first app is http://localhost:3001/${appName}/setting/findOne`
|
|
293
305
|
)
|
|
@@ -1157,57 +1169,6 @@ class APP {
|
|
|
1157
1169
|
|
|
1158
1170
|
if (where) {
|
|
1159
1171
|
if (fn === 'findAndCountAll') {
|
|
1160
|
-
const $lt = {
|
|
1161
|
-
check: (param) => typeof param === 'string',
|
|
1162
|
-
result: (param, key) => {
|
|
1163
|
-
return {
|
|
1164
|
-
[key]: Sequelize.literal(param[key]),
|
|
1165
|
-
}
|
|
1166
|
-
},
|
|
1167
|
-
}
|
|
1168
|
-
const $in = {
|
|
1169
|
-
check: (param) => typeof param === 'string',
|
|
1170
|
-
result: (param, key) => {
|
|
1171
|
-
return {
|
|
1172
|
-
[key]: [Sequelize.literal(param[key])],
|
|
1173
|
-
}
|
|
1174
|
-
},
|
|
1175
|
-
}
|
|
1176
|
-
const $between = {
|
|
1177
|
-
check: (param) =>
|
|
1178
|
-
Array.isArray(param) &&
|
|
1179
|
-
param.every((p) => p.includes('now()')),
|
|
1180
|
-
result: (param, key) => {
|
|
1181
|
-
return {
|
|
1182
|
-
[key]: param[key].map(Sequelize.literal),
|
|
1183
|
-
}
|
|
1184
|
-
},
|
|
1185
|
-
}
|
|
1186
|
-
const mapper = {
|
|
1187
|
-
$between,
|
|
1188
|
-
notBetween: $between,
|
|
1189
|
-
$lt,
|
|
1190
|
-
$lte: $lt,
|
|
1191
|
-
$gt: $lt,
|
|
1192
|
-
$gte: $lt,
|
|
1193
|
-
$in,
|
|
1194
|
-
$notIn: $in,
|
|
1195
|
-
}
|
|
1196
|
-
const formatObj = (target) => {
|
|
1197
|
-
for (const key of Object.keys(mapper)) {
|
|
1198
|
-
if (Object.hasOwnProperty.call(target, key)) {
|
|
1199
|
-
if (mapper[key].check(target[key])) {
|
|
1200
|
-
return mapper[key].result(target, key)
|
|
1201
|
-
} else {
|
|
1202
|
-
return target
|
|
1203
|
-
}
|
|
1204
|
-
} else {
|
|
1205
|
-
continue
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
return target
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
1172
|
if (
|
|
1212
1173
|
where.hasOwnProperty('id') &&
|
|
1213
1174
|
typeof where.id === 'string' &&
|
|
@@ -1222,7 +1183,7 @@ class APP {
|
|
|
1222
1183
|
|
|
1223
1184
|
const formatWhere = _.mapValues(where, (item) => {
|
|
1224
1185
|
if (!_.isObject(item)) return item
|
|
1225
|
-
return
|
|
1186
|
+
return formatLiteralObj(item)
|
|
1226
1187
|
})
|
|
1227
1188
|
_where = _.cloneDeep(formatWhere)
|
|
1228
1189
|
} else {
|
|
@@ -1282,12 +1243,12 @@ class APP {
|
|
|
1282
1243
|
return {
|
|
1283
1244
|
...item,
|
|
1284
1245
|
where: {
|
|
1285
|
-
...item.where,
|
|
1286
1246
|
...(includeWhere[item.model.getName()]
|
|
1287
1247
|
? {
|
|
1288
1248
|
...includeWhere[item.model.getName()],
|
|
1289
1249
|
}
|
|
1290
1250
|
: {}),
|
|
1251
|
+
...item.where,
|
|
1291
1252
|
},
|
|
1292
1253
|
}
|
|
1293
1254
|
})
|
|
@@ -2091,6 +2052,7 @@ APP.Validator = Validator
|
|
|
2091
2052
|
APP.ServiceError = ServiceError
|
|
2092
2053
|
APP.TransactionError = TransactionError
|
|
2093
2054
|
APP.moment = moment
|
|
2055
|
+
APP.utils = require('./file/utils')
|
|
2094
2056
|
APP.is_dev = is_dev
|
|
2095
2057
|
|
|
2096
2058
|
global.moment = moment
|
|
@@ -309,7 +309,9 @@ exports.getTable = async (ctx) => {
|
|
|
309
309
|
return ctx.SUCCESS(app.cache.get(`${_model}-table`))
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
const model = app.config[_model].model || _model
|
|
312
|
+
const model = (app.config[_model] && app.config[_model].model) || _model
|
|
313
|
+
|
|
314
|
+
if (!app.config[model]) return ctx.SUCCESS(null)
|
|
313
315
|
|
|
314
316
|
const _result = await app.sequelize.getQueryInterface().describeTable(model)
|
|
315
317
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const { getConfig, lodash
|
|
1
|
+
const { getConfig, lodash } = require('q-koa')
|
|
2
|
+
const { formatLiteralObj } = require('../../utils')
|
|
2
3
|
const formatPostFunction = (str) => `eval(${str})`
|
|
3
4
|
const nodeVm = require('vm')
|
|
4
5
|
const axios = require('axios')
|
|
@@ -33,6 +34,7 @@ exports.initData = async ({ includes, excludes, app, ctx }) => {
|
|
|
33
34
|
excludeInclude,
|
|
34
35
|
autoInclude = true,
|
|
35
36
|
is_cache = false,
|
|
37
|
+
defaultValue,
|
|
36
38
|
} = route
|
|
37
39
|
|
|
38
40
|
if (url.includes('http')) {
|
|
@@ -134,8 +136,14 @@ exports.initData = async ({ includes, excludes, app, ctx }) => {
|
|
|
134
136
|
|
|
135
137
|
if (app.controller[model] && app.controller[model][fn]) {
|
|
136
138
|
return app.controller[model][fn](ctx, data).then((result) => {
|
|
137
|
-
if (
|
|
139
|
+
if (
|
|
140
|
+
result === undefined &&
|
|
141
|
+
process.env.NODE_ENV !== 'production'
|
|
142
|
+
) {
|
|
138
143
|
console.error(`需要在控制器${fn}中返回`)
|
|
144
|
+
return {
|
|
145
|
+
[item]: defaultValue || result,
|
|
146
|
+
}
|
|
139
147
|
}
|
|
140
148
|
return {
|
|
141
149
|
[item]: result,
|
|
@@ -208,49 +216,15 @@ exports.initData = async ({ includes, excludes, app, ctx }) => {
|
|
|
208
216
|
data &&
|
|
209
217
|
lodash.isObject(data) &&
|
|
210
218
|
data.hasOwnProperty('where')
|
|
211
|
-
?
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return {
|
|
218
|
-
..._a,
|
|
219
|
-
...(['$gt', '$lt'].some((i) =>
|
|
220
|
-
data[b][_b].hasOwnProperty(i)
|
|
221
|
-
)
|
|
222
|
-
? {
|
|
223
|
-
[_b]: data[b][_b],
|
|
224
|
-
...(typeof data[b][_b].$gt ===
|
|
225
|
-
'string' &&
|
|
226
|
-
data[b][_b].hasOwnProperty('$gt')
|
|
227
|
-
? {
|
|
228
|
-
[_b]: {
|
|
229
|
-
$gt: Sequelize.literal(
|
|
230
|
-
data[b][_b].$gt
|
|
231
|
-
),
|
|
232
|
-
},
|
|
233
|
-
}
|
|
234
|
-
: {}),
|
|
235
|
-
...(typeof data[b][_b].$lt ===
|
|
236
|
-
'string' &&
|
|
237
|
-
data[b][_b].hasOwnProperty('$lt')
|
|
238
|
-
? {
|
|
239
|
-
[_b]: {
|
|
240
|
-
$lt: Sequelize.literal(
|
|
241
|
-
data[b][_b].$lt
|
|
242
|
-
),
|
|
243
|
-
},
|
|
244
|
-
}
|
|
245
|
-
: {}),
|
|
246
|
-
}
|
|
247
|
-
: { [_b]: data[b][_b] }),
|
|
248
|
-
}
|
|
249
|
-
}, {}),
|
|
250
|
-
}
|
|
251
|
-
: { [b]: data[b] }),
|
|
219
|
+
? lodash.mapValues(data, (value, key) => {
|
|
220
|
+
if (key === 'where') {
|
|
221
|
+
return lodash.mapValues(data.where, (item) => {
|
|
222
|
+
if (!lodash.isObject(item)) return item
|
|
223
|
+
return formatLiteralObj(item)
|
|
224
|
+
})
|
|
252
225
|
}
|
|
253
|
-
|
|
226
|
+
return value
|
|
227
|
+
})
|
|
254
228
|
: data
|
|
255
229
|
// console.log('formatData', data, '-->', formatData)
|
|
256
230
|
return app.model[model][fn]({
|
|
@@ -6,7 +6,20 @@ module.exports = {
|
|
|
6
6
|
availableSort: false,
|
|
7
7
|
order: [],
|
|
8
8
|
referenceSelect: [],
|
|
9
|
-
select: [
|
|
9
|
+
select: [
|
|
10
|
+
'id',
|
|
11
|
+
'code',
|
|
12
|
+
'name',
|
|
13
|
+
'is_front',
|
|
14
|
+
'is_cache',
|
|
15
|
+
'is_control',
|
|
16
|
+
{
|
|
17
|
+
key: 'extra',
|
|
18
|
+
extra: {
|
|
19
|
+
list: ['is_admin', 'is_purchase', 'is_custom', 'is_supply'],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
],
|
|
10
23
|
excludes: [],
|
|
11
24
|
limit: 20,
|
|
12
25
|
defaultOrder: [],
|
|
@@ -4,6 +4,7 @@ const {
|
|
|
4
4
|
getConfig,
|
|
5
5
|
lodash,
|
|
6
6
|
moment,
|
|
7
|
+
sleep,
|
|
7
8
|
} = require('q-koa')
|
|
8
9
|
const { Pay } = require('@sigodenjs/wechatpay')
|
|
9
10
|
const WXPay = require('weixin-pay-fork')
|
|
@@ -480,13 +481,23 @@ exports.handleUserMessage = async ({ app, result }) => {
|
|
|
480
481
|
secrect: app_secrect,
|
|
481
482
|
})
|
|
482
483
|
weixinMp.init()
|
|
484
|
+
const touser = result.FromUserName
|
|
485
|
+
await weixinMp.handleTyping({
|
|
486
|
+
touser,
|
|
487
|
+
is_typing: true,
|
|
488
|
+
})
|
|
489
|
+
await sleep(3)
|
|
483
490
|
await weixinMp.handleMessage({
|
|
484
|
-
touser
|
|
491
|
+
touser,
|
|
485
492
|
msgtype: 'text',
|
|
486
493
|
text: {
|
|
487
494
|
content: `你说${result.Content},是吗?`,
|
|
488
495
|
},
|
|
489
496
|
})
|
|
497
|
+
await weixinMp.handleTyping({
|
|
498
|
+
touser,
|
|
499
|
+
is_typing: false,
|
|
500
|
+
})
|
|
490
501
|
}
|
|
491
502
|
}
|
|
492
503
|
|
|
@@ -20,6 +20,8 @@ const sendMessageUrl =
|
|
|
20
20
|
'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%s'
|
|
21
21
|
const handleMessageUrl =
|
|
22
22
|
'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s'
|
|
23
|
+
const handleTypingUrl =
|
|
24
|
+
'https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=%s'
|
|
23
25
|
const uploadFile =
|
|
24
26
|
'https://api.weixin.qq.com/cgi-bin/media/upload?access_token=%s&type=%s'
|
|
25
27
|
const serviceMarketUrl =
|
|
@@ -558,6 +560,24 @@ module.exports = class Singleton {
|
|
|
558
560
|
return result
|
|
559
561
|
}
|
|
560
562
|
|
|
563
|
+
async handleTyping({ touser, is_typing = true }) {
|
|
564
|
+
const options = {
|
|
565
|
+
touser,
|
|
566
|
+
command: is_typing ? 'Typing' : 'CancelTyping',
|
|
567
|
+
}
|
|
568
|
+
const access_token = await this.getAccessToken()
|
|
569
|
+
const url = util.format(handleTypingUrl, access_token)
|
|
570
|
+
const result = await axios.post(url, options).then((res) => res.data)
|
|
571
|
+
if (result.errcode) {
|
|
572
|
+
if (result.errcode === 40001) {
|
|
573
|
+
cache.reset()
|
|
574
|
+
return await this.handleTyping(options)
|
|
575
|
+
}
|
|
576
|
+
throw new Error(`${result.errcode};${result.errmsg}`)
|
|
577
|
+
}
|
|
578
|
+
return result
|
|
579
|
+
}
|
|
580
|
+
|
|
561
581
|
async uploadFile(imgUrl) {
|
|
562
582
|
if (!imgUrl || !imgUrl.includes('//')) throw new Error('检查imgUrl是否链接')
|
|
563
583
|
|
package/core/file/utils/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const { lodash } = require('q-koa')
|
|
2
|
+
const Sequelize = require('sequelize')
|
|
2
3
|
const md5 = require('md5')
|
|
4
|
+
const moment = require('moment')
|
|
3
5
|
|
|
4
6
|
const findConfig = (type) => (item) =>
|
|
5
7
|
item.key === type ||
|
|
@@ -205,3 +207,124 @@ exports.signResult = (params, salt) => {
|
|
|
205
207
|
var signStr = paramArray.join('&')
|
|
206
208
|
return md5(signStr)
|
|
207
209
|
}
|
|
210
|
+
|
|
211
|
+
function isDateTime(str) {
|
|
212
|
+
const dateRegex = /^[\u4e00-\u9fa5]{4}-[\u4e00-\u9fa5]{2}-[\u4e00-\u9fa5]{2}$/
|
|
213
|
+
return dateRegex.test(str)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const $lt = {
|
|
217
|
+
check: (param) => typeof param === 'string',
|
|
218
|
+
result: (param, key) => {
|
|
219
|
+
return {
|
|
220
|
+
[key]: Sequelize.literal(param[key]),
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
}
|
|
224
|
+
const $in = {
|
|
225
|
+
check: (param) => typeof param === 'string',
|
|
226
|
+
result: (param, key) => {
|
|
227
|
+
return {
|
|
228
|
+
[key]: [Sequelize.literal(param[key])],
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
}
|
|
232
|
+
const $between = {
|
|
233
|
+
check: (param) =>
|
|
234
|
+
Array.isArray(param) && param.every((p) => typeof param === 'string'),
|
|
235
|
+
result: (param, key) => {
|
|
236
|
+
return {
|
|
237
|
+
[key]: param[key].map(Sequelize.literal),
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
}
|
|
241
|
+
const mapper = {
|
|
242
|
+
$between,
|
|
243
|
+
notBetween: $between,
|
|
244
|
+
$lt,
|
|
245
|
+
$lte: $lt,
|
|
246
|
+
$gt: $lt,
|
|
247
|
+
$gte: $lt,
|
|
248
|
+
$in,
|
|
249
|
+
$notIn: $in,
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
exports.formatLiteralObj = (target) => {
|
|
253
|
+
for (const key of Object.keys(mapper)) {
|
|
254
|
+
if (Object.hasOwnProperty.call(target, key)) {
|
|
255
|
+
if (mapper[key].check(target[key])) {
|
|
256
|
+
return mapper[key].result(target, key)
|
|
257
|
+
} else {
|
|
258
|
+
return target
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
continue
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return target
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
exports.filterFunction = (target, data) => {
|
|
268
|
+
if (!target) {
|
|
269
|
+
console.error(`target为null`)
|
|
270
|
+
return false
|
|
271
|
+
}
|
|
272
|
+
return Object.keys(target).every((key) => {
|
|
273
|
+
if (key.includes('.')) {
|
|
274
|
+
return lodash.get(data, key) === target[key]
|
|
275
|
+
}
|
|
276
|
+
if (typeof target[key] === 'boolean') {
|
|
277
|
+
return Boolean(data[key]) === target[key]
|
|
278
|
+
}
|
|
279
|
+
if (Array.isArray(target[key])) {
|
|
280
|
+
return target[key].includes(data[key])
|
|
281
|
+
}
|
|
282
|
+
if (lodash.isObject(target[key])) {
|
|
283
|
+
if (Object.prototype.hasOwnProperty.call(target[key], '$gt')) {
|
|
284
|
+
if (key.endsWith('time') || key.endsWith('_at')) {
|
|
285
|
+
return moment(data[key]).diff(moment(target[key].$gt), 'seconds') > 0
|
|
286
|
+
}
|
|
287
|
+
return data[key] > target[key].$gt
|
|
288
|
+
} else if (Object.prototype.hasOwnProperty.call(target[key], '$gte')) {
|
|
289
|
+
if (key.endsWith('time') || key.endsWith('_at')) {
|
|
290
|
+
return moment(data[key]).diff(moment(target[key].$gt), 'seconds') >= 0
|
|
291
|
+
}
|
|
292
|
+
return data[key] >= target[key].$gte
|
|
293
|
+
} else if (Object.prototype.hasOwnProperty.call(target[key], '$lt')) {
|
|
294
|
+
if (key.endsWith('time') || key.endsWith('_at')) {
|
|
295
|
+
return moment(target[key].$gt).diff(moment(data[key]), 'seconds') < 0
|
|
296
|
+
}
|
|
297
|
+
return data[key] < target[key].$lt
|
|
298
|
+
} else if (Object.prototype.hasOwnProperty.call(target[key], '$lte')) {
|
|
299
|
+
if (key.endsWith('time') || key.endsWith('_at')) {
|
|
300
|
+
return moment(target[key].$gt).diff(moment(data[key]), 'seconds') <= 0
|
|
301
|
+
}
|
|
302
|
+
return data[key] <= target[key].$lte
|
|
303
|
+
} else if (Object.prototype.hasOwnProperty.call(target[key], '$notIn')) {
|
|
304
|
+
return !target[key].$notIn.includes(data[key])
|
|
305
|
+
} else if (Object.prototype.hasOwnProperty.call(target[key], '$in')) {
|
|
306
|
+
return target[key].$in.includes(data[key])
|
|
307
|
+
} else if (
|
|
308
|
+
Object.prototype.hasOwnProperty.call(target[key], '$between')
|
|
309
|
+
) {
|
|
310
|
+
if (
|
|
311
|
+
!Array.isArray(target[key].$between) ||
|
|
312
|
+
target[key].$between.length !== 2
|
|
313
|
+
) {
|
|
314
|
+
throw new Error(`$between example : [2,5]`)
|
|
315
|
+
}
|
|
316
|
+
const min = target[key].$between[0]
|
|
317
|
+
const max = target[key].$between[1]
|
|
318
|
+
return data[key] >= min && data[key] <= max
|
|
319
|
+
} else if (Object.prototype.hasOwnProperty.call(target[key], '$ne')) {
|
|
320
|
+
return data[key] !== target[key].$ne
|
|
321
|
+
} else if (Object.prototype.hasOwnProperty.call(target[key], '$neq')) {
|
|
322
|
+
return data[key] !== target[key].$neq
|
|
323
|
+
} else if (Object.prototype.hasOwnProperty.call(target[key], '$eq')) {
|
|
324
|
+
return data[key] === target[key].$eq
|
|
325
|
+
}
|
|
326
|
+
return data[key] === target[key]
|
|
327
|
+
}
|
|
328
|
+
return data[key] === target[key]
|
|
329
|
+
})
|
|
330
|
+
}
|