二次编辑商品
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { readError } from '@/shared/utils/error'
|
||||
import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import { fetchFileBlobByURL, uploadFile } from '@/shared/api/files'
|
||||
import {
|
||||
@@ -16,7 +16,12 @@ import {
|
||||
type PublishSalePriceConfig,
|
||||
type ScreenshotKey,
|
||||
} from '@/features/listings/api/listingOptions'
|
||||
import { createListing } from '@/features/listings/api/listings'
|
||||
import {
|
||||
createListing,
|
||||
fetchSellerListing,
|
||||
updateListing,
|
||||
type Listing,
|
||||
} from '@/features/listings/api/listings'
|
||||
import { usePricingCalculator } from '@/shared/composables/usePricingCalculator'
|
||||
import {
|
||||
buildPublishDraft,
|
||||
@@ -51,6 +56,7 @@ interface UsePublishFormOptions {
|
||||
|
||||
export function usePublishForm(options: UsePublishFormOptions) {
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const loading = ref(false)
|
||||
const uploading = ref(false)
|
||||
const suppressDraftSave = ref(false)
|
||||
@@ -69,6 +75,11 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
||||
const screenshotPreviews = reactive<Record<string, string[]>>({})
|
||||
const selectedSkins = ref<string[]>([])
|
||||
let draftSaveTimer: number | undefined
|
||||
const editListingID = computed(() => Number(route.params.id || 0))
|
||||
const isEditMode = computed(() => Number.isFinite(editListingID.value) && editListingID.value > 0)
|
||||
const pageTitle = computed(() => (isEditMode.value ? '编辑账号' : '发布账号'))
|
||||
const submitButtonText = computed(() => (isEditMode.value ? '提交修改' : '立即发布'))
|
||||
const submitLoadingText = computed(() => (isEditMode.value ? '提交中...' : '发布中...'))
|
||||
|
||||
const pricing = usePricingCalculator({
|
||||
form,
|
||||
@@ -93,11 +104,14 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
||||
commonOnlineTimes.filter(time => !canUseOnlineEnd(time))
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
restoreDraft()
|
||||
draftReady.value = true
|
||||
onMounted(async () => {
|
||||
if (!isEditMode.value) restoreDraft()
|
||||
if (options.persistBeforeUnload) window.addEventListener('beforeunload', handleBeforeUnload)
|
||||
loadPublishOptions()
|
||||
await loadPublishOptions()
|
||||
if (isEditMode.value) {
|
||||
await loadEditingListing()
|
||||
}
|
||||
draftReady.value = true
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -164,7 +178,22 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadEditingListing() {
|
||||
if (!isEditMode.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
const listing = await fetchSellerListing(editListingID.value)
|
||||
applyListingToForm(listing)
|
||||
} catch (error) {
|
||||
options.notifyError(readError(error, '商品信息加载失败'))
|
||||
await router.push(options.submitSuccessPath)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function saveDraft(saveOptions: { force?: boolean } = {}) {
|
||||
if (isEditMode.value) return
|
||||
if (suppressDraftSave.value) {
|
||||
clearDraftSaveTimer()
|
||||
return
|
||||
@@ -229,6 +258,65 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
||||
hydrateScreenshotPreviews()
|
||||
}
|
||||
|
||||
function applyListingToForm(listing: Listing) {
|
||||
const summary = recordValue(listing.asset_summary)
|
||||
const onlineTime = recordValue(summary.online_time)
|
||||
const screenshotGroups = recordValue(summary.screenshot_groups)
|
||||
const skinGroups = recordValue(summary.skin_groups)
|
||||
const breakdown = recordValue(summary.price_breakdown)
|
||||
|
||||
clearRecord(quantityValues)
|
||||
clearRecord(quantityModes)
|
||||
clearRecord(screenshotFiles)
|
||||
revokeAllScreenshotPreviews()
|
||||
|
||||
Object.assign(form, {
|
||||
server_region: listing.server_region || '',
|
||||
face_owner: stringValue(summary.face_owner),
|
||||
haf_coin_amount: listing.haf_coin_amount > 0 ? listing.haf_coin_amount / 1000000 : '',
|
||||
rank_level: listing.rank_level || '',
|
||||
secret_kd: stringValue(summary.secret_kd),
|
||||
fire_level: numberOrEmpty(summary.fire_level),
|
||||
daily_loss_m: numberOrDefault(summary.daily_loss_m, 10),
|
||||
accelerated_sale_ratio: numberOrEmpty(breakdown.accelerated_sale_ratio),
|
||||
season_insurance: stringValue(summary.season_insurance),
|
||||
stamina_level: stringValue(summary.stamina_level),
|
||||
load_level: stringValue(summary.load_level),
|
||||
login_method: listing.login_platform || '',
|
||||
online_start: stringValue(onlineTime.start),
|
||||
online_end: stringValue(onlineTime.end),
|
||||
ban_record: stringValue(summary.ban_record),
|
||||
common_regions: stringArray(summary.common_regions),
|
||||
depositAmountYuan: listing.deposit_amount_cent > 0 ? listing.deposit_amount_cent / 100 : '',
|
||||
remark: listing.description || stringValue(summary.remark),
|
||||
})
|
||||
|
||||
for (const item of publishOptions.value.quantity_items) {
|
||||
quantityValues[item.key] = 0
|
||||
}
|
||||
for (const item of arrayValue(summary.resources)) {
|
||||
const resource = recordValue(item)
|
||||
const key = stringValue(resource.key)
|
||||
if (!key) continue
|
||||
quantityValues[key] = numberOrDefault(resource.quantity, 0)
|
||||
const mode = stringValue(resource.mode)
|
||||
quantityModes[key] = mode === '赠送' ? '赠送' : '收费'
|
||||
}
|
||||
|
||||
for (const [key, urls] of Object.entries(screenshotGroups)) {
|
||||
const cleaned = stringArray(urls)
|
||||
if (cleaned.length) screenshotFiles[key] = cleaned
|
||||
}
|
||||
if (!Object.keys(screenshotFiles).length && listing.screenshot_urls.length) {
|
||||
screenshotFiles.coin = [...listing.screenshot_urls]
|
||||
}
|
||||
|
||||
selectedSkins.value = Object.values(skinGroups).flatMap(value => stringArray(value))
|
||||
virtualAssetSaleAgreementChecked.value = true
|
||||
sellerAgreementChecked.value = true
|
||||
hydrateScreenshotPreviews()
|
||||
}
|
||||
|
||||
function resetDraftState() {
|
||||
Object.assign(form, defaultPublishForm())
|
||||
clearRecord(quantityValues)
|
||||
@@ -351,6 +439,11 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
||||
}
|
||||
|
||||
async function handleResetDraft() {
|
||||
if (isEditMode.value) {
|
||||
await loadEditingListing()
|
||||
options.notifySuccess('已恢复原商品信息')
|
||||
return
|
||||
}
|
||||
try {
|
||||
await options.confirmReset?.()
|
||||
} catch {
|
||||
@@ -565,7 +658,7 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
const listing = await createListing({
|
||||
const payload = {
|
||||
title: pricing.publishTitle.value,
|
||||
description: form.remark,
|
||||
server_region: form.server_region,
|
||||
@@ -578,18 +671,27 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
||||
deposit_amount_cent: yuanToCent(Number(form.depositAmountYuan)),
|
||||
agreed_virtual_asset_sale: virtualAssetSaleAgreementChecked.value,
|
||||
agreed_seller_agreement: sellerAgreementChecked.value,
|
||||
})
|
||||
removePublishDraft(options.draftKey)
|
||||
}
|
||||
const listing = isEditMode.value
|
||||
? await updateListing(editListingID.value, payload)
|
||||
: await createListing(payload)
|
||||
if (!isEditMode.value) removePublishDraft(options.draftKey)
|
||||
suppressDraftSave.value = true
|
||||
clearDraftSaveTimer()
|
||||
options.notifySuccess(
|
||||
listing.status === 'published' && listing.review_status === 'approved'
|
||||
? '发布成功,已上架'
|
||||
: '发布成功,等待后台审核'
|
||||
? isEditMode.value
|
||||
? '修改成功,已上架'
|
||||
: '发布成功,已上架'
|
||||
: isEditMode.value
|
||||
? '修改成功,等待后台审核'
|
||||
: '发布成功,等待后台审核'
|
||||
)
|
||||
await router.push(options.submitSuccessPath)
|
||||
} catch (error) {
|
||||
options.notifyError(readError(error, '发布失败,请确认已登录并完成实名认证'))
|
||||
options.notifyError(
|
||||
readError(error, isEditMode.value ? '修改失败,请稍后重试' : '发布失败,请确认已登录并完成实名认证')
|
||||
)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -763,6 +865,37 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
||||
return pricing.screenshotSlots.value.find(item => item.key === key)?.label || '该截图'
|
||||
}
|
||||
|
||||
function recordValue(value: unknown): Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
||||
? (value as Record<string, unknown>)
|
||||
: {}
|
||||
}
|
||||
|
||||
function arrayValue(value: unknown): unknown[] {
|
||||
return Array.isArray(value) ? value : []
|
||||
}
|
||||
|
||||
function stringValue(value: unknown) {
|
||||
if (value === undefined || value === null) return ''
|
||||
return String(value)
|
||||
}
|
||||
|
||||
function stringArray(value: unknown) {
|
||||
return Array.isArray(value)
|
||||
? value.filter((item): item is string => typeof item === 'string' && Boolean(item))
|
||||
: []
|
||||
}
|
||||
|
||||
function numberOrEmpty(value: unknown): number | '' {
|
||||
const parsed = Number(value)
|
||||
return Number.isFinite(parsed) && parsed > 0 ? parsed : ''
|
||||
}
|
||||
|
||||
function numberOrDefault(value: unknown, fallback: number) {
|
||||
const parsed = Number(value)
|
||||
return Number.isFinite(parsed) ? parsed : fallback
|
||||
}
|
||||
|
||||
return {
|
||||
...pricing,
|
||||
dailyLossOptions,
|
||||
@@ -785,6 +918,10 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
||||
selectedSkins,
|
||||
uploadedScreenshotCount,
|
||||
requiredScreenshotCount,
|
||||
isEditMode,
|
||||
pageTitle,
|
||||
submitButtonText,
|
||||
submitLoadingText,
|
||||
disabledOnlineStartOptions,
|
||||
disabledOnlineEndOptions,
|
||||
loadPublishOptions,
|
||||
|
||||
Reference in New Issue
Block a user