@@ -32,7 +32,7 @@ import { message } from '../utils/antdMessage';
const { Text } = Typography ;
type HandbookKind = 'elite' | 'esports' ;
type HandbookKind = 'elite' | 'esports' | 'peace' ;
const TASK_STATUS_COLORS : Record < string , string > = {
planned : 'default' ,
@@ -83,6 +83,12 @@ const ESPORTS_QUICK_ACTIONS = [
{ key : 'donate_esports_firework_gift' , icon : < GiftOutlined / > } ,
] ;
const PEACE_QUICK_ACTIONS = [
{ key : 'query_xpd_role' , icon : < SearchOutlined / > } ,
{ key : 'refresh_xpd_goods' , icon : < ReloadOutlined / > } ,
{ key : 'query_xpd_balance' , icon : < SearchOutlined / > } ,
] ;
const ELITE_TASK_TYPES = new Set ( [
'get_bind_qr' ,
'confirm_bind' ,
@@ -115,6 +121,11 @@ const ESPORTS_TASK_TYPES = new Set([
'donate_esports_chicken_gift' ,
'donate_esports_firework_gift' ,
] ) ;
const PEACE_TASK_TYPES = new Set ( [
'query_xpd_role' ,
'refresh_xpd_goods' ,
'query_xpd_balance' ,
] ) ;
const DOUYU_GOLD_AMOUNT_STORAGE_KEY = 'douyu_task_gold_amount' ;
const DOUYU_GIFT_COUNT_STORAGE_KEY = 'douyu_task_gift_count' ;
const DOUYU_LAYOUT_MODE_STORAGE_KEY = 'douyu_task_layout_mode' ;
@@ -201,6 +212,13 @@ function goodsLabel(item: DouyuGoodsItem): string {
return ` ${ item . name || item . commodity_id } ${ item . score ? ` / ${ item . score } 积分 ` : '' } ${ stockText } ` ;
}
function xpdGoodsLabel ( item : DouyuGoodsItem ) : string {
const xpd = item as DouyuGoodsItem & { price? : number | null ; goods_left? : number | null } ;
const price = xpd . price != null ? ` / ${ xpd . price } 点券 ` : '' ;
const left = xpd . goods_left != null ? ` / 剩 ${ xpd . goods_left } ` : '' ;
return ` ${ item . name || item . commodity_id } ${ price } ${ left } ` ;
}
function formatWaitSeconds ( seconds : number | null | undefined ) : string {
if ( seconds == null || Number . isNaN ( Number ( seconds ) ) ) return '' ;
const total = Math . max ( 0 , Math . floor ( Number ( seconds ) ) ) ;
@@ -265,13 +283,22 @@ function savedPositiveInteger(key: string, fallback = 1): number {
}
export default function DouyuTasksPage ( { handbook } : { handbook : HandbookKind } ) {
const isPeaceHandbook = handbook === 'peace' ;
const isEsportsHandbook = handbook === 'esports' ;
const handbookTitle = isEsportsHandbook ? '电竞手册工作台' : '精英宝典工作台' ;
const handbookDescription = isEsportsHandbook
? '电竞手册角色绑定与开通任务'
: '精英宝典绑定、开通、积分与兑换任务' ;
const activeTaskTypes = isEsportsHandbook ? ESPORTS_TASK_TYPES : ELITE_TASK_TYPES ;
const quickActions = isEsportsHandbook ? ESPORTS_QUICK_ACTIONS : ELITE_QUICK_ACTIONS ;
const handbookTitle = isPeaceHandbook
? '和平小店工作台'
: ( isEsportsHandbook ? '电竞手册工作台' : '精英宝典工作台' ) ;
const handbookDescription = isPeaceHandbook
? '和平小店绑定角色、商品与点券余额查询'
: ( isEsportsHandbook
? '电竞手册角色绑定与开通任务'
: '精英宝典绑定、开通、积分与兑换任务' ) ;
const activeTaskTypes = isPeaceHandbook
? PEACE_TASK_TYPES
: ( isEsportsHandbook ? ESPORTS_TASK_TYPES : ELITE_TASK_TYPES ) ;
const quickActions = isPeaceHandbook
? PEACE_QUICK_ACTIONS
: ( isEsportsHandbook ? ESPORTS_QUICK_ACTIONS : ELITE_QUICK_ACTIONS ) ;
const { can } = usePermissions ( ) ;
const [ accounts , setAccounts ] = useState < DouyuTaskAccountItem [ ] > ( [ ] ) ;
// 工作台已导入账号 ID( localStorage 持久化,默认空白,用户手动导入/移除)
@@ -462,7 +489,9 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
try {
const [ accResult , goodsResult , taskResult , cfgResult , typeResult ] = await Promise . allSettled ( [
workbenchIds . length > 0 ? douyuApi . listAccounts ( { ids : workbenchIds.join ( ',' ) } ) : Promise . resolve ( [ ] ) ,
isEsportsHandbook ? douyuApi . listEsportsGoods ( ) : douyuApi . listGoods ( ) ,
isPeaceHandbook
? douyuApi . listPeaceGoods ( )
: ( isEsportsHandbook ? douyuApi . listEsportsGoods ( ) : douyuApi . listGoods ( ) ) ,
douyuApi . listTasks ( ) ,
canConfig ? douyuApi . getConfig ( ) : Promise . resolve ( null ) ,
douyuApi . taskTypes ( ) ,
@@ -508,7 +537,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
} finally {
setLoading ( false ) ;
}
} , [ canConfig , isEsportsHandbook , workbenchIds ] ) ;
} , [ canConfig , isEsportsHandbook , isPeaceHandbook , workbenchIds ] ) ;
const loadTasks = useCallback ( async ( ) = > {
if ( tasksLoadingRef . current ) return ;
@@ -1104,6 +1133,11 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
{
title : '游戏名' , dataIndex : 'game_name' , width : 170 ,
render : ( _ , record ) = > {
if ( isPeaceHandbook ) {
return record . xpd_game_name
? < Text ellipsis title = { record . xpd_game_name } > { record . xpd_game_name } < / Text >
: < Text type = "secondary" > 未 查 < / Text > ;
}
const queryTask = isEsportsHandbook
? latestEsportsStateTaskByAccount . get ( record . id ) || null
: latestQueryGameTaskByAccount . get ( record . id ) || null ;
@@ -1175,8 +1209,8 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
} ,
} ,
{
title : isEsportsHandbook ? '电竞积分' : '积分' ,
dataIndex : isEsportsHandbook ? 'esports_points' : 'points' ,
title : isPeaceHandbook ? '点券' : ( isEsportsHandbook ? '电竞积分' : '积分' ) ,
dataIndex : isPeaceHandbook ? 'xpd_balance' : ( isEsportsHandbook ? 'esports_points' : 'points' ) ,
width : 80 ,
render : ( v ) = > v ? ? < Text type = "secondary" > - < / Text > ,
} ,
@@ -1201,6 +1235,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
{
title : '换绑时间' , dataIndex : 'change_role_wait_time' , width : 130 ,
render : ( _ , record ) = > {
if ( isPeaceHandbook ) return < Text type = "secondary" > - < / Text > ;
const fromTask = latestChangeWaitByAccount . get ( record . id ) ;
const canChangeTime = fromTask ? . canChangeTime ? ? (
isEsportsHandbook ? record.esports_can_change_time : null
@@ -1239,6 +1274,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
return < Text type = "secondary" > { text || '-' } < / Text > ;
} ,
sorter : ( a , b ) = > {
if ( isPeaceHandbook ) return 0 ;
const aw = isEsportsHandbook
? latestChangeWaitByAccount . get ( a . id ) ? . canChangeTime ? ? a . esports_can_change_time ? ? - 1
: latestChangeWaitByAccount.get ( a . id ) ? . wait
@@ -1398,7 +1434,39 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
) ;
const operationBody = (
< >
{ isEsportsHandbook ? (
{ isPeaceHandbook ? (
< div style = { compactOperationGridStyle } >
< div style = { sectionStyle } >
< div style = { sectionTitleStyle } >
< SearchOutlined / >
< span > 小 店 查 询 < / span >
< / div >
< Space direction = "vertical" style = { { width : '100%' } } size = { 6 } >
{ renderActionButton ( 'query_xpd_role' , 'primary' ) }
{ renderActionButton ( 'query_xpd_balance' , 'primary' ) }
{ renderActionButton ( 'refresh_xpd_goods' ) }
< / Space >
< / div >
< div style = { sectionStyle } >
< div style = { sectionTitleStyle } >
< ShoppingOutlined / >
< span > 小 店 商 品 < / span >
< / div >
< Space direction = "vertical" style = { { width : '100%' } } size = { 6 } >
< Select
size = "small"
value = { selectedGoodsId || undefined }
onChange = { setSelectedGoodsId }
options = { goods . map ( ( item ) = > ( { value : item.commodity_id , label : xpdGoodsLabel ( item ) } ) ) }
placeholder = "选择小店商品"
showSearch
optionFilterProp = "label"
style = { { width : '100%' } }
/ >
< / Space >
< / div >
< / div >
) : isEsportsHandbook ? (
< div style = { compactOperationGridStyle } >
< div style = { sectionStyle } >
< div style = { sectionTitleStyle } >
@@ -1690,7 +1758,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
< / Card >
< Card
size = "small"
title = { isEsportsHandbook ? '电竞手册操作' : '精英宝典操作' }
title = { isPeaceHandbook ? '和平小店操作' : ( isEsportsHandbook ? '电竞手册操作' : '精英宝典操作' ) }
extra = { operationExtra }
style = { { width : 340 , flexShrink : 0 , minHeight : 0 , display : 'flex' , flexDirection : 'column' , overflow : 'hidden' } }
styles = { { body : { padding : 8 , flex : 1 , minHeight : 0 , overflowY : 'auto' } } }
@@ -1702,7 +1770,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
< >
< Card
size = "small"
title = { isEsportsHandbook ? '电竞手册操作' : '精英宝典操作' }
title = { isPeaceHandbook ? '和平小店操作' : ( isEsportsHandbook ? '电竞手册操作' : '精英宝典操作' ) }
extra = { operationExtra }
style = { { flexShrink : 0 , marginBottom : 12 } }
styles = { { body : { padding : 8 } } }
@@ -1788,12 +1856,12 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
{ title : '标签' , dataIndex : 'tag' , width : 110 , render : ( v : string ) = > ( v ? < Tag color = "blue" > { v } < / Tag > : '-' ) } ,
{
title : '游戏名' ,
dataIndex : isEsportsHandbook ? 'esports_game_name' : 'game_name' ,
dataIndex : isPeaceHandbook ? 'xpd_game_name' : ( isEsportsHandbook ? 'esports_game_name' : 'game_name' ) ,
render : ( v ) = > v || '-' ,
} ,
{
title : isEsportsHandbook ? '电竞积分' : '积分' ,
dataIndex : isEsportsHandbook ? 'esports_points' : 'points' ,
title : isPeaceHandbook ? '点券' : ( isEsportsHandbook ? '电竞积分' : '积分' ) ,
dataIndex : isPeaceHandbook ? 'xpd_balance' : ( isEsportsHandbook ? 'esports_points' : 'points' ) ,
render : ( v ) = > v ? ? '-' ,
} ,
] }
@@ -1804,7 +1872,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
{ /* Config modal */ }
< Modal
title = { isEsportsHandbook ? '电竞手册配置' : '精英宝典配置' }
title = { isPeaceHandbook ? '和平小店配置' : ( isEsportsHandbook ? '电竞手册配置' : '精英宝典配置' ) }
open = { configOpen }
onCancel = { ( ) = > setConfigOpen ( false ) }
onOk = { ( ) = > configFormValues && saveConfig ( configFormValues ) }
@@ -1813,7 +1881,11 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
>
{ configFormValues && (
< Space direction = "vertical" style = { { width : '100%' } } size = { 8 } >
{ ( isEsportsHandbook ? [
{ ( isPeaceHandbook ? [
{ label : '小店活动代号' , key : 'xpd_act_alias' } ,
{ label : '道聚城活动 ID' , key : 'xpd_act_id' } ,
{ label : '房间 ID' , key : 'xpd_rid' } ,
] : isEsportsHandbook ? [
{ label : '电竞手册 manualID' , key : 'esports_manual_id' } ,
{ label : '电竞手册活动' , key : 'esports_act_alias' } ,
{ label : '房间 ID' , key : 'room_id' } ,
@@ -1840,7 +1912,7 @@ export default function DouyuTasksPage({ handbook }: { handbook: HandbookKind })
/ >
< / Space >
) ) }
{ ( isEsportsHandbook ? [
{ ( isPeaceHandbook ? [ ] : isEsportsHandbook ? [
{ label : '电竞手册金额(分)' , key : 'esports_amount' } ,
] : [
{ label : '宝典金额(分)' , key : 'elite_amount' } ,