增加菜单栏帮助中心和登录页面相关协议的文档1.0版本 & allowedDevOrigins添加IP地址

This commit is contained in:
Eamon-meng
2025-12-12 14:17:24 +08:00
parent a7f4556d9d
commit ee7433e320
38 changed files with 10092 additions and 1729 deletions

View File

@@ -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>

View File

@@ -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"

View File

@@ -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 - TXT2 - 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"
}
]
```

View File

@@ -1,11 +0,0 @@
# 浏览器设置代理教程
打开IE浏览器选择“设置”点击“Internet选项”在弹出的“局域网LAN设置”中代理服务器的复选框打上勾并填写从神龙HTTP获取的ip地址及端口号点击确定刷新浏览器浏览器的IP就改变了。
1、打开IE浏览器选择“设置”
2、点击“Internet选项”
3、弹出“Internet选项”弹窗选择连接—局域网设置
4、在弹出的“局域网LAN设置”中代理服务器的复选框打上勾并填写从神龙HTTP代理获取的ip地址及端口。点击确定即设置成功了。

View 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}