增加菜单栏帮助中心和登录页面相关协议的文档1.0版本 & allowedDevOrigins添加IP地址
This commit is contained in:
@@ -18,7 +18,7 @@ import {toast} from 'sonner'
|
||||
import {merge} from '@/lib/utils'
|
||||
import {Combobox} from '@/components/ui/combobox'
|
||||
import cities from './_assets/cities.json'
|
||||
import ExtractDocs from '@/components/docs/extract.mdx'
|
||||
import ExtractDocs from '@/docs/extract.mdx'
|
||||
import Link from 'next/link'
|
||||
import {useProfileStore} from '@/components/stores-provider'
|
||||
|
||||
@@ -71,14 +71,16 @@ export default function Extract(props: ExtractProps) {
|
||||
)}
|
||||
>
|
||||
<CardSection>
|
||||
<Alert variant="warn" className="flex items-center">
|
||||
<CircleAlert/>
|
||||
<AlertTitle className="flex">提取IP前需要将本机IP添加到白名单后才可使用</AlertTitle>
|
||||
<Alert variant="warn" className="flex items-center justify-between">
|
||||
<span className="flex items-center gap-2">
|
||||
<CircleAlert/>
|
||||
<AlertTitle className="flex text-gray-900">提取IP前需要将本机IP添加到白名单后才可使用</AlertTitle>
|
||||
</span>
|
||||
<Link
|
||||
href="/admin/whitelist"
|
||||
className="flex-none text-blue-600 hover:text-blue-800 hover:underline font-medium ml-2 flex gap-0.5 items-center"
|
||||
className="flex-none text-orange-600 font-medium ml-2 flex gap-0.5 items-center"
|
||||
>
|
||||
<span>去添加</span>
|
||||
<span>添加白名单</span>
|
||||
<ArrowRight className="size-4"/>
|
||||
</Link>
|
||||
</Alert>
|
||||
@@ -335,6 +337,8 @@ function SelectResource() {
|
||||
setStatus('load')
|
||||
try {
|
||||
const resp = await allResource()
|
||||
console.log(resp, '套餐管理resprespresp')
|
||||
|
||||
if (!resp.success) {
|
||||
console.log(11111)
|
||||
throw new Error('获取套餐失败,请稍后再试')
|
||||
@@ -392,12 +396,15 @@ function SelectResource() {
|
||||
<Timer size={20}/>
|
||||
<span>{name(resource)}</span>
|
||||
</div>
|
||||
<div className="flex text-xs text-weak">
|
||||
<span>{resource.resource_no}</span>
|
||||
</div>
|
||||
<div className="flex justify-between gap-2 text-xs text-weak">
|
||||
<span>
|
||||
到期时间:
|
||||
{format(resource.short.expire, 'yyyy-MM-dd HH:mm')}
|
||||
{format(resource.short.expire_at, 'yyyy-MM-dd HH:mm')}
|
||||
</span>
|
||||
<span>{intlFormatDistance(resource.short.expire, new Date())}</span>
|
||||
<span>{intlFormatDistance(resource.short.expire_at, new Date())}</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -407,6 +414,9 @@ function SelectResource() {
|
||||
<Box size={20}/>
|
||||
<span>{name(resource)}</span>
|
||||
</div>
|
||||
<div className="flex text-xs text-weak">
|
||||
<span>{resource.resource_no}</span>
|
||||
</div>
|
||||
<div className="flex justify-between gap-2 text-xs text-weak">
|
||||
<span>
|
||||
提取数量:
|
||||
@@ -428,12 +438,15 @@ function SelectResource() {
|
||||
<Timer size={20}/>
|
||||
<span>{name(resource)}</span>
|
||||
</div>
|
||||
<div className="flex text-xs text-weak">
|
||||
<span>{resource.resource_no}</span>
|
||||
</div>
|
||||
<div className="flex justify-between gap-2 text-xs text-weak">
|
||||
<span>
|
||||
到期时间:
|
||||
{format(resource.long.expire, 'yyyy-MM-dd HH:mm')}
|
||||
{format(resource.long.expire_at, 'yyyy-MM-dd HH:mm')}
|
||||
</span>
|
||||
<span>{intlFormatDistance(resource.long.expire, new Date())}</span>
|
||||
<span>{intlFormatDistance(resource.long.expire_at, new Date())}</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -443,6 +456,9 @@ function SelectResource() {
|
||||
<Box size={20}/>
|
||||
<span>{name(resource)}</span>
|
||||
</div>
|
||||
<div className="flex text-xs text-weak">
|
||||
<span>{resource.resource_no}</span>
|
||||
</div>
|
||||
<div className="flex justify-between gap-2 text-xs text-weak">
|
||||
<span>
|
||||
提取数量:
|
||||
|
||||
@@ -29,12 +29,14 @@ export default function UserCenter(props: UserCenterProps) {
|
||||
const pathname = usePathname()
|
||||
const isAdminPage = pathname.startsWith('/admin') // 判断是否在后台页面
|
||||
const displayName = () => {
|
||||
if (props.profile.username) return props.profile.username // 优先显示用户名
|
||||
if (props.profile.phone) {
|
||||
const phone = props.profile.phone
|
||||
return `${phone.substring(0, 3)}****${phone.substring(7)}`
|
||||
const {username, email, phone} = props.profile
|
||||
|
||||
switch (true) {
|
||||
case !!username: return username
|
||||
case !!phone: return `${phone.substring(0, 3)}****${phone.substring(7)}`
|
||||
case !!email: return email
|
||||
default: return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const handleAvatarClick = () => {
|
||||
@@ -55,22 +57,14 @@ export default function UserCenter(props: UserCenterProps) {
|
||||
<AvatarImage src={props.profile.avatar} alt="avatar"/>
|
||||
<AvatarFallback className="bg-primary-muted"><UserIcon/></AvatarFallback>
|
||||
</Avatar>
|
||||
{/* 根据是否在后台页面显示不同内容 */}
|
||||
{isAdminPage ? (
|
||||
<span>{displayName() || '用户'}</span> // 后台显示姓名/脱敏手机号/默认"用户"
|
||||
<span>{displayName() || '用户'}</span>
|
||||
) : (
|
||||
<span>进入控制台</span> // 前台显示"进入控制台"
|
||||
<span>进入控制台</span>
|
||||
)}
|
||||
</Button>
|
||||
</HoverCardTrigger>
|
||||
<HoverCardContent className="w-36 p-1" align="end">
|
||||
{/* <Button
|
||||
theme="ghost"
|
||||
className="w-full justify-start text-sm h-9 px-3"
|
||||
onClick={() => router.push('/admin/profile')}>
|
||||
<UserPenIcon/>
|
||||
个人中心
|
||||
</Button> */}
|
||||
<Button
|
||||
theme="ghost"
|
||||
color="fail"
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
# 提取代理接口文档
|
||||
|
||||
## 请求方式
|
||||
|
||||
`GET https://lanhuip.com/api/extract`
|
||||
|
||||
## 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|----------|------|----------------------------------------------------------------------------------------------------------------------------|
|
||||
| i | number | 是 | 用于提取的套餐 ID |
|
||||
| t | number | 是 | 认证类型:1 - 白名单,2 - 密码 |
|
||||
| a | string | 否 | 归属地省份。默认全局随机 |
|
||||
| b | string | 否 | 归属地城市。默认全局随机 |
|
||||
| s | string | 否 | 归属地运营商。默认全局随机 |
|
||||
| d | string | 否 | 是否去重:1 - 是,0 - 否。默认为是 |
|
||||
| rt | string | 否 | 返回类型:1 - TXT,2 - JSON。默认 TXT |
|
||||
| rs | number[] | 否 | 返回时要使用的分隔符,值为该字符的 ascii 编码,可以有多个字符,多个字符用半角逗号连接。默认为 13,10,即回车 + 换行(\r\n) |
|
||||
| rb | number[] | 否 | 返回时要使用的换行符,值为该字符的 ascii 编码,可以有多个字符,多个字符用半角逗号连接。默认为 124,即垂直线( \| ) |
|
||||
| n | number | 否 | 提取数量。默认为 1 |
|
||||
|
||||
## 响应参数
|
||||
|
||||
如果请求参数中返回类型为 TXT,则响应为纯文本格式,内容为提取的代理列表,每个代理信息占一行。
|
||||
|
||||
如果请求参数中返回类型为 JSON,则响应为 JSON 格式,内容为提取的代理列表,每个代理信息为一个对象,包含以下字段:
|
||||
|
||||
| 参数名 | 类型 | 描述 |
|
||||
|----------|--------|--------------------------------------------- |
|
||||
| host | string | 代理服务器地址 |
|
||||
| port | number | 代理服务器端口 |
|
||||
| username | string | 代理服务器用户名(仅在认证类型为密码时返回) |
|
||||
| password | string | 代理服务器密码(仅在认证类型为密码时返回) |
|
||||
|
||||
|
||||
## 示例
|
||||
|
||||
### 请求示例
|
||||
|
||||
```http
|
||||
GET https://lanhuip.com/api/extract?i=1&t=2&a=广东省&b=广州市&s=移动&d=1&rt=2&n=3
|
||||
```
|
||||
|
||||
### 响应示例
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"host": "fwd1.lanhuip.com",
|
||||
"port": 20000,
|
||||
"username": "user1",
|
||||
"password": "pass1"
|
||||
},
|
||||
{
|
||||
"host": "fwd1.lanhuip.com",
|
||||
"port": 20001,
|
||||
"username": "user2",
|
||||
"password": "pass2"
|
||||
},
|
||||
{
|
||||
"host": "fwd1.lanhuip.com",
|
||||
"port": 20002,
|
||||
"username": "user3",
|
||||
"password": "pass3"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# 浏览器设置代理教程
|
||||
|
||||
打开IE浏览器,选择“设置”,点击“Internet选项”,在弹出的“局域网LAN设置”中,代理服务器的复选框打上勾,并填写从神龙HTTP获取的ip地址及端口号,点击确定,刷新浏览器,浏览器的IP就改变了。
|
||||
|
||||
1、打开IE浏览器,选择“设置”;
|
||||
|
||||
2、点击“Internet选项”;
|
||||
|
||||
3、弹出“Internet选项”弹窗,选择连接—局域网设置;
|
||||
|
||||
4、在弹出的“局域网LAN设置”中,代理服务器的复选框打上勾,并填写从神龙HTTP代理获取的ip地址及端口。点击确定,即设置成功了。
|
||||
46
src/components/ui/badge.tsx
Normal file
46
src/components/ui/badge.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import * as React from 'react'
|
||||
import {Slot} from '@radix-ui/react-slot'
|
||||
import {cva, type VariantProps} from 'class-variance-authority'
|
||||
|
||||
import {merge} from '@/lib/utils'
|
||||
|
||||
const badgeVariants = cva(
|
||||
'inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90',
|
||||
secondary:
|
||||
'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90',
|
||||
destructive:
|
||||
'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
|
||||
outline:
|
||||
'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
function Badge({
|
||||
className,
|
||||
variant,
|
||||
asChild = false,
|
||||
...props
|
||||
}: React.ComponentProps<'span'> &
|
||||
VariantProps<typeof badgeVariants> & {asChild?: boolean}) {
|
||||
const Comp = asChild ? Slot : 'span'
|
||||
|
||||
return (
|
||||
<Comp
|
||||
data-slot="badge"
|
||||
className={merge(badgeVariants({variant}), className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export {Badge, badgeVariants}
|
||||
Reference in New Issue
Block a user