q-koa 7.8.6 → 7.9.2
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/file/plugins/cache/config.js +19 -0
- package/core/file/plugins/cache/model.js +24 -0
- package/core/file/plugins/system/controller.js +2 -0
- package/core/file/plugins/system/service.js +92 -5
- package/core/file/plugins/user/controller.js +0 -1
- package/core/file/plugins/weixin/controller.js +171 -1
- package/core/file/plugins/weixin/service.js +1 -1
- package/core/file/plugins/weixin/validate.js +11 -0
- package/core/file/services/express.js +6 -1
- package/core/file/services/weixinMP.js +17 -4
- package/package.json +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
name: '缓存',
|
|
3
|
+
belongs: 'auth',
|
|
4
|
+
multiple: false,
|
|
5
|
+
availableSort: false,
|
|
6
|
+
order: [],
|
|
7
|
+
select: [],
|
|
8
|
+
excludes: [],
|
|
9
|
+
limit: 20,
|
|
10
|
+
defaultOrder: [],
|
|
11
|
+
sortOrder: 1,
|
|
12
|
+
reference: [],
|
|
13
|
+
excludeAuth: [],
|
|
14
|
+
initList: [],
|
|
15
|
+
is_split: false,
|
|
16
|
+
is_split_count: false,
|
|
17
|
+
show_virtual: false,
|
|
18
|
+
deleteCheckList: [],
|
|
19
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const { Sequelize, Random } = require('q-koa')
|
|
2
|
+
|
|
3
|
+
exports.key = {
|
|
4
|
+
type: Sequelize.STRING,
|
|
5
|
+
comment: 'key',
|
|
6
|
+
allowNull: false,
|
|
7
|
+
is_mock: true,
|
|
8
|
+
unique: true,
|
|
9
|
+
sortOrder: 1,
|
|
10
|
+
mock: () => Random.ctitle(),
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
exports.result = {
|
|
14
|
+
type: Sequelize.JSON,
|
|
15
|
+
comment: '结果',
|
|
16
|
+
allowNull: false,
|
|
17
|
+
is_mock: false,
|
|
18
|
+
sortOrder: 2,
|
|
19
|
+
get: function () {
|
|
20
|
+
return this.getDataValue('result') === null
|
|
21
|
+
? null
|
|
22
|
+
: this.getDataValue('result')
|
|
23
|
+
},
|
|
24
|
+
}
|
|
@@ -166,6 +166,8 @@ exports.showTables = async (ctx) => {
|
|
|
166
166
|
autoData: lodash.get(target, 'autoData', null),
|
|
167
167
|
// 有些model需要前置查询其它model数据
|
|
168
168
|
initList: lodash.get(target, 'initList', []),
|
|
169
|
+
// 批量修改
|
|
170
|
+
bulkCreateList: lodash.get(target, 'bulkCreateList', []),
|
|
169
171
|
// 局部更新列表
|
|
170
172
|
editInline: lodash.get(target, 'editInline', {}),
|
|
171
173
|
// 有些model需要前置查询其它model数据
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { getConfig, lodash } = require('q-koa')
|
|
2
2
|
const formatPostFunction = (str) => `eval(${str})`
|
|
3
3
|
const nodeVm = require('vm')
|
|
4
|
+
const { is } = require('cheerio/lib/api/traversing')
|
|
4
5
|
|
|
5
6
|
exports.initData = async ({ includes, excludes, app, ctx }) => {
|
|
6
7
|
const appConfig = getConfig(app)
|
|
@@ -77,8 +78,68 @@ exports.initData = async ({ includes, excludes, app, ctx }) => {
|
|
|
77
78
|
}
|
|
78
79
|
})
|
|
79
80
|
} else if (app.model[model]) {
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
if (app.model[model][fn]) {
|
|
82
|
+
if (
|
|
83
|
+
data &&
|
|
84
|
+
data.cache_level &&
|
|
85
|
+
data.cache_level === 2 &&
|
|
86
|
+
app.model.cache
|
|
87
|
+
) {
|
|
88
|
+
return app.model.cache
|
|
89
|
+
.findOne({
|
|
90
|
+
where: {
|
|
91
|
+
key: JSON.stringify({
|
|
92
|
+
order,
|
|
93
|
+
limit,
|
|
94
|
+
include: myInclude,
|
|
95
|
+
...data,
|
|
96
|
+
}),
|
|
97
|
+
},
|
|
98
|
+
})
|
|
99
|
+
.then((res) => {
|
|
100
|
+
if (res && res.result) {
|
|
101
|
+
console.log(`${model}有cache`)
|
|
102
|
+
return Promise.resolve({
|
|
103
|
+
[item]: res.result,
|
|
104
|
+
})
|
|
105
|
+
} else {
|
|
106
|
+
return app.model[model][fn]({
|
|
107
|
+
order,
|
|
108
|
+
limit,
|
|
109
|
+
include: myInclude,
|
|
110
|
+
...data,
|
|
111
|
+
}).then((result) => {
|
|
112
|
+
const list =
|
|
113
|
+
data && data.omit && Array.isArray(data.omit)
|
|
114
|
+
? result.map((obj) => {
|
|
115
|
+
return lodash.omit(obj.toJSON(), data.omit)
|
|
116
|
+
})
|
|
117
|
+
: result
|
|
118
|
+
if (
|
|
119
|
+
data &&
|
|
120
|
+
data.cache_level &&
|
|
121
|
+
data.cache_level === 2 &&
|
|
122
|
+
list.length > 0
|
|
123
|
+
) {
|
|
124
|
+
app.model.cache &&
|
|
125
|
+
app.model.cache.create({
|
|
126
|
+
key: JSON.stringify({
|
|
127
|
+
order,
|
|
128
|
+
limit,
|
|
129
|
+
include: myInclude,
|
|
130
|
+
...data,
|
|
131
|
+
}),
|
|
132
|
+
result: list,
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
[item]: list,
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
} else {
|
|
142
|
+
return app.model[model][fn]({
|
|
82
143
|
order,
|
|
83
144
|
limit,
|
|
84
145
|
include: myInclude,
|
|
@@ -90,13 +151,39 @@ exports.initData = async ({ includes, excludes, app, ctx }) => {
|
|
|
90
151
|
return lodash.omit(obj.toJSON(), data.omit)
|
|
91
152
|
})
|
|
92
153
|
: result
|
|
154
|
+
if (
|
|
155
|
+
data &&
|
|
156
|
+
data.cache_level &&
|
|
157
|
+
data.cache_level === 1 &&
|
|
158
|
+
list.length > 0
|
|
159
|
+
) {
|
|
160
|
+
app.model.cache &&
|
|
161
|
+
app.model.cache.update(
|
|
162
|
+
{
|
|
163
|
+
result: list,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
where: {
|
|
167
|
+
key: JSON.stringify({
|
|
168
|
+
order,
|
|
169
|
+
limit,
|
|
170
|
+
include: myInclude,
|
|
171
|
+
...data,
|
|
172
|
+
}),
|
|
173
|
+
},
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
}
|
|
93
177
|
return {
|
|
94
178
|
[item]: list,
|
|
95
179
|
}
|
|
96
180
|
})
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
return Promise.resolve({
|
|
184
|
+
[item]: [],
|
|
185
|
+
})
|
|
186
|
+
}
|
|
100
187
|
} else {
|
|
101
188
|
return Promise.resolve({
|
|
102
189
|
[item]: [],
|
|
@@ -171,6 +171,99 @@ exports.getPhone = async (ctx) => {
|
|
|
171
171
|
return ctx.SUCCESS({ phoneNumber })
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
exports.mp_getPhoneNew = async (ctx) => {
|
|
175
|
+
const { app, appName } = getAppByCtx(ctx)
|
|
176
|
+
|
|
177
|
+
const { code } = ctx.request.body
|
|
178
|
+
|
|
179
|
+
const user_id = ctx.request[appName + '-user'].id
|
|
180
|
+
const appConfig = getConfig(app)
|
|
181
|
+
const { app_id, app_secrect } = await appConfig.getObject('weixin_mp')
|
|
182
|
+
|
|
183
|
+
const weixinMp = new WeixinMp({
|
|
184
|
+
appid: app_id,
|
|
185
|
+
secrect: app_secrect,
|
|
186
|
+
})
|
|
187
|
+
weixinMp.init()
|
|
188
|
+
|
|
189
|
+
const { phoneNumber } = await weixinMp.getPhoneNumber(code)
|
|
190
|
+
|
|
191
|
+
if (!phoneNumber) throw new Error('微信获取手机失败,请重试')
|
|
192
|
+
|
|
193
|
+
const exist = await app.model.user.findOne({
|
|
194
|
+
where: {
|
|
195
|
+
mobile: phoneNumber,
|
|
196
|
+
},
|
|
197
|
+
include: [
|
|
198
|
+
{
|
|
199
|
+
model: app.model.mp_user,
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
const mobileExist =
|
|
205
|
+
exist &&
|
|
206
|
+
exist.mp_user &&
|
|
207
|
+
(!exist.mp_user.appid || exist.mp_user.appid === app_id)
|
|
208
|
+
|
|
209
|
+
if (mobileExist) {
|
|
210
|
+
throw new Error('系统已存在该手机号')
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
await app.model.user.upsert({
|
|
214
|
+
id: user_id,
|
|
215
|
+
mobile: phoneNumber,
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
const result = await app.model.user.findOne({
|
|
219
|
+
where: {
|
|
220
|
+
id: user_id,
|
|
221
|
+
},
|
|
222
|
+
include: [
|
|
223
|
+
{
|
|
224
|
+
model: app.model.h5_user,
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
model: app.model.mp_user,
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
model: app.model.toutiao_user,
|
|
231
|
+
},
|
|
232
|
+
...app.include.user,
|
|
233
|
+
].filter((item) => item.model),
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
const tokenResult = {
|
|
237
|
+
id: result.id,
|
|
238
|
+
name: result.name,
|
|
239
|
+
mobile: result.mobile,
|
|
240
|
+
h5_user: result.h5_user
|
|
241
|
+
? {
|
|
242
|
+
openid: result.h5_user && result.h5_user.openid,
|
|
243
|
+
}
|
|
244
|
+
: null,
|
|
245
|
+
mp_user: result.mp_user
|
|
246
|
+
? {
|
|
247
|
+
openid: result.mp_user && result.mp_user.openid,
|
|
248
|
+
}
|
|
249
|
+
: null,
|
|
250
|
+
toutiao_user: result.toutiao_user
|
|
251
|
+
? {
|
|
252
|
+
openid: result.toutiao_user && result.toutiao_user.openid,
|
|
253
|
+
}
|
|
254
|
+
: null,
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const token = await app.sign({
|
|
258
|
+
user: tokenResult,
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
return ctx.SUCCESS({
|
|
262
|
+
token,
|
|
263
|
+
user: result,
|
|
264
|
+
})
|
|
265
|
+
}
|
|
266
|
+
|
|
174
267
|
/**
|
|
175
268
|
* 微信小程序登录
|
|
176
269
|
*/
|
|
@@ -251,7 +344,9 @@ exports.mp_login = async (ctx) => {
|
|
|
251
344
|
try {
|
|
252
345
|
await app.sequelize.transaction(async (transaction) => {
|
|
253
346
|
const user = await app.model.user.create(
|
|
254
|
-
{
|
|
347
|
+
{
|
|
348
|
+
mp_openid: post.openid,
|
|
349
|
+
},
|
|
255
350
|
{
|
|
256
351
|
transaction,
|
|
257
352
|
}
|
|
@@ -998,3 +1093,78 @@ exports.article = async (ctx) => {
|
|
|
998
1093
|
|
|
999
1094
|
return ctx.SUCCESS(result)
|
|
1000
1095
|
}
|
|
1096
|
+
|
|
1097
|
+
exports.checkPay = async (ctx) => {
|
|
1098
|
+
const { app, appName, controller } = getAppByCtx(ctx)
|
|
1099
|
+
|
|
1100
|
+
const { id, prefix } = ctx.request.body
|
|
1101
|
+
|
|
1102
|
+
const orderModel = prefix ? `${prefix}_order` : 'order'
|
|
1103
|
+
const result = await app.model[orderModel].findOne({
|
|
1104
|
+
where: {
|
|
1105
|
+
id,
|
|
1106
|
+
},
|
|
1107
|
+
})
|
|
1108
|
+
if (!result) return ctx.SUCCESS('找不到')
|
|
1109
|
+
|
|
1110
|
+
const appConfig = getConfig(app)
|
|
1111
|
+
const app_id = (await appConfig.getObject('weixin_mp')).app_id
|
|
1112
|
+
const { mchId, key } = await appConfig.getObject('weixin_pay')
|
|
1113
|
+
|
|
1114
|
+
const wxpay = WXPay({
|
|
1115
|
+
appid: app_id,
|
|
1116
|
+
mch_id: mchId,
|
|
1117
|
+
partner_key: key, // 微信商户平台API密钥
|
|
1118
|
+
})
|
|
1119
|
+
|
|
1120
|
+
const checkOrder = (obj) => {
|
|
1121
|
+
return new Promise((resolve, reject) => {
|
|
1122
|
+
wxpay.queryOrder(obj, function (err, order) {
|
|
1123
|
+
if (err) throw new Error(err)
|
|
1124
|
+
resolve(order)
|
|
1125
|
+
})
|
|
1126
|
+
})
|
|
1127
|
+
}
|
|
1128
|
+
const orderPrefix = prefix ? `${prefix}-` : ''
|
|
1129
|
+
const out_trade_no = `${appName}_${orderPrefix}${id}_MP-WEIXIN`
|
|
1130
|
+
const payResult = await checkOrder({
|
|
1131
|
+
out_trade_no,
|
|
1132
|
+
})
|
|
1133
|
+
|
|
1134
|
+
if (payResult.trade_state_desc === '支付成功') {
|
|
1135
|
+
const order_price = Number(payResult.total_fee) / 100
|
|
1136
|
+
await app.service[orderModel].notify({
|
|
1137
|
+
app,
|
|
1138
|
+
order: orderModel,
|
|
1139
|
+
order_id: id,
|
|
1140
|
+
order_price,
|
|
1141
|
+
transaction_id: payResult.transaction_id,
|
|
1142
|
+
})
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
ctx.SUCCESS({ prefix, out_trade_no, ...payResult })
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
exports.init_mp_openid = async (ctx) => {
|
|
1149
|
+
const { app, appName } = getAppByCtx(ctx)
|
|
1150
|
+
|
|
1151
|
+
const list = await app.model.user.findAll({
|
|
1152
|
+
where: {
|
|
1153
|
+
mp_openid: '',
|
|
1154
|
+
},
|
|
1155
|
+
include: app.model.mp_user,
|
|
1156
|
+
})
|
|
1157
|
+
|
|
1158
|
+
const result = list.map((item) => {
|
|
1159
|
+
return {
|
|
1160
|
+
id: item.id,
|
|
1161
|
+
mp_openid: item.mp_user.openid,
|
|
1162
|
+
}
|
|
1163
|
+
})
|
|
1164
|
+
|
|
1165
|
+
await app.model.user.bulkCreate(result, {
|
|
1166
|
+
updateOnDuplicate: ['mp_openid'],
|
|
1167
|
+
})
|
|
1168
|
+
|
|
1169
|
+
ctx.SUCCESS(result.length)
|
|
1170
|
+
}
|
|
@@ -91,7 +91,7 @@ exports.cash = async ({ ctx, id, user_id, number }) => {
|
|
|
91
91
|
if (!user) throw new Error('找不到该用户')
|
|
92
92
|
if (!user.mp_user.openid) throw new Error('找不到该用户openid')
|
|
93
93
|
|
|
94
|
-
const amount = Math.abs(number) * 100
|
|
94
|
+
const amount = Number((Math.abs(number) * 100).toFixed(0))
|
|
95
95
|
|
|
96
96
|
const result = await payObj.transfers({
|
|
97
97
|
partner_trade_no: `${id}`,
|
|
@@ -108,3 +108,14 @@ exports.sendMessage = async (ctx) => {
|
|
|
108
108
|
}
|
|
109
109
|
await new Validator(params).validate(ctx.request.body)
|
|
110
110
|
}
|
|
111
|
+
|
|
112
|
+
exports.checkPay = async (ctx) => {
|
|
113
|
+
const params = {
|
|
114
|
+
id: {
|
|
115
|
+
type: 'number',
|
|
116
|
+
required: true,
|
|
117
|
+
message: 'id不能未空',
|
|
118
|
+
},
|
|
119
|
+
}
|
|
120
|
+
await new Validator(params).validate(ctx.request.body)
|
|
121
|
+
}
|
|
@@ -28,7 +28,12 @@ module.exports = class Singleton {
|
|
|
28
28
|
Authorization: `APPCODE ${this.config.app_code}`,
|
|
29
29
|
},
|
|
30
30
|
}).then((res) => res.data)
|
|
31
|
-
|
|
31
|
+
|
|
32
|
+
if (result.msg === 'ok' || result.status === '205') {
|
|
33
|
+
return result.result
|
|
34
|
+
} else {
|
|
35
|
+
throw new Error(result.msg)
|
|
36
|
+
}
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
getConfig() {
|
|
@@ -4,6 +4,8 @@ const axios = require('axios')
|
|
|
4
4
|
const { lodash } = require('q-koa')
|
|
5
5
|
const getAccessTokenUrl =
|
|
6
6
|
'https://api.weixin.qq.com/cgi-bin/token?grant_type=%s&appid=%s&secret=%s'
|
|
7
|
+
const getPhoneNumberUrl =
|
|
8
|
+
'https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s'
|
|
7
9
|
const createQRCodeUrl =
|
|
8
10
|
'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s'
|
|
9
11
|
const sendMessageUrl =
|
|
@@ -273,16 +275,27 @@ module.exports = class Singleton {
|
|
|
273
275
|
if (result.errcode) {
|
|
274
276
|
if (result.errcode === 40001) {
|
|
275
277
|
cache.reset()
|
|
276
|
-
return await this.getLive(
|
|
277
|
-
start,
|
|
278
|
-
limit,
|
|
279
|
-
})
|
|
278
|
+
return await this.getLive(start, limit)
|
|
280
279
|
}
|
|
281
280
|
throw new Error(`${result.errcode};${result.errmsg}`)
|
|
282
281
|
}
|
|
283
282
|
return result.room_info
|
|
284
283
|
}
|
|
285
284
|
|
|
285
|
+
async getPhoneNumber(code) {
|
|
286
|
+
const access_token = await this.getAccessToken()
|
|
287
|
+
const url = util.format(getPhoneNumberUrl, access_token)
|
|
288
|
+
const result = await axios.post(url, { code }).then((res) => res.data)
|
|
289
|
+
if (result.errcode) {
|
|
290
|
+
if (result.errcode === 40001) {
|
|
291
|
+
cache.reset()
|
|
292
|
+
return await this.getPhoneNumber(code)
|
|
293
|
+
}
|
|
294
|
+
throw new Error(`${result.errcode};${result.errmsg}`)
|
|
295
|
+
}
|
|
296
|
+
return result.phone_info
|
|
297
|
+
}
|
|
298
|
+
|
|
286
299
|
async createQR(options) {
|
|
287
300
|
if (!this.config.targetPath) throw new Error('没有配置文件夹')
|
|
288
301
|
const access_token = await this.getAccessToken()
|