This commit is contained in:
zhangjianjun 2026-07-09 18:06:49 +08:00
parent 40a6f6ae7b
commit 27be8638a5
6 changed files with 99 additions and 23 deletions

View File

@ -19,12 +19,12 @@ function App() {
let isMounted = true let isMounted = true
async function initConfig() { async function initConfig() {
if(initialPackage) { if (initialPackage) {
window.localStorage.setItem('package', initialPackage || '') window.localStorage.setItem('package', initialPackage || '')
} }
if (initialToken) { if (initialToken) {
window.localStorage.setItem('token', initialToken || '') window.localStorage.setItem('token', initialToken || '')
} else if(!window.localStorage.getItem('token')) { } else if (!window.localStorage.getItem('token')) {
navigate('/twins', { replace: true }) navigate('/twins', { replace: true })
} }
@ -38,7 +38,7 @@ function App() {
return () => { return () => {
isMounted = false isMounted = false
} }
}, [initialToken, navigate]) }, [initialPackage, initialToken, navigate])
if (!isConfigReady) { if (!isConfigReady) {
return null; return null;

View File

@ -5,14 +5,24 @@ export type UserConfig = {
[key: string]: unknown [key: string]: unknown
} }
export type ServiceConfig = {
corpid?: string
'kf.address'?: string
[key: string]: unknown
}
export type PackageInfo = {
[key: string]: unknown
}
export function getConfig() { export function getConfig() {
return get<ApiResponse<UserConfig>>('/api/user/config') return get<ApiResponse<UserConfig>>('/api/user/config')
} }
export function getService() { export function getService() {
return get<ApiResponse<UserConfig>>('/api/weixin/service') return get<ApiResponse<ServiceConfig>>('/api/weixin/service')
} }
export function getPackage({package_name}: {package_name: string}) { export function getPackage({ package_name }: { package_name: string }) {
return get<ApiResponse<Package>>('/api/package') return get<ApiResponse<PackageInfo>>('/api/package', { package_name })
} }

View File

@ -471,6 +471,7 @@ p {
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
text-decoration: none;
img { img {
width: 20px; width: 20px;
@ -738,6 +739,7 @@ p {
position: absolute; position: absolute;
right: 10px; right: 10px;
bottom: 17px; bottom: 17px;
text-decoration: none;
img { img {
width: 26px; width: 26px;

View File

@ -1,6 +1,7 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { checkOrder, getGoods, order, type GoodsItem } from '@/api/pay' import { checkOrder, getGoods, order, type GoodsItem } from '@/api/pay'
import { getService } from '@/api/user'
const PAY_METHOD_LIST = [ const PAY_METHOD_LIST = [
{ code: 'weixin', icon: '/images/pay/icon-wechatpay.png', name: '微信支付' }, { code: 'weixin', icon: '/images/pay/icon-wechatpay.png', name: '微信支付' },
@ -33,6 +34,7 @@ function PayPage() {
const [currentIndex, setCurrentIndex] = useState(0) const [currentIndex, setCurrentIndex] = useState(0)
const [selectedPayType, setSelectedPayType] = useState('') const [selectedPayType, setSelectedPayType] = useState('')
const [isPaying, setIsPaying] = useState(false) const [isPaying, setIsPaying] = useState(false)
const [serviceUrl, setServiceUrl] = useState('')
const pollingTimerRef = useRef<number | null>(null) const pollingTimerRef = useRef<number | null>(null)
const pollingCountRef = useRef(0) const pollingCountRef = useRef(0)
const pollingSessionRef = useRef(0) const pollingSessionRef = useRef(0)
@ -93,6 +95,31 @@ function PayPage() {
} }
}, []) }, [])
useEffect(() => {
let isMounted = true
async function initServiceUrl() {
try {
const { data } = await getService()
const nextServiceUrl = data['kf.address']
if (isMounted && typeof nextServiceUrl === 'string') {
setServiceUrl(nextServiceUrl)
}
} catch {
if (isMounted) {
setServiceUrl('')
}
}
}
initServiceUrl()
return () => {
isMounted = false
}
}, [])
useEffect(() => { useEffect(() => {
return () => { return () => {
isMountedRef.current = false isMountedRef.current = false
@ -268,7 +295,7 @@ function PayPage() {
onSelectPayType={handleSelectPayType} onSelectPayType={handleSelectPayType}
selectedPayType={selectedPayType} selectedPayType={selectedPayType}
/> />
<ContactUs /> <ContactUs serviceUrl={serviceUrl} />
</div> </div>
) )
} }
@ -493,12 +520,16 @@ function PayMethod({ methods, onSelectPayType, selectedPayType }: PayMethodProps
) )
} }
function ContactUs() { type ContactUsProps = {
serviceUrl: string
}
function ContactUs({ serviceUrl }: ContactUsProps) {
return ( return (
<div className="contact-us"> <a className="contact-us" href={serviceUrl || undefined} target="_blank" rel="noreferrer">
<img src="/images/pay/icon-concat.png" alt="" /> <img src="/images/pay/icon-concat.png" alt="" />
<span></span> <span></span>
</div> </a>
) )
} }

View File

@ -1,10 +1,45 @@
import { useEffect } from "react" import { useEffect, useState } from 'react'
import { getConfig, getService } from '@/api/user'
import { TEMP_TOKEN_STORAGE_KEY } from '@/utils/request'
function Twins() { function Twins() {
const [serviceUrl, setServiceUrl] = useState('')
useEffect(() => {
let isMounted = true
async function initTwinsConfig() {
try {
const { data: config } = await getConfig()
if (config.token) {
window.sessionStorage.setItem(TEMP_TOKEN_STORAGE_KEY, config.token)
}
const { data: service } = await getService()
const nextServiceUrl = service['kf.address']
if (isMounted && typeof nextServiceUrl === 'string') {
setServiceUrl(nextServiceUrl)
}
} catch {
if (isMounted) {
setServiceUrl('')
}
}
}
initTwinsConfig()
return () => {
isMounted = false
}
}, [])
return ( return (
<div id="Twins"> <div id="Twins">
<Header /> <Header />
<Card /> <Card serviceUrl={serviceUrl} />
</div> </div>
) )
} }
@ -33,7 +68,11 @@ function Header() {
) )
} }
function Card() { type CardProps = {
serviceUrl: string
}
function Card({ serviceUrl }: CardProps) {
const steps = [ const steps = [
{ {
label: '步骤一', label: '步骤一',
@ -58,13 +97,6 @@ function Card() {
sideBg: "./images/app-twins/step2-side.png" sideBg: "./images/app-twins/step2-side.png"
} }
] ]
useEffect(() => {
const packageName = window.localStorage.getItem('package')
console.log("packageName", packageName)
if(packageName) {
}
}, [])
return ( return (
<div className="card"> <div className="card">
<div className="card-title"> <div className="card-title">
@ -92,7 +124,7 @@ function Card() {
)) ))
} }
</div> </div>
<a className="contact-us" href="" > <a className="contact-us" href={serviceUrl || undefined} target="_blank" rel="noreferrer">
<img src="./images/app-twins/icon-concat.png" alt="客服1对1指导安装"></img> <img src="./images/app-twins/icon-concat.png" alt="客服1对1指导安装"></img>
<span>11<br/></span> <span>11<br/></span>
</a> </a>

View File

@ -38,6 +38,7 @@ declare global {
} }
const SYS_INFO_STORAGE_KEY = 'sysInfo' const SYS_INFO_STORAGE_KEY = 'sysInfo'
export const TEMP_TOKEN_STORAGE_KEY = 'tempToken'
function isRecord(value: unknown): value is Record<string, RequestPrimitive> { function isRecord(value: unknown): value is Record<string, RequestPrimitive> {
return Object.prototype.toString.call(value) === '[object Object]' return Object.prototype.toString.call(value) === '[object Object]'
@ -165,7 +166,7 @@ function setCommonHeaders(headers: Headers) {
headers.set('x-channel', toHeaderValue(sysInfo.channel)) headers.set('x-channel', toHeaderValue(sysInfo.channel))
headers.set('x-click-id', toHeaderValue(params.get('bd_vid') ?? sysInfo.bd_vid ?? '')) headers.set('x-click-id', toHeaderValue(params.get('bd_vid') ?? sysInfo.bd_vid ?? ''))
headers.set('x-app-id', toHeaderValue(__APP_ID__)) headers.set('x-app-id', toHeaderValue(__APP_ID__))
const token = window.localStorage.getItem("token") const token = window.localStorage.getItem('token') || window.sessionStorage.getItem(TEMP_TOKEN_STORAGE_KEY)
if(token){ if(token){
headers.set('x-token', token) headers.set('x-token', token)
} }