| | |
| | | entity: AppComplainEntity, |
| | | insertParam: ctx => { |
| | | return { |
| | | userId: ctx.user.id, |
| | | userId: ctx.user.userId, |
| | | }; |
| | | }, |
| | | pageQueryOp: { |
| | | fieldEq: ['a.type'], |
| | | where: ctx => { |
| | | const userId = ctx.user.id; |
| | | const userId = ctx.user.userId; |
| | | return [['a.userId = :userId', { userId }]]; |
| | | }, |
| | | }, |
| | |
| | | |
| | | @Post('/submit', { summary: '提交投诉举报' }) |
| | | async submit(@Body() info) { |
| | | info.userId = this.ctx.user.id; |
| | | info.userId = this.ctx.user.userId; |
| | | await this.appComplainService.submit(info); |
| | | return this.ok(); |
| | | } |
| | |
| | | entity: AppFeedbackEntity, |
| | | insertParam: ctx => { |
| | | return { |
| | | userId: ctx.user.id, |
| | | userId: ctx.user.userId, |
| | | }; |
| | | }, |
| | | pageQueryOp: { |
| | | fieldEq: ['a.type'], |
| | | where: ctx => { |
| | | const userId = ctx.user.id; |
| | | const userId = ctx.user.userId; |
| | | return [['a.userId = :userId', { userId }]]; |
| | | }, |
| | | }, |
| | |
| | | |
| | | @Post('/submit', { summary: '提交意见反馈' }) |
| | | async submit(@Body() info) { |
| | | info.userId = this.ctx.user.id; |
| | | info.userId = this.ctx.user.userId; |
| | | await this.appFeedbackService.submit(info); |
| | | return this.ok(); |
| | | } |
| | |
| | | "data": "400", |
| | | "dataType": 0, |
| | | "remark": "逐台查询设备时的间隔,避免触发 QPS 限流" |
| | | }, |
| | | { |
| | | "keyName": "wx.mini.appId", |
| | | "name": "小程序AppId", |
| | | "data": "wx88c344d1b0db243a", |
| | | "dataType": 0, |
| | | "remark": "微信小程序 AppId,用于手机号登录" |
| | | }, |
| | | { |
| | | "keyName": "wx.mini.appSecret", |
| | | "name": "小程序AppSecret", |
| | | "data": "", |
| | | "dataType": 0, |
| | | "remark": "微信公众平台-开发管理-开发设置中的 AppSecret,用于用授权码换取手机号" |
| | | } |
| | | ], |
| | | "base_sys_conf": [ |
| | |
| | | }, |
| | | ], |
| | | where: ctx => { |
| | | return [['d.userId = :userId', { userId: ctx.user?.id }]]; |
| | | return [['d.userId = :userId', { userId: ctx.user?.userId }]]; |
| | | }, |
| | | }, |
| | | }) |
| | |
| | | |
| | | @Get('/unreadCount', { summary: '未读消息数' }) |
| | | async unreadCount() { |
| | | return this.ok(await this.csMsgService.unreadCount(this.ctx.user?.id, 1)); |
| | | return this.ok( |
| | | await this.csMsgService.unreadCount(this.ctx.user?.userId, 1) |
| | | ); |
| | | } |
| | | |
| | | @Post('/read', { summary: '标记已读' }) |
| | |
| | | |
| | | @Get('/detail', { summary: '会话详情' }) |
| | | async detail() { |
| | | return this.ok(await this.csSessionService.detail(this.ctx.user?.id)); |
| | | return this.ok(await this.csSessionService.detail(this.ctx.user?.userId)); |
| | | } |
| | | |
| | | @Post('/create', { summary: '创建会话' }) |
| | | async create() { |
| | | return this.ok(await this.csSessionService.create(this.ctx.user?.id)); |
| | | return this.ok(await this.csSessionService.create(this.ctx.user?.userId)); |
| | | } |
| | | } |
| | |
| | | import { Provide } from '@midwayjs/core'; |
| | | import { BaseService } from '@cool-midway/core'; |
| | | import { BaseService, CoolCommException } from '@cool-midway/core'; |
| | | import { InjectEntityModel } from '@midwayjs/typeorm'; |
| | | import { Repository } from 'typeorm'; |
| | | import { CsSessionEntity } from '../entity/session'; |
| | |
| | | * @returns |
| | | */ |
| | | async create(userId: number) { |
| | | if (!userId) { |
| | | throw new CoolCommException('用户不存在'); |
| | | } |
| | | const check = await this.detail(userId); |
| | | if (check) { |
| | | return check; |
| | |
| | | import { Config, Middleware } from '@midwayjs/core'; |
| | | import { Config, Inject, Middleware } from '@midwayjs/core'; |
| | | import { NextFunction } from '@midwayjs/socketio'; |
| | | import * as jwt from 'jsonwebtoken'; |
| | | import { UserInfoService } from '../../../user/service/info'; |
| | | |
| | | @Middleware() |
| | | export class CsSocketTokenMiddleware { |
| | |
| | | |
| | | @Config('module.base.jwt') |
| | | adminJwtConfig; |
| | | |
| | | @Inject() |
| | | userInfoService: UserInfoService; |
| | | |
| | | resolve() { |
| | | return async (ctx, next: NextFunction) => { |
| | |
| | | token, |
| | | isAdmin ? this.adminJwtConfig.secret : this.appJwtConfig.secret |
| | | ); |
| | | let userId = isAdmin ? data.userId : data.id; |
| | | if (!isAdmin) { |
| | | const info = await this.userInfoService.person(data.id); |
| | | userId = info?.id; |
| | | } |
| | | ctx.connData = { |
| | | userId: isAdmin ? data.userId : data.id, |
| | | userId, |
| | | isAdmin, |
| | | }; |
| | | } catch (error) { |
| | |
| | | entity: GoodsCommentEntity, |
| | | insertParam: ctx => { |
| | | return { |
| | | userId: ctx.user.id, |
| | | userId: ctx.user.userId, |
| | | }; |
| | | }, |
| | | pageQueryOp: { |
| | |
| | | @Body('orderId') orderId: number |
| | | ) { |
| | | return this.ok( |
| | | await this.goodsCommentService.submit(this.ctx.user.id, orderId, data) |
| | | await this.goodsCommentService.submit(this.ctx.user.userId, orderId, data) |
| | | ); |
| | | } |
| | | } |
| | |
| | | service: UserAddressService, |
| | | insertParam: ctx => { |
| | | return { |
| | | userId: ctx.user.id, |
| | | userId: ctx.user.userId, |
| | | }; |
| | | }, |
| | | pageQueryOp: { |
| | | where: async ctx => { |
| | | return [['userId =:userId', { userId: ctx.user.id }]]; |
| | | return [['userId =:userId', { userId: ctx.user.userId }]]; |
| | | }, |
| | | addOrderBy: { |
| | | isDefault: 'DESC', |
| | |
| | | |
| | | @Get('/default', { summary: '默认地址' }) |
| | | async default() { |
| | | return this.ok(await this.userAddressService.default(this.ctx.user.id)); |
| | | return this.ok( |
| | | await this.userAddressService.default(this.ctx.user.userId) |
| | | ); |
| | | } |
| | | } |
| | |
| | | import { CoolController, BaseController } from '@cool-midway/core'; |
| | | import { |
| | | CoolController, |
| | | BaseController, |
| | | CoolUrlTag, |
| | | CoolTag, |
| | | TagTypes, |
| | | } from '@cool-midway/core'; |
| | | import { Body, Get, Inject, Post } from '@midwayjs/core'; |
| | | import { UserInfoService } from '../../service/info'; |
| | | import { UserInfoEntity } from '../../entity/info'; |
| | |
| | | /** |
| | | * 用户信息 |
| | | */ |
| | | @CoolUrlTag() |
| | | @CoolController({ |
| | | api: [], |
| | | entity: UserInfoEntity, |
| | |
| | | ); |
| | | } |
| | | |
| | | @Post('/dashboard', { summary: '获取用户碳积分信息' }) |
| | | @CoolTag(TagTypes.IGNORE_TOKEN) |
| | | @Post('/dashboard', { summary: '获取用户碳积分信息' }) |
| | | async dashboard(@Body() body) { |
| | | console.log(body) |
| | | const {unionid} = body; |
| | | const { unionid } = body; |
| | | return this.ok( |
| | | await this.userInfoService.dashboard( |
| | | unionid |
| | |
| | | } |
| | | |
| | | @CoolTag(TagTypes.IGNORE_TOKEN) |
| | | @Post('/miniPhone', { summary: '绑定小程序手机号' }) |
| | | @Post('/miniPhone', { summary: '小程序手机号授权登录' }) |
| | | async miniPhone(@Body() body) { |
| | | const { code, encryptedData, iv } = body; |
| | | const { code, encryptedData, iv, loginCode } = body; |
| | | return this.ok( |
| | | await this.userLoginService.miniPhone(code, encryptedData, iv) |
| | | await this.userLoginService.miniPhone(code, encryptedData, iv, loginCode) |
| | | ); |
| | | } |
| | | |
| | | @CoolTag(TagTypes.IGNORE_TOKEN) |
| | | @Post('/miniAuto', { summary: '小程序静默登录' }) |
| | | async miniAuto(@Body('code') code: string) { |
| | | return this.ok(await this.userLoginService.miniAuto(code)); |
| | | } |
| | | |
| | | @CoolTag(TagTypes.IGNORE_TOKEN) |
| | | @Get('/captcha', { summary: '图片验证码' }) |
| | | async captcha( |
| | | @Query('width') width: number, |
| | |
| | | import * as _ from 'lodash'; |
| | | import { CoolCommException, CoolUrlTagData, TagTypes } from '@cool-midway/core'; |
| | | import { Utils } from '../../../comm/utils'; |
| | | import { UserInfoService } from '../service/info'; |
| | | |
| | | /** |
| | | * 用户 |
| | |
| | | let { url } = ctx; |
| | | url = url.replace(this.prefix, '').split('?')[0]; |
| | | if (_.startsWith(url, '/app/')) { |
| | | const token = ctx.get('Authorization'); |
| | | let token = ctx.get('Authorization') || ''; |
| | | token = token.replace(/^Bearer\s+/i, '').trim(); |
| | | try { |
| | | ctx.user = jwt.verify(token, this.jwtConfig.secret); |
| | | |
| | | if (ctx.user.isRefresh) { |
| | | throw new CoolCommException('登录失效~'); |
| | | } catch (error) { |
| | | ctx.user = undefined; |
| | | if (token) { |
| | | console.error('[user] token无效:', (error as Error).message); |
| | | } |
| | | } catch (error) {} |
| | | } |
| | | if (ctx.user?.isRefresh) { |
| | | ctx.user = undefined; |
| | | } else if (ctx.user?.id) { |
| | | try { |
| | | // 令牌里的 id 是 unionid(手机号登录时就是手机号),整型 userId 列要用用户主键 |
| | | const userInfoService = await ctx.requestContext.getAsync( |
| | | UserInfoService |
| | | ); |
| | | const info = await userInfoService.person(ctx.user.id); |
| | | if (info?.id) { |
| | | ctx.user.userId = info.id; |
| | | } |
| | | } catch (error) {} |
| | | } |
| | | // 使用matchUrl方法来检查URL是否应该被忽略 |
| | | const isIgnored = this.ignoreUrls.some(pattern => |
| | | this.utils.matchUrl(pattern, url) |
| | |
| | | async list() { |
| | | return this.userAddressEntity |
| | | .createQueryBuilder() |
| | | .where('userId = :userId ', { userId: this.ctx.user.id }) |
| | | .where('userId = :userId ', { userId: this.ctx.user.userId }) |
| | | .addOrderBy('isDefault', 'DESC') |
| | | .getMany(); |
| | | } |
| | |
| | | .createQueryBuilder() |
| | | .update() |
| | | .set({ isDefault: false }) |
| | | .where('userId = :userId ', { userId: this.ctx.user.id }) |
| | | .where('userId = :userId ', { userId: this.ctx.user.userId }) |
| | | .andWhere('id != :id', { id: data.id }) |
| | | .execute(); |
| | | } |
| | |
| | | * @returns |
| | | */ |
| | | async person(id) { |
| | | const info = await this.userInfoEntity.findOneBy({ id: Equal(id) }); |
| | | //delete info.password; |
| | | const idText = id === undefined || id === null ? '' : String(id); |
| | | // 手机号登录签发的是 unionid(手机号),不能拿去查整型主键 |
| | | let info = null; |
| | | if (/^\d{1,10}$/.test(idText)) { |
| | | info = await this.userInfoEntity.findOneBy({ id: Equal(Number(idText)) }); |
| | | } |
| | | if (!info && idText) { |
| | | info = await this.userInfoEntity.findOneBy({ |
| | | unionid: Equal(idText), |
| | | }); |
| | | } |
| | | return info; |
| | | } |
| | | |
| | |
| | | * @param userId |
| | | */ |
| | | async logoff(userId: number) { |
| | | const info = await this.person(userId); |
| | | if (!info) { |
| | | throw new CoolCommException('用户不存在'); |
| | | } |
| | | await this.userInfoEntity.update( |
| | | { id: userId }, |
| | | { id: info.id }, |
| | | { |
| | | status: 2, |
| | | phone: "", |
| | |
| | | } |
| | | } catch (err) { } |
| | | try { |
| | | return await this.userInfoEntity.update({ id }, param); |
| | | return await this.userInfoEntity.update({ id: info.id }, param); |
| | | } catch (err) { |
| | | throw new CoolCommException('更新失败,参数错误或者手机号已存在'); |
| | | } |
| | |
| | | throw new CoolCommException('验证码错误'); |
| | | } |
| | | |
| | | await this.userInfoEntity.update(user.unionid, { |
| | | await this.userInfoEntity.update(user.id, { |
| | | password: md5(password), |
| | | }); |
| | | } |
| | |
| | | if (!check) { |
| | | throw new CoolCommException('验证码错误'); |
| | | } |
| | | await this.userInfoEntity.update({ id: userId }, { phone }); |
| | | const info = await this.person(userId); |
| | | if (!info) { |
| | | throw new CoolCommException('用户不存在'); |
| | | } |
| | | await this.userInfoEntity.update({ id: info.id }, { phone }); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param encryptedData |
| | | * @param iv |
| | | */ |
| | | async miniPhone(code, encryptedData, iv) { |
| | | async miniPhone(code, encryptedData, iv, loginCode?) { |
| | | const phone = await this.userWxService.miniPhone(code, encryptedData, iv); |
| | | if (phone) { |
| | | return await this.phone(phone); |
| | | } else { |
| | | if (!phone) { |
| | | throw new CoolCommException('获得手机号失败,请检查配置'); |
| | | } |
| | | const token = await this.phone(phone); |
| | | await this.bindMiniOpenid(phone, loginCode); |
| | | return { |
| | | ...token, |
| | | phone, |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * 小程序再次打开时,用 openid 静默登录 |
| | | */ |
| | | async miniAuto(code: string) { |
| | | if (!code) { |
| | | return null; |
| | | } |
| | | const session = await this.userWxService.miniSession(code); |
| | | if (!session?.openid || session.errcode) { |
| | | return null; |
| | | } |
| | | const wx = await this.userWxEntity.findOneBy({ |
| | | openid: Equal(session.openid), |
| | | }); |
| | | if (!wx?.unionid) { |
| | | return null; |
| | | } |
| | | const user = await this.userInfoEntity.findOneBy({ |
| | | unionid: Equal(wx.unionid), |
| | | }); |
| | | if (!user?.phone || user.status === 2) { |
| | | return null; |
| | | } |
| | | const token = await this.token({ id: user.unionid }); |
| | | return { |
| | | ...token, |
| | | phone: user.phone, |
| | | nickName: user.nickName, |
| | | avatarUrl: user.avatarUrl, |
| | | unionid: user.unionid, |
| | | id: user.id, |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * 把当前微信 openid 记到手机号账号上,供下次静默登录 |
| | | */ |
| | | async bindMiniOpenid(phone: string, loginCode?: string) { |
| | | if (!loginCode) { |
| | | return; |
| | | } |
| | | try { |
| | | const session = await this.userWxService.miniSession(loginCode); |
| | | if (!session?.openid || session.errcode) { |
| | | return; |
| | | } |
| | | const user = await this.userInfoEntity.findOneBy({ |
| | | phone: Equal(phone), |
| | | }); |
| | | if (!user) { |
| | | return; |
| | | } |
| | | const unionid = user.unionid || session.unionid || phone; |
| | | const exist = await this.userWxEntity.findOneBy({ |
| | | openid: Equal(session.openid), |
| | | }); |
| | | await this.userWxEntity.save({ |
| | | id: exist?.id, |
| | | openid: session.openid, |
| | | unionid, |
| | | nickName: user.nickName, |
| | | avatarUrl: user.avatarUrl, |
| | | type: 0, |
| | | }); |
| | | } catch (err) { |
| | | // 绑定 openid 失败不影响本次手机号登录 |
| | | } |
| | | } |
| | | |
| | |
| | | user = { |
| | | phone, |
| | | unionid: phone, |
| | | loginType: 2, |
| | | loginType: 0, |
| | | departmentId: 1, |
| | | nickName: phone.replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2'), |
| | | }; |
| | | await this.userInfoEntity.insert(user); |
| | |
| | | import * as moment from 'moment'; |
| | | import { Equal, Repository } from 'typeorm'; |
| | | import { v1 as uuid } from 'uuid'; |
| | | import { BaseSysParamEntity } from '../../base/entity/sys/param'; |
| | | import { PluginService } from '../../plugin/service/info'; |
| | | import { UserInfoEntity } from '../entity/info'; |
| | | import { UserWxEntity } from '../entity/wx'; |
| | |
| | | @Config('module.user') |
| | | config; |
| | | |
| | | @Config('wxMini') |
| | | wxMini: { appId?: string; appSecret?: string }; |
| | | |
| | | @InjectEntityModel(UserInfoEntity) |
| | | userInfoEntity: Repository<UserInfoEntity>; |
| | | |
| | | @InjectEntityModel(UserWxEntity) |
| | | userWxEntity: Repository<UserWxEntity>; |
| | | |
| | | @InjectEntityModel(BaseSysParamEntity) |
| | | baseSysParamEntity: Repository<BaseSysParamEntity>; |
| | | |
| | | @Inject() |
| | | pluginService: PluginService; |
| | | |
| | | private miniTokenCache: { appId: string; token: string; expireAt: number }; |
| | | |
| | | /** |
| | | * 获得插件实例 |
| | |
| | | async getMiniApp() { |
| | | const wxPlugin: any = await this.getPlugin(); |
| | | return wxPlugin.MiniApp(); |
| | | } |
| | | |
| | | async readParam(key: string) { |
| | | const row = await this.baseSysParamEntity.findOneBy({ keyName: key }); |
| | | return (row?.data || '').trim(); |
| | | } |
| | | |
| | | /** |
| | | * 小程序账号。优先插件,其次系统参数 wx.mini.appId / wx.mini.appSecret |
| | | */ |
| | | async getMiniCredential() { |
| | | try { |
| | | const app = await this.getMiniApp(); |
| | | const account = app.getAccount(); |
| | | const appId = account.getAppId?.() || account.appId; |
| | | const secret = account.getSecret?.() || account.appSecret || account.secret; |
| | | if (appId && secret) { |
| | | return { appId, secret }; |
| | | } |
| | | } catch (error) { |
| | | // 未安装微信插件时改用系统参数 |
| | | } |
| | | |
| | | const paramAppId = await this.readParam('wx.mini.appId'); |
| | | const paramSecret = await this.readParam('wx.mini.appSecret'); |
| | | const appId = paramAppId || this.wxMini?.appId || ''; |
| | | const secret = paramSecret || this.wxMini?.appSecret || ''; |
| | | if (!appId || !secret) { |
| | | throw new CoolCommException( |
| | | '未配置小程序密钥。请在系统参数填写 wx.mini.appSecret(微信公众平台-开发管理-开发设置)' |
| | | ); |
| | | } |
| | | return { appId, secret }; |
| | | } |
| | | |
| | | async getMiniAccessToken() { |
| | | const { appId, secret } = await this.getMiniCredential(); |
| | | const now = Date.now(); |
| | | if ( |
| | | this.miniTokenCache && |
| | | this.miniTokenCache.appId === appId && |
| | | this.miniTokenCache.expireAt > now |
| | | ) { |
| | | return this.miniTokenCache.token; |
| | | } |
| | | |
| | | const { data } = await axios.get('https://api.weixin.qq.com/cgi-bin/token', { |
| | | params: { |
| | | grant_type: 'client_credential', |
| | | appid: appId, |
| | | secret, |
| | | }, |
| | | }); |
| | | if (!data?.access_token) { |
| | | throw new CoolCommException(data?.errmsg || '获取微信凭证失败,请检查 AppSecret'); |
| | | } |
| | | this.miniTokenCache = { |
| | | appId, |
| | | token: data.access_token, |
| | | expireAt: now + Math.max(60, (data.expires_in || 7200) - 120) * 1000, |
| | | }; |
| | | return data.access_token; |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param conf 配置 |
| | | */ |
| | | async miniSession(code) { |
| | | const app = await this.getMiniApp(); |
| | | const utils = app.getUtils(); |
| | | const result = await utils.codeToSession(code); |
| | | return result; |
| | | const { appId, secret } = await this.getMiniCredential(); |
| | | const { data } = await axios.get( |
| | | 'https://api.weixin.qq.com/sns/jscode2session', |
| | | { |
| | | params: { |
| | | appid: appId, |
| | | secret, |
| | | js_code: code, |
| | | grant_type: 'authorization_code', |
| | | }, |
| | | } |
| | | ); |
| | | console.log('[miniSession] appId=', appId, 'code前6位=', String(code).slice(0,6), 'ret=', JSON.stringify(data)); |
| | | return data; |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param iv |
| | | */ |
| | | async miniPhone(code, encryptedData, iv) { |
| | | // 新版获取手机号只返回动态令牌,由服务端向微信换取手机号 |
| | | if (!encryptedData || !iv) { |
| | | return await this.getPhoneNumber(code); |
| | | } |
| | | |
| | | const session = await this.miniSession(code); |
| | | if (session.errcode) { |
| | | throw new CoolCommException('获取手机号失败,请刷新重试'); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 用手机号动态令牌换取手机号 |
| | | * @param code getPhoneNumber 返回的 code |
| | | */ |
| | | async getPhoneNumber(code: string) { |
| | | if (!code) { |
| | | throw new CoolCommException('未获取到手机号授权'); |
| | | } |
| | | |
| | | const accessToken = await this.getMiniAccessToken(); |
| | | |
| | | const { data } = await axios.post( |
| | | 'https://api.weixin.qq.com/wxa/business/getuserphonenumber', |
| | | { code }, |
| | | { |
| | | params: { |
| | | access_token: accessToken, |
| | | }, |
| | | } |
| | | ); |
| | | |
| | | if (data?.errcode) { |
| | | throw new CoolCommException(data.errmsg || '获取手机号失败'); |
| | | } |
| | | |
| | | const phone = |
| | | data?.phone_info?.purePhoneNumber || data?.phone_info?.phoneNumber; |
| | | |
| | | if (!phone) { |
| | | throw new CoolCommException('获得手机号失败,请检查配置'); |
| | | } |
| | | |
| | | return phone; |
| | | } |
| | | |
| | | /** |
| | | * 小程序信息解密 |
| | | * @param encryptedData |
| | | * @param iv |
| | |
| | | mchid: string; |
| | | key: string; |
| | | notify_url: string; |
| | | publicKey: Buffer; |
| | | privateKey: Buffer; |
| | | publicKey: string; |
| | | privateKey: string; |
| | | verifyPublicKey?: string; |
| | | }): Promise<any>; |
| | | /** |
| | | * 获得Buffer |
| | | * @param path |
| | | * @returns |
| | | */ |
| | | getBuffer(path: string): Promise<Buffer<any>>; |
| | | /** |
| | | * 根据给定的 URL 下载文件并返回一个 Buffer。 |
| | | * @param {string} url 文件的 URL |
| | |
| | | mchid: string; |
| | | key: string; |
| | | notify_url: string; |
| | | publicKey: Buffer; |
| | | privateKey: Buffer; |
| | | publicKey: string; |
| | | privateKey: string; |
| | | verifyPublicKey?: string; |
| | | }, |
| | | ): Promise<any>; |
| | | } |
| | |
| | | import * as wxBaseMessage from './wxBaseMessage'; |
| | | import * as wuliu from './wuliu'; |
| | | import * as pay_wx from './pay-wx'; |
| | | import * as wx from './wx'; |
| | |
| | | wx: wx.CoolPlugin; |
| | | 'pay-wx': pay_wx.CoolPlugin; |
| | | wuliu: wuliu.CoolPlugin; |
| | | wxBaseMessage: wxBaseMessage.CoolPlugin; |
| | | } |
| | |
| | | Work, |
| | | OpenWork, |
| | | } from 'node-easywechat'; |
| | | import { IncomingMessage } from 'http'; |
| | | /** |
| | | * 微信 |
| | | */ |
| | |
| | | */ |
| | | OfficialAccount(config?: any): Promise<any>; |
| | | /** |
| | | * 创建请求 |
| | | * @param req |
| | | * @returns |
| | | */ |
| | | createRequest(req: IncomingMessage): Promise<any>; |
| | | /** |
| | | * 小程序 |
| | | * @param config |
| | | * @returns |
| New file |
| | |
| | | import { BasePlugin } from '@cool-midway/plugin-cli'; |
| | | interface TemplateDataItem { |
| | | value: string; |
| | | color?: string; |
| | | } |
| | | interface TemplateData { |
| | | [key: string]: TemplateDataItem; |
| | | } |
| | | interface MiniProgramParams { |
| | | appid?: string; |
| | | pagepath?: string; |
| | | } |
| | | interface SendTemplateMessageParams { |
| | | touser: string; |
| | | template_id: string; |
| | | url?: string; |
| | | miniprogram?: MiniProgramParams; |
| | | data: TemplateData; |
| | | client_msg_id?: string; |
| | | } |
| | | interface SendResult { |
| | | msgid: number; |
| | | errcode: number; |
| | | errmsg: string; |
| | | } |
| | | interface MassSendFilter { |
| | | is_to_all?: boolean; |
| | | tag_id?: string; |
| | | } |
| | | interface MassSendByOpenIdParams { |
| | | touser: string[]; |
| | | msgtype: string; |
| | | mpnews?: { |
| | | media_id: string; |
| | | }; |
| | | text?: { |
| | | content: string; |
| | | }; |
| | | voice?: { |
| | | media_id: string; |
| | | }; |
| | | image?: { |
| | | media_ids: string[]; |
| | | recommend?: string; |
| | | title?: string; |
| | | need_open_comment?: number; |
| | | only_fans_can_comment?: number; |
| | | }; |
| | | mpvideo?: { |
| | | media_id: string; |
| | | title?: string; |
| | | description?: string; |
| | | }; |
| | | wxcard?: { |
| | | card_id: string; |
| | | }; |
| | | send_ignore_reprint?: number; |
| | | clientmsgid?: string; |
| | | } |
| | | interface MassSendByTagParams { |
| | | filter: MassSendFilter; |
| | | msgtype: string; |
| | | mpnews?: { |
| | | media_id: string; |
| | | }; |
| | | text?: { |
| | | content: string; |
| | | }; |
| | | voice?: { |
| | | media_id: string; |
| | | }; |
| | | image?: { |
| | | media_ids: string[]; |
| | | recommend?: string; |
| | | title?: string; |
| | | need_open_comment?: number; |
| | | only_fans_can_comment?: number; |
| | | }; |
| | | mpvideo?: { |
| | | media_id: string; |
| | | title?: string; |
| | | description?: string; |
| | | }; |
| | | wxcard?: { |
| | | card_id: string; |
| | | }; |
| | | clientmsgid?: string; |
| | | } |
| | | interface MassSendResult { |
| | | type: string; |
| | | msg_id: number; |
| | | msg_data_id: number; |
| | | errcode: number; |
| | | errmsg: string; |
| | | } |
| | | interface SubscribeDataItem { |
| | | value: string; |
| | | } |
| | | interface SubscribeData { |
| | | [key: string]: SubscribeDataItem; |
| | | } |
| | | interface SendSubscribeMsgParams { |
| | | template_id: string; |
| | | touser: string; |
| | | page?: string; |
| | | data: SubscribeData; |
| | | miniprogram_state: string; |
| | | lang?: string; |
| | | } |
| | | interface SubscribeResult { |
| | | errcode: number; |
| | | errmsg: string; |
| | | } |
| | | interface OneTimeMiniProgram { |
| | | appid: string; |
| | | pagepath: string; |
| | | } |
| | | interface OneTimeMsgData { |
| | | content: { |
| | | value: string; |
| | | color?: string; |
| | | }; |
| | | } |
| | | interface SendOneTimeSubscribeParams { |
| | | touser: string; |
| | | template_id: string; |
| | | url?: string; |
| | | miniprogram?: OneTimeMiniProgram; |
| | | scene: string; |
| | | title: string; |
| | | data: OneTimeMsgData; |
| | | } |
| | | interface OneTimeSubscribeResult { |
| | | errcode: number; |
| | | errmsg: string; |
| | | } |
| | | export declare class CoolPlugin extends BasePlugin { |
| | | private getAccessToken; |
| | | private handleApiError; |
| | | private validateMassSendParams; |
| | | massSendByOpenId(params: MassSendByOpenIdParams): Promise<MassSendResult>; |
| | | massSendByTag(params: MassSendByTagParams): Promise<MassSendResult>; |
| | | sendTemplateMessage(params: SendTemplateMessageParams): Promise<SendResult>; |
| | | batchSendTemplateMessage( |
| | | paramsList: SendTemplateMessageParams[], |
| | | ): Promise<SendResult[]>; |
| | | sendSubscribeMsg(params: SendSubscribeMsgParams): Promise<SubscribeResult>; |
| | | sendOneTimeSubscribeMsg( |
| | | params: SendOneTimeSubscribeParams, |
| | | ): Promise<OneTimeSubscribeResult>; |
| | | } |
| | | export declare const Plugin: typeof CoolPlugin; |
| | | export {}; |