发布流程增加解锁赛伊德与腾讯安全中心截图教程
- 解锁赛伊德:皮肤与交接分区新增是/否必选项,存入 asset_summary, 仅当号主选「是」时在买家端列表/详情展示「解锁赛伊德:是」 - 腾讯安全中心截图:新增可复用 GuideImage 组件(缩略图 + 点击全屏放大), 在该截图槽位展示处罚截图教程图,仅提示用途、不占用上传数量 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
a88008f783
commit
f336957391
Vendored
+1
@@ -62,6 +62,7 @@ declare module 'vue' {
|
|||||||
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
|
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
|
||||||
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
|
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
|
||||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||||
|
GuideImage: typeof import('./src/components/GuideImage.vue')['default']
|
||||||
InAppBrowserPrompt: typeof import('./src/components/InAppBrowserPrompt.vue')['default']
|
InAppBrowserPrompt: typeof import('./src/components/InAppBrowserPrompt.vue')['default']
|
||||||
MobileBottomNav: typeof import('./src/components/MobileBottomNav.vue')['default']
|
MobileBottomNav: typeof import('./src/components/MobileBottomNav.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 142 KiB |
@@ -0,0 +1,93 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
src: string
|
||||||
|
label?: string
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
label: '点击查看示例',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const open = ref(false)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="guide-image">
|
||||||
|
<button type="button" class="guide-thumb" @click="open = true">
|
||||||
|
<img :src="src" alt="示例图" loading="lazy" decoding="async" />
|
||||||
|
<span class="guide-thumb-tip">{{ label }}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<Teleport to="body">
|
||||||
|
<div v-if="open" class="guide-viewer" @click="open = false">
|
||||||
|
<button type="button" class="guide-viewer-close" @click="open = false">关闭</button>
|
||||||
|
<img class="guide-viewer-img" :src="src" alt="示例大图" @click.stop />
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.guide-image {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-thumb {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 4px 8px 4px 4px;
|
||||||
|
border: 1px dashed #c0c4cc;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #f7f9fc;
|
||||||
|
cursor: zoom-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-thumb img {
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 6px;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-thumb-tip {
|
||||||
|
color: #409eff;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-viewer {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 3000;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 24px 12px;
|
||||||
|
overflow: auto;
|
||||||
|
background: rgba(0, 0, 0, 0.82);
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-viewer-img {
|
||||||
|
width: min(720px, 94vw);
|
||||||
|
height: fit-content;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-viewer-close {
|
||||||
|
position: fixed;
|
||||||
|
top: 16px;
|
||||||
|
right: 16px;
|
||||||
|
z-index: 3001;
|
||||||
|
padding: 6px 16px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(255, 255, 255, 0.92);
|
||||||
|
color: #1f2937;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -17,6 +17,7 @@ export function defaultPublishForm(): PublishForm {
|
|||||||
login_method: '',
|
login_method: '',
|
||||||
online_start: '',
|
online_start: '',
|
||||||
online_end: '',
|
online_end: '',
|
||||||
|
unlock_said: '',
|
||||||
ban_record: '',
|
ban_record: '',
|
||||||
common_regions: [],
|
common_regions: [],
|
||||||
depositAmountYuan: '',
|
depositAmountYuan: '',
|
||||||
|
|||||||
@@ -285,6 +285,7 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
|||||||
login_method: listing.login_platform || '',
|
login_method: listing.login_platform || '',
|
||||||
online_start: stringValue(onlineTime.start),
|
online_start: stringValue(onlineTime.start),
|
||||||
online_end: stringValue(onlineTime.end),
|
online_end: stringValue(onlineTime.end),
|
||||||
|
unlock_said: stringValue(summary.unlock_said),
|
||||||
ban_record: stringValue(summary.ban_record),
|
ban_record: stringValue(summary.ban_record),
|
||||||
common_regions: stringArray(summary.common_regions),
|
common_regions: stringArray(summary.common_regions),
|
||||||
depositAmountYuan: listing.deposit_amount_cent > 0 ? listing.deposit_amount_cent / 100 : '',
|
depositAmountYuan: listing.deposit_amount_cent > 0 ? listing.deposit_amount_cent / 100 : '',
|
||||||
@@ -730,6 +731,7 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pricing.banRecordOptions.value.length && !form.ban_record) return '请选择封禁记录'
|
if (pricing.banRecordOptions.value.length && !form.ban_record) return '请选择封禁记录'
|
||||||
|
if (!form.unlock_said) return '请选择是否解锁赛伊德'
|
||||||
if (form.depositAmountYuan === '' || Number(form.depositAmountYuan) < 0) return '请填写押金'
|
if (form.depositAmountYuan === '' || Number(form.depositAmountYuan) < 0) return '请填写押金'
|
||||||
if (!Number.isFinite(Number(form.depositAmountYuan))) return '押金格式不正确'
|
if (!Number.isFinite(Number(form.depositAmountYuan))) return '押金格式不正确'
|
||||||
if (
|
if (
|
||||||
@@ -825,6 +827,7 @@ export function usePublishForm(options: UsePublishFormOptions) {
|
|||||||
start: form.online_start,
|
start: form.online_start,
|
||||||
end: form.online_end,
|
end: form.online_end,
|
||||||
},
|
},
|
||||||
|
unlock_said: form.unlock_said,
|
||||||
ban_record: form.ban_record,
|
ban_record: form.ban_record,
|
||||||
common_regions: form.common_regions,
|
common_regions: form.common_regions,
|
||||||
remark: form.remark,
|
remark: form.remark,
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import MobileBottomNav from '@/components/MobileBottomNav.vue'
|
|||||||
import { usePublishForm } from '@/features/seller/composables/usePublishForm'
|
import { usePublishForm } from '@/features/seller/composables/usePublishForm'
|
||||||
import { formatMoney } from '@/shared/utils/money'
|
import { formatMoney } from '@/shared/utils/money'
|
||||||
import type { AgreementContent } from '@/features/listings/api/listingOptions'
|
import type { AgreementContent } from '@/features/listings/api/listingOptions'
|
||||||
|
import GuideImage from '@/components/GuideImage.vue'
|
||||||
|
import tencentSecurityGuide from '@/assets/tencent-security-guide.webp'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
commonOnlineTimes,
|
commonOnlineTimes,
|
||||||
@@ -115,6 +117,13 @@ function openPublishAgreement(agreement: AgreementContent) {
|
|||||||
function selectRadio<T extends string>(value: T, setter: (value: T) => void) {
|
function selectRadio<T extends string>(value: T, setter: (value: T) => void) {
|
||||||
setter(value)
|
setter(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unlockSaidOptions = ['是', '否']
|
||||||
|
|
||||||
|
// 截图槽位的指导示例图(仅展示、点击放大,不占用上传数量)
|
||||||
|
const screenshotGuides: Record<string, string> = {
|
||||||
|
tencentSecurity: tencentSecurityGuide,
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -356,6 +365,23 @@ function selectRadio<T extends string>(value: T, setter: (value: T) => void) {
|
|||||||
优先推荐【账密登录】,出售速度约为扫码的数倍,两种方式安全性一致,账密登录更便捷,请自行衡量
|
优先推荐【账密登录】,出售速度约为扫码的数倍,两种方式安全性一致,账密登录更便捷,请自行衡量
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<van-field label="解锁赛伊德" required class="publish-field">
|
||||||
|
<template #input>
|
||||||
|
<div class="radio-group">
|
||||||
|
<button
|
||||||
|
v-for="opt in unlockSaidOptions"
|
||||||
|
:key="opt"
|
||||||
|
type="button"
|
||||||
|
class="radio-btn"
|
||||||
|
:class="{ active: form.unlock_said === opt }"
|
||||||
|
@click="selectRadio(opt, value => (form.unlock_said = value))"
|
||||||
|
>
|
||||||
|
{{ opt }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
|
||||||
<div class="time-row">
|
<div class="time-row">
|
||||||
<div class="time-field-group">
|
<div class="time-field-group">
|
||||||
<van-field
|
<van-field
|
||||||
@@ -487,6 +513,11 @@ function selectRadio<T extends string>(value: T, setter: (value: T) => void) {
|
|||||||
<small v-if="getScreenshotLimitHint(slot.key)">{{
|
<small v-if="getScreenshotLimitHint(slot.key)">{{
|
||||||
getScreenshotLimitHint(slot.key)
|
getScreenshotLimitHint(slot.key)
|
||||||
}}</small>
|
}}</small>
|
||||||
|
<GuideImage
|
||||||
|
v-if="screenshotGuides[slot.key]"
|
||||||
|
:src="screenshotGuides[slot.key] || ''"
|
||||||
|
label="点击查看处罚截图教程"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="getScreenshotCount(slot.key)" class="upload-preview-list">
|
<div v-if="getScreenshotCount(slot.key)" class="upload-preview-list">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import { formatMoney } from '@/shared/utils/money'
|
|||||||
import type { AgreementContent } from '@/features/listings/api/listingOptions'
|
import type { AgreementContent } from '@/features/listings/api/listingOptions'
|
||||||
import OptionChips from './components/OptionChips.vue'
|
import OptionChips from './components/OptionChips.vue'
|
||||||
import PublishSection from './components/PublishSection.vue'
|
import PublishSection from './components/PublishSection.vue'
|
||||||
|
import GuideImage from '@/components/GuideImage.vue'
|
||||||
|
import tencentSecurityGuide from '@/assets/tencent-security-guide.webp'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
commonOnlineTimes,
|
commonOnlineTimes,
|
||||||
@@ -115,6 +117,13 @@ const activeAgreement = ref<AgreementContent | null>(null)
|
|||||||
const activeAgreementTitle = computed(() => activeAgreement.value?.title || '协议内容')
|
const activeAgreementTitle = computed(() => activeAgreement.value?.title || '协议内容')
|
||||||
const activeAgreementContent = computed(() => activeAgreement.value?.content || '')
|
const activeAgreementContent = computed(() => activeAgreement.value?.content || '')
|
||||||
|
|
||||||
|
const unlockSaidOptions = ['是', '否']
|
||||||
|
|
||||||
|
// 截图槽位的指导示例图(仅展示、点击放大,不占用上传数量)
|
||||||
|
const screenshotGuides: Record<string, string> = {
|
||||||
|
tencentSecurity: tencentSecurityGuide,
|
||||||
|
}
|
||||||
|
|
||||||
function toggleSkinOption(value: string | number) {
|
function toggleSkinOption(value: string | number) {
|
||||||
toggleSkin(String(value))
|
toggleSkin(String(value))
|
||||||
}
|
}
|
||||||
@@ -322,6 +331,15 @@ function selectDailyLoss(value: string | number) {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="field-row panel-field-row">
|
||||||
|
<label>解锁赛伊德<span>*</span></label>
|
||||||
|
<OptionChips
|
||||||
|
:options="unlockSaidOptions"
|
||||||
|
:model-value="form.unlock_said"
|
||||||
|
@select="form.unlock_said = String($event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="time-preset-panel">
|
<div class="time-preset-panel">
|
||||||
<div class="time-preset-row">
|
<div class="time-preset-row">
|
||||||
<strong>在线开始<span>*</span></strong>
|
<strong>在线开始<span>*</span></strong>
|
||||||
@@ -427,6 +445,11 @@ function selectDailyLoss(value: string | number) {
|
|||||||
<em v-if="getScreenshotLimitHint(slot.key)">{{
|
<em v-if="getScreenshotLimitHint(slot.key)">{{
|
||||||
getScreenshotLimitHint(slot.key)
|
getScreenshotLimitHint(slot.key)
|
||||||
}}</em>
|
}}</em>
|
||||||
|
<GuideImage
|
||||||
|
v-if="screenshotGuides[slot.key]"
|
||||||
|
:src="screenshotGuides[slot.key] || ''"
|
||||||
|
label="点击查看处罚截图教程"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="getScreenshotCount(slot.key)" class="upload-preview-list">
|
<div v-if="getScreenshotCount(slot.key)" class="upload-preview-list">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export type PublishForm = {
|
|||||||
login_method: string
|
login_method: string
|
||||||
online_start: string
|
online_start: string
|
||||||
online_end: string
|
online_end: string
|
||||||
|
unlock_said: string
|
||||||
ban_record: string
|
ban_record: string
|
||||||
common_regions: string[]
|
common_regions: string[]
|
||||||
depositAmountYuan: number | ''
|
depositAmountYuan: number | ''
|
||||||
|
|||||||
@@ -133,6 +133,10 @@ export function getListingChips(item: Listing): ListingDisplayChip[] {
|
|||||||
if (online) {
|
if (online) {
|
||||||
chips.push({ label: '方便上号', value: online })
|
chips.push({ label: '方便上号', value: online })
|
||||||
}
|
}
|
||||||
|
// 解锁赛伊德为必选项,仅在号主勾选「是」时展示
|
||||||
|
if (readAssetString(item, 'unlock_said') === '是') {
|
||||||
|
chips.push({ label: '解锁赛伊德', value: '是' })
|
||||||
|
}
|
||||||
return chips.filter(chip => chip.value)
|
return chips.filter(chip => chip.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user