引入 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

@@ -61,12 +61,14 @@ export default function Extract(props: ExtractProps) {
// ======================
return (
<Form form={form} className={merge(
`bg-white flex flex-col gap-4 rounded-md`,
props.className,
)}
<Form
form={form}
className={merge(
`bg-white flex flex-col gap-4 rounded-md`,
props.className,
)}
>
<Alert variant={`warn`}>
<Alert variant="warn">
<CircleAlert/>
<AlertTitle>IP前需要将本机IP添加到白名单后才可使用</AlertTitle>
</Alert>
@@ -80,35 +82,34 @@ export default function Extract(props: ExtractProps) {
const FormFields = memo(() => {
return (
<div className={`flex flex-col gap-4`}>
<div className="flex flex-col gap-4">
{/* 选择套餐 */}
<SelectResource/>
{/* 地区筛选 */}
<SelectRegion/>
{/* 运营商筛选 */}
<div className="flex items-center">
<FormField name="isp" label={`运营商筛选`}>
<FormField name="isp" label="运营商筛选">
{({id, field}) => (
<RadioGroup
onValueChange={field.onChange}
defaultValue={field.value}
className="flex gap-4">
<FormLabel htmlFor={`${id}-v-all`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-all`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="all" id={`${id}-v-all`}/>
<span></span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-telecom`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-telecom`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="1" id={`${id}-v-telecom`}/>
<span></span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-mobile`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-mobile`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="2" id={`${id}-v-mobile`}/>
<span></span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-unicom`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-unicom`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="3" id={`${id}-v-unicom`}/>
<span></span>
</FormLabel>
@@ -119,25 +120,25 @@ const FormFields = memo(() => {
{/* 协议类型 */}
<div className="flex items-center">
<FormField name="proto" label={`协议类型`}>
<FormField name="proto" label="协议类型">
{({id, field}) => (
<RadioGroup
onValueChange={field.onChange}
defaultValue={field.value}
className="flex gap-4">
<FormLabel htmlFor={`${id}-v-all`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-all`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="all" id={`${id}-v-all`} className="mr-2"/>
<span></span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-http`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-http`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="1" id={`${id}-v-http`} className="mr-2"/>
<span>HTTP</span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-https`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-https`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="2" id={`${id}-v-https`} className="mr-2"/>
<span>HTTPS</span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-socks5`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-socks5`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="3" id={`${id}-v-socks5`} className="mr-2"/>
<span>SOCKS5</span>
</FormLabel>
@@ -148,17 +149,17 @@ const FormFields = memo(() => {
{/* 认证方式 */}
<div className="flex items-center">
<FormField name="authType" label={`协议类型`}>
<FormField name="authType" label="协议类型">
{({id, field}) => (
<RadioGroup
onValueChange={field.onChange}
defaultValue={field.value}
className="flex gap-4">
<FormLabel htmlFor={`${id}-v-http`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-http`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="1" id={`${id}-v-http`} className="mr-2"/>
<span></span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-https`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-https`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="2" id={`${id}-v-https`} className="mr-2"/>
<span></span>
</FormLabel>
@@ -169,17 +170,17 @@ const FormFields = memo(() => {
{/* 去重选项 */}
<div className="flex items-center">
<FormField name="distinct" label={`去重选项`}>
<FormField name="distinct" label="去重选项">
{({id, field}) => (
<RadioGroup
onValueChange={field.onChange}
defaultValue={field.value}
className="flex gap-4">
<FormLabel htmlFor={`${id}-v-true`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-true`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="1" id={`${id}-v-true`} className="mr-2"/>
<span></span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-false`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-false`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="0" id={`${id}-v-false`} className="mr-2"/>
<span></span>
</FormLabel>
@@ -190,18 +191,18 @@ const FormFields = memo(() => {
{/* 导出格式 */}
<div className="flex items-center">
<FormField name="format" label={`导出格式`}>
<FormField name="format" label="导出格式">
{({id, field}) => (
<RadioGroup
onValueChange={field.onChange}
defaultValue={field.value}
className="flex gap-4"
>
<FormLabel htmlFor={`${id}-v-txt`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-txt`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="text" id={`${id}-v-txt`} className="mr-2"/>
<span>TXT </span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-json`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-json`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="json" id={`${id}-v-json`} className="mr-2"/>
<span>JSON </span>
</FormLabel>
@@ -212,21 +213,21 @@ const FormFields = memo(() => {
{/* 分隔符 */}
<div className="flex items-center">
<FormField name="separator" label={`分隔符`}>
<FormField name="separator" label="分隔符">
{({id, field}) => (
<RadioGroup
onValueChange={field.onChange}
defaultValue={field.value}
className="flex gap-4">
<FormLabel htmlFor={`${id}-v-comma`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-comma`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="124" id={`${id}-v-comma`} className="mr-2"/>
<span>线 ( | )</span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-semicolon`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-semicolon`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="58" id={`${id}-v-semicolon`} className="mr-2"/>
<span> ( : )</span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-space`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-space`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="9" id={`${id}-v-space`} className="mr-2"/>
<span> ( \t )</span>
</FormLabel>
@@ -237,21 +238,21 @@ const FormFields = memo(() => {
{/* 换行符 */}
<div className="flex items-center">
<FormField name="breaker" label={`换行符`}>
<FormField name="breaker" label="换行符">
{({id, field}) => (
<RadioGroup
onValueChange={field.onChange}
defaultValue={field.value}
className="flex gap-4">
<FormLabel htmlFor={`${id}-v-newline2`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-newline2`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="13,10" id={`${id}-v-newline2`} className="mr-2"/>
<span> ( \r\n )</span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-newline`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-newline`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="10" id={`${id}-v-newline`} className="mr-2"/>
<span> ( \n )</span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-newline3`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-newline3`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="13" id={`${id}-v-newline3`} className="mr-2"/>
<span> ( \r )</span>
</FormLabel>
@@ -262,7 +263,7 @@ const FormFields = memo(() => {
{/* 提取数量 */}
<div className="flex items-center">
<FormField name="count" label={`提取数量`}>
<FormField name="count" label="提取数量">
{({id, field}) => (
<Input
{...field}
@@ -308,74 +309,110 @@ function SelectResource() {
return (
<div className="flex items-center">
<FormField name="resource" label={`选择套餐`}>
<FormField name="resource" label="选择套餐">
{({field}) => (
<Select
value={field.value ? String(field.value) : undefined}
onValueChange={value => field.onChange(Number(value))}
>
<SelectTrigger className={`min-h-10 h-auto w-84`}>
<SelectValue placeholder={`选择套餐`}/>
<SelectTrigger className="min-h-10 h-auto w-84">
<SelectValue placeholder="选择套餐"/>
</SelectTrigger>
<SelectContent>
{status === 'load' ? (
<div className={`p-4 flex gap-1 items-center`}>
<Loader className={`animate-spin`} size={20}/>
<div className="p-4 flex gap-1 items-center">
<Loader className="animate-spin" size={20}/>
<span>...</span>
</div>
) : resources.length === 0 ? (
<div className={`p-4 flex gap-1 items-center`}>
<Loader className={`animate-spin`} size={20}/>
<div className="p-4 flex gap-1 items-center">
<Loader className="animate-spin" size={20}/>
<span></span>
</div>
) : resources.map((resource, i) => (<>
<SelectItem
key={`${resource.id}`} value={String(resource.id)} className={`p-3`}>
<div className={`flex flex-col gap-2 w-72`}>
{resource.type === 1 && resource.short.type === 1 && (<>
<div className={`flex gap-2 items-center bg-green-50 w-fit px-2 py-1 rounded-md text-sm`}>
<Timer size={20}/>
<span>{name(resource)}</span>
</div>
<div className={`flex justify-between gap-2 text-xs text-weak`}>
<span>{format(resource.short.expire, 'yyyy-MM-dd HH:mm')}</span>
<span>{intlFormatDistance(resource.short.expire, new Date())}</span>
</div>
</>)}
{resource.type === 1 && resource.short.type === 2 && (<>
<div className={`flex gap-2 items-center bg-blue-50 w-fit px-2 py-1 rounded-md text-sm`}>
<Box size={20}/>
<span>{name(resource)}</span>
</div>
<div className={`flex justify-between gap-2 text-xs text-weak`}>
<span>{resource.short.used} / {resource.short.quota}</span>
<span> {resource.short.quota - resource.short.used}</span>
</div>
</>)}
{resource.type === 2 && resource.long.type === 1 && (<>
<div className={`flex gap-2 items-center bg-green-50 w-fit px-2 py-1 rounded-md text-sm`}>
<Timer size={20}/>
<span>{name(resource)}</span>
</div>
<div className={`flex justify-between gap-2 text-xs text-weak`}>
<span>{format(resource.long.expire, 'yyyy-MM-dd HH:mm')}</span>
<span>{intlFormatDistance(resource.long.expire, new Date())}</span>
</div>
</>)}
{resource.type === 2 && resource.long.type === 2 && (<>
<div className={`flex gap-2 items-center bg-blue-50 w-fit px-2 py-1 rounded-md text-sm`}>
<Box size={20}/>
<span>{name(resource)}</span>
</div>
<div className={`flex justify-between gap-2 text-xs text-weak`}>
<span>{resource.long.used} / {resource.long.quota}</span>
<span> {resource.long.quota - resource.long.used}</span>
</div>
</>)}
</div>
</SelectItem>
{i < resources.length - 1 && <SelectSeparator className={`m-1`}/>}
</>))}
) : resources.map((resource, i) => (
<>
<SelectItem
key={`${resource.id}`}
value={String(resource.id)}
className="p-3">
<div className="flex flex-col gap-2 w-72">
{resource.type === 1 && resource.short.type === 1 && (
<>
<div className="flex gap-2 items-center bg-green-50 w-fit px-2 py-1 rounded-md text-sm">
<Timer size={20}/>
<span>{name(resource)}</span>
</div>
<div className="flex justify-between gap-2 text-xs text-weak">
<span>
{format(resource.short.expire, 'yyyy-MM-dd HH:mm')}
</span>
<span>{intlFormatDistance(resource.short.expire, new Date())}</span>
</div>
</>
)}
{resource.type === 1 && resource.short.type === 2 && (
<>
<div className="flex gap-2 items-center bg-blue-50 w-fit px-2 py-1 rounded-md text-sm">
<Box size={20}/>
<span>{name(resource)}</span>
</div>
<div className="flex justify-between gap-2 text-xs text-weak">
<span>
{resource.short.used}
{' '}
/
{resource.short.quota}
</span>
<span>
{resource.short.quota - resource.short.used}
</span>
</div>
</>
)}
{resource.type === 2 && resource.long.type === 1 && (
<>
<div className="flex gap-2 items-center bg-green-50 w-fit px-2 py-1 rounded-md text-sm">
<Timer size={20}/>
<span>{name(resource)}</span>
</div>
<div className="flex justify-between gap-2 text-xs text-weak">
<span>
{format(resource.long.expire, 'yyyy-MM-dd HH:mm')}
</span>
<span>{intlFormatDistance(resource.long.expire, new Date())}</span>
</div>
</>
)}
{resource.type === 2 && resource.long.type === 2 && (
<>
<div className="flex gap-2 items-center bg-blue-50 w-fit px-2 py-1 rounded-md text-sm">
<Box size={20}/>
<span>{name(resource)}</span>
</div>
<div className="flex justify-between gap-2 text-xs text-weak">
<span>
{resource.long.used}
{' '}
/
{resource.long.quota}
</span>
<span>
{resource.long.quota - resource.long.used}
</span>
</div>
</>
)}
</div>
</SelectItem>
{i < resources.length - 1 && <SelectSeparator className="m-1"/>}
</>
))}
</SelectContent>
</Select>
)}
@@ -392,7 +429,7 @@ function SelectRegion() {
return (
<div className="flex flex-col gap-4">
<FormField name="regionType" label={`地区筛选`}>
<FormField name="regionType" label="地区筛选">
{({id, field}) => (
<RadioGroup
onValueChange={(e) => {
@@ -405,11 +442,11 @@ function SelectRegion() {
defaultValue={field.value}
className="flex gap-4"
>
<FormLabel htmlFor={`${id}-v-unlimited`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-unlimited`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="unlimited" id={`${id}-v-unlimited`} className="mr-2"/>
<span></span>
</FormLabel>
<FormLabel htmlFor={`${id}-v-specific`} className={`px-3 h-10 border rounded-md flex items-center w-40 text-sm`}>
<FormLabel htmlFor={`${id}-v-specific`} className="px-3 h-10 border rounded-md flex items-center w-40 text-sm">
<RadioGroupItem value="specific" id={`${id}-v-specific`} className="mr-2"/>
<span></span>
</FormLabel>
@@ -419,11 +456,11 @@ function SelectRegion() {
{regionType === 'specific' && (
<Combobox
className={`w-84`}
placeholder={`请选择地区`}
className="w-84"
placeholder="请选择地区"
options={cities.options}
value={[prov || '', city || '']}
onChange={value => {
onChange={(value) => {
form.setValue('prov', value[0])
form.setValue('city', value[1])
}}
@@ -474,7 +511,7 @@ function ApplyLink() {
break
}
},
errors => {
(errors) => {
const desc: (string | undefined)[] = []
Object.entries(errors).forEach(([field, error]) => {
if (error.message) {
@@ -483,7 +520,10 @@ function ApplyLink() {
})
toast.error('请完成填写:', {
description: desc.map((msg, i) => (
<span key={i}>- {msg}</span>
<span key={i}>
-
{msg}
</span>
)),
})
},
@@ -495,7 +535,7 @@ function ApplyLink() {
`rounded-lg`,
)}>
{/* 展示链接地址 */}
<div className={`bg-neutral-900 text-white p-4 rounded-md break-all`}>
<div className="bg-neutral-900 text-white p-4 rounded-md break-all">
{link(values)}
</div>
@@ -548,7 +588,6 @@ function link(values: Schema) {
function name(resource: Resource) {
switch (resource.type) {
case 1:
// 短效套餐
switch (resource.short.type) {