From c30914b53804e8699507cc46423a30730e58c2ae Mon Sep 17 00:00:00 2001 From: yml2213 Date: Wed, 24 Jun 2026 01:57:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8F=91=E5=B8=83=E7=A1=AE?= =?UTF-8?q?=E8=AE=A4=E4=B8=8E=E8=AE=A2=E5=8D=95=E8=B5=84=E9=87=91=E6=8B=86?= =?UTF-8?q?=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/views/AdminOrderDetailView.vue | 78 +++++++++++++------ .../seller/composables/usePublishForm.ts | 16 +++- .../views/MobileSellerListingCreateView.vue | 8 ++ .../seller/views/SellerListingCreateView.vue | 8 ++ 4 files changed, 83 insertions(+), 27 deletions(-) diff --git a/frontend/src/features/admin/views/AdminOrderDetailView.vue b/frontend/src/features/admin/views/AdminOrderDetailView.vue index dda126f..b31f277 100644 --- a/frontend/src/features/admin/views/AdminOrderDetailView.vue +++ b/frontend/src/features/admin/views/AdminOrderDetailView.vue @@ -42,6 +42,12 @@ const paymentRecords = ref([]) const actionType = ref<'close' | 'abnormal' | 'reset' | ''>('') const reason = ref('') const refundStatus = ref(null) + +type FundSplitRow = { + label: string + amountCent: number | null | undefined +} + const listingCode = computed(() => order.value ? formatListingNo(order.value.listing_no, order.value.listing_id) : '-' ) @@ -109,10 +115,14 @@ const assetSummary = computed(() => { if (typeof summary !== 'object' || summary === null) return null return summary as Record }) -const snapshotRatio = computed(() => { +const snapshotPriceBreakdown = computed(() => { const breakdown = assetSummary.value?.price_breakdown if (typeof breakdown !== 'object' || breakdown === null) return null - const row = breakdown as Record + return breakdown as Record +}) +const snapshotRatio = computed(() => { + const row = snapshotPriceBreakdown.value + if (!row) return null const sellerRatio = Number(row.seller_ratio || 0) const buyerRatio = Number(row.buyer_ratio || 0) const publishRatio = Number(assetSummary.value?.publish_ratio || 0) @@ -121,6 +131,36 @@ const snapshotRatio = computed(() => { sellRatio: buyerRatio > 0 ? buyerRatio : 0, } }) +const ownerCoinBasePriceCent = computed(() => readPriceBreakdownCent('seller_coin_base_price')) +const ownerLossPriceCent = computed(() => { + const consumableCent = readPriceBreakdownCent('consumable_price') + if (consumableCent !== null) return consumableCent + if (ownerCoinBasePriceCent.value === null || !order.value?.owner_rent_amount_cent) return null + return Math.max(Number(order.value.owner_rent_amount_cent) - ownerCoinBasePriceCent.value, 0) +}) +const hasOwnerRentBreakdown = computed(() => ownerCoinBasePriceCent.value !== null) +const fundSplitRows = computed(() => { + if (!order.value) return [] + const rows: FundSplitRow[] = [ + { label: '租客租金', amountCent: order.value.rent_amount_cent }, + ] + if (hasOwnerRentBreakdown.value) { + rows.push( + { label: '号主纯币价格', amountCent: ownerCoinBasePriceCent.value }, + { label: '号主损耗', amountCent: ownerLossPriceCent.value ?? 0 }, + { label: '号主租金合计', amountCent: order.value.owner_rent_amount_cent } + ) + } else { + rows.push({ label: '号主租金', amountCent: order.value.owner_rent_amount_cent }) + } + rows.push( + { label: '平台费用', amountCent: order.value.platform_fee_cent }, + { label: '实付押金', amountCent: order.value.deposit_amount_cent }, + { label: '原始押金', amountCent: order.value.deposit_original_amount_cent }, + { label: '免押额度', amountCent: order.value.deposit_waived_amount_cent } + ) + return rows +}) const snapshotSeasonTags = computed(() => { const tags = currentSnapshot.value?.season_tags return Array.isArray(tags) ? tags.map(item => String(item)).filter(Boolean) : [] @@ -298,6 +338,14 @@ function moneyCent(value: number | undefined | null) { return formatCentWithSymbol(Number(value || 0)) } +function readPriceBreakdownCent(key: string) { + const raw = snapshotPriceBreakdown.value?.[key] + if (raw === undefined || raw === null || raw === '') return null + const value = Number(raw) + if (!Number.isFinite(value)) return null + return Math.round(value * 100) +} + function firstQueryValue(value: unknown) { if (Array.isArray(value)) return typeof value[0] === 'string' ? value[0] : '' return typeof value === 'string' ? value : '' @@ -564,29 +612,9 @@ function paymentPaidAt(record: AdminPayment) { {{ priceRoleLabel(order.price_role) }}
-
- 租客租金 - {{ moneyCent(order.rent_amount_cent) }} -
-
- 号主租金 - {{ moneyCent(order.owner_rent_amount_cent) }} -
-
- 平台费用 - {{ moneyCent(order.platform_fee_cent) }} -
-
- 实付押金 - {{ moneyCent(order.deposit_amount_cent) }} -
-
- 原始押金 - {{ moneyCent(order.deposit_original_amount_cent) }} -
-
- 免押额度 - {{ moneyCent(order.deposit_waived_amount_cent) }} +
+ {{ row.label }} + {{ moneyCent(row.amountCent) }}
订单实付合计 diff --git a/frontend/src/features/seller/composables/usePublishForm.ts b/frontend/src/features/seller/composables/usePublishForm.ts index 7c507ef..3178ecf 100644 --- a/frontend/src/features/seller/composables/usePublishForm.ts +++ b/frontend/src/features/seller/composables/usePublishForm.ts @@ -67,6 +67,7 @@ export function usePublishForm(options: UsePublishFormOptions) { const publishAgreements = ref(emptyListingPublishAgreements) const virtualAssetSaleAgreementChecked = ref(false) const sellerAgreementChecked = ref(false) + const passwordAndDeviceConfirmed = ref(false) const fileInput = ref(null) const activeUploadKey = ref('coin') const form = reactive(defaultPublishForm()) @@ -81,6 +82,7 @@ export function usePublishForm(options: UsePublishFormOptions) { const pageTitle = computed(() => (isEditMode.value ? '编辑账号' : '发布账号')) const submitButtonText = computed(() => (isEditMode.value ? '提交修改' : '立即发布')) const submitLoadingText = computed(() => (isEditMode.value ? '提交中...' : '发布中...')) + const showBanRecordRiskHint = false const pricing = usePricingCalculator({ form, @@ -96,7 +98,10 @@ export function usePublishForm(options: UsePublishFormOptions) { ) const requiredScreenshotCount = ref(0) const canPublishAfterAgreements = computed( - () => virtualAssetSaleAgreementChecked.value && sellerAgreementChecked.value + () => + virtualAssetSaleAgreementChecked.value && + sellerAgreementChecked.value && + passwordAndDeviceConfirmed.value ) const disabledOnlineStartOptions = computed(() => commonOnlineTimes.filter(time => !canUseOnlineStart(time)) @@ -316,6 +321,7 @@ export function usePublishForm(options: UsePublishFormOptions) { selectedSkins.value = Object.values(skinGroups).flatMap(value => stringArray(value)) virtualAssetSaleAgreementChecked.value = true sellerAgreementChecked.value = true + passwordAndDeviceConfirmed.value = true hydrateScreenshotPreviews() } @@ -328,6 +334,7 @@ export function usePublishForm(options: UsePublishFormOptions) { selectedSkins.value = [] virtualAssetSaleAgreementChecked.value = false sellerAgreementChecked.value = false + passwordAndDeviceConfirmed.value = false activeUploadKey.value = 'coin' // Also re-initialize quantityValues to 0 @@ -767,7 +774,10 @@ export function usePublishForm(options: UsePublishFormOptions) { if (!pricing.calculatedFinalPrice.value) return '请完善币数、保险、体力和负重后再发布' if (!Number.isFinite(pricing.calculatedFinalPrice.value)) return '发布价格计算异常,请检查填写内容' - if (!canPublishAfterAgreements.value) return '请先阅读并勾选两份发布协议' + if (!virtualAssetSaleAgreementChecked.value || !sellerAgreementChecked.value) { + return '请先阅读并勾选两份发布协议' + } + if (!passwordAndDeviceConfirmed.value) return '请确认已知晓打完需改密并清除登录设备' for (const item of pricing.screenshotSlots.value) { if (isScreenshotRequired(item) && getScreenshotCount(item.key) === 0) return `请上传${item.label}` @@ -931,7 +941,9 @@ export function usePublishForm(options: UsePublishFormOptions) { publishAgreements, virtualAssetSaleAgreementChecked, sellerAgreementChecked, + passwordAndDeviceConfirmed, canPublishAfterAgreements, + showBanRecordRiskHint, fileInput, activeUploadKey, form, diff --git a/frontend/src/features/seller/views/MobileSellerListingCreateView.vue b/frontend/src/features/seller/views/MobileSellerListingCreateView.vue index e13c752..0494852 100644 --- a/frontend/src/features/seller/views/MobileSellerListingCreateView.vue +++ b/frontend/src/features/seller/views/MobileSellerListingCreateView.vue @@ -23,7 +23,9 @@ const { publishAgreements, virtualAssetSaleAgreementChecked, sellerAgreementChecked, + passwordAndDeviceConfirmed, canPublishAfterAgreements, + showBanRecordRiskHint, fileInput, activeUploadKey, form, @@ -474,6 +476,9 @@ const screenshotGuides: Record = {
+

+ 刚出租结算完的账号需冷号七天才可再次出租,IP频繁变动会导致封号。 +

@@ -744,6 +749,9 @@ const screenshotGuides: Record = { + + 我已知晓打完需改密并清除登录设备 +
diff --git a/frontend/src/features/seller/views/SellerListingCreateView.vue b/frontend/src/features/seller/views/SellerListingCreateView.vue index e1ca8fd..af4d04b 100644 --- a/frontend/src/features/seller/views/SellerListingCreateView.vue +++ b/frontend/src/features/seller/views/SellerListingCreateView.vue @@ -26,7 +26,9 @@ const { publishAgreements, virtualAssetSaleAgreementChecked, sellerAgreementChecked, + passwordAndDeviceConfirmed, canPublishAfterAgreements, + showBanRecordRiskHint, fileInput, activeUploadKey, form, @@ -414,6 +416,9 @@ function selectDailyLoss(value: string | number) { @select="form.ban_record = String($event)" />
+

+ 刚出租结算完的账号需冷号七天才可再次出租,IP频繁变动会导致封号。 +