子账号登录微信授权

This commit is contained in:
2026-07-10 11:03:11 +08:00
parent f4f4f1b4aa
commit 9c5cb69730
11 changed files with 535 additions and 251 deletions
@@ -0,0 +1,29 @@
import { Navigate, useLocation } from 'react-router-dom';
import { getPartnerProfile, hasPartnerWxSession } from '../lib/api';
import { usePartnerSession } from '../contexts/PartnerSessionContext';
import { partnerHomePath } from '../lib/partnerAccess';
const PUBLIC_PATHS = new Set(['/login']);
export default function AuthGate({ children }: { children: React.ReactNode }) {
const { ready, authenticated, account } = usePartnerSession();
const location = useLocation();
if (!ready) {
return <div className="empty">...</div>;
}
if (authenticated && location.pathname === '/login') {
return <Navigate to={partnerHomePath(account ?? getPartnerProfile())} replace />;
}
if (!authenticated && !PUBLIC_PATHS.has(location.pathname)) {
const profile = getPartnerProfile();
if (profile && hasPartnerWxSession()) {
return <Navigate to="/login?quick=1" replace state={{ from: location }} />;
}
return <Navigate to="/login" replace state={{ from: location }} />;
}
return <>{children}</>;
}
@@ -1,4 +1,4 @@
import { useEffect, useId, useRef, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { uploadFileToOss, type OssMediaType } from '../lib/upload';
import { toastError } from '../lib/toast';
import {
@@ -33,11 +33,15 @@ function formatWechatUploadError(e: unknown): string {
const formatted = formatChooseImageFailMessage(msg);
if (formatted) return formatted;
if (/invalid signature/i.test(msg)) {
return '微信 JSSDK 签名校验失败:请确认公众号已配置 JS 接口安全域名为 user.runxian.top,并刷新页面后重试';
return '微信 JSSDK 签名校验失败:请确认公众号已配置 JS 接口安全域名,并刷新页面后重试';
}
return msg;
}
function acceptsImages(accept: string) {
return accept.includes('image');
}
export default function OssUploadField({
value,
onChange,
@@ -50,7 +54,6 @@ export default function OssUploadField({
wechatReady,
onWechatReadyChange,
}: OssUploadFieldProps) {
const inputId = useId();
const inputRef = useRef<HTMLInputElement>(null);
const [uploading, setUploading] = useState(false);
const [authorizing, setAuthorizing] = useState(false);
@@ -60,7 +63,9 @@ export default function OssUploadField({
const resolvedAccept =
accept ?? (mediaType === 'VIDEO' ? 'video/*' : mediaType === 'FILE' ? 'image/*,.pdf' : 'image/*');
const useWechatPicker = isWechatEnv() && mediaType === 'IMAGE';
const inWechat = isWechatEnv();
const useWechatPicker =
inWechat && (mediaType === 'IMAGE' || (mediaType === 'FILE' && acceptsImages(resolvedAccept)));
const needsAuth = useWechatPicker && needsWechatAuth(profile, clientConfig) && wechatReady !== true;
useEffect(() => {
@@ -124,7 +129,7 @@ export default function OssUploadField({
await weixinSdk.init();
const files = await weixinSdk.chooseImages({
count: 1,
sourceType: ['album'],
sourceType: ['album', 'camera'],
});
if (files?.[0]) {
await uploadSelectedFile(files[0]);
@@ -161,6 +166,7 @@ export default function OssUploadField({
const isImage = mediaType === 'IMAGE' && value;
const isFile = mediaType === 'FILE' && value;
const busy = uploading || authorizing;
const pickerLabel = label ?? (useWechatPicker ? '拍照 / 从相册选择' : '点击上传');
const triggerProps = {
type: 'button' as const,
@@ -172,7 +178,7 @@ export default function OssUploadField({
<div className="partner-oss-upload">
{needsAuth && (
<div className="partner-wechat-auth-hint" role="status">
<p className="body-md"></p>
<p className="body-md"></p>
<button
type="button"
className="partner-btn-outline"
@@ -180,23 +186,23 @@ export default function OssUploadField({
disabled={authorizing}
onClick={() => void startWechatAuth()}
>
{authorizing ? '跳转授权中…' : '微信授权'}
{authorizing ? '跳转授权中…' : '微信授权绑定'}
</button>
</div>
)}
<input
id={inputId}
ref={inputRef}
type="file"
accept={resolvedAccept}
capture={mediaType === 'FILE' && isWechatEnv() ? 'environment' : undefined}
className="partner-oss-upload-input"
disabled={busy}
onChange={(e) => {
const file = e.target.files?.[0];
if (file) void uploadSelectedFile(file);
}}
/>
{!useWechatPicker && (
<input
ref={inputRef}
type="file"
accept={resolvedAccept}
className="partner-oss-upload-input"
disabled={busy}
onChange={(e) => {
const file = e.target.files?.[0];
if (file) void uploadSelectedFile(file);
}}
/>
)}
{isImage ? (
<button {...triggerProps} className={`partner-upload-preview${wide ? ' partner-upload-preview--wide' : ''}`}>
<img src={value} alt={label ?? '已上传'} />
@@ -224,7 +230,7 @@ export default function OssUploadField({
{busy ? 'hourglass_top' : 'add_a_photo'}
</span>
<span className="text-primary" style={{ fontWeight: 500 }}>
{uploading ? '上传中…' : needsAuth ? '请先微信授权' : (label ?? (useWechatPicker ? '从相册选择' : '点击上传'))}
{uploading ? '上传中…' : needsAuth ? '请先微信授权' : pickerLabel}
</span>
</button>
)}