chore: src/modules/user/service/wx.ts

This commit is contained in:
2026-07-01 17:57:45 +08:00
parent 258814bb3f
commit 4d730d972f
+281
View File
@@ -0,0 +1,281 @@
import { BaseService, CoolCommException } from '@cool-midway/core';
import { Config, Inject, Provide } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import axios from 'axios';
import * as crypto from 'crypto';
import * as moment from 'moment';
import { Equal, Repository } from 'typeorm';
import { v1 as uuid } from 'uuid';
import { PluginService } from '../../plugin/service/info';
import { UserInfoEntity } from '../entity/info';
import { UserWxEntity } from '../entity/wx';
/**
* 微信
*/
@Provide()
export class UserWxService extends BaseService {
@Config('module.user')
config;
@InjectEntityModel(UserInfoEntity)
userInfoEntity: Repository<UserInfoEntity>;
@InjectEntityModel(UserWxEntity)
userWxEntity: Repository<UserWxEntity>;
@Inject()
pluginService: PluginService;
/**
* 获得插件实例
* @returns
*/
async getPlugin() {
try {
const wxPlugin: any = await this.pluginService.getInstance('wx');
return wxPlugin;
} catch (error) {
throw new CoolCommException(
'未配置微信插件,请到插件市场下载安装配置:https://cool-js.com/plugin/70'
);
}
}
/**
* 获得小程序实例
* @returns
*/
async getMiniApp() {
const wxPlugin: any = await this.getPlugin();
return wxPlugin.MiniApp();
}
/**
* 获得公众号实例
* @returns
*/
async getOfficialAccount() {
const wxPlugin: any = await this.getPlugin();
return wxPlugin.OfficialAccount();
}
/**
* 获得App实例
* @returns
*/
async getOpenPlatform() {
const wxPlugin: any = await this.getPlugin();
return wxPlugin.OpenPlatform();
}
/**
* 获得用户的openId
* @param userId
* @param type 0-小程序 1-公众号 2-App
*/
async getOpenid(userId: number, type = 0) {
const user = await this.userInfoEntity.findOneBy({
id: Equal(userId),
status: 1,
});
if (!user) {
throw new CoolCommException('用户不存在或已被禁用');
}
const wx = await this.userWxEntity
.createQueryBuilder('a')
.where('a.type = :type', { type })
.andWhere('(a.unionid = :unionid or a.openid =:openid )', {
unionid: user.unionid,
openid: user.unionid,
})
.getOne();
return wx ? wx.openid : null;
}
/**
* 获得微信配置
* @param appId
* @param appSecret
* @param url 当前网页的URL,不包含#及其后面部分(必须是调用JS接口页面的完整URL)
*/
public async getWxMpConfig(url: string) {
const token = await this.getWxToken();
const ticket = await axios.get(
'https://api.weixin.qq.com/cgi-bin/ticket/getticket',
{
params: {
access_token: token,
type: 'jsapi',
},
}
);
const account = (await this.getOfficialAccount()).getAccount();
const appid = account.getAppId();
// 返回结果集
const result = {
timestamp: parseInt(moment().valueOf() / 1000 + ''),
nonceStr: uuid(),
appId: appid, //appid
signature: '',
};
const signArr = [];
signArr.push('jsapi_ticket=' + ticket.data.ticket);
signArr.push('noncestr=' + result.nonceStr);
signArr.push('timestamp=' + result.timestamp);
signArr.push('url=' + decodeURI(url));
// 敏感信息加密处理
result.signature = crypto
.createHash('sha1')
.update(signArr.join('&'))
.digest('hex')
.toUpperCase();
return result;
}
/**
* 获得公众号用户信息
* @param code
*/
async mpUserInfo(code) {
const token = await this.openOrMpToken(code, 'mp');
return await this.openOrMpUserInfo(token);
}
/**
* 获得app用户信息
* @param code
*/
async appUserInfo(code) {
const token = await this.openOrMpToken(code, 'open');
return await this.openOrMpUserInfo(token);
}
/**
* 获得微信token 不用code
* @param appid
* @param secret
*/
public async getWxToken(type = 'mp') {
let app;
if (type == 'mp') {
app = await this.getOfficialAccount();
} else {
app = await this.getOpenPlatform();
}
return await app.getAccessToken().getToken();
}
/**
* 获得用户信息
* @param token
*/
async openOrMpUserInfo(token) {
return await axios
.get('https://api.weixin.qq.com/sns/userinfo', {
params: {
access_token: token.access_token,
openid: token.openid,
lang: 'zh_CN',
},
})
.then(res => {
return res.data;
});
}
/**
* 获得token嗯
* @param code
* @param type
*/
async openOrMpToken(code, type = 'mp') {
const account =
type == 'mp'
? (await this.getOfficialAccount()).getAccount()
: (await this.getMiniApp()).getAccount();
const result = await axios.get(
'https://api.weixin.qq.com/sns/oauth2/access_token',
{
params: {
appid: account.getAppId(),
secret: account.getSecret(),
code,
grant_type: 'authorization_code',
},
}
);
return result.data;
}
/**
* 获得小程序session
* @param code 微信code
* @param conf 配置
*/
async miniSession(code) {
const app = await this.getMiniApp();
const utils = app.getUtils();
const result = await utils.codeToSession(code);
return result;
}
/**
* 获得小程序用户信息
* @param code
* @param encryptedData
* @param iv
*/
async miniUserInfo(code, encryptedData, iv) {
const session = await this.miniSession(code);
if (session.errcode) {
throw new CoolCommException('登录失败,请重试');
}
const info: any = await this.miniDecryptData(
encryptedData,
iv,
session.session_key
);
if (info) {
delete info['watermark'];
return {
...info,
openid: session['openid'],
unionid: session['unionid'],
};
}
return null;
}
/**
* 获得小程序手机
* @param code
* @param encryptedData
* @param iv
*/
async miniPhone(code, encryptedData, iv) {
const session = await this.miniSession(code);
if (session.errcode) {
throw new CoolCommException('获取手机号失败,请刷新重试');
}
const result = await this.miniDecryptData(
encryptedData,
iv,
session.session_key
);
return result.phoneNumber;
}
/**
* 小程序信息解密
* @param encryptedData
* @param iv
* @param sessionKey
*/
async miniDecryptData(encryptedData, iv, sessionKey) {
const app = await this.getMiniApp();
const utils = app.getUtils();
return await utils.decryptSession(sessionKey, iv, encryptedData);
}
}