套餐编码可视化改造
This commit is contained in:
200
src/components/products/index.tsx
Normal file
200
src/components/products/index.tsx
Normal file
@@ -0,0 +1,200 @@
|
||||
import type { ChangeEvent } from "react"
|
||||
import {
|
||||
type Control,
|
||||
type Path,
|
||||
type UseControllerReturn,
|
||||
useController,
|
||||
} from "react-hook-form"
|
||||
import { ProductCode } from "@/lib/base"
|
||||
import {
|
||||
Field,
|
||||
FieldError,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
FieldLegend,
|
||||
} from "../ui/field"
|
||||
import { Input } from "../ui/input"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "../ui/select"
|
||||
|
||||
export function ProductCodeField<
|
||||
T extends {
|
||||
code: string
|
||||
},
|
||||
>(props: { control: Control<T>; name: Path<T>; code: ProductCode }) {
|
||||
const rt = useController(props)
|
||||
|
||||
switch (props.code) {
|
||||
case ProductCode.Short:
|
||||
return <ProductShortCode {...rt} />
|
||||
case ProductCode.Long:
|
||||
return <ProductLongCode {...rt} />
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function ProductShortCode<T extends { code: string }>(
|
||||
props: UseControllerReturn<T>,
|
||||
) {
|
||||
const { field, fieldState } = props
|
||||
|
||||
const params = new URLSearchParams(field.value)
|
||||
const setParams = (data: {
|
||||
mode?: string
|
||||
live?: string
|
||||
expire?: string
|
||||
}) => {
|
||||
if (data.mode) params.set("mode", data.mode)
|
||||
if (data.live) params.set("live", data.live)
|
||||
if (data.expire) params.set("expire", data.expire)
|
||||
field.onChange(params.toString())
|
||||
}
|
||||
|
||||
const onModeChange = (value: string) => {
|
||||
setParams({ mode: value })
|
||||
}
|
||||
const onLiveChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
let value = e.target.value || "0"
|
||||
if (value.length > 1 && value[0] === "0") {
|
||||
value = value.substring(1, value.length)
|
||||
}
|
||||
if (!/^([0-9]+)$/.test(value)) return
|
||||
setParams({ live: value })
|
||||
}
|
||||
const onExpireChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
let value = e.target.value || "0"
|
||||
if (value.length > 1 && value[0] === "0") {
|
||||
value = value.substring(1, value.length)
|
||||
}
|
||||
if (!/^([0-9]+)$/.test(value)) return
|
||||
setParams({ expire: value })
|
||||
}
|
||||
|
||||
return (
|
||||
<FieldLegend>
|
||||
<FieldLegend>短效套餐详情</FieldLegend>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel>套餐类型</FieldLabel>
|
||||
<Select
|
||||
defaultValue={params.get("mode") ?? "quota"}
|
||||
onValueChange={onModeChange}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="请选择套餐类型" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="time">包时</SelectItem>
|
||||
<SelectItem value="quota">包量</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>有效期(分钟)</FieldLabel>
|
||||
<Input
|
||||
type="number"
|
||||
value={params.get("live") ?? "0"}
|
||||
onChange={onLiveChange}
|
||||
/>
|
||||
</Field>
|
||||
{params.get("mode") === "time" && (
|
||||
<Field>
|
||||
<FieldLabel>过期时间(天)</FieldLabel>
|
||||
<Input
|
||||
type="number"
|
||||
value={params.get("expire") ?? "0"}
|
||||
onChange={onExpireChange}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
{fieldState.error && <FieldError errors={[fieldState.error]} />}
|
||||
</FieldGroup>
|
||||
</FieldLegend>
|
||||
)
|
||||
}
|
||||
|
||||
function ProductLongCode<T extends { code: string }>(
|
||||
props: UseControllerReturn<T>,
|
||||
) {
|
||||
const { field, fieldState } = props
|
||||
|
||||
const params = new URLSearchParams(field.value)
|
||||
const setParams = (data: {
|
||||
mode?: string
|
||||
live?: string
|
||||
expire?: string
|
||||
}) => {
|
||||
if (data.mode) params.set("mode", data.mode)
|
||||
if (data.live) params.set("live", data.live)
|
||||
if (data.expire) params.set("expire", data.expire)
|
||||
field.onChange(params.toString())
|
||||
}
|
||||
|
||||
const onModeChange = (value: string) => {
|
||||
setParams({ mode: value })
|
||||
}
|
||||
const onLiveChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
let value = e.target.value || "0"
|
||||
if (value.length > 1 && value[0] === "0") {
|
||||
value = value.substring(1, value.length)
|
||||
}
|
||||
if (!/^([0-9]+)$/.test(value)) return
|
||||
setParams({ live: value })
|
||||
}
|
||||
const onExpireChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
let value = e.target.value || "0"
|
||||
if (value.length > 1 && value[0] === "0") {
|
||||
value = value.substring(1, value.length)
|
||||
}
|
||||
if (!/^([0-9]+)$/.test(value)) return
|
||||
setParams({ expire: value })
|
||||
}
|
||||
|
||||
return (
|
||||
<FieldLegend>
|
||||
<FieldLegend>长效套餐详情</FieldLegend>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel>套餐类型</FieldLabel>
|
||||
<Select
|
||||
defaultValue={params.get("mode") ?? "quota"}
|
||||
onValueChange={onModeChange}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="请选择套餐类型" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="time">包时</SelectItem>
|
||||
<SelectItem value="quota">包量</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>有效期(分钟)</FieldLabel>
|
||||
<Input
|
||||
type="number"
|
||||
value={params.get("live") ?? "0"}
|
||||
onChange={onLiveChange}
|
||||
/>
|
||||
</Field>
|
||||
{params.get("mode") === "time" && (
|
||||
<Field>
|
||||
<FieldLabel>过期时间(天)</FieldLabel>
|
||||
<Input
|
||||
type="number"
|
||||
value={params.get("expire") ?? "0"}
|
||||
onChange={onExpireChange}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
{fieldState.error && <FieldError errors={[fieldState.error]} />}
|
||||
</FieldGroup>
|
||||
</FieldLegend>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user