引入 husky,并全局重新格式化

This commit is contained in:
2025-06-07 11:49:57 +08:00
parent 05fce179c9
commit c7527177b0
89 changed files with 2140 additions and 1899 deletions

View File

@@ -111,198 +111,221 @@ export default function LongResource(props: LongResourceProps) {
await refresh(1, data.size)
}
return <>
{/* 操作区 */}
<section className={`flex justify-between flex-wrap`}>
<div>
return (
<>
{/* 操作区 */}
<section className="flex justify-between flex-wrap">
<div>
</div>
</div>
<Form form={form} onSubmit={onSubmit} className={`flex items-end gap-4 flex-wrap`}>
<FormField name={`resource_no`} label={<span className={`text-sm`}></span>}>
{({id, field}) => (
<Input {...field} id={id} className={`h-9`}/>
)}
</FormField>
<FormField name={`type`} label={<span className={`text-sm`}></span>}>
{({field}) => (
<Select value={field.value} onValueChange={field.onChange}>
<SelectTrigger className={`w-24 h-9`}>
<SelectValue placeholder={`选择套餐类型`}/>
</SelectTrigger>
<SelectContent>
<SelectItem value={`all`}></SelectItem>
<SelectItem value={`expire`}></SelectItem>
<SelectItem value={`quota`}></SelectItem>
</SelectContent>
</Select>
)}
</FormField>
<div className={`flex flex-col gap-2`}>
<Label className={`text-sm`}></Label>
<div className={`flex items-center`}>
<FormField name={`create_after`}>
{({field}) => (
<DatePicker
{...field}
className={`w-36`}
placeholder={`开始时间`}
format={`yyyy-MM-dd`}
/>
)}
</FormField>
<span className={`px-1`}>-</span>
<FormField name={`create_before`}>
{({field}) => (
<DatePicker
{...field}
className={`w-36`}
placeholder={`结束时间`}
format={`yyyy-MM-dd`}
/>
)}
</FormField>
</div>
</div>
<div className={`flex flex-col gap-2`}>
<Label className={`text-sm`}>使</Label>
<div className={`flex items-center`}>
<FormField name={`expire_after`}>
{({field}) => (
<DatePicker
{...field}
className={`w-36`}
placeholder={`开始时间`}
format={`yyyy-MM-dd`}
/>
)}
</FormField>
<span className={`px-1`}>-</span>
<FormField name={`expire_before`}>
{({field}) => (
<DatePicker
{...field}
className={`w-36`}
placeholder={`结束时间`}
format={`yyyy-MM-dd`}
/>
)}
</FormField>
</div>
</div>
<div className={`flex gap-4`}>
<Button className={`h-9`}>
<Search/>
<span></span>
</Button>
<Button theme={`outline`} className={`h-9`} onClick={() => form.reset({
type: 'all',
resource_no: '',
create_after: undefined,
create_before: undefined,
expire_after: undefined,
expire_before: undefined,
})}>
<Eraser/>
<span></span>
</Button>
</div>
</Form>
</section>
{/* 数据表 */}
<DataTable
data={data.list}
status={status}
pagination={{
total: data.total,
page: data.page,
size: data.size,
onPageChange: async (page: number) => {
await refresh(page, data.size)
},
onSizeChange: async (size: number) => {
await refresh(data.page, size)
},
}}
columns={[
{
accessorKey: 'resource_no', header: `套餐编号`,
},
{
accessorKey: 'type', header: `类型`, cell: ({row}) => (
<div className={`flex gap-2 items-center`}>
{row.original.long.type === 1 && (
<div className={`flex gap-2 items-center bg-green-50 w-fit px-2 py-1 rounded-md`}>
<Timer size={20}/>
<span></span>
</div>
)}
{row.original.long.type === 2 && (
<div className={`flex gap-2 items-center bg-blue-50 w-fit px-2 py-1 rounded-md`}>
<Box size={20}/>
<span></span>
</div>
)}
<Form form={form} onSubmit={onSubmit} className="flex items-end gap-4 flex-wrap">
<FormField name="resource_no" label={<span className="text-sm"></span>}>
{({id, field}) => (
<Input {...field} id={id} className="h-9"/>
)}
</FormField>
<FormField name="type" label={<span className="text-sm"></span>}>
{({field}) => (
<Select value={field.value} onValueChange={field.onChange}>
<SelectTrigger className="w-24 h-9">
<SelectValue placeholder="选择套餐类型"/>
</SelectTrigger>
<SelectContent>
<SelectItem value="all"></SelectItem>
<SelectItem value="expire"></SelectItem>
<SelectItem value="quota"></SelectItem>
</SelectContent>
</Select>
)}
</FormField>
<div className="flex flex-col gap-2">
<Label className="text-sm"></Label>
<div className="flex items-center">
<FormField name="create_after">
{({field}) => (
<DatePicker
{...field}
className="w-36"
placeholder="开始时间"
format="yyyy-MM-dd"
/>
)}
</FormField>
<span className="px-1">-</span>
<FormField name="create_before">
{({field}) => (
<DatePicker
{...field}
className="w-36"
placeholder="结束时间"
format="yyyy-MM-dd"
/>
)}
</FormField>
</div>
),
},
{
accessorKey: 'live', header: `IP 时效`, cell: ({row}) => (
<span>
{row.original.long.live}
</span>
),
},
{
accessorKey: 'expire', header: `使用情况`, cell: ({row}) => (
<div className={`flex gap-1`}>
{row.original.long.type === 1 ? (
<div className={`flex gap-1`}>
{isAfter(row.original.long.expire, new Date())
? <span className={`text-green-500`}></span>
: <span className={`text-red-500`}></span>}
<span>|</span>
<span>{row.original.long.daily_used} / {row.original.long.daily_limit}</span>
<span>|</span>
<span>{intlFormatDistance(row.original.long.expire, new Date())} </span>
</div>
) : row.original.long.type === 2 ? (
<div className={`flex gap-1`}>
{row.original.long.used < row.original.long.quota
? <span className={`text-green-500`}></span>
: <span className={`text-red-500`}></span>}
<span>|</span>
<span>{row.original.long.used} / {row.original.long.quota}</span>
</div>
) : (
<span>-</span>
)}
</div>
<div className="flex flex-col gap-2">
<Label className="text-sm">使</Label>
<div className="flex items-center">
<FormField name="expire_after">
{({field}) => (
<DatePicker
{...field}
className="w-36"
placeholder="开始时间"
format="yyyy-MM-dd"
/>
)}
</FormField>
<span className="px-1">-</span>
<FormField name="expire_before">
{({field}) => (
<DatePicker
{...field}
className="w-36"
placeholder="结束时间"
format="yyyy-MM-dd"
/>
)}
</FormField>
</div>
),
},
{
accessorKey: 'daily_last', header: '最近使用时间', cell: ({row}) => {
return (
format(row.original.long.daily_last, 'yyyy-MM-dd') === '0001-01-01'
? '-'
: format(row.original.long.daily_last, 'yyyy-MM-dd HH:mm')
)
</div>
<div className="flex gap-4">
<Button className="h-9">
<Search/>
<span></span>
</Button>
<Button
theme="outline"
className="h-9"
onClick={() => form.reset({
type: 'all',
resource_no: '',
create_after: undefined,
create_before: undefined,
expire_after: undefined,
expire_before: undefined,
})}>
<Eraser/>
<span></span>
</Button>
</div>
</Form>
</section>
{/* 数据表 */}
<DataTable
data={data.list}
status={status}
pagination={{
total: data.total,
page: data.page,
size: data.size,
onPageChange: async (page: number) => {
await refresh(page, data.size)
},
},
{
accessorKey: 'created_at', header: '开通时间', cell: ({row}) => (
format(row.getValue('created_at'), 'yyyy-MM-dd HH:mm')
),
},
{
accessorKey: 'action', header: `操作`, cell: (item) => (
<div className={`flex gap-2`}>
-
</div>
),
},
]}
/>
</>
onSizeChange: async (size: number) => {
await refresh(data.page, size)
},
}}
columns={[
{
accessorKey: 'resource_no', header: `套餐编号`,
},
{
accessorKey: 'type', header: `类型`, cell: ({row}) => (
<div className="flex gap-2 items-center">
{row.original.long.type === 1 && (
<div className="flex gap-2 items-center bg-green-50 w-fit px-2 py-1 rounded-md">
<Timer size={20}/>
<span></span>
</div>
)}
{row.original.long.type === 2 && (
<div className="flex gap-2 items-center bg-blue-50 w-fit px-2 py-1 rounded-md">
<Box size={20}/>
<span></span>
</div>
)}
</div>
),
},
{
accessorKey: 'live', header: `IP 时效`, cell: ({row}) => (
<span>
{row.original.long.live}
{' '}
</span>
),
},
{
accessorKey: 'expire', header: `使用情况`, cell: ({row}) => (
<div className="flex gap-1">
{row.original.long.type === 1 ? (
<div className="flex gap-1">
{isAfter(row.original.long.expire, new Date())
? <span className="text-green-500"></span>
: <span className="text-red-500"></span>}
<span>|</span>
<span>
{row.original.long.daily_used}
{' '}
/
{row.original.long.daily_limit}
</span>
<span>|</span>
<span>
{intlFormatDistance(row.original.long.expire, new Date())}
{' '}
</span>
</div>
) : row.original.long.type === 2 ? (
<div className="flex gap-1">
{row.original.long.used < row.original.long.quota
? <span className="text-green-500"></span>
: <span className="text-red-500"></span>}
<span>|</span>
<span>
{row.original.long.used}
{' '}
/
{row.original.long.quota}
</span>
</div>
) : (
<span>-</span>
)}
</div>
),
},
{
accessorKey: 'daily_last', header: '最近使用时间', cell: ({row}) => {
return (
format(row.original.long.daily_last, 'yyyy-MM-dd') === '0001-01-01'
? '-'
: format(row.original.long.daily_last, 'yyyy-MM-dd HH:mm')
)
},
},
{
accessorKey: 'created_at', header: '开通时间', cell: ({row}) => (
format(row.getValue('created_at'), 'yyyy-MM-dd HH:mm')
),
},
{
accessorKey: 'action', header: `操作`, cell: item => (
<div className="flex gap-2">
-
</div>
),
},
]}
/>
</>
)
}

