133 lines
3.9 KiB
Vue
133 lines
3.9 KiB
Vue
<script setup lang="ts">
|
||
import { ElMessage } from "element-plus";
|
||
import { onMounted, ref } from "vue";
|
||
import { useRoute, useRouter } from "vue-router";
|
||
|
||
import { fetchListing, type Listing } from "@/api/listings";
|
||
import { createOrder } from "@/api/orders";
|
||
|
||
const route = useRoute();
|
||
const router = useRouter();
|
||
const loading = ref(false);
|
||
const ordering = ref(false);
|
||
const rentHours = ref(1);
|
||
const listing = ref<Listing | null>(null);
|
||
|
||
onMounted(async () => {
|
||
loading.value = true;
|
||
try {
|
||
listing.value = await fetchListing(String(route.params.id));
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
});
|
||
|
||
async function handleCreateOrder() {
|
||
if (!listing.value) return;
|
||
ordering.value = true;
|
||
try {
|
||
const order = await createOrder(listing.value.id, rentHours.value);
|
||
ElMessage.success("订单已创建,账号已锁定");
|
||
await router.push(`/orders/${order.id}`);
|
||
} catch (error) {
|
||
ElMessage.error(readError(error, "下单失败"));
|
||
} finally {
|
||
ordering.value = false;
|
||
}
|
||
}
|
||
|
||
function readError(error: unknown, fallback: string) {
|
||
if (typeof error === "object" && error && "response" in error) {
|
||
const response = (error as { response?: { data?: { message?: string } } })
|
||
.response;
|
||
return response?.data?.message || fallback;
|
||
}
|
||
return fallback;
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<section class="pc-detail page" v-loading="loading">
|
||
<div class="anti-fraud-strip compact">
|
||
<span
|
||
>防骗提示:下单后请按平台交接流程确认收号与归还,不要私下交易。</span
|
||
>
|
||
</div>
|
||
|
||
<div v-if="listing" class="pc-detail-layout">
|
||
<section class="pc-detail-main">
|
||
<div class="detail-cover">
|
||
<img
|
||
v-if="listing.screenshot_urls?.[0]"
|
||
:src="listing.screenshot_urls[0]"
|
||
:alt="listing.title"
|
||
/>
|
||
<span v-else>HFB ACCOUNT</span>
|
||
</div>
|
||
<div class="page-header detail-title">
|
||
<p class="eyebrow">
|
||
{{ listing.server_region }} / {{ listing.login_platform }}
|
||
</p>
|
||
<h1>{{ listing.title }}</h1>
|
||
<p>{{ listing.description || "号主暂未填写详细说明。" }}</p>
|
||
</div>
|
||
|
||
<div class="detail-grid">
|
||
<div class="metric-card">
|
||
<span>哈夫币</span>
|
||
<strong>{{ listing.haf_coin_amount }}</strong>
|
||
</div>
|
||
<div class="metric-card">
|
||
<span>时租</span>
|
||
<strong>¥{{ listing.price_hourly }}</strong>
|
||
</div>
|
||
<div class="metric-card">
|
||
<span>日租</span>
|
||
<strong>¥{{ listing.price_daily }}</strong>
|
||
</div>
|
||
<div class="metric-card">
|
||
<span>押金</span>
|
||
<strong>¥{{ listing.deposit_amount }}</strong>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<aside class="order-panel pc-order-card">
|
||
<h2>立即租用</h2>
|
||
<p class="order-safe-text">
|
||
平台托管订单与押金,租期 {{ listing.min_rent_hours }}-{{
|
||
listing.max_rent_hours
|
||
}}
|
||
小时。
|
||
</p>
|
||
<el-form label-position="top">
|
||
<el-form-item label="租用时长">
|
||
<el-input-number
|
||
v-model="rentHours"
|
||
:min="listing.min_rent_hours"
|
||
:max="listing.max_rent_hours"
|
||
class="full-control"
|
||
/>
|
||
</el-form-item>
|
||
<div class="order-total-box">
|
||
<span>预计租金</span>
|
||
<strong
|
||
>¥{{ (listing.price_hourly * rentHours).toFixed(2) }}</strong
|
||
>
|
||
<em>押金 ¥{{ listing.deposit_amount }}</em>
|
||
</div>
|
||
<el-button
|
||
type="warning"
|
||
size="large"
|
||
:loading="ordering"
|
||
class="full-control"
|
||
@click="handleCreateOrder"
|
||
>
|
||
立即下单并锁定账号
|
||
</el-button>
|
||
</el-form>
|
||
</aside>
|
||
</div>
|
||
</section>
|
||
</template>
|