@@ -0,0 +1,96 @@
import { useEffect , useMemo , useState } from 'react' ;
import { Alert , Button , Card , Col , Descriptions , Image , Radio , Row , Select , Space , Steps , Tag , Typography , message } from 'antd' ;
import { CheckCircleOutlined , QrcodeOutlined , ReloadOutlined , ShoppingCartOutlined , WechatOutlined } from '@ant-design/icons' ;
import { yybApi } from '../api/modules' ;
import type { YybSelectionOptions , YybTask } from '../api/types' ;
import { getUser } from '../store/auth' ;
import { usePermissions } from '../hooks/usePermissions' ;
const { Title , Text } = Typography ;
const phaseIndex : Record < string , number > = { login : 0 , selection : 1 , payment : 2 , completed : 3 } ;
export default function YybRechargePage() {
const [ task , setTask ] = useState < YybTask | null > ( null ) ;
const [ options , setOptions ] = useState < YybSelectionOptions | null > ( null ) ;
const [ platform , setPlatform ] = useState < 'android' | 'ios' > ( 'android' ) ;
const [ points , setPoints ] = useState < number > ( ) ;
const [ zoneId , setZoneId ] = useState < string > ( ) ;
const [ roleId , setRoleId ] = useState < string > ( ) ;
const [ loading , setLoading ] = useState ( false ) ;
const { can } = usePermissions ( getUser ( ) ) ;
const refresh = async ( ) = > {
if ( ! task ) return ;
try { setTask ( await yybApi . getTask ( task . id ) ) ; } catch { /* 保留当前状态 */ }
} ;
useEffect ( ( ) = > {
if ( ! task || [ 'success' , 'failed' ] . includes ( task . status ) ) return ;
const timer = window . setInterval ( refresh , 2500 ) ;
return ( ) = > window . clearInterval ( timer ) ;
} , [ task ? . id , task ? . status ] ) ;
useEffect ( ( ) = > {
if ( task ? . status === 'ready' && task . phase === 'selection' && ! options ) {
void loadOptions ( platform ) ;
}
} , [ task ? . status , task ? . phase ] ) ;
const loadOptions = async ( nextPlatform : 'android' | 'ios' , nextPoints? : number , nextZone? : string ) = > {
if ( ! task ) return ;
setLoading ( true ) ;
try {
const data = await yybApi . options ( task . id , nextPlatform , nextPoints , nextZone ) ;
setOptions ( data ) ;
if ( nextPoints === undefined && data . default_product ) setPoints ( data . default_product . points ) ;
if ( nextZone === undefined && data . default_zone ) setZoneId ( data . default_zone . zone_id ) ;
setRoleId ( undefined ) ;
} catch ( error ) { message . error ( error instanceof Error ? error . message : '查询商品失败' ) ; }
finally { setLoading ( false ) ; }
} ;
const selectedProduct = useMemo ( ( ) = > options ? . products . find ( item = > item . points === points ) , [ options , points ] ) ;
const selectedZone = useMemo ( ( ) = > options ? . zones . find ( item = > item . zone_id === zoneId ) , [ options , zoneId ] ) ;
const selectedRole = useMemo ( ( ) = > options ? . roles . find ( item = > item . role_id === roleId ) , [ options , roleId ] ) ;
const createTask = async ( ) = > {
setLoading ( true ) ;
try { setTask ( await yybApi . createTask ( ) ) ; setOptions ( null ) ; } catch ( error ) { message . error ( error instanceof Error ? error . message : '创建任务失败' ) ; }
finally { setLoading ( false ) ; }
} ;
const startLogin = async ( provider : 'qq' | 'wechat' ) = > {
if ( ! task ) return ;
setLoading ( true ) ;
try { setTask ( await yybApi . login ( task . id , provider ) ) ; } catch ( error ) { message . error ( error instanceof Error ? error . message : '启动登录失败' ) ; }
finally { setLoading ( false ) ; }
} ;
const submitSelection = async ( ) = > {
if ( ! task || ! selectedProduct || ! selectedZone || ! selectedRole ) return ;
setLoading ( true ) ;
try {
setTask ( await yybApi . select ( task . id , { platform , points : selectedProduct.points , product_id : selectedProduct.product_id , zone_id : selectedZone.zone_id , zone_name : selectedZone.name , role_id : selectedRole.role_id , role_name : selectedRole.name } ) ) ;
message . success ( '选择已保存' ) ;
} catch ( error ) { message . error ( error instanceof Error ? error . message : '保存选择失败' ) ; }
finally { setLoading ( false ) ; }
} ;
const createPayment = async ( ) = > {
if ( ! task ) return ;
setLoading ( true ) ;
try { setTask ( await yybApi . payment ( task . id ) ) ; } catch ( error ) { message . error ( error instanceof Error ? error . message : '创建付款码失败' ) ; }
finally { setLoading ( false ) ; }
} ;
return < Space direction = "vertical" size = { 16 } style = { { width : '100%' } } >
< Row justify = "space-between" align = "middle" > < Title level = { 3 } style = { { margin : 0 } } > 应 用 宝 和 平 精 英 充 值 < / Title > < Button icon = { < ReloadOutlined / > } onClick = { task ? refresh : createTask } > { task ? '刷新任务' : '新建充值任务' } < / Button > < / Row >
< Steps current = { phaseIndex [ task ? . phase || 'login' ] } items = { [ { title : '扫码登录' } , { title : '选择充值信息' } , { title : '微信付款' } , { title : '完成' } ] } / >
{ ! task && < Card > < Space direction = "vertical" > < Text > 每 次 充 值 使 用 独 立 的 YYB 登 录 会 话 。 < / Text > < Button type = "primary" icon = { < ShoppingCartOutlined / > } onClick = { createTask } loading = { loading } > 开 始 充 值 < / Button > < / Space > < / Card > }
{ task && < >
{ task . status === 'failed' && < Alert type = "error" showIcon message = { task . message || '任务失败' } / > }
{ task . phase === 'login' && < Card title = "扫码登录" > < Space direction = "vertical" size = { 12 } > < Radio.Group value = { task . provider || undefined } onChange = { event = > void startLogin ( event . target . value ) } disabled = { loading } > < Radio.Button value = "qq" > QQ 登 录 < / Radio.Button > < Radio.Button value = "wechat" > < WechatOutlined / > 微 信 登 录 < / Radio.Button > < / Radio.Group > { task . login_qr_data && < Image width = { 240 } preview src = { ` data: ${ task . login_qr_mime_type || 'image/jpeg' } ;base64, ${ task . login_qr_data } ` } / > } < Text type = "secondary" > { task . message } < / Text > < / Space > < / Card > }
{ task . phase === 'selection' && < Card title = "选择充值信息" loading = { loading } > < Space direction = "vertical" style = { { width : '100%' } } > < Radio.Group value = { platform } onChange = { event = > { const value = event . target . value ; setPlatform ( value ) ; void loadOptions ( value ) ; } } > < Radio.Button value = "android" > Android 区 < / Radio.Button > < Radio.Button value = "ios" > iOS 区 < / Radio.Button > < / Radio.Group > { options && < Row gutter = { [ 12 , 12 ] } > < Col xs = { 24 } md = { 8 } > < Select style = { { width : '100%' } } placeholder = "点券档位" value = { points } options = { options . products . map ( item = > ( { value : item.points , label : ` ${ item . points } 点券( ${ ( item . price_fen / 100 ) . toFixed ( 2 ) } 元) ` } ) ) } onChange = { value = > { setPoints ( value ) ; void loadOptions ( platform , value , zoneId ) ; } } / > < / Col > < Col xs = { 24 } md = { 8 } > < Select style = { { width : '100%' } } placeholder = "区服" value = { zoneId } options = { options . zones . map ( item = > ( { value : item.zone_id , label : ` ${ item . name } ( ${ item . zone_id } ) ` } ) ) } onChange = { value = > { setZoneId ( value ) ; void loadOptions ( platform , points , value ) ; } } / > < / Col > < Col xs = { 24 } md = { 8 } > < Select style = { { width : '100%' } } placeholder = "角色" value = { roleId } options = { options . roles . filter ( item = > item . ban_status !== '1' ) . map ( item = > ( { value : item.role_id , label : ` ${ item . name } ( ${ item . role_id } ) ` } ) ) } onChange = { setRoleId } / > < / Col > < / Row > } < Button type = "primary" disabled = { ! selectedProduct || ! selectedZone || ! selectedRole } onClick = { submitSelection } > 确 认 充 值 信 息 < / Button > < / Space > < / Card > }
{ task . phase === 'payment' && < Card title = "微信付款" > < Descriptions column = { 1 } size = "small" > < Descriptions.Item label = "平台" > { task . platform === 'ios' ? 'iOS' : 'Android' } < / Descriptions.Item > < Descriptions.Item label = "商品" > { task . points } 点 券 < / Descriptions.Item > < Descriptions.Item label = "区服" > { task . zone_name } < / Descriptions.Item > < Descriptions.Item label = "角色" > { task . role_name } ( { task . role_id } ) < / Descriptions.Item > < / Descriptions > { task . payment_qr_data ? < Space direction = "vertical" > < Image width = { 280 } preview src = { ` data: ${ task . payment_qr_mime_type || 'image/png' } ;base64, ${ task . payment_qr_data } ` } / > < Tag icon = { < QrcodeOutlined / > } color = "blue" > 请 使 用 微 信 扫 码 付 款 < / Tag > < / Space > : can ( 'yyb:recharge' ) ? < Button type = "primary" icon = { < WechatOutlined / > } onClick = { createPayment } loading = { loading || task . status === 'running' } disabled = { task . status === 'running' } > { task . status === 'running' ? '正在生成付款码' : '生成微信付款码' } < / Button > : < Text type = "secondary" > 当 前 账 号 没 有 创 建 付 款 码 权 限 。 < / Text > } < div > < Text type = "secondary" > { task . message } < / Text > < / div > < / Card > }
{ task . phase === 'completed' && < Alert type = "success" showIcon icon = { < CheckCircleOutlined / > } message = "充值订单已确认完成" description = { task . message } / > }
< / > }
< / Space > ;
}