View File

@@ -112,198 +112,221 @@ export default function ShortResource(props: ShortResourceProps) {
await refresh(1, data.size)
}
return <>
{/* 操作区 */}
<section className={`flex justify-between flex-wrap`}>
<div>
return (
<>
{/* 操作区 */}
<section className="flex justify-between flex-wrap">
<div>
</div>
</div>
<Form form={form} onSubmit={onSubmit} className={`flex items-end gap-4 flex-wrap`}>
<FormField name={`resource_no`} label={<span className={`text-sm`}></span>}>
{({id, field}) => (
<Input {...field} id={id} className={`h-9`}/>
)}
</FormField>
<FormField name={`type`} label={<span className={`text-sm`}></span>}>
{({field}) => (
<Select value={field.value} onValueChange={field.onChange}>
<SelectTrigger className={`w-24 h-9`}>
<SelectValue placeholder={`选择套餐类型`}/>
</SelectTrigger>
<SelectContent>
<SelectItem value={`all`}></SelectItem>
<SelectItem value={`expire`}></SelectItem>
<SelectItem value={`quota`}></SelectItem>
</SelectContent>
</Select>
)}
</FormField>
<div className={`flex flex-col gap-2`}>
<Label className={`text-sm`}></Label>
<div className={`flex items-center`}>
<FormField name={`create_after`}>
{({field}) => (
<DatePicker
{...field}
className={`w-36`}
placeholder={`开始时间`}
format={`yyyy-MM-dd`}
/>
)}
</FormField>
<span className={`px-1`}>-</span>
<FormField name={`create_before`}>
{({field}) => (
<DatePicker
{...field}
className={`w-36`}
placeholder={`结束时间`}
format={`yyyy-MM-dd`}
/>
)}
</FormField>
</div>
</div>
<div className={`flex flex-col gap-2`}>
<Label className={`text-sm`}>使</Label>
<div className={`flex items-center`}>
<FormField name={`expire_after`}>
{({field}) => (
<DatePicker
{...field}
className={`w-36`}
placeholder={`开始时间`}
format={`yyyy-MM-dd`}
/>
)}
</FormField>
<span className={`px-1`}>-</span>
<FormField name={`expire_before`}>
{({field}) => (
<DatePicker
{...field}
className={`w-36`}
placeholder={`结束时间`}
format={`yyyy-MM-dd`}
/>
)}
</FormField>
</div>
</div>
<div className={`flex gap-4`}>
<Button className={`h-9`}>
<Search/>
<span></span>
</Button>
<Button theme={`outline`} className={`h-9`} onClick={() => form.reset({
type: 'all',
resource_no: '',
create_after: undefined,
create_before: undefined,
expire_after: undefined,
expire_before: undefined,
})}>
<Eraser/>
<span></span>
</Button>
</div>
</Form>
</section>
{/* 数据表 */}
<DataTable
data={data.list}
status={status}
pagination={{
total: data.total,
page: data.page,
size: data.size,
onPageChange: async (page: number) => {
await refresh(page, data.size)
},
onSizeChange: async (size: number) => {
await refresh(data.page, size)
},
}}
columns={[
{
accessorKey: 'resource_no', header: `套餐编号`,
},
{
accessorKey: 'type', header: `类型`, cell: ({row}) => (
<div className={`flex gap-2 items-center`}>
{row.original.short.type === 1 && (
<div className={`flex gap-2 items-center bg-green-50 w-fit px-2 py-1 rounded-md`}>
<Timer size={20}/>
<span></span>
</div>
)}
{row.original.short.type === 2 && (
<div className={`flex gap-2 items-center bg-blue-50 w-fit px-2 py-1 rounded-md`}>
<Box size={20}/>
<span></span>
</div>
)}
<Form form={form} onSubmit={onSubmit} className="flex items-end gap-4 flex-wrap">
<FormField name="resource_no" label={<span className="text-sm"></span>}>
{({id, field}) => (
<Input {...field} id={id} className="h-9"/>
)}
</FormField>
<FormField name="type" label={<span className="text-sm"></span>}>
{({field}) => (
<Select value={field.value} onValueChange={field.onChange}>
<SelectTrigger className="w-24 h-9">
<SelectValue placeholder="选择套餐类型"/>
</SelectTrigger>
<SelectContent>
<SelectItem value="all"></SelectItem>
<SelectItem value="expire"></SelectItem>
<SelectItem value="quota"></SelectItem>
</SelectContent>
</Select>
)}
</FormField>
<div className="flex flex-col gap-2">
<Label className="text-sm"></Label>
<div className="flex items-center">
<FormField name="create_after">
{({field}) => (
<DatePicker
{...field}
className="w-36"
placeholder="开始时间"
format="yyyy-MM-dd"
/>
)}
</FormField>
<span className="px-1">-</span>
<FormField name="create_before">
{({field}) => (
<DatePicker
{...field}
className="w-36"
placeholder="结束时间"
format="yyyy-MM-dd"
/>
)}
</FormField>
</div>
),
},
{
accessorKey: 'live', header: `IP 时效`, cell: ({row}) => (
<span>
{row.original.short.live / 60}
</span>
),
},
{
accessorKey: 'expire', header: `使用情况`, cell: ({row}) => (
<div className={`flex gap-1`}>
{row.original.short.type === 1 ? (
<div className={`flex gap-1`}>
{isAfter(row.original.short.expire, new Date())
? <span className={`text-green-500`}></span>
: <span className={`text-red-500`}></span>}
<span>|</span>
<span>{row.original.short.daily_used} / {row.original.short.daily_limit}</span>
<span>|</span>
<span>{intlFormatDistance(row.original.short.expire, new Date())} </span>
</div>
) : row.original.short.type === 2 ? (
<div className={`flex gap-1`}>
{row.original.short.used < row.original.short.quota
? <span className={`text-green-500`}></span>
: <span className={`text-red-500`}></span>}
<span>|</span>
<span>{row.original.short.used} / {row.original.short.quota}</span>
</div>
) : (
<span>-</span>
)}
</div>
<div className="flex flex-col gap-2">
<Label className="text-sm">使</Label>
<div className="flex items-center">
<FormField name="expire_after">
{({field}) => (
<DatePicker
{...field}
className="w-36"
placeholder="开始时间"
format="yyyy-MM-dd"
/>
)}
</FormField>
<span className="px-1">-</span>
<FormField name="expire_before">
{({field}) => (
<DatePicker
{...field}
className="w-36"
placeholder="结束时间"
format="yyyy-MM-dd"
/>
)}
</FormField>
</div>
),
},
{
accessorKey: 'daily_last', header: '最近使用时间', cell: ({row}) => {
return (
format(row.original.short.daily_last, 'yyyy-MM-dd') === '0001-01-01'
? '-'
: format(row.original.short.daily_last, 'yyyy-MM-dd HH:mm')
)
</div>
<div className="flex gap-4">
<Button className="h-9">
<Search/>
<span></span>
</Button>
<Button
theme="outline"
className="h-9"
onClick={() => form.reset({
type: 'all',
resource_no: '',
create_after: undefined,
create_before: undefined,
expire_after: undefined,
expire_before: undefined,
})}>
<Eraser/>
<span></span>
</Button>
</div>
</Form>
</section>
{/* 数据表 */}
<DataTable
data={data.list}
status={status}
pagination={{
total: data.total,
page: data.page,
size: data.size,
onPageChange: async (page: number) => {
await refresh(page, data.size)
},
},
{
accessorKey: 'created_at', header: '开通时间', cell: ({row}) => (
format(row.getValue('created_at'), 'yyyy-MM-dd HH:mm')
),
},
{
accessorKey: 'action', header: `操作`, cell: (item) => (
<div className={`flex gap-2`}>
-
</div>
),
},
]}
/>
</>
onSizeChange: async (size: number) => {
await refresh(data.page, size)
},
}}
columns={[
{
accessorKey: 'resource_no', header: `套餐编号`,
},
{
accessorKey: 'type', header: `类型`, cell: ({row}) => (
<div className="flex gap-2 items-center">
{row.original.short.type === 1 && (
<div className="flex gap-2 items-center bg-green-50 w-fit px-2 py-1 rounded-md">
<Timer size={20}/>
<span></span>
</div>
)}
{row.original.short.type === 2 && (
<div className="flex gap-2 items-center bg-blue-50 w-fit px-2 py-1 rounded-md">
<Box size={20}/>
<span></span>
</div>
)}
</div>
),
},
{
accessorKey: 'live', header: `IP 时效`, cell: ({row}) => (
<span>
{row.original.short.live / 60}
{' '}
</span>
),
},
{
accessorKey: 'expire', header: `使用情况`, cell: ({row}) => (
<div className="flex gap-1">
{row.original.short.type === 1 ? (
<div className="flex gap-1">
{isAfter(row.original.short.expire, new Date())
? <span className="text-green-500"></span>
: <span className="text-red-500"></span>}
<span>|</span>
<span>
{row.original.short.daily_used}
{' '}
/
{row.original.short.daily_limit}
</span>
<span>|</span>
<span>
{intlFormatDistance(row.original.short.expire, new Date())}
{' '}
</span>
</div>
) : row.original.short.type === 2 ? (
<div className="flex gap-1">
{row.original.short.used < row.original.short.quota
? <span className="text-green-500"></span>
: <span className="text-red-500"></span>}
<span>|</span>
<span>
{row.original.short.used}
{' '}
/
{row.original.short.quota}
</span>
</div>
) : (
<span>-</span>
)}
</div>
),
},
{
accessorKey: 'daily_last', header: '最近使用时间', cell: ({row}) => {
return (
format(row.original.short.daily_last, 'yyyy-MM-dd') === '0001-01-01'
? '-'
: format(row.original.short.daily_last, 'yyyy-MM-dd HH:mm')
)
},
},
{
accessorKey: 'created_at', header: '开通时间', cell: ({row}) => (
format(row.getValue('created_at'), 'yyyy-MM-dd HH:mm')
),
},
{
accessorKey: 'action', header: `操作`, cell: item => (
<div className="flex gap-2">
-
</div>
),
},
]}
/>
</>
)
}

