增加前端格式检查配置
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { computed, nextTick, onMounted, ref, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import { fetchListing, type Listing } from "@/features/listings/api/listings";
|
||||
import { createOrder, fetchOrderAgreements, type OrderAgreements } from "@/features/orders/api/orders";
|
||||
import { useSessionStore } from "@/stores/session";
|
||||
import { roundMoney, formatMoney } from "@/shared/utils/money";
|
||||
import { fetchListing, type Listing } from '@/features/listings/api/listings'
|
||||
import {
|
||||
createOrder,
|
||||
fetchOrderAgreements,
|
||||
type OrderAgreements,
|
||||
} from '@/features/orders/api/orders'
|
||||
import { useSessionStore } from '@/stores/session'
|
||||
import { roundMoney, formatMoney } from '@/shared/utils/money'
|
||||
import {
|
||||
assetRegions,
|
||||
formatEstimatedRentalDuration,
|
||||
@@ -26,45 +30,45 @@ import {
|
||||
getServerRegion,
|
||||
readAssetNumber,
|
||||
readAssetString,
|
||||
} from "@/utils/listingDisplay";
|
||||
} from '@/utils/listingDisplay'
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const session = useSessionStore();
|
||||
const loading = ref(false);
|
||||
const ordering = ref(false);
|
||||
const agreementsLoading = ref(false);
|
||||
const agreementVisible = ref(false);
|
||||
const agreements = ref<OrderAgreements | null>(null);
|
||||
const virtualAgreementRead = ref(false);
|
||||
const renterAgreementRead = ref(false);
|
||||
const virtualAgreementChecked = ref(false);
|
||||
const renterAgreementChecked = ref(false);
|
||||
const virtualAgreementRef = ref<HTMLElement | null>(null);
|
||||
const renterAgreementRef = ref<HTMLElement | null>(null);
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const session = useSessionStore()
|
||||
const loading = ref(false)
|
||||
const ordering = ref(false)
|
||||
const agreementsLoading = ref(false)
|
||||
const agreementVisible = ref(false)
|
||||
const agreements = ref<OrderAgreements | null>(null)
|
||||
const virtualAgreementRead = ref(false)
|
||||
const renterAgreementRead = ref(false)
|
||||
const virtualAgreementChecked = ref(false)
|
||||
const renterAgreementChecked = ref(false)
|
||||
const virtualAgreementRef = ref<HTMLElement | null>(null)
|
||||
const renterAgreementRef = ref<HTMLElement | null>(null)
|
||||
|
||||
const canCreateOrderAfterAgreement = computed(
|
||||
() =>
|
||||
virtualAgreementRead.value &&
|
||||
renterAgreementRead.value &&
|
||||
virtualAgreementChecked.value &&
|
||||
renterAgreementChecked.value,
|
||||
);
|
||||
const listing = ref<Listing | null>(null);
|
||||
renterAgreementChecked.value
|
||||
)
|
||||
const listing = ref<Listing | null>(null)
|
||||
|
||||
onMounted(async () => {
|
||||
loading.value = true;
|
||||
loading.value = true
|
||||
try {
|
||||
listing.value = await fetchListing(String(route.params.id));
|
||||
listing.value = await fetchListing(String(route.params.id))
|
||||
} finally {
|
||||
loading.value = false;
|
||||
loading.value = false
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
const orderTotal = computed(() => {
|
||||
if (!listing.value) return "0";
|
||||
return formatMoney(getListingDisplayPrice(listing.value));
|
||||
});
|
||||
if (!listing.value) return '0'
|
||||
return formatMoney(getListingDisplayPrice(listing.value))
|
||||
})
|
||||
|
||||
const orderPriceBreakdown = computed(() => {
|
||||
if (!listing.value) {
|
||||
@@ -72,260 +76,253 @@ const orderPriceBreakdown = computed(() => {
|
||||
rent: 0,
|
||||
consumable: 0,
|
||||
total: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
rent: getListingRentPrice(listing.value),
|
||||
consumable: getListingConsumablePrice(listing.value),
|
||||
total: roundMoney(getListingDisplayPrice(listing.value)),
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
const coverURL = computed(() => {
|
||||
if (!listing.value) return "";
|
||||
return listing.value.cover_url || listing.value.screenshot_urls?.[0] || "";
|
||||
});
|
||||
if (!listing.value) return ''
|
||||
return listing.value.cover_url || listing.value.screenshot_urls?.[0] || ''
|
||||
})
|
||||
|
||||
const detailMetrics = computed(() => {
|
||||
if (!listing.value) return [];
|
||||
const dailyLoss = getDailyLoss(listing.value);
|
||||
if (!listing.value) return []
|
||||
const dailyLoss = getDailyLoss(listing.value)
|
||||
return [
|
||||
{ label: "纯币", value: formatHafCoinM(getCoinWan(listing.value)), tone: "coin" },
|
||||
{ label: '纯币', value: formatHafCoinM(getCoinWan(listing.value)), tone: 'coin' },
|
||||
{
|
||||
label: "日损耗",
|
||||
value: dailyLoss ? `${dailyLoss}/天` : "--",
|
||||
tone: "coin",
|
||||
label: '日损耗',
|
||||
value: dailyLoss ? `${dailyLoss}/天` : '--',
|
||||
tone: 'coin',
|
||||
},
|
||||
{ label: "价格", value: `¥${orderTotal.value}`, tone: "price" },
|
||||
{ label: "押金", value: `¥${listing.value.deposit_amount}`, tone: "" },
|
||||
];
|
||||
});
|
||||
{ label: '价格', value: `¥${orderTotal.value}`, tone: 'price' },
|
||||
{ label: '押金', value: `¥${listing.value.deposit_amount}`, tone: '' },
|
||||
]
|
||||
})
|
||||
|
||||
const detailScreenshots = computed(() => {
|
||||
if (!listing.value) return [];
|
||||
const groupedScreenshots = readGroupedScreenshots(listing.value);
|
||||
if (groupedScreenshots.length) return groupedScreenshots;
|
||||
const labels = ["纯币截图", "游戏ID截图", "总资产截图", "腾讯安全中心截图", "皮肤截图"];
|
||||
if (!listing.value) return []
|
||||
const groupedScreenshots = readGroupedScreenshots(listing.value)
|
||||
if (groupedScreenshots.length) return groupedScreenshots
|
||||
const labels = ['纯币截图', '游戏ID截图', '总资产截图', '腾讯安全中心截图', '皮肤截图']
|
||||
return (listing.value.screenshot_urls || []).map((url, index) => ({
|
||||
label: labels[index] || `账号截图${index + 1}`,
|
||||
url,
|
||||
}));
|
||||
});
|
||||
}))
|
||||
})
|
||||
|
||||
function readGroupedScreenshots(item: Listing) {
|
||||
const groups = item.asset_summary?.screenshot_groups;
|
||||
if (typeof groups !== "object" || groups === null) return [];
|
||||
const groups = item.asset_summary?.screenshot_groups
|
||||
if (typeof groups !== 'object' || groups === null) return []
|
||||
const slots = [
|
||||
{ key: "coin", label: "纯币截图" },
|
||||
{ key: "gameId", label: "游戏ID截图" },
|
||||
{ key: "totalAsset", label: "总资产截图" },
|
||||
{ key: "tencentSecurity", label: "腾讯安全中心截图" },
|
||||
{ key: "skin", label: "皮肤截图" },
|
||||
];
|
||||
return slots.flatMap((slot) => {
|
||||
const urls = (groups as Record<string, unknown>)[slot.key];
|
||||
if (!Array.isArray(urls)) return [];
|
||||
const validUrls = urls.filter((url): url is string => typeof url === "string" && Boolean(url));
|
||||
{ key: 'coin', label: '纯币截图' },
|
||||
{ key: 'gameId', label: '游戏ID截图' },
|
||||
{ key: 'totalAsset', label: '总资产截图' },
|
||||
{ key: 'tencentSecurity', label: '腾讯安全中心截图' },
|
||||
{ key: 'skin', label: '皮肤截图' },
|
||||
]
|
||||
return slots.flatMap(slot => {
|
||||
const urls = (groups as Record<string, unknown>)[slot.key]
|
||||
if (!Array.isArray(urls)) return []
|
||||
const validUrls = urls.filter((url): url is string => typeof url === 'string' && Boolean(url))
|
||||
return validUrls.map((url, index) => ({
|
||||
label: validUrls.length > 1 ? `${slot.label}${index + 1}` : slot.label,
|
||||
url,
|
||||
}));
|
||||
});
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
const detailSkinGroups = computed(() => {
|
||||
if (!listing.value) return [];
|
||||
const groups = listing.value.asset_summary?.skin_groups;
|
||||
if (typeof groups !== "object" || groups === null) return [];
|
||||
if (!listing.value) return []
|
||||
const groups = listing.value.asset_summary?.skin_groups
|
||||
if (typeof groups !== 'object' || groups === null) return []
|
||||
const titles: Record<string, string> = {
|
||||
melee: "近战皮肤",
|
||||
operator: "干员皮肤",
|
||||
operatorGold: "干员金皮",
|
||||
operatorRed: "干员红皮",
|
||||
weapon: "武器皮肤",
|
||||
};
|
||||
melee: '近战皮肤',
|
||||
operator: '干员皮肤',
|
||||
operatorGold: '干员金皮',
|
||||
operatorRed: '干员红皮',
|
||||
weapon: '武器皮肤',
|
||||
}
|
||||
return Object.entries(groups as Record<string, unknown>)
|
||||
.map(([key, value]) => ({
|
||||
key,
|
||||
title: titles[key] || key,
|
||||
options: Array.isArray(value)
|
||||
? value.filter((skin): skin is string => typeof skin === "string")
|
||||
? value.filter((skin): skin is string => typeof skin === 'string')
|
||||
: [],
|
||||
}))
|
||||
.filter((group) => group.options.length);
|
||||
});
|
||||
.filter(group => group.options.length)
|
||||
})
|
||||
|
||||
const accountRows = computed(() => {
|
||||
if (!listing.value) return [];
|
||||
const regions = assetRegions(listing.value);
|
||||
if (!listing.value) return []
|
||||
const regions = assetRegions(listing.value)
|
||||
return [
|
||||
{ label: "所属区服", value: getServerRegion(listing.value) || "--" },
|
||||
{ label: "上号方式", value: getLoginMethod(listing.value) || "--" },
|
||||
{ label: "游戏段位", value: listing.value.rank_level || "--" },
|
||||
{ label: "M单价", value: formatRatio(listing.value) },
|
||||
{ label: "方便上号", value: getOnlineTimeText(listing.value) || "--" },
|
||||
{ label: "预计可租", value: formatEstimatedRentalDuration(listing.value) },
|
||||
{ label: "常用登录地", value: regions.length ? regions.join("、") : "--" },
|
||||
{ label: "封禁记录", value: readAssetString(listing.value, "ban_record") || "无" },
|
||||
];
|
||||
});
|
||||
{ label: '所属区服', value: getServerRegion(listing.value) || '--' },
|
||||
{ label: '上号方式', value: getLoginMethod(listing.value) || '--' },
|
||||
{ label: '游戏段位', value: listing.value.rank_level || '--' },
|
||||
{ label: 'M单价', value: formatRatio(listing.value) },
|
||||
{ label: '方便上号', value: getOnlineTimeText(listing.value) || '--' },
|
||||
{ label: '预计可租', value: formatEstimatedRentalDuration(listing.value) },
|
||||
{ label: '常用登录地', value: regions.length ? regions.join('、') : '--' },
|
||||
{ label: '封禁记录', value: readAssetString(listing.value, 'ban_record') || '无' },
|
||||
]
|
||||
})
|
||||
|
||||
async function handleCreateOrder() {
|
||||
if (!listing.value) return;
|
||||
if (!listing.value) return
|
||||
if (!session.token) {
|
||||
await router.push({ path: "/login", query: { redirect: route.fullPath } });
|
||||
return;
|
||||
await router.push({ path: '/login', query: { redirect: route.fullPath } })
|
||||
return
|
||||
}
|
||||
|
||||
if (session.realnameStatus !== "verified") {
|
||||
if (session.realnameStatus !== 'verified') {
|
||||
try {
|
||||
await session.loadMe();
|
||||
await session.loadMe()
|
||||
} catch {
|
||||
// 登录态失效时由全局请求拦截处理。
|
||||
}
|
||||
}
|
||||
|
||||
if (session.realnameStatus !== "verified") {
|
||||
if (session.realnameStatus !== 'verified') {
|
||||
try {
|
||||
await ElMessageBox.confirm("租号下单前需要完成实名认证。", "请先实名认证", {
|
||||
confirmButtonText: "去认证",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
});
|
||||
await router.push({ path: "/realname", query: { redirect: route.fullPath } });
|
||||
await ElMessageBox.confirm('租号下单前需要完成实名认证。', '请先实名认证', {
|
||||
confirmButtonText: '去认证',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
await router.push({ path: '/realname', query: { redirect: route.fullPath } })
|
||||
} catch {
|
||||
// 用户取消认证时停留在当前页面。
|
||||
}
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
await openAgreementBeforeOrder();
|
||||
await openAgreementBeforeOrder()
|
||||
}
|
||||
|
||||
async function openAgreementBeforeOrder() {
|
||||
agreementsLoading.value = true;
|
||||
agreementsLoading.value = true
|
||||
try {
|
||||
agreements.value = await fetchOrderAgreements();
|
||||
virtualAgreementRead.value = false;
|
||||
renterAgreementRead.value = false;
|
||||
virtualAgreementChecked.value = false;
|
||||
renterAgreementChecked.value = false;
|
||||
agreementVisible.value = true;
|
||||
await nextTick();
|
||||
updateAgreementReadState("virtual");
|
||||
updateAgreementReadState("renter");
|
||||
agreements.value = await fetchOrderAgreements()
|
||||
virtualAgreementRead.value = false
|
||||
renterAgreementRead.value = false
|
||||
virtualAgreementChecked.value = false
|
||||
renterAgreementChecked.value = false
|
||||
agreementVisible.value = true
|
||||
await nextTick()
|
||||
updateAgreementReadState('virtual')
|
||||
updateAgreementReadState('renter')
|
||||
} catch (error) {
|
||||
ElMessage.error(readError(error, "协议加载失败"));
|
||||
ElMessage.error(readError(error, '协议加载失败'))
|
||||
} finally {
|
||||
agreementsLoading.value = false;
|
||||
agreementsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleConfirmAgreementAndCreateOrder() {
|
||||
if (!canCreateOrderAfterAgreement.value) {
|
||||
ElMessage.warning("请先阅读并勾选两份协议");
|
||||
return;
|
||||
ElMessage.warning('请先阅读并勾选两份协议')
|
||||
return
|
||||
}
|
||||
agreementVisible.value = false;
|
||||
await submitOrder();
|
||||
agreementVisible.value = false
|
||||
await submitOrder()
|
||||
}
|
||||
|
||||
async function submitOrder() {
|
||||
if (!listing.value) return;
|
||||
ordering.value = true;
|
||||
if (!listing.value) return
|
||||
ordering.value = true
|
||||
try {
|
||||
const order = await createOrder(listing.value.id);
|
||||
ElMessage.success("订单已创建,请完成支付");
|
||||
await router.push(`/orders/${order.id}`);
|
||||
const order = await createOrder(listing.value.id)
|
||||
ElMessage.success('订单已创建,请完成支付')
|
||||
await router.push(`/orders/${order.id}`)
|
||||
} catch (error) {
|
||||
ElMessage.error(readError(error, "下单失败"));
|
||||
ElMessage.error(readError(error, '下单失败'))
|
||||
} finally {
|
||||
ordering.value = false;
|
||||
ordering.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleAgreementScroll(type: "virtual" | "renter") {
|
||||
updateAgreementReadState(type);
|
||||
function handleAgreementScroll(type: 'virtual' | 'renter') {
|
||||
updateAgreementReadState(type)
|
||||
}
|
||||
|
||||
function updateAgreementReadState(type: "virtual" | "renter") {
|
||||
const el = type === "virtual" ? virtualAgreementRef.value : renterAgreementRef.value;
|
||||
if (!el) return;
|
||||
const read = el.scrollTop + el.clientHeight >= el.scrollHeight - 8;
|
||||
if (type === "virtual") {
|
||||
virtualAgreementRead.value = read;
|
||||
function updateAgreementReadState(type: 'virtual' | 'renter') {
|
||||
const el = type === 'virtual' ? virtualAgreementRef.value : renterAgreementRef.value
|
||||
if (!el) return
|
||||
const read = el.scrollTop + el.clientHeight >= el.scrollHeight - 8
|
||||
if (type === 'virtual') {
|
||||
virtualAgreementRead.value = read
|
||||
} else {
|
||||
renterAgreementRead.value = read;
|
||||
renterAgreementRead.value = read
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
if (typeof error === 'object' && error && 'response' in error) {
|
||||
const response = (error as { response?: { data?: { message?: string } } }).response
|
||||
return response?.data?.message || fallback
|
||||
}
|
||||
return fallback;
|
||||
return fallback
|
||||
}
|
||||
|
||||
// 手动锁定/解锁背景滚动
|
||||
watch(agreementVisible, (visible) => {
|
||||
watch(agreementVisible, visible => {
|
||||
// 只锁定 .pc-main 容器,不影响 body 和 sticky 导航栏
|
||||
const pcMain = document.querySelector('.pc-main') as HTMLElement;
|
||||
if (!pcMain) return;
|
||||
const pcMain = document.querySelector('.pc-main') as HTMLElement
|
||||
if (!pcMain) return
|
||||
|
||||
if (visible) {
|
||||
// 保存当前滚动位置
|
||||
const scrollTop = pcMain.scrollTop || 0;
|
||||
const scrollTop = pcMain.scrollTop || 0
|
||||
|
||||
// 锁定主容器滚动
|
||||
pcMain.style.overflow = 'hidden';
|
||||
pcMain.style.position = 'fixed';
|
||||
pcMain.style.top = `-${scrollTop}px`;
|
||||
pcMain.style.left = '0';
|
||||
pcMain.style.right = '0';
|
||||
pcMain.style.width = '100%';
|
||||
pcMain.style.overflow = 'hidden'
|
||||
pcMain.style.position = 'fixed'
|
||||
pcMain.style.top = `-${scrollTop}px`
|
||||
pcMain.style.left = '0'
|
||||
pcMain.style.right = '0'
|
||||
pcMain.style.width = '100%'
|
||||
|
||||
// 保存滚动位置供恢复使用
|
||||
pcMain.dataset.scrollTop = String(scrollTop);
|
||||
pcMain.dataset.scrollTop = String(scrollTop)
|
||||
} else {
|
||||
// 恢复主容器滚动
|
||||
const scrollTop = parseInt(pcMain.dataset.scrollTop || '0', 10);
|
||||
const scrollTop = parseInt(pcMain.dataset.scrollTop || '0', 10)
|
||||
|
||||
pcMain.style.overflow = '';
|
||||
pcMain.style.position = '';
|
||||
pcMain.style.top = '';
|
||||
pcMain.style.left = '';
|
||||
pcMain.style.right = '';
|
||||
pcMain.style.width = '';
|
||||
pcMain.style.overflow = ''
|
||||
pcMain.style.position = ''
|
||||
pcMain.style.top = ''
|
||||
pcMain.style.left = ''
|
||||
pcMain.style.right = ''
|
||||
pcMain.style.width = ''
|
||||
|
||||
// 恢复滚动位置
|
||||
pcMain.scrollTop = scrollTop;
|
||||
delete pcMain.dataset.scrollTop;
|
||||
pcMain.scrollTop = scrollTop
|
||||
delete pcMain.dataset.scrollTop
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
function listingPrice(item: Listing) {
|
||||
return formatMoney(getListingDisplayPrice(item));
|
||||
return formatMoney(getListingDisplayPrice(item))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="pc-detail page" v-loading="loading">
|
||||
<div class="anti-fraud-strip compact">
|
||||
<span
|
||||
>防骗提示:下单后请按平台交接流程确认收号与归还,不要私下交易。</span
|
||||
>
|
||||
<span>防骗提示:下单后请按平台交接流程确认收号与归还,不要私下交易。</span>
|
||||
</div>
|
||||
|
||||
<div v-if="listing" class="pc-detail-layout">
|
||||
<section class="pc-detail-main">
|
||||
<div class="detail-hero-card">
|
||||
<img
|
||||
v-if="coverURL"
|
||||
:src="coverURL"
|
||||
:alt="getListingTitle(listing)"
|
||||
/>
|
||||
<img v-if="coverURL" :src="coverURL" :alt="getListingTitle(listing)" />
|
||||
<span v-else>HFB ACCOUNT</span>
|
||||
<div class="detail-hero-overlay">
|
||||
<div class="detail-tags">
|
||||
@@ -340,7 +337,12 @@ function listingPrice(item: Listing) {
|
||||
|
||||
<div class="detail-body">
|
||||
<div class="detail-summary-row">
|
||||
<div v-for="metric in detailMetrics" :key="metric.label" class="detail-metric" :class="`is-${metric.tone}`">
|
||||
<div
|
||||
v-for="metric in detailMetrics"
|
||||
:key="metric.label"
|
||||
class="detail-metric"
|
||||
:class="`is-${metric.tone}`"
|
||||
>
|
||||
<span>{{ metric.label }}</span>
|
||||
<strong>{{ metric.value }}</strong>
|
||||
</div>
|
||||
@@ -349,7 +351,7 @@ function listingPrice(item: Listing) {
|
||||
<section class="detail-section">
|
||||
<div class="detail-section-head">
|
||||
<h2>账号资料</h2>
|
||||
<span>{{ listing.game_name || "三角洲行动" }}</span>
|
||||
<span>{{ listing.game_name || '三角洲行动' }}</span>
|
||||
</div>
|
||||
<div class="detail-chip-row">
|
||||
<span v-for="chip in getListingChips(listing)" :key="chip.label">
|
||||
@@ -370,13 +372,17 @@ function listingPrice(item: Listing) {
|
||||
<span>{{ getListingResources(listing).length }} 项</span>
|
||||
</div>
|
||||
<div class="detail-resource-grid">
|
||||
<div v-for="resource in getListingResources(listing)" :key="resource.key" class="detail-resource-card">
|
||||
<div
|
||||
v-for="resource in getListingResources(listing)"
|
||||
:key="resource.key"
|
||||
class="detail-resource-card"
|
||||
>
|
||||
<span>{{ resource.label }}</span>
|
||||
<strong>{{ resource.quantity }}</strong>
|
||||
<em>
|
||||
<b>{{ resource.mode || "--" }}</b>
|
||||
<b>{{ resource.mode || '--' }}</b>
|
||||
<small v-if="resource.amount > 0">¥{{ resource.amount }}</small>
|
||||
<small v-else-if="resource.mode === '收费'">{{ resource.price || "¥0" }}</small>
|
||||
<small v-else-if="resource.mode === '收费'">{{ resource.price || '¥0' }}</small>
|
||||
<small v-else>无额外收费</small>
|
||||
</em>
|
||||
</div>
|
||||
@@ -402,7 +408,7 @@ function listingPrice(item: Listing) {
|
||||
<div class="detail-section-head">
|
||||
<h2>号主备注</h2>
|
||||
</div>
|
||||
<p class="detail-description">{{ listing.description || "号主暂未填写详细说明。" }}</p>
|
||||
<p class="detail-description">{{ listing.description || '号主暂未填写详细说明。' }}</p>
|
||||
</section>
|
||||
|
||||
<section v-if="detailScreenshots.length" class="detail-section">
|
||||
@@ -444,11 +450,11 @@ function listingPrice(item: Listing) {
|
||||
<dl class="order-check-list">
|
||||
<div>
|
||||
<dt>账号区服</dt>
|
||||
<dd>{{ getServerRegion(listing) || "--" }}</dd>
|
||||
<dd>{{ getServerRegion(listing) || '--' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>上号方式</dt>
|
||||
<dd>{{ getLoginMethod(listing) || "--" }}</dd>
|
||||
<dd>{{ getLoginMethod(listing) || '--' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>预计可租</dt>
|
||||
@@ -463,7 +469,7 @@ function listingPrice(item: Listing) {
|
||||
class="full-control"
|
||||
@click="handleCreateOrder"
|
||||
>
|
||||
{{ listing.in_transaction ? "交易中" : "立即下单" }}
|
||||
{{ listing.in_transaction ? '交易中' : '立即下单' }}
|
||||
</el-button>
|
||||
</el-form>
|
||||
</aside>
|
||||
@@ -560,7 +566,7 @@ function listingPrice(item: Listing) {
|
||||
.detail-hero-card::after {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
content: "";
|
||||
content: '';
|
||||
background:
|
||||
linear-gradient(180deg, rgba(15, 23, 42, 0.06), rgba(15, 23, 42, 0.58)),
|
||||
linear-gradient(90deg, rgba(15, 23, 42, 0.76), rgba(15, 23, 42, 0.08) 62%);
|
||||
|
||||
Reference in New Issue
Block a user