更新登录功能

This commit is contained in:
Eamon
2026-08-13 18:28:20 +08:00
parent 115ee3bfeb
commit 4235458bea
25 changed files with 1900 additions and 873 deletions

View File

@@ -1,6 +1,5 @@
// 定义后端服务URL和OAuth2配置
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL
if (!API_BASE_URL) throw new Error("VITE_API_BASE_URL is not set")
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ?? ""
const CLIENT_ID = import.meta.env.VITE_CLIENT_ID
if (!CLIENT_ID) throw new Error("VITE_CLIENT_ID is not set")
@@ -12,7 +11,7 @@ if (!CLIENT_SECRET) throw new Error("VITE_CLIENT_SECRET is not set")
type ApiResponse<T = undefined> =
| {
success: false
status: number
status?: number
message: string
}
| {
@@ -20,32 +19,4 @@ type ApiResponse<T = undefined> =
data: T
}
type PageRecord<T = unknown> = {
total: number
page: number
size: number
list: T[]
}
// 工具类型:用于提取请求参数和返回数据
type ExtraReq<T extends (...args: never) => unknown> = T extends (
...args: infer P
) => unknown
? P[0]
: never
type ExtraResp<T extends (...args: never) => unknown> =
Awaited<ReturnType<T>> extends ApiResponse<infer D> ? D : never
// 预定义错误
const UnauthorizedError = new Error("未授权访问")
export {
API_BASE_URL,
type ApiResponse,
CLIENT_ID,
CLIENT_SECRET,
type ExtraReq,
type ExtraResp,
type PageRecord,
UnauthorizedError,
}
export { API_BASE_URL, type ApiResponse, CLIENT_ID, CLIENT_SECRET }

View File

@@ -1,13 +0,0 @@
import { callPublic } from "@/api/base"
// 获取验证码
// 假设你的后端接口为 /api/captcha/get,返回 { token: 'abc', base64: 'data:image/png...' }
export async function getCaptcha() {
return await callPublic<{ token: string; base64: string }>("/api/captcha/get")
}
// 校验验证码
// 假设后端接口为 /api/captcha/verify,返回 { success: true/false }
export async function verifyCaptcha(token: string, answer: string) {
return await callPublic<boolean>("/api/captcha/verify", { token, answer })
}

View File