View File

@@ -1,6 +1,5 @@
import { ReactNode } from 'react'
import { Metadata } from 'next'
import {ReactNode} from 'react'
import {Metadata} from 'next'
export async function generateMetadata(): Promise<Metadata> {
return {
@@ -9,9 +8,9 @@ export async function generateMetadata(): Promise<Metadata> {
}
export type ResourcesLayoutProps = {
children: ReactNode
children: ReactNode
}
export default async function ResourcesLayout(props: ResourcesLayoutProps) {
return props.children
}
}

View File

@@ -4,22 +4,21 @@ import ShortResource from '@/app/admin/resources/_client/short'
import LongResource from '@/app/admin/resources/_client/long'
export default async function ResourcesPage() {
// ======================
// render
// ======================
return (
<Page>
<Tabs defaultValue={`short`}>
<TabsList className={`bg-card p-1.5 rounded-lg`}>
<TabsTrigger value={`short`} className={`w-30 h-9 data-[state=active]:bg-primary-muted text-base rounded-md`}></TabsTrigger>
<TabsTrigger value={`long`} className={`w-30 h-9 data-[state=active]:bg-primary-muted text-base rounded-md`}></TabsTrigger>
<Tabs defaultValue="short">
<TabsList className="bg-card p-1.5 rounded-lg">
<TabsTrigger value="short" className="w-30 h-9 data-[state=active]:bg-primary-muted text-base rounded-md"></TabsTrigger>
<TabsTrigger value="long" className="w-30 h-9 data-[state=active]:bg-primary-muted text-base rounded-md"></TabsTrigger>
</TabsList>
<TabsContent value={`short`} className={`flex flex-col gap-4`}>
<TabsContent value="short" className="flex flex-col gap-4">
<ShortResource/>
</TabsContent>
<TabsContent value={`long`} className={`flex flex-col gap-4`}>
<TabsContent value="long" className="flex flex-col gap-4">
<LongResource/>
</TabsContent>
</Tabs>