From 0d90e20ec20f0aeee642756a7ebf9e8514174124 Mon Sep 17 00:00:00 2001
From: wangrong <wangrong@shsening.com>
Date: 星期一, 26 十月 2026 21:15:20 +0800
Subject: [PATCH] 微信小程序插件支持
---
src/modules/user/service/wx.ts | 129 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 125 insertions(+), 4 deletions(-)
diff --git a/src/modules/user/service/wx.ts b/src/modules/user/service/wx.ts
index 9c1c97a..6c85ac7 100644
--- a/src/modules/user/service/wx.ts
+++ b/src/modules/user/service/wx.ts
@@ -6,6 +6,7 @@
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';
@@ -18,14 +19,22 @@
@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 };
/**
* 鑾峰緱鎻掍欢瀹炰緥
@@ -49,6 +58,68 @@
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;
}
/**
@@ -215,10 +286,20 @@
* @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;
}
/**
@@ -255,6 +336,11 @@
* @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('鑾峰彇鎵嬫満鍙峰け璐ワ紝璇峰埛鏂伴噸璇�');
@@ -268,6 +354,41 @@
}
/**
+ * 鐢ㄦ墜鏈哄彿鍔ㄦ�佷护鐗屾崲鍙栨墜鏈哄彿
+ * @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
--
Gitblit v1.9.1