购买页面 & IP提取页面样式调整

This commit is contained in:
Eamon-meng
2026-04-27 17:08:41 +08:00
parent 78d916ade1
commit 574ad0e662
7 changed files with 102 additions and 87 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "lanhu-web", "name": "lanhu-web",
"version": "1.10.0", "version": "1.11.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev -H 0.0.0.0 --turbopack", "dev": "next dev -H 0.0.0.0 --turbopack",

View File

@@ -71,7 +71,7 @@ export default function Extract(props: ExtractProps) {
)} )}
> >
<CardSection> <CardSection>
<Alert variant="warn" className="flex items-center justify-between"> {/* <Alert variant="warn" className="flex items-center justify-between">
<span className="flex items-center gap-2"> <span className="flex items-center gap-2">
<CircleAlert/> <CircleAlert/>
<AlertTitle className="flex text-gray-900">提取IP前需要将本机IP添加到白名单后才可使用</AlertTitle> <AlertTitle className="flex text-gray-900">提取IP前需要将本机IP添加到白名单后才可使用</AlertTitle>
@@ -83,7 +83,7 @@ export default function Extract(props: ExtractProps) {
<span>添加白名单</span> <span>添加白名单</span>
<ArrowRight className="size-4"/> <ArrowRight className="size-4"/>
</Link> </Link>
</Alert> </Alert> */}
<FormFields/> <FormFields/>
</CardSection> </CardSection>
@@ -494,6 +494,8 @@ function SelectRegion() {
const regionType = useWatch({control, name: 'regionType'}) const regionType = useWatch({control, name: 'regionType'})
const prov = useWatch({control, name: 'prov'}) const prov = useWatch({control, name: 'prov'})
const city = useWatch({control, name: 'city'}) const city = useWatch({control, name: 'city'})
console.log(regionType, 'regionType')
console.log(prov, 'prov', city, 'city')
return ( return (
<div className="flex flex-col gap-4 md:max-w-[calc(160px*2+1rem)]"> <div className="flex flex-col gap-4 md:max-w-[calc(160px*2+1rem)]">
@@ -604,25 +606,40 @@ function ApplyLink() {
} }
return ( return (
<div className={merge( <div className="flex flex-col gap-3 rounded-lg">
`flex flex-col gap-4`, <Alert variant="warn" className="flex items-center justify-between">
`rounded-lg`, <div className="flex items-center gap-2">
)}> <CircleAlert className="size-4 shrink-0"/>
<h4>API </h4> <AlertTitle className="text-orange-600">
IP IP 使
</AlertTitle>
</div>
<Link href="/admin/whitelist" className="flex-none text-orange-600 font-medium flex items-center gap-1">
<span></span>
<ArrowRight className="size-4"/>
</Link>
</Alert>
{/* 展示链接地址 */} <Alert className="flex items-center justify-between">
<div className="bg-secondary p-4 rounded-md break-all"> <div className="flex items-center gap-2">
<CircleAlert className="size-4 shrink-0"/>
<AlertTitle> socks5 http </AlertTitle>
</div>
<div className="w-[88px]"/>
</Alert>
<h4 className="text-base font-medium">API </h4>
<div className="bg-gray-100 rounded-md p-4 break-all font-mono text-sm">
{link(form.getValues())} {link(form.getValues())}
</div> </div>
{/* 操作 */} <div className="flex gap-3">
<div className="flex gap-4"> <Button type="button" onClick={() => submit('copy')} className="gap-1">
<Button type="button" onClick={() => submit('copy')}> <CopyIcon className="size-4"/>
<CopyIcon/>
<span></span> <span></span>
</Button> </Button>
<Button type="button" onClick={() => submit('open')}> <Button type="button" onClick={() => submit('open')} className="gap-1">
<ExternalLinkIcon/> <ExternalLinkIcon className="size-4"/>
<span></span> <span></span>
</Button> </Button>
</div> </div>

View File

@@ -81,6 +81,35 @@ export default function Center({skuData}: {
return ( return (
<Card className="flex-auto p-6 flex flex-col gap-10 relative"> <Card className="flex-auto p-6 flex flex-col gap-10 relative">
<BillingMethodField modeList={modeList} timeDailyLimit={100}/> <BillingMethodField modeList={modeList} timeDailyLimit={100}/>
{/* 套餐时效 */}
{type === '1' && (
<FormField name="expire" label="套餐有效时间" description="有效时间内可用于提取 IP">
{({id, field}) => (
<RadioGroup
id={id}
value={field.value}
onValueChange={(value) => {
field.onChange(value)
const nextLiveList = getAvailablePurchaseLives(skuData, {mode: type, expire: value})
if (!nextLiveList.includes(live) && nextLiveList[0]) {
setValue('live', nextLiveList[0])
}
}}
className="flex gap-4 flex-wrap">
{expireList.map(day => (
<FormOption
key={day}
id={`${id}-${day}`}
value={day}
label={`${day}`}
compare={field.value}
/>
))}
</RadioGroup>
)}
</FormField>
)}
{/* IP 时效 */} {/* IP 时效 */}
<FormField<Schema, 'live'> <FormField<Schema, 'live'>
@@ -129,36 +158,6 @@ export default function Center({skuData}: {
)} )}
</FormField> </FormField>
{/* 套餐时效 */}
{type === '1' && (
<FormField name="expire" label="套餐有效时间" description="有效时间内可用于提取 IP">
{({id, field}) => (
<RadioGroup
id={id}
value={field.value}
onValueChange={(value) => {
field.onChange(value)
const nextLiveList = getAvailablePurchaseLives(skuData, {mode: type, expire: value})
if (!nextLiveList.includes(live) && nextLiveList[0]) {
setValue('live', nextLiveList[0])
}
}}
className="flex gap-4 flex-wrap">
{expireList.map(day => (
<FormOption
key={day}
id={`${id}-${day}`}
value={day}
label={`${day}`}
compare={field.value}
/>
))}
</RadioGroup>
)}
</FormField>
)}
{/* 每日提取上限/购买数量 */} {/* 每日提取上限/购买数量 */}
{type === '1' ? ( {type === '1' ? (
<NumberStepperField <NumberStepperField

View File

@@ -20,7 +20,7 @@ export type Schema = z.infer<typeof schema>
export default function LongForm({skuList}: {skuList: ProductItem['skus']}) { export default function LongForm({skuList}: {skuList: ProductItem['skus']}) {
const skuData = parsePurchaseSkuList('long', skuList) const skuData = parsePurchaseSkuList('long', skuList)
const defaultMode = skuData.modeList.includes('2') ? '2' : '1' const defaultMode = skuData.modeList.includes('1') ? '1' : '2'
const defaultLive = getAvailablePurchaseLives(skuData, {mode: defaultMode})[0] || '' const defaultLive = getAvailablePurchaseLives(skuData, {mode: defaultMode})[0] || ''
const defaultExpire = defaultMode === '1' const defaultExpire = defaultMode === '1'
? getAvailablePurchaseExpires(skuData, {mode: defaultMode, live: defaultLive})[0] || '0' ? getAvailablePurchaseExpires(skuData, {mode: defaultMode, live: defaultLive})[0] || '0'

View File

@@ -34,15 +34,6 @@ export function BillingMethodField(props: {
}} }}
className="flex gap-4 max-md:flex-col" className="flex gap-4 max-md:flex-col"
> >
{props.modeList.includes('2') && (
<FormOption
id={`${id}-2`}
value="2"
label="包量套餐"
description="适用于短期或不定期高提取业务场景"
compare={field.value}
/>
)}
{props.modeList.includes('1') && ( {props.modeList.includes('1') && (
<FormOption <FormOption
@@ -53,6 +44,15 @@ export function BillingMethodField(props: {
compare={field.value} compare={field.value}
/> />
)} )}
{props.modeList.includes('2') && (
<FormOption
id={`${id}-2`}
value="2"
label="包量套餐"
description="适用于短期或不定期高提取业务场景"
compare={field.value}
/>
)}
</RadioGroup> </RadioGroup>
)} )}
</FormField> </FormField>

View File

@@ -82,6 +82,35 @@ export default function Center({
return ( return (
<Card className="flex-auto p-6 flex flex-col gap-10 relative"> <Card className="flex-auto p-6 flex flex-col gap-10 relative">
<BillingMethodField modeList={modeList} timeDailyLimit={2000}/> <BillingMethodField modeList={modeList} timeDailyLimit={2000}/>
{/* 套餐时效 */}
{type === '1' && (
<FormField name="expire" label="套餐有效时间" description="有效时间内可用于提取 IP">
{({id, field}) => (
<RadioGroup
id={id}
value={field.value}
onValueChange={(value) => {
field.onChange(value)
const nextLiveList = getAvailablePurchaseLives(skuData, {mode: type, expire: value})
if (!nextLiveList.includes(live) && nextLiveList[0]) {
setValue('live', nextLiveList[0])
}
}}
className="flex gap-4 flex-wrap">
{expireList.map(day => (
<FormOption
key={day}
id={`${id}-${day}`}
value={day}
label={`${day}`}
compare={field.value}
/>
))}
</RadioGroup>
)}
</FormField>
)}
{/* IP 时效 */} {/* IP 时效 */}
<FormField<Schema, 'live'> <FormField<Schema, 'live'>
@@ -133,36 +162,6 @@ export default function Center({
)} )}
</FormField> </FormField>
{/* 套餐时效 */}
{type === '1' && (
<FormField name="expire" label="套餐有效时间" description="有效时间内可用于提取 IP">
{({id, field}) => (
<RadioGroup
id={id}
value={field.value}
onValueChange={(value) => {
field.onChange(value)
const nextLiveList = getAvailablePurchaseLives(skuData, {mode: type, expire: value})
if (!nextLiveList.includes(live) && nextLiveList[0]) {
setValue('live', nextLiveList[0])
}
}}
className="flex gap-4 flex-wrap">
{expireList.map(day => (
<FormOption
key={day}
id={`${id}-${day}`}
value={day}
label={`${day}`}
compare={field.value}
/>
))}
</RadioGroup>
)}
</FormField>
)}
{/* 每日提取上限/购买数量 */} {/* 每日提取上限/购买数量 */}
{type === '1' ? ( {type === '1' ? (
<NumberStepperField <NumberStepperField

View File

@@ -20,7 +20,7 @@ export type Schema = z.infer<typeof schema>
export default function ShortForm({skuList}: {skuList: ProductItem['skus']}) { export default function ShortForm({skuList}: {skuList: ProductItem['skus']}) {
const skuData = parsePurchaseSkuList('short', skuList) const skuData = parsePurchaseSkuList('short', skuList)
const defaultMode = skuData.modeList.includes('2') ? '2' : '1' const defaultMode = skuData.modeList.includes('1') ? '1' : '2'
const defaultLive = getAvailablePurchaseLives(skuData, {mode: defaultMode})[0] || '' const defaultLive = getAvailablePurchaseLives(skuData, {mode: defaultMode})[0] || ''
const defaultExpire = defaultMode === '1' const defaultExpire = defaultMode === '1'
? getAvailablePurchaseExpires(skuData, {mode: defaultMode, live: defaultLive})[0] || '0' ? getAvailablePurchaseExpires(skuData, {mode: defaultMode, live: defaultLive})[0] || '0'