feat;提交管理端和城市合伙人端
This commit is contained in:
@@ -7,6 +7,7 @@ import { PayWechatProvider } from './pay/pay.wechat.provider';
|
||||
import { DeliveryMockProvider } from './delivery/delivery.mock.provider';
|
||||
import { WechatApiProvider } from './wechat/wechat.api.provider';
|
||||
import { WechatDisabledProvider } from './wechat/wechat.disabled.provider';
|
||||
import { WechatMockProvider } from './wechat/wechat.mock.provider';
|
||||
import { OssMockProvider } from './oss/oss.mock.provider';
|
||||
import { OssAliyunProvider } from './oss/oss.aliyun.provider';
|
||||
import {
|
||||
@@ -27,16 +28,24 @@ import type { IOssProvider } from './oss/oss.interface';
|
||||
{ provide: SMS_PROVIDER, useClass: SmsMockProvider },
|
||||
WechatApiProvider,
|
||||
WechatDisabledProvider,
|
||||
WechatMockProvider,
|
||||
{
|
||||
provide: WECHAT_PROVIDER,
|
||||
useFactory: (api: WechatApiProvider, disabled: WechatDisabledProvider): IWechatProvider => {
|
||||
useFactory: (
|
||||
api: WechatApiProvider,
|
||||
disabled: WechatDisabledProvider,
|
||||
mock: WechatMockProvider,
|
||||
): IWechatProvider => {
|
||||
const cfg = loadAppConfig();
|
||||
const enabled =
|
||||
(cfg.wechatAuthEnabled || cfg.wechatPayEnabled) &&
|
||||
(!!cfg.wxAppId || !!process.env.WX_MCH_ID);
|
||||
return enabled ? api : disabled;
|
||||
if (enabled) return api;
|
||||
// preV1:真实微信未配置但开启 Mock 授权登录
|
||||
if (cfg.mockWechat) return mock;
|
||||
return disabled;
|
||||
},
|
||||
inject: [WechatApiProvider, WechatDisabledProvider],
|
||||
inject: [WechatApiProvider, WechatDisabledProvider, WechatMockProvider],
|
||||
},
|
||||
PayMockProvider,
|
||||
PayWechatProvider,
|
||||
|
||||
@@ -34,6 +34,10 @@ export class WechatApiProvider implements IWechatProvider {
|
||||
return this.config.wechatAuthEnabled && !!this.appId && !!this.appSecret;
|
||||
}
|
||||
|
||||
isMock() {
|
||||
return false;
|
||||
}
|
||||
|
||||
isPayEnabled() {
|
||||
return (
|
||||
this.config.wechatPayEnabled &&
|
||||
|
||||
@@ -7,6 +7,10 @@ export class WechatDisabledProvider implements IWechatProvider {
|
||||
return false;
|
||||
}
|
||||
|
||||
isMock() {
|
||||
return false;
|
||||
}
|
||||
|
||||
isPayEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@ export type WechatPayNotifyResult = {
|
||||
export interface IWechatProvider {
|
||||
isEnabled(): boolean;
|
||||
|
||||
/** 是否为 preV1 Mock 实现(登录时可回落到演示账号) */
|
||||
isMock(): boolean;
|
||||
|
||||
/** 微信支付是否已配置(商户号 + 证书) */
|
||||
isPayEnabled(): boolean;
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import { createHash } from 'crypto';
|
||||
import { Injectable, NotImplementedException } from '@nestjs/common';
|
||||
import type {
|
||||
IWechatProvider,
|
||||
WechatCodeSession,
|
||||
WechatOAuthSession,
|
||||
} from './wechat.interface';
|
||||
|
||||
/**
|
||||
* preV1 Mock 微信 Provider。
|
||||
*
|
||||
* 目的:让「微信授权登录」按钮在不接真实微信的情况下走通。前端仍按真实 OAuth 流程
|
||||
* (跳转 oauth-url → 回调携带 code),Mock 端将授权 URL 直接回跳并返回稳定 openId。
|
||||
* 后续填入 WX_APP_ID/WX_APP_SECRET 并置 MOCK_WECHAT=false 即切换到真实实现。
|
||||
*/
|
||||
@Injectable()
|
||||
export class WechatMockProvider implements IWechatProvider {
|
||||
isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
isMock() {
|
||||
return true;
|
||||
}
|
||||
|
||||
isPayEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
getMchId() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/** 由 code 派生稳定 openId,保证同一 code 多次授权指向同一账号 */
|
||||
private openIdFromCode(code: string): string {
|
||||
return `mockwx_${createHash('md5').update(code).digest('hex').slice(0, 24)}`;
|
||||
}
|
||||
|
||||
async code2Session(code: string): Promise<WechatCodeSession> {
|
||||
return { openId: this.openIdFromCode(code), sessionKey: 'mock-session-key' };
|
||||
}
|
||||
|
||||
async oauth2AccessToken(code: string): Promise<WechatOAuthSession> {
|
||||
return { openId: this.openIdFromCode(code), accessToken: 'mock-access-token' };
|
||||
}
|
||||
|
||||
async createJssdkConfig(url: string) {
|
||||
return {
|
||||
appId: 'mock-appid',
|
||||
timestamp: Math.floor(Date.now() / 1000),
|
||||
nonceStr: 'mocknonce',
|
||||
signature: 'mocksignature',
|
||||
url,
|
||||
jsApiList: ['getLocation', 'scanQRCode', 'chooseImage'],
|
||||
} as unknown as Awaited<ReturnType<IWechatProvider['createJssdkConfig']>>;
|
||||
}
|
||||
|
||||
/** 直接把授权链接回跳到 redirectUri 并附带 mock code,模拟微信授权完成 */
|
||||
buildOAuthUrl(redirectUri: string, state: string): string {
|
||||
const sep = redirectUri.includes('?') ? '&' : '?';
|
||||
const code = `mockcode_${state || 'default'}`;
|
||||
return `${redirectUri}${sep}code=${encodeURIComponent(code)}&state=${encodeURIComponent(state)}`;
|
||||
}
|
||||
|
||||
async getPhoneNumberByCode(): Promise<string> {
|
||||
throw new NotImplementedException('Mock 微信不支持获取手机号,请用短信绑定');
|
||||
}
|
||||
|
||||
createJsapiPrepay(): never {
|
||||
throw new NotImplementedException('FEATURE_DISABLED');
|
||||
}
|
||||
|
||||
parsePayNotification(): never {
|
||||
throw new NotImplementedException('FEATURE_DISABLED');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user