@@ -5,6 +5,7 @@ export type Version = {
export type Product = {
id: string
productId: number
title: string
price: number
desc?: string
@@ -14,6 +15,7 @@ export type Product = {
duration?: string
version?: string
features?: string[]
isTest?: boolean
}
export type Brand = {
@@ -29,267 +31,109 @@ export type Tab = {
brands: Brand[]
}
export const PRODUCT_DATA: Tab[] = [
{
id: "dynamic",
label: "动态独享IP",
brands: [
{
id: "fox",
name: "极狐IP(推荐)",
versions: [
{ id: "v1", label: "尊享版-不限速" },
{ id: "v2", label: "高级版-限速6M" },
{ id: "v3", label: "普通版-限速2M" },
],
products: [
{
id: "1",
title: "免费",
price: 0,
desc: "注册即送3次",
card: "测试卡",
duration: "1小时",
version: "v1",
},
{
id: "2",
title: "首单低至",
price: 0.1,
originalPrice: 0.1,
// card: "测试卡",
duration: "24小时",
version: "v1",
},
{
id: "3",
title: "周卡套餐",
price: 37.5,
tag: "8.5折",
originalPrice: 37.5,
// card: "周卡",
duration: "7天",
version: "v1",
},
{
id: "4",
title: "月卡套餐",
price: 78,
tag: "8.5折",
originalPrice: 80.0,
// card: "月卡",
duration: "30天",
version: "v2",
},
{
id: "5",
title: "季卡套餐",
price: 208,
tag: "8.5折",
originalPrice: 220.0,
// card: "季卡",
duration: "90天",
version: "v2",
},
{
id: "6",
title: "年卡套餐",
price: 770,
tag: "8.5折",
originalPrice: 800.0,
card: "年卡",
duration: "365天",
version: "v3",
},
],
},
{
id: "aurora",
name: "极光IP(推荐)",
versions: [
{ id: "v1", label: "尊享版-不限速" },
{ id: "v2", label: "高级版-限速6M" },
{ id: "v3", label: "普通版-限速2M" },
],
products: [
{
id: "7",
title: "周卡套餐",
price: 37.5,
originalPrice: 37.5,
card: "周卡",
duration: "7天",
version: "v1",
},
{
id: "8",
title: "月卡套餐",
price: 78,
tag: "8.5折",
originalPrice: 80.0,
card: "月卡",
duration: "30天",
version: "v2",
},
{
id: "9",
title: "季卡套餐",
price: 208,
tag: "8.5折",
originalPrice: 220.0,
card: "季卡",
duration: "90天",
version: "v3",
},
],
},
{
id: "mushroom",
name: "蘑菇IP",
products: [
{
id: "10",
title: "免费",
price: 0,
desc: "注册即送3次",
card: "测试卡",
duration: "1小时",
},
{
id: "11",
title: "首单低至",
price: 0.1,
originalPrice: 0.1,
// card: "测试卡",
duration: "24小时",
},
{
id: "12",
title: "周卡套餐",
price: 37.5,
originalPrice: 37.5,
// card: "周卡",
duration: "7天",
},
],
},
{
id: "kylin",
name: "麒麟IP",
products: [
{
id: "13",
title: "测试卡",
price: 0.1,
card: "测试卡",
duration: "1小时",
},
{
id: "14",
title: "24小时套餐",
price: 37.5,
originalPrice: 37.5,
card: "24小时卡",
duration: "24小时",
},
{
id: "15",
title: "周卡套餐",
price: 37.5,
originalPrice: 37.5,
card: "周卡",
duration: "7天",
},
],
},
{
id: "cheetah",
name: "猎豹IP",
products: [
{
id: "16",
title: "月卡套餐",
price: 78,
tag: "8.5折",
originalPrice: 80.0,
card: "月卡",
duration: "30天",
},
{
id: "17",
title: "季卡套餐",
price: 208,
tag: "8.5折",
originalPrice: 220.0,
card: "季卡",
duration: "90天",
},
{
id: "18",
title: "年卡套餐",
price: 770,
tag: "8.5折",
originalPrice: 800.0,
card: "年卡",
duration: "365天",
},
],
},
{
id: "info",
name: "购买说明",
products: [],
},
],
},
{
id: "static",
label: "静态IP",
brands: [
{
id: "drip",
name: "水滴独享IP",
products: [
{
id: "19",
title: "纯住宅池",
price: 50,
desc: "分散式真实住宅IP",
// card: "住宅卡",
features: [
"带宽充足,IP段优质分布广",
"适合对IP要求高的业务",
"IP 3-7天周期性变化",
"线路切换每天20次",
],
},
{
id: "20",
title: "多拨池",
price: 60,
desc: "集中拨号住宅,带宽较高",
// card: "拨号卡",
features: [
"IP段较多,稳定性较高",
"IP 3-7天周期性变化",
"线路切换每天20次",
],
},
{
id: "21",
title: "固定池",
price: 70,
desc: "天翼云节点",
// card: "固定卡",
features: ["IP段多IP不变化,稳定性高", "线路切换每日限制为20次"],
},
],
},
],
},
{
id: "single",
label: "单窗口单IP",
brands: [],
},
]
export type ProductItem = {
Product: {
Id: number
Name: string
Image: string
Sort: number
Content: string
Profile: string
TenantId: number
OnLine: number
ContentLine: string[]
}
Packages: PackageItem[]
}
export type PackageItem = {
Id: number
TenantId: number
ProductId: number
PackageType: number
Name: string
Title: string
Image: string
Status: number
Profile: string
Price: number
LinePrice: number
DayPrice: number
MinPrice: number
DayCount: number
OriginKey: string
OriginName: string
IsTest: number
DeleteTag: number
}
function extractTier(name: string): string {
const match = name.match(/\((.+?)\)$/)
return match ? match[1] : "默认"
}
export function transformToTabs(data: ProductItem[]): Tab[] {
const activeProducts = data.filter(p => p.Product.OnLine === 1)
activeProducts.sort((a, b) => a.Product.Sort - b.Product.Sort)
console.log(
activeProducts,
"activeProductsactiveProductsactiveProductsactiveProducts",
)
const brands: Brand[] = activeProducts.map(item => {
const activePackages = item.Packages.filter(pkg => pkg.Status === 1)
const tierMap = new Map<string, PackageItem[]>()
for (const pkg of activePackages) {
const tier = extractTier(pkg.Name)
if (!tierMap.has(tier)) tierMap.set(tier, [])
tierMap.get(tier)?.push(pkg)
}
const tiers = Array.from(tierMap.entries())
const versions: Version[] | undefined =
tiers.length > 1
? tiers.map(([tier]) => ({ id: tier, label: tier }))
: undefined
const products: Product[] = []
for (const [tier, packages] of tiers) {
for (const pkg of packages) {
products.push({
id: pkg.Id.toString(),
productId: item.Product.Id,
title: pkg.Name,
price: pkg.Price,
originalPrice: pkg.LinePrice,
duration: pkg.Profile,
card: pkg.OriginName,
version: tier,
isTest: pkg.IsTest === 1,
})
}
}
return {
id: item.Product.Name,
name: item.Product.Name,
versions,
products,
}
})
brands.push({
id: "info",
name: "购买须知",
products: [],
})
return [
{
id: "dynamic",
label: "动态独享IP",
brands,
},
]
}