接口处理
This commit is contained in:
parent
c7bfc2729c
commit
346ad0a4ec
3
.env.dev
3
.env.dev
@ -1 +1,2 @@
|
|||||||
VITE_APP_BASE_URL=https://api.hifast.biz/v1
|
# https://api.hifast.biz
|
||||||
|
VITE_APP_BASE_URL=
|
||||||
|
|||||||
@ -1,31 +1,3 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { ref, computed } from 'vue'
|
|
||||||
import { Button } from '@/components/ui/button'
|
|
||||||
|
|
||||||
interface PaymentOption {
|
|
||||||
label: string
|
|
||||||
value: number | string
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
methods: any[]
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const list = computed(() =>
|
|
||||||
props.methods.map((item) => ({
|
|
||||||
label: item.name,
|
|
||||||
value: item.id,
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
|
|
||||||
// 当前选中的值,默认选中第一个
|
|
||||||
const selectedValue = ref<number | string>(props.methods[0]?.id || 1)
|
|
||||||
|
|
||||||
const handleSelect = (value: number | string) => {
|
|
||||||
selectedValue.value = value
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="bg-[#A8FF53] px-6 pt-7 font-sans text-black">
|
<div class="bg-[#A8FF53] px-6 pt-7 font-sans text-black">
|
||||||
@ -57,16 +29,18 @@ const handleSelect = (value: number | string) => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="px-6 pt-[55px]">
|
<div class="px-6 pt-[55px]">
|
||||||
<h2 class="mb-1 text-center text-2xl font-bold">订单信息</h2>
|
<h2 class="mb-1 text-center text-2xl font-bold">订单信息</h2>
|
||||||
<div class="ml-[11px] pt-[22px] text-[16px] font-semibold">365天套餐</div>
|
<div class="ml-[11px] pt-[22px] text-[16px] font-semibold">
|
||||||
|
{{ selectedPlan?.days }}天套餐
|
||||||
|
</div>
|
||||||
<div class="ml-[11px] flex items-center justify-between pt-[22px] text-[16px] font-semibold">
|
<div class="ml-[11px] flex items-center justify-between pt-[22px] text-[16px] font-semibold">
|
||||||
<div>订单金额</div>
|
<div>订单金额</div>
|
||||||
<div>USD 44.99</div>
|
<div>USD {{ selectedPlan?.price }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-6 pt-[85px] pb-[23px]">
|
<div class="px-6 pt-[85px] pb-[23px]">
|
||||||
<Button
|
<Button
|
||||||
@click="$emit('pay', selectedValue)"
|
@click="$emit('pay', selectedValue)"
|
||||||
class="h-[50px] w-full rounded-[32px] border-none bg-black text-[16px] font-black text-white hover:bg-black/90"
|
class="h-[50px] w-full rounded-[32px] border-none bg-black text-[16px] font-black text-white transition-all hover:bg-black/90 active:scale-[0.98]"
|
||||||
>
|
>
|
||||||
立即支付
|
立即支付
|
||||||
</Button>
|
</Button>
|
||||||
@ -74,6 +48,35 @@ const handleSelect = (value: number | string) => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
|
||||||
|
interface PaymentOption {
|
||||||
|
label: string
|
||||||
|
value: number | string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
methods: any[]
|
||||||
|
selectedPlan: any
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const list = computed(() =>
|
||||||
|
props.methods.map((item) => ({
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
|
||||||
|
// 当前选中的值,默认选中第一个
|
||||||
|
const selectedValue = ref<number | string>(props.methods[0]?.id || 1)
|
||||||
|
|
||||||
|
const handleSelect = (value: number | string) => {
|
||||||
|
selectedValue.value = value
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* 如果需要特殊的斜体感,可以在这里微调 */
|
/* 如果需要特殊的斜体感,可以在这里微调 */
|
||||||
span {
|
span {
|
||||||
|
|||||||
@ -5,7 +5,9 @@
|
|||||||
<img src="../avatar.png" class="size-[60px]" alt="" />
|
<img src="../avatar.png" class="size-[60px]" alt="" />
|
||||||
<div class="flex h-full flex-col justify-center text-white">
|
<div class="flex h-full flex-col justify-center text-white">
|
||||||
<div class="text-xl font-semibold">{{ userInfo.email }}</div>
|
<div class="text-xl font-semibold">{{ userInfo.email }}</div>
|
||||||
<div class="text-xs">到期时间: {{ userInfo.expireDate }}</div>
|
<div class="text-xs" :class="{ 'text-[#FF00B7]': expireDateInfo.highlight }">
|
||||||
|
{{ expireDateInfo.text }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -15,20 +17,25 @@
|
|||||||
<div class="overflow-hidden rounded-4xl bg-[#A8FF53]">
|
<div class="overflow-hidden rounded-4xl bg-[#A8FF53]">
|
||||||
<PlanCard :plans="plans" :currentPlanIndex="currentPlanIndex" @select="handlePlanSelect" />
|
<PlanCard :plans="plans" :currentPlanIndex="currentPlanIndex" @select="handlePlanSelect" />
|
||||||
<div class="pt-2">
|
<div class="pt-2">
|
||||||
<PaymentMethod :methods="payments" />
|
<PaymentMethod
|
||||||
|
:methods="payments"
|
||||||
|
:selectedPlan="selectedPlan"
|
||||||
|
@pay="(id: number | string) => $emit('pay', id)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pt-8 pb-[calc(50px+env(safe-area-inset-bottom))]">
|
<div class="px-6 pt-8 pb-[calc(50px+env(safe-area-inset-bottom))]">
|
||||||
<Button
|
<!-- <Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
class="mb-[10px] h-[50px] w-full rounded-[32px] border-2 border-[#FF00B7] bg-transparent text-xl font-bold text-[#FF00B7] transition-all hover:bg-[#FF00FF]/90 active:scale-[0.98]"
|
class="mb-[10px] h-[50px] w-full rounded-[32px] border-2 border-[#FF00B7] bg-transparent text-xl font-bold text-[#FF00B7] transition-all hover:bg-[#FF00FF]/90 active:scale-[0.98]"
|
||||||
>
|
>
|
||||||
注销账户
|
注销账户
|
||||||
</Button>
|
</Button>-->
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
|
@click="logout"
|
||||||
class="h-[50px] w-full rounded-[32px] border-2 border-white bg-transparent text-xl font-bold text-white transition-all hover:bg-white/90 active:scale-[0.98]"
|
class="h-[50px] w-full rounded-[32px] border-2 border-white bg-transparent text-xl font-bold text-white transition-all hover:bg-white/90 active:scale-[0.98]"
|
||||||
>
|
>
|
||||||
退出登录
|
退出登录
|
||||||
@ -38,28 +45,75 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { computed } from 'vue'
|
||||||
import PlanCard from '@/components/user-center/PlanCard.vue'
|
import PlanCard from '@/components/user-center/PlanCard.vue'
|
||||||
import DeviceList from '@/components/user-center/DeviceList.vue'
|
import DeviceList from '@/components/user-center/DeviceList.vue'
|
||||||
import PaymentMethod from '@/components/user-center/PaymentMethod.vue'
|
import PaymentMethod from '@/components/user-center/PaymentMethod.vue'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { toast } from 'vue-sonner'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
const router = useRouter()
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
devices: any[]
|
devices: any[]
|
||||||
plans: any[]
|
plans: any[]
|
||||||
payments: any[]
|
payments: any[]
|
||||||
userInfo: { email: string; expireDate: string }
|
alreadySubscribed: any[]
|
||||||
|
userInfo: { email: string }
|
||||||
|
selectedPlanId: string
|
||||||
|
selectedPlan: any
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
// --- State ---
|
const emit = defineEmits(['select-plan', 'pay'])
|
||||||
const selectedPlanId = ref('p2')
|
|
||||||
const selectedPayment = ref('alipay')
|
|
||||||
|
|
||||||
// --- Handlers ---
|
// --- Handlers ---
|
||||||
const handlePlanSelect = (id: string) => {
|
const handlePlanSelect = (id: string) => {
|
||||||
selectedPlanId.value = id
|
emit('select-plan', id)
|
||||||
|
}
|
||||||
|
const currentPlanIndex = computed(() => {
|
||||||
|
return props.plans.findIndex((p) => p.id === props.selectedPlanId)
|
||||||
|
})
|
||||||
|
|
||||||
|
const expireDateInfo = computed(() => {
|
||||||
|
const first = props.alreadySubscribed[0]
|
||||||
|
let text = ''
|
||||||
|
let highlight = false
|
||||||
|
|
||||||
|
if (!first || !first.expireDate) {
|
||||||
|
text = '尚未购买套餐'
|
||||||
|
highlight = true
|
||||||
|
} else {
|
||||||
|
// 尝试解析日期,兼容多种格式
|
||||||
|
const dateStr = first.expireDate.replace(/ /g, 'T')
|
||||||
|
const expireDateTime = new Date(dateStr)
|
||||||
|
|
||||||
|
if (isNaN(expireDateTime.getTime())) {
|
||||||
|
text = '套餐信息无效'
|
||||||
|
} else if (expireDateTime < new Date()) {
|
||||||
|
const year = expireDateTime.getFullYear()
|
||||||
|
const month = String(expireDateTime.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(expireDateTime.getDate()).padStart(2, '0')
|
||||||
|
text = `已于 ${year}/${month}/${day} 到期`
|
||||||
|
highlight = true
|
||||||
|
} else {
|
||||||
|
const year = expireDateTime.getFullYear()
|
||||||
|
const month = String(expireDateTime.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(expireDateTime.getDate()).padStart(2, '0')
|
||||||
|
const hour = String(expireDateTime.getHours()).padStart(2, '0')
|
||||||
|
const minute = String(expireDateTime.getMinutes()).padStart(2, '0')
|
||||||
|
const second = String(expireDateTime.getSeconds()).padStart(2, '0')
|
||||||
|
text = `到期时间:${year}/${month}/${day} ${hour}:${minute}:${second}`
|
||||||
|
highlight = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { text, highlight }
|
||||||
|
})
|
||||||
|
|
||||||
|
function logout() {
|
||||||
|
router.push('/')
|
||||||
|
localStorage.removeItem('Authorization')
|
||||||
|
toast.success('退出成功')
|
||||||
}
|
}
|
||||||
const currentPlanIndex = ref(3)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -21,17 +21,22 @@
|
|||||||
<!-- Main Neon Green Card -->
|
<!-- Main Neon Green Card -->
|
||||||
<div class="px-[18px]">
|
<div class="px-[18px]">
|
||||||
<MobileLayout
|
<MobileLayout
|
||||||
|
:already-subscribed="alreadySubscribed"
|
||||||
:devices="devices"
|
:devices="devices"
|
||||||
:plans="plans"
|
:plans="plans"
|
||||||
:payments="payments"
|
:payments="payments"
|
||||||
:user-info="userSubInfo"
|
:user-info="userSubInfo"
|
||||||
|
:selected-plan-id="selectedPlanId"
|
||||||
|
:selected-plan="activePlan"
|
||||||
|
@select-plan="handlePlanSelect"
|
||||||
|
@pay="handlePay"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import MobileLayout from './MobileLayout/index.vue'
|
import MobileLayout from './MobileLayout/index.vue'
|
||||||
import Logo from '@/pages/Home/logo.svg?component'
|
import Logo from '@/pages/Home/logo.svg?component'
|
||||||
import MobileLogo from '@/pages/Home/mobile-logo.svg?component'
|
import MobileLogo from '@/pages/Home/mobile-logo.svg?component'
|
||||||
@ -39,51 +44,125 @@ import request from '@/utils/request'
|
|||||||
|
|
||||||
// --- State ---
|
// --- State ---
|
||||||
const selectedPlanId = ref('p2')
|
const selectedPlanId = ref('p2')
|
||||||
const selectedPayment = ref('alipay')
|
const selectedPayment = ref('alipay') // This variable is no longer directly used for payment selection in the UI, but kept for potential future use or if other parts of the app rely on it.
|
||||||
|
|
||||||
const devices = ref([])
|
const devices = ref<any[]>([])
|
||||||
const plans = ref([])
|
const plans = ref<any[]>([])
|
||||||
const payments = ref([])
|
const payments = ref<any[]>([])
|
||||||
|
const alreadySubscribed = ref<any[]>([])
|
||||||
const userSubInfo = ref({
|
const userSubInfo = ref({
|
||||||
email: '',
|
email: '',
|
||||||
expireDate: '',
|
expireDate: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// --- Data Mapping ---
|
||||||
|
const mapPlans = (apiList: any[]) => {
|
||||||
|
const flattened: any[] = []
|
||||||
|
let globalIndex = 0
|
||||||
|
apiList.forEach((item: any) => {
|
||||||
|
const unitDays = item.unit_time === 'Day' ? 1 : 365
|
||||||
|
if (!item.discount || item.discount.length === 0) {
|
||||||
|
flattened.push({
|
||||||
|
id: item.id.toString(),
|
||||||
|
planId: item.id,
|
||||||
|
quantity: 1,
|
||||||
|
days: unitDays,
|
||||||
|
price: (item.unit_price / 100).toFixed(2),
|
||||||
|
daily: (item.unit_price / 100 / unitDays).toFixed(2),
|
||||||
|
discount: '',
|
||||||
|
})
|
||||||
|
globalIndex++
|
||||||
|
} else {
|
||||||
|
item.discount.forEach((opt: any) => {
|
||||||
|
const totalDays = opt.quantity * unitDays
|
||||||
|
const ratioToPay = opt.discount === 0 || opt.discount === undefined ? 100 : opt.discount
|
||||||
|
const totalPrice = (item.unit_price / 100) * opt.quantity * (ratioToPay / 100)
|
||||||
|
|
||||||
|
flattened.push({
|
||||||
|
id: `${item.id}-${opt.quantity}`,
|
||||||
|
planId: item.id,
|
||||||
|
quantity: opt.quantity,
|
||||||
|
days: totalDays,
|
||||||
|
price: totalPrice.toFixed(2),
|
||||||
|
daily: (totalPrice / totalDays).toFixed(2),
|
||||||
|
discount:
|
||||||
|
globalIndex > 0 && ratioToPay < 100 ? `${Math.ceil(100 - ratioToPay)}% off` : '',
|
||||||
|
})
|
||||||
|
globalIndex++
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return flattened
|
||||||
|
}
|
||||||
|
|
||||||
// --- Handlers ---
|
// --- Handlers ---
|
||||||
|
const activePlan = computed(() => {
|
||||||
|
return plans.value.find((p) => p.id === selectedPlanId.value)
|
||||||
|
})
|
||||||
|
|
||||||
const handlePlanSelect = (id: string) => {
|
const handlePlanSelect = (id: string) => {
|
||||||
selectedPlanId.value = id
|
selectedPlanId.value = id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handlePay = (methodId: number | string) => {
|
||||||
|
const plan = plans.value.find((p) => p.id === selectedPlanId.value)
|
||||||
|
if (!plan) return
|
||||||
|
|
||||||
|
const already = alreadySubscribed.value.find((s: any) => s.subscribe_id === plan.planId)
|
||||||
|
const isRenewal = !!already
|
||||||
|
const api = isRenewal ? '/api/v1//public/order/renewal' : '/api/v1/public/order/purchase'
|
||||||
|
const params: any = {
|
||||||
|
subscribe_id: plan.planId,
|
||||||
|
quantity: plan.quantity,
|
||||||
|
payment: methodId,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRenewal) {
|
||||||
|
params.user_subscribe_id = already.id
|
||||||
|
}
|
||||||
|
console.log(params)
|
||||||
|
request.post(api, params).then((res: any) => {
|
||||||
|
request
|
||||||
|
.post('/api/v1/public/portal/order/checkout', {
|
||||||
|
orderNo: res.order_no,
|
||||||
|
returnUrl: window.location.origin,
|
||||||
|
})
|
||||||
|
.then((checkoutRes: any) => {
|
||||||
|
if (checkoutRes.type === 'url' && checkoutRes.checkout_url) {
|
||||||
|
window.location.href = checkoutRes.checkout_url
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
// 设备列表
|
// 用户信息 & 设备列表
|
||||||
// request.get('/public/user/devices').then((res: any) => {
|
request.get('/api/v1/public/user/info').then((res: any) => {
|
||||||
// devices.value =
|
|
||||||
// res.list?.map((item: any) => ({
|
|
||||||
// id: item.id,
|
|
||||||
// name: item.user_agent || 'Unknown Device',
|
|
||||||
// type: item.user_agent?.toLowerCase().includes('android') ? 'mobile' : 'desktop',
|
|
||||||
// deviceId: item.id,
|
|
||||||
// })) || []
|
|
||||||
// })
|
|
||||||
|
|
||||||
// 用户信息
|
|
||||||
request.get('/public/user/info').then((res: any) => {
|
|
||||||
const emailInfo = res.auth_methods?.find((item: any) => item.auth_type === 'email')
|
|
||||||
devices.value = res.user_devices
|
devices.value = res.user_devices
|
||||||
console.log(res.user_devices)
|
|
||||||
|
|
||||||
|
const emailInfo = res.auth_methods?.find((item: any) => item.auth_type === 'email')
|
||||||
if (emailInfo) {
|
if (emailInfo) {
|
||||||
userSubInfo.value.email = emailInfo.auth_identifier
|
userSubInfo.value.email = emailInfo.auth_identifier
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// 订阅详情
|
|
||||||
request.get('/public/subscribe/list').then((res: any) => {
|
// 已订阅列表
|
||||||
plans.value = res.list
|
request.get('/api/v1/public/user/subscribe').then((res: any) => {
|
||||||
console.log(plans.value)
|
alreadySubscribed.value = res.list || []
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 订阅套餐列表
|
||||||
|
request.get('/api/v1/public/subscribe/list').then((res: any) => {
|
||||||
|
plans.value = mapPlans(res.list || [])
|
||||||
|
if (plans.value.length > 0) {
|
||||||
|
selectedPlanId.value = plans.value[0].id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 获取支付方式
|
// 获取支付方式
|
||||||
request.get('/public/payment/methods').then((res: any) => {
|
request.get('/api/v1/public/payment/methods').then((res: any) => {
|
||||||
payments.value = res.list || []
|
console.log(res)
|
||||||
|
payments.value = res.list?.filter((p: any) => p.platform !== 'apple_iap') || []
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
init()
|
init()
|
||||||
|
|||||||
@ -37,7 +37,9 @@ export class HiAesUtil {
|
|||||||
*/
|
*/
|
||||||
static encryptData(plainText, keyStr) {
|
static encryptData(plainText, keyStr) {
|
||||||
// 生成 ISO8601 时间戳 (与 Dart DateTime.now().toIso8601String() 对应)
|
// 生成 ISO8601 时间戳 (与 Dart DateTime.now().toIso8601String() 对应)
|
||||||
const nonce = new Date().toISOString()
|
// Dart: 2025-12-30T21:05:06.075850 (no Z, 6 decimal places)
|
||||||
|
const now = new Date()
|
||||||
|
const nonce = now.toISOString().replace('Z', '') + '000'
|
||||||
|
|
||||||
const key = this._generateKey(keyStr)
|
const key = this._generateKey(keyStr)
|
||||||
const iv = this._generateIv(nonce, keyStr)
|
const iv = this._generateIv(nonce, keyStr)
|
||||||
|
|||||||
@ -97,13 +97,34 @@ export default class Request {
|
|||||||
config.data = HiAesUtil.encryptData(plainText, encryptionKey)
|
config.data = HiAesUtil.encryptData(plainText, encryptionKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.method?.toLowerCase() === 'get' || config.params) {
|
||||||
|
const paramsToEncrypt = config.params || {} // 为空则加密 "{}"
|
||||||
|
const plainParamsText = JSON.stringify(paramsToEncrypt)
|
||||||
|
const encryptedParams = HiAesUtil.encryptData(plainParamsText, encryptionKey)
|
||||||
|
|
||||||
|
// 将原参数替换为加密后的 data 和 time 字段
|
||||||
|
config.params = {
|
||||||
|
data: encryptedParams.data,
|
||||||
|
time: encryptedParams.time,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.data?.time) {
|
||||||
|
console.log(
|
||||||
|
'解密',
|
||||||
|
HiAesUtil.decryptData(config.data.data, config.data.time, encryptionKey),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
config.headers = mergeExtraConfig.formatHeader({
|
config.headers = mergeExtraConfig.formatHeader({
|
||||||
...this.config.headers,
|
...this.config.headers,
|
||||||
...config.headers,
|
...config.headers,
|
||||||
|
lang: 'zh_CN',
|
||||||
|
'login-type': 'device',
|
||||||
...(mergeExtraConfig.withToken && {
|
...(mergeExtraConfig.withToken && {
|
||||||
[mergeExtraConfig.tokenKey]: mergeExtraConfig.getToken(),
|
[mergeExtraConfig.tokenKey]: mergeExtraConfig.getToken(),
|
||||||
}),
|
}),
|
||||||
})
|
} as any)
|
||||||
config.extraConfig = mergeExtraConfig
|
config.extraConfig = mergeExtraConfig
|
||||||
if (mergeExtraConfig.cancelRepetition) {
|
if (mergeExtraConfig.cancelRepetition) {
|
||||||
axiosCanceler.addPending(config)
|
axiosCanceler.addPending(config)
|
||||||
|
|||||||
@ -14,4 +14,23 @@ export default defineConfig({
|
|||||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
// 将所有以 /api 开头的请求转发到目标服务器
|
||||||
|
// 1. 匹配所有以 /public 开头的请求
|
||||||
|
'/api/v1': {
|
||||||
|
target: 'https://api.hifast.biz',
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||||
|
autoRewrite: true,
|
||||||
|
// 3. 关键:将路径重写,在前面补上 /api/v1
|
||||||
|
// 验证请求是否进入代理,可以在终端看到打印
|
||||||
|
configure: (proxy, _options) => {
|
||||||
|
proxy.on('proxyReq', (proxyReq, req, _res) => {
|
||||||
|
console.log('代理请求:', req.method, req.url, ' -> ', proxyReq.path)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user