refactor(admin): split GoodsView into dialog components; fix(GoodsView): raw member names, no primary badges, member price grid; feat(tag): 光板 maps to 不打印

This commit is contained in:
yeuimu
2026-08-28 16:40:48 +08:00
parent 34d84a7a7c
commit 10197c47a8
14 changed files with 1719 additions and 1441 deletions
@@ -0,0 +1,123 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import type { CategoryTree, Country, Tag } from '@/types'
import { goodsApi } from '@/api/goods'
import { countriesApi } from '@/api/countries'
import { buildCascader } from '@/utils/category-tree'
const props = defineProps<{
visible: boolean
countries: Country[]
categories: CategoryTree[]
/** 分组后的标签选项 {id,label,tags} */
tagOptionGroups: Array<{ id: string; label: string; tags: Tag[] }>
}>()
const emit = defineEmits<{
(e: 'update:visible', v: boolean): void
(e: 'created', good: any): void
/** 快捷新建国家后由父级刷新字典 */
(e: 'dictionaries-changed'): void
}>()
const loading = ref(false)
const form = ref({
goodName: '', goodImage: '', goodPrice: '', countryId: '',
cascaderCategory: [] as string[], categoryId: '', tagIds: [] as string[],
goodPriority: 0,
})
watch(() => props.visible, (v) => {
if (v) {
form.value = {
goodName: '', goodImage: '', goodPrice: '', countryId: '',
cascaderCategory: [], categoryId: '', tagIds: [], goodPriority: 0,
}
}
})
const categoryCascader = computed(() => buildCascader(props.categories))
function onCascaderChange(val: any) {
const path = Array.isArray(val) ? val : []
form.value.categoryId = path.length ? String(path[path.length - 1]) : ''
}
async function quickCreateCountry() {
try {
const { value } = await ElMessageBox.prompt('请输入国家名称', '新增国家', {
confirmButtonText: '新增', cancelButtonText: '取消', inputPlaceholder: '国家名称',
})
if (!value.trim()) return
const created = await countriesApi.createCountry({ countryName: value.trim() } as any)
emit('dictionaries-changed')
if (created?.id) form.value.countryId = created.id
ElMessage.success('已创建并选中')
} catch {}
}
async function handleSubmit() {
if (!form.value.goodName.trim()) { ElMessage.warning('请输入商品名称'); return }
if (!form.value.countryId) { ElMessage.warning('请选择国家'); return }
if (!form.value.categoryId) { ElMessage.warning('请选择分类'); return }
loading.value = true
try {
const created = await goodsApi.createCustomGood({
goodName: form.value.goodName.trim(),
goodImage: form.value.goodImage || undefined,
goodPrice: form.value.goodPrice || null,
countryId: Number(form.value.countryId),
categoryId: Number(form.value.categoryId),
tagIds: form.value.tagIds.map(Number),
goodPriority: form.value.goodPriority,
detail: {},
})
ElMessage.success('自定义商品已创建,可继续完善详情、尺码、包装和 SKU')
emit('update:visible', false)
emit('created', created)
} catch (error: any) {
ElMessage.error(error?.response?.data?.message || '自定义商品创建失败')
} finally { loading.value = false }
}
</script>
<template>
<el-dialog :model-value="visible" title="新增自定义商品" width="620px" destroy-on-close @update:model-value="emit('update:visible', $event)">
<el-alert
title="自定义商品不关联 SDS 原产品,名称、图片、价格、详情、尺码、包装和 SKU 均可维护。"
type="info"
:closable="false"
style="margin-bottom:16px"
/>
<el-form label-width="90px">
<el-form-item label="商品名称" required><el-input v-model="form.goodName" /></el-form-item>
<el-form-item label="商品图片"><ImageUpload v-model="form.goodImage" label="上传图片" /></el-form-item>
<el-form-item label="基础价格"><el-input v-model="form.goodPrice" placeholder="例如 28.00" /></el-form-item>
<el-form-item label="国家" required>
<div class="select-inline">
<el-select v-model="form.countryId" filterable placeholder="请选择国家" style="width:100%">
<el-option v-for="c in countries" :key="c.id" :label="c.countryName" :value="c.id" />
</el-select>
<el-button text :icon="Plus" @click="quickCreateCountry" />
</div>
</el-form-item>
<el-form-item label="分类" required>
<el-cascader v-model="form.cascaderCategory" :options="categoryCascader as any" :props="{ checkStrictly: true }" placeholder="请选择分类" style="width:100%" @change="onCascaderChange" />
</el-form-item>
<el-form-item label="标签">
<el-select v-model="form.tagIds" multiple filterable placeholder="请选择标签" style="width:100%">
<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-form-item>
<el-form-item label="优先级"><el-input-number v-model="form.goodPriority" :min="0" /></el-form-item>
</el-form>
<template #footer>
<el-button @click="emit('update:visible', false)">取消</el-button>
<el-button type="primary" :loading="loading" @click="handleSubmit">创建并完善详情</el-button>
</template>
</el-dialog>
</template>