统一单入口 Go 工程与前端依赖目录,增加后台供应商配置、候选审核、计划预算、成交冲正、持仓复盘和站内通知。接入策略版本、Python 回测、可配置 A 股公开行情及 zap 文件轮转日志,补充迁移、契约与验证。
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import {useState} from "react"
|
||||
import {Text} from "react-native"
|
||||
import {useQuery,useQueryClient} from "@tanstack/react-query"
|
||||
import {useRouter} from "expo-router"
|
||||
import {useSession} from "../../src/state/session"
|
||||
import {useAccounts} from "../../src/state/accounts"
|
||||
import {Body,Button,EmptyState,ErrorMessage,Panel,Screen,Title,styles} from "../../src/components/ui"
|
||||
import {planStates,type Plan} from "../../src/lib/plans"
|
||||
export default function Plans(){
|
||||
const {session,client}=useSession(),{selected}=useAccounts(),router=useRouter(),cache=useQueryClient()
|
||||
const [confirming,setConfirming]=useState<Plan|null>(null),[busy,setBusy]=useState(false),[error,setError]=useState("")
|
||||
const query=useQuery({queryKey:["plans",session?.user.id,selected?.id],enabled:!!session,queryFn:({signal})=>client<Plan[]>("/api/v1/plans",{signal}),refetchInterval:15000})
|
||||
const plans=query.data?.filter(p=>p.account_id===selected?.id)
|
||||
async function cancel(){if(!confirming)return;setBusy(true);setError("");try{await client(`/api/v1/plans/${confirming.id}/cancel`,{method:"POST",body:{expected_version:confirming.version}});setConfirming(null);await query.refetch();await cache.invalidateQueries({queryKey:["budget"]})}catch(e){setError(e instanceof Error?e.message:"取消失败")}finally{setBusy(false)}}
|
||||
return <Screen><Title>计划</Title><Body>{selected?`当前账户:${selected.name}`:"先选择账户,再从候选创建计划。"}计划保留预算,成交需另行记录。</Body><Button secondary title={query.isFetching?"刷新中…":"刷新计划"} disabled={query.isFetching||busy} onPress={()=>void query.refetch()}/>{query.error&&<ErrorMessage message={query.error.message}/>}<ErrorMessage message={error}/>{plans?.length===0&&<><EmptyState title="暂无交易计划" detail="从已发布候选查看依据,再预览数量与资金预算。"/><Button title="查看候选" onPress={()=>router.push("/(tabs)/opportunities")}/></>}{plans?.map(p=><Panel key={p.id}><Text style={styles.badge}>{planStates[p.status]??p.status} · 模拟计划</Text><Text style={styles.subtitle}>{p.candidate_content.name} · {p.candidate_content.symbol}</Text><Body>数量 {p.quantity} 股 · 已记录 {p.filled_quantity} 股</Body><Body>保留预算 ¥{p.reserved_amount} · 有效截止 {new Date(p.valid_until).toLocaleString("zh-CN")}</Body>{p.status!=="COMPLETED"&&p.status!=="CANCELLED"&&<Button title="记录此计划的实际模拟买入" onPress={()=>router.push({pathname:"/fills/create",params:{plan_id:p.id,symbol:p.candidate_content.symbol,exchange:p.candidate_content.exchange,name:p.candidate_content.name}})}/>}<Button secondary title="查看原始候选依据" onPress={()=>router.push({pathname:"/candidates/[id]",params:{id:p.candidate_revision_id}})}/>{["ACTIVE","PART_FILLED"].includes(p.status)&&<Button secondary title="取消计划" disabled={busy} onPress={()=>{setConfirming(p);setError("")}}/>}{confirming?.id===p.id&&<><Body>确认取消 {p.candidate_content.name} 的计划?保留额度将释放;已记录成交保留。</Body><Button title="确认取消" busy={busy} onPress={()=>void cancel()}/><Button secondary title="保留计划" disabled={busy} onPress={()=>setConfirming(null)}/></>}</Panel>)}</Screen>
|
||||
}
|
||||
Reference in New Issue
Block a user