更新登录功能
This commit is contained in:
@@ -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 }
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user