feat(goods): per-member detail tabs in edit dialog; revert right-tree to raw names; split configured/family badges; add GET /origin-goods/:id
This commit is contained in:
@@ -286,12 +286,12 @@ function buildRightTree(tree: OriginGoodsTreeResponse) {
|
||||
}
|
||||
}
|
||||
const roots = tree.tree.map(mapCat)
|
||||
// 已配置数按族计入:链接成族(或已配置商品)即视为已配置,后序汇总到各级分类
|
||||
// 已配置数 = 已配置为官网商品的链接(成族但未配置不算)
|
||||
function fillConfiguredEff(nodes: any[]): number {
|
||||
let count = 0
|
||||
for (const n of nodes) {
|
||||
if (n.isOG) {
|
||||
n.configuredEff = n.configuredCount > 0 || n.familyId ? 1 : 0
|
||||
n.configuredEff = n.configuredCount > 0 ? 1 : 0
|
||||
} else {
|
||||
n.configuredEff = fillConfiguredEff(n.children ?? [])
|
||||
}
|
||||
@@ -305,12 +305,8 @@ function buildRightTree(tree: OriginGoodsTreeResponse) {
|
||||
|
||||
function rightFilterNode(_value: string, data: any) {
|
||||
if (data.isOG) {
|
||||
// 「仅未配置」同样把族内链接视为已配置
|
||||
if (showUnconfiguredOnly.value && (data.configuredCount > 0 || data.familyId)) return false
|
||||
if (searchKeyword.value) {
|
||||
const kw = searchKeyword.value
|
||||
if (!data.label.includes(kw) && !cleanLinkName(data.label).includes(kw)) return false
|
||||
}
|
||||
if (showUnconfiguredOnly.value && data.configuredCount > 0) return false
|
||||
if (searchKeyword.value && !data.label.includes(searchKeyword.value)) return false
|
||||
return true
|
||||
}
|
||||
return true
|
||||
@@ -519,13 +515,14 @@ function locateInRightTree(originGoodId: string) {
|
||||
const locateFlashGoodId = ref<string>('')
|
||||
|
||||
function locateInLeftTree(originGoodId: string) {
|
||||
// 链接 → 商品:优先精确匹配该链接配置的商品,其次同族商品(族内任一链接都可定位)
|
||||
// 链接 → 商品:主链接精确匹配 → 同族商品 → 旧副源合并商品
|
||||
const ogNode = findOgNodeById(originGoodId)
|
||||
const familyId = ogNode?.familyId ?? null
|
||||
const good = allGoods.value.find(g => String(g.originGoodId) === String(originGoodId))
|
||||
?? (familyId
|
||||
? allGoods.value.find(g => g.originGood?.family?.familyId === familyId)
|
||||
: null)
|
||||
?? allGoods.value.find(g => (g.mergedOriginGoods ?? []).some(m => String(m.id) === String(originGoodId)))
|
||||
if (!good) {
|
||||
ElMessage.warning('该原产品尚未配置到官网')
|
||||
return
|
||||
@@ -1049,12 +1046,17 @@ onMounted(() => loadAll())
|
||||
<div v-if="data.isOG" class="og-node" draggable="true" @dragstart="onOGDragStart($event, data)">
|
||||
<el-image v-if="data.goodImage" :src="data.goodImage" fit="cover" class="og-thumb" />
|
||||
<div v-else class="og-thumb og-thumb-placeholder" />
|
||||
<span class="og-name" :title="data.label">{{ cleanLinkName(data.label) }}</span>
|
||||
<span class="og-name" :title="data.goodName">{{ data.label }}</span>
|
||||
<span
|
||||
v-if="data.familyId || data.configuredCount > 0"
|
||||
v-if="data.configuredCount > 0"
|
||||
class="og-badge og-badge--ok"
|
||||
:title="data.familyId ? `族 ${data.familyCode || ''} · ${data.familyName || ''}` : `已配置 ${data.configuredCount} 国`"
|
||||
:title="`已配置 ${data.configuredCount} 国`"
|
||||
>已配置{{ data.configuredCount > 1 ? ' ' + data.configuredCount : '' }}</span>
|
||||
<span
|
||||
v-else-if="data.familyId"
|
||||
class="og-badge og-badge--family"
|
||||
:title="`族 ${data.familyCode || ''}:已归族但尚未配置为官网商品`"
|
||||
>成族</span>
|
||||
<span
|
||||
v-else
|
||||
class="og-badge og-badge--warn"
|
||||
@@ -1076,12 +1078,12 @@ onMounted(() => loadAll())
|
||||
@click.stop="handleSyncOriginDetail(data)"
|
||||
/>
|
||||
<el-button
|
||||
v-if="data.configuredCount > 0 || data.familyId"
|
||||
v-if="data.configuredCount > 0"
|
||||
size="small" link :icon="Aim" title="定位到官网商品"
|
||||
@click.stop="locateInLeftTree(data.rawId)"
|
||||
/>
|
||||
<el-button
|
||||
v-if="!data.configuredCount && !data.familyId"
|
||||
v-if="!data.configuredCount"
|
||||
size="small" type="primary" link class="og-config-btn"
|
||||
@click.stop="openConfigFromRightTree(data)"
|
||||
>配置</el-button>
|
||||
@@ -1453,6 +1455,9 @@ onMounted(() => loadAll())
|
||||
.og-badge--ok {
|
||||
color: #67c23a; background: #f0f9eb;
|
||||
}
|
||||
.og-badge--family {
|
||||
color: #337ecc; background: #ecf5ff;
|
||||
}
|
||||
.og-badge--warn {
|
||||
color: #ff6800; background: #fff2e8;
|
||||
}
|
||||
|
||||
@@ -31,30 +31,15 @@ const emit = defineEmits<{
|
||||
|
||||
const editLoading = ref(false)
|
||||
const editDetailLoading = ref(false)
|
||||
const detailSyncing = ref(false)
|
||||
/** 正在同步详情的成员行 id */
|
||||
const detailSyncing = ref<string>('')
|
||||
const editGood = ref<Good | GoodDetail | null>(null)
|
||||
const editForm = ref({
|
||||
id: '', goodName: '', goodImage: '', countryId: '', cascaderCategory: [] as string[],
|
||||
categoryId: '', positionId: '',
|
||||
})
|
||||
|
||||
const editOriginDetail = computed(() => (editGood.value as GoodDetail | null)?.originDetail ?? null)
|
||||
const editVariants = computed(() => (editGood.value as GoodDetail | null)?.variants ?? [])
|
||||
const editSizeColumns = computed(() => editOriginDetail.value?.sizeChart?.columns ?? [])
|
||||
const editSizeRows = computed(() => {
|
||||
const rows = editOriginDetail.value?.sizeChart?.rows ?? []
|
||||
return rows.map((row: any) => ({
|
||||
...row,
|
||||
...(row.measurements ?? []).reduce((out: Record<string, string>, item: any) => {
|
||||
out[item.key] = item.cm ?? '-'
|
||||
return out
|
||||
}, {}),
|
||||
}))
|
||||
})
|
||||
const editPackageRows = computed(() => editOriginDetail.value?.packageSpecs?.rows ?? [])
|
||||
const editIsCustom = computed(() => editGood.value?.originGood?.isCustom === true)
|
||||
/** 商品自身链接的定价维度(SKU 表列) */
|
||||
const editLinkDims = computed(() => linkDims(editGood.value?.originGood?.goodName ?? null))
|
||||
const categoryCascader = computed(() => buildCascader(props.categories))
|
||||
|
||||
// ─── 自定义商品内容编辑 ───
|
||||
@@ -176,10 +161,70 @@ function toggleMemberExpand(key: string) {
|
||||
else {
|
||||
next.add(key)
|
||||
loadMemberPrices(key)
|
||||
ensureMemberDetail(key)
|
||||
}
|
||||
expandedMemberKeys.value = next
|
||||
}
|
||||
|
||||
// ─── 成员详情(懒加载:GET /origin-goods/:id) ───
|
||||
const memberDetailCache = ref<Record<string, any>>({})
|
||||
|
||||
function memberDetail(id: string) {
|
||||
return memberDetailCache.value[id]
|
||||
}
|
||||
|
||||
async function ensureMemberDetail(ogId: string) {
|
||||
const row = editFamilyMembers.value.find((m) => m.id === ogId)
|
||||
if (!row || row.source !== 'SDS' || memberDetailCache.value[ogId] !== undefined) return
|
||||
memberDetailCache.value[ogId] = { loading: true }
|
||||
try {
|
||||
memberDetailCache.value[ogId] = await originGoodsApi.getOriginGood(ogId)
|
||||
} catch {
|
||||
memberDetailCache.value[ogId] = null
|
||||
}
|
||||
}
|
||||
|
||||
function memberSizeColumns(id: string) {
|
||||
return memberDetail(id)?.detail?.sizeChart?.columns ?? []
|
||||
}
|
||||
|
||||
function memberSizeRows(id: string) {
|
||||
const rows = memberDetail(id)?.detail?.sizeChart?.rows ?? []
|
||||
return rows.map((row: any) => ({
|
||||
...row,
|
||||
...(row.measurements ?? []).reduce((out: Record<string, string>, item: any) => {
|
||||
out[item.key] = item.cm ?? '-'
|
||||
return out
|
||||
}, {}),
|
||||
}))
|
||||
}
|
||||
|
||||
function memberPackageRows(id: string) {
|
||||
return memberDetail(id)?.detail?.packageSpecs?.rows ?? []
|
||||
}
|
||||
|
||||
function memberVariants(id: string) {
|
||||
return memberDetail(id)?.variants ?? []
|
||||
}
|
||||
|
||||
function memberDims(id: string) {
|
||||
const row = editFamilyMembers.value.find((m) => m.id === id)
|
||||
return linkDims(row?.goodName ?? null)
|
||||
}
|
||||
|
||||
async function handleSyncMemberDetail(row: { id: string; sdsGoodId: string }) {
|
||||
if (!row.sdsGoodId || detailSyncing.value) return
|
||||
detailSyncing.value = row.id
|
||||
try {
|
||||
const result = await syncApi.syncOneProductDetail(row.sdsGoodId)
|
||||
memberDetailCache.value[row.id] = await originGoodsApi.getOriginGood(row.id)
|
||||
ElMessage.success(`详情同步完成,共 ${result.variants} 个 SKU`)
|
||||
emit('changed')
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error?.response?.data?.message || '商品详情同步失败')
|
||||
} finally { detailSyncing.value = '' }
|
||||
}
|
||||
|
||||
/** 该链接在族价格矩阵中的格子(craft/logistics 即该链接的标签维度) */
|
||||
function loadMemberPrices(ogId: string) {
|
||||
const row = editFamilyMembers.value.find((m) => m.id === ogId)
|
||||
@@ -406,22 +451,6 @@ function onEditCascaderChange(val: any) {
|
||||
editForm.value.categoryId = path.length ? String(path[path.length - 1]) : ''
|
||||
}
|
||||
|
||||
async function handleSyncOneDetail() {
|
||||
if (editIsCustom.value) return
|
||||
const sdsGoodId = editGood.value?.originGood?.sdsGoodId
|
||||
if (!sdsGoodId) return
|
||||
detailSyncing.value = true
|
||||
try {
|
||||
const result = await syncApi.syncOneProductDetail(sdsGoodId)
|
||||
const detail = await goodsApi.getGoodById(editGood.value!.id)
|
||||
applyGood(detail)
|
||||
ElMessage.success(`详情同步完成,共 ${result.variants} 个 SKU`)
|
||||
emit('changed')
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error?.response?.data?.message || '商品详情同步失败')
|
||||
} finally { detailSyncing.value = false }
|
||||
}
|
||||
|
||||
async function handleEditSubmit() {
|
||||
let customPayload: any = null
|
||||
if (editIsCustom.value) {
|
||||
@@ -564,28 +593,21 @@ async function handleDeleteGood() {
|
||||
<span class="md-label">工艺位置</span><span class="md-val">{{ row.craftLabel || '-' }}</span>
|
||||
<span class="md-label">仓库</span><span class="md-val">{{ row.warehouseLabel || '-' }}</span>
|
||||
</div>
|
||||
<div class="member-tags-edit">
|
||||
<span class="md-label">标签</span>
|
||||
<el-select
|
||||
v-model="memberTagEdits[row.id]"
|
||||
multiple filterable size="small"
|
||||
placeholder="选择标签"
|
||||
style="flex:1"
|
||||
>
|
||||
<el-option-group v-for="g in tagOptionGroups" :key="g.id" :label="g.label">
|
||||
<el-option v-for="t in g.tags" :key="t.id" :label="t.tagName" :value="t.id" />
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
<el-button size="small" type="primary" :loading="memberTagSaving === row.id" @click="saveMemberTags(row)">保存标签</el-button>
|
||||
<el-button v-if="row.tagsManual" size="small" :loading="memberTagSaving === row.id" @click="resetMemberTags(row)">恢复自动</el-button>
|
||||
<el-button
|
||||
v-if="row.id === editGood?.originGoodId"
|
||||
size="small"
|
||||
:icon="Refresh"
|
||||
:loading="detailSyncing"
|
||||
@click="handleSyncOneDetail"
|
||||
>同步详情</el-button>
|
||||
</div>
|
||||
<div class="member-tags-edit">
|
||||
<span class="md-label">标签</span>
|
||||
<el-select
|
||||
v-model="memberTagEdits[row.id]"
|
||||
multiple filterable size="small"
|
||||
placeholder="选择标签"
|
||||
style="flex:1"
|
||||
>
|
||||
<el-option-group v-for="g in tagOptionGroups" :key="g.id" :label="g.label">
|
||||
<el-option v-for="t in g.tags" :key="t.id" :label="t.tagName" :value="t.id" />
|
||||
</el-option-group>
|
||||
</el-select>
|
||||
<el-button size="small" type="primary" :loading="memberTagSaving === row.id" @click="saveMemberTags(row)">保存标签</el-button>
|
||||
<el-button v-if="row.tagsManual" size="small" :loading="memberTagSaving === row.id" @click="resetMemberTags(row)">恢复自动</el-button>
|
||||
</div>
|
||||
<div v-if="row.craftLabel && row.logisticsLabel" class="member-price-block">
|
||||
<div class="member-price-head">
|
||||
<span class="md-label">尺码 × 颜色 → 价格</span>
|
||||
@@ -612,6 +634,71 @@ async function handleDeleteGood() {
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-if="row.source === 'SDS'" class="member-extra">
|
||||
<div v-if="!memberDetail(row.id) || memberDetail(row.id).loading" class="md-empty">详情加载中…</div>
|
||||
<div v-else-if="!memberDetail(row.id).hasDetail" class="md-empty">
|
||||
尚未同步详情
|
||||
<el-button size="small" :icon="Refresh" :loading="detailSyncing === row.id" @click="handleSyncMemberDetail(row)">同步详情</el-button>
|
||||
</div>
|
||||
<el-tabs v-else class="member-detail-tabs">
|
||||
<el-tab-pane label="商品详情">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="商品编码">{{ memberDetail(row.id).detail.productCode || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="英文名称">{{ memberDetail(row.id).detail.englishName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="生产周期">{{ memberDetail(row.id).detail.productionCycleHours ?? '-' }} 小时</el-descriptions-item>
|
||||
<el-descriptions-item label="净重">{{ memberDetail(row.id).detail.minWeightG ?? '-' }} g</el-descriptions-item>
|
||||
<el-descriptions-item label="生产工艺">{{ memberDetail(row.id).detail.productionProcess || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="材质">{{ memberDetail(row.id).detail.materialDescription || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="`尺码表 (${memberSizeRows(row.id).length})`">
|
||||
<el-table :data="memberSizeRows(row.id)" border size="small" max-height="240">
|
||||
<el-table-column prop="sizeName" label="尺码" width="100" fixed />
|
||||
<el-table-column
|
||||
v-for="column in memberSizeColumns(row.id)"
|
||||
:key="column.key"
|
||||
:prop="column.key"
|
||||
:label="`${column.name} (cm)`"
|
||||
min-width="110"
|
||||
/>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="`包装规格 (${memberPackageRows(row.id).length})`">
|
||||
<el-table :data="memberPackageRows(row.id)" border size="small" max-height="240">
|
||||
<el-table-column prop="sizeName" label="尺码" width="90" fixed />
|
||||
<el-table-column label="包装尺寸 (cm)" min-width="150">
|
||||
<template #default="{ row: pkg }">
|
||||
{{ pkg.dimensionsCm ? `${pkg.dimensionsCm.length}×${pkg.dimensionsCm.width}×${pkg.dimensionsCm.height}` : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="volumeCm3" label="体积 (cm³)" width="110" />
|
||||
<el-table-column prop="grossWeightG" label="含包装重量 (g)" width="140" />
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="`SKU (${memberVariants(row.id).length})`">
|
||||
<el-table :data="memberVariants(row.id)" border size="small" max-height="240">
|
||||
<el-table-column prop="sku" label="SKU" min-width="160" fixed />
|
||||
<el-table-column label="物流" width="100">
|
||||
<template #default>{{ memberDims(row.id).logistics || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="工艺" width="90">
|
||||
<template #default>{{ memberDims(row.id).crafts.join(' / ') || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="印花数量" width="95">
|
||||
<template #default>{{ memberDims(row.id).printCount || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sizeName" label="尺码" width="85" />
|
||||
<el-table-column prop="colorName" label="颜色" width="100" />
|
||||
<el-table-column prop="price" label="价格" width="90" />
|
||||
<el-table-column label="状态" width="80">
|
||||
<template #default="{ row: variant }">
|
||||
<el-tag :type="variant.enabled ? 'success' : 'info'" size="small">{{ variant.enabled ? '可用' : '停用' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="!editFamilyLoaded && editFamilyId" class="edit-family-loading">族成员加载中…</div>
|
||||
@@ -644,9 +731,10 @@ async function handleDeleteGood() {
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-tabs v-if="editOriginDetail" class="detail-tabs">
|
||||
<!-- 自定义商品内容编辑(SDS 商品的详情在「关联原产品」成员面板内查看) -->
|
||||
<el-tabs v-if="editIsCustom" class="detail-tabs">
|
||||
<el-tab-pane label="商品详情">
|
||||
<el-form v-if="editIsCustom" label-width="100px" class="custom-detail-form">
|
||||
<el-form label-width="100px" class="custom-detail-form">
|
||||
<el-form-item label="商品编码"><el-input v-model="customContentForm.productCode" /></el-form-item>
|
||||
<el-form-item label="英文名称"><el-input v-model="customContentForm.englishName" /></el-form-item>
|
||||
<el-form-item label="生产周期"><el-input-number v-model="customContentForm.productionCycleHours" :min="0" /><span style="margin-left:8px">小时</span></el-form-item>
|
||||
@@ -667,86 +755,35 @@ async function handleDeleteGood() {
|
||||
<el-form-item label="商品选项 JSON"><el-input v-model="customContentForm.optionsJson" type="textarea" :rows="6" /></el-form-item>
|
||||
<el-form-item label="媒体数据 JSON"><el-input v-model="customContentForm.mediaJson" type="textarea" :rows="6" /></el-form-item>
|
||||
</el-form>
|
||||
<el-descriptions v-else :column="2" border size="small">
|
||||
<el-descriptions-item label="商品编码">{{ editOriginDetail.productCode || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="英文名称">{{ editOriginDetail.englishName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="生产周期">{{ editOriginDetail.productionCycleHours ?? '-' }} 小时</el-descriptions-item>
|
||||
<el-descriptions-item label="净重">{{ editOriginDetail.minWeightG ?? '-' }} g</el-descriptions-item>
|
||||
<el-descriptions-item label="生产工艺">{{ editOriginDetail.productionProcess || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="材质">{{ editOriginDetail.materialDescription || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="`尺码表 (${editSizeRows.length})`">
|
||||
<el-input v-if="editIsCustom" v-model="customContentForm.sizeChartJson" type="textarea" :rows="14" placeholder="尺码表 JSON" />
|
||||
<el-table v-else :data="editSizeRows" border max-height="320">
|
||||
<el-table-column prop="sizeName" label="尺码" width="100" fixed />
|
||||
<el-table-column
|
||||
v-for="column in editSizeColumns"
|
||||
:key="column.key"
|
||||
:prop="column.key"
|
||||
:label="`${column.name} (cm)`"
|
||||
min-width="120"
|
||||
/>
|
||||
</el-table>
|
||||
<el-tab-pane label="尺码表">
|
||||
<el-input v-model="customContentForm.sizeChartJson" type="textarea" :rows="14" placeholder="尺码表 JSON" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="`包装规格 (${editPackageRows.length})`">
|
||||
<el-input v-if="editIsCustom" v-model="customContentForm.packageSpecsJson" type="textarea" :rows="14" placeholder="包装规格 JSON" />
|
||||
<el-table v-else :data="editPackageRows" border max-height="320">
|
||||
<el-table-column prop="sizeName" label="尺码" width="90" fixed />
|
||||
<el-table-column label="包装尺寸 (cm)" min-width="160">
|
||||
<template #default="{ row }">
|
||||
{{ row.dimensionsCm ? `${row.dimensionsCm.length}×${row.dimensionsCm.width}×${row.dimensionsCm.height}` : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="volumeCm3" label="体积 (cm³)" width="120" />
|
||||
<el-table-column prop="grossWeightG" label="含包装重量 (g)" width="150" />
|
||||
</el-table>
|
||||
<el-tab-pane label="包装规格">
|
||||
<el-input v-model="customContentForm.packageSpecsJson" type="textarea" :rows="14" placeholder="包装规格 JSON" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="`SKU (${editVariants.length})`">
|
||||
<template v-if="editIsCustom">
|
||||
<div style="display:flex;justify-content:flex-end;margin-bottom:8px"><el-button size="small" :icon="Plus" @click="addCustomVariant">添加 SKU</el-button></div>
|
||||
<el-table :data="customContentForm.variants" border max-height="320">
|
||||
<el-table-column label="SKU" min-width="160"><template #default="{ row }"><el-input v-model="row.sku" /></template></el-table-column>
|
||||
<el-table-column label="尺码 ID" width="120"><template #default="{ row }"><el-input v-model="row.sizeId" /></template></el-table-column>
|
||||
<el-table-column label="尺码" width="120"><template #default="{ row }"><el-input v-model="row.sizeName" /></template></el-table-column>
|
||||
<el-table-column label="颜色 ID" width="120"><template #default="{ row }"><el-input v-model="row.colorId" /></template></el-table-column>
|
||||
<el-table-column label="颜色" width="120"><template #default="{ row }"><el-input v-model="row.colorName" /></template></el-table-column>
|
||||
<el-table-column label="色值" width="120"><template #default="{ row }"><el-input v-model="row.colorHex" placeholder="#FFFFFF" /></template></el-table-column>
|
||||
<el-table-column label="图片" min-width="180"><template #default="{ row }"><el-input v-model="row.imageUrl" /></template></el-table-column>
|
||||
<el-table-column label="价格" width="120"><template #default="{ row }"><el-input v-model="row.price" /></template></el-table-column>
|
||||
<el-table-column label="原价" width="120"><template #default="{ row }"><el-input v-model="row.originalPrice" /></template></el-table-column>
|
||||
<el-table-column label="重量(g)" width="120"><template #default="{ row }"><el-input v-model="row.weightG" /></template></el-table-column>
|
||||
<el-table-column label="包装长(cm)" width="130"><template #default="{ row }"><el-input v-model="row.boxLengthCm" /></template></el-table-column>
|
||||
<el-table-column label="包装宽(cm)" width="130"><template #default="{ row }"><el-input v-model="row.boxWidthCm" /></template></el-table-column>
|
||||
<el-table-column label="包装高(cm)" width="130"><template #default="{ row }"><el-input v-model="row.boxHeightCm" /></template></el-table-column>
|
||||
<el-table-column label="设计数据 JSON" min-width="220"><template #default="{ row }"><el-input v-model="row.designDataJson" type="textarea" :rows="2" /></template></el-table-column>
|
||||
<el-table-column label="启用" width="80"><template #default="{ row }"><el-switch v-model="row.enabled" /></template></el-table-column>
|
||||
<el-table-column label="操作" width="70"><template #default="{ $index }"><el-button link type="danger" @click="customContentForm.variants.splice($index, 1)">删除</el-button></template></el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
<el-table v-else :data="editVariants" border max-height="320">
|
||||
<el-table-column prop="sku" label="SKU" min-width="170" fixed />
|
||||
<el-table-column label="物流" width="110">
|
||||
<template #default>{{ editLinkDims.logistics || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="工艺" width="100">
|
||||
<template #default>{{ editLinkDims.crafts.join(' / ') || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="印花数量" width="100">
|
||||
<template #default>{{ editLinkDims.printCount || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sizeName" label="尺码" width="90" />
|
||||
<el-table-column prop="colorName" label="颜色" width="100" />
|
||||
<el-table-column prop="price" label="价格" width="100" />
|
||||
<el-table-column label="状态" width="90">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.enabled ? 'success' : 'info'" size="small">{{ row.enabled ? '可用' : '停用' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-tab-pane :label="`SKU (${customContentForm.variants.length})`">
|
||||
<div style="display:flex;justify-content:flex-end;margin-bottom:8px"><el-button size="small" :icon="Plus" @click="addCustomVariant">添加 SKU</el-button></div>
|
||||
<el-table :data="customContentForm.variants" border max-height="320">
|
||||
<el-table-column label="SKU" min-width="160"><template #default="{ row }"><el-input v-model="row.sku" /></template></el-table-column>
|
||||
<el-table-column label="尺码 ID" width="120"><template #default="{ row }"><el-input v-model="row.sizeId" /></template></el-table-column>
|
||||
<el-table-column label="尺码" width="120"><template #default="{ row }"><el-input v-model="row.sizeName" /></template></el-table-column>
|
||||
<el-table-column label="颜色 ID" width="120"><template #default="{ row }"><el-input v-model="row.colorId" /></template></el-table-column>
|
||||
<el-table-column label="颜色" width="120"><template #default="{ row }"><el-input v-model="row.colorName" /></template></el-table-column>
|
||||
<el-table-column label="色值" width="120"><template #default="{ row }"><el-input v-model="row.colorHex" placeholder="#FFFFFF" /></template></el-table-column>
|
||||
<el-table-column label="图片" min-width="180"><template #default="{ row }"><el-input v-model="row.imageUrl" /></template></el-table-column>
|
||||
<el-table-column label="价格" width="120"><template #default="{ row }"><el-input v-model="row.price" /></template></el-table-column>
|
||||
<el-table-column label="原价" width="120"><template #default="{ row }"><el-input v-model="row.originalPrice" /></template></el-table-column>
|
||||
<el-table-column label="重量(g)" width="120"><template #default="{ row }"><el-input v-model="row.weightG" /></template></el-table-column>
|
||||
<el-table-column label="包装长(cm)" width="130"><template #default="{ row }"><el-input v-model="row.boxLengthCm" /></template></el-table-column>
|
||||
<el-table-column label="包装宽(cm)" width="130"><template #default="{ row }"><el-input v-model="row.boxWidthCm" /></template></el-table-column>
|
||||
<el-table-column label="包装高(cm)" width="130"><template #default="{ row }"><el-input v-model="row.boxHeightCm" /></template></el-table-column>
|
||||
<el-table-column label="设计数据 JSON" min-width="220"><template #default="{ row }"><el-input v-model="row.designDataJson" type="textarea" :rows="2" /></template></el-table-column>
|
||||
<el-table-column label="启用" width="80"><template #default="{ row }"><el-switch v-model="row.enabled" /></template></el-table-column>
|
||||
<el-table-column label="操作" width="70"><template #default="{ $index }"><el-button link type="danger" @click="customContentForm.variants.splice($index, 1)">删除</el-button></template></el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-empty v-else-if="!editDetailLoading" description="尚未同步商品详情" :image-size="60" />
|
||||
<template #footer>
|
||||
<el-button type="danger" @click="handleDeleteGood">删除</el-button>
|
||||
<el-button @click="emit('update:visible', false)">取消</el-button>
|
||||
@@ -800,6 +837,12 @@ async function handleDeleteGood() {
|
||||
.member-tags-edit .md-label { flex-shrink: 0; }
|
||||
.member-price-block { border-top: 1px dashed #e4e7ed; padding-top: 8px; }
|
||||
.member-price-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
|
||||
.member-extra { border-top: 1px dashed #e4e7ed; padding-top: 8px; }
|
||||
.md-empty {
|
||||
display: flex; align-items: center; justify-content: space-between; gap: 8px;
|
||||
font-size: 12px; color: var(--el-text-color-placeholder); padding: 4px 0;
|
||||
}
|
||||
.member-detail-tabs :deep(.el-tabs__header) { margin-bottom: 8px; }
|
||||
.edit-family-loading { color: var(--el-text-color-placeholder); font-size: 12px; padding: 4px 0; }
|
||||
.detail-tabs { margin-top: 12px; padding-top: 4px; border-top: 1px solid #ebeef5; }
|
||||
.select-inline { display: flex; align-items: center; gap: 6px; width: 100%; }
|
||||
|
||||
Reference in New Issue
Block a user