|
@@ -0,0 +1,270 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <el-drawer v-model="visible" title="产品详情" direction="rtl" size="1000px" :before-close="handleClose" destroy-on-close>
|
|
|
|
|
+ <div v-loading="loading" class="px-2">
|
|
|
|
|
+ <!-- 产品基础信息 -->
|
|
|
|
|
+ <div class="section-title">产品基础信息</div>
|
|
|
|
|
+
|
|
|
|
|
+ <el-descriptions :column="2" border class="mb-4">
|
|
|
|
|
+ <el-descriptions-item label="产品编号">{{ baseInfo?.productNo || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="产品名称">{{ baseInfo?.itemName || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="商品类型">
|
|
|
|
|
+ <el-tag v-if="(baseInfo as any)?.productCategory === 1" type="info">默认类型</el-tag>
|
|
|
|
|
+ <el-tag v-else-if="(baseInfo as any)?.productCategory === 2" type="success">精选商品</el-tag>
|
|
|
|
|
+ <el-tag v-else-if="(baseInfo as any)?.productCategory === 3" type="danger">停售商品</el-tag>
|
|
|
|
|
+ <span v-else>-</span>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="产品类别">
|
|
|
|
|
+ {{ [(baseInfo as any)?.topCategoryName, (baseInfo as any)?.mediumCategoryName, (baseInfo as any)?.bottomCategoryName].filter(Boolean).join(' / ') || '-' }}
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="品牌">{{ (baseInfo as any)?.brandName || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="单位">{{ (baseInfo as any)?.unitName || '-' }}</el-descriptions-item>
|
|
|
|
|
+ </el-descriptions>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 价格信息 -->
|
|
|
|
|
+ <div class="sub-title">价格信息</div>
|
|
|
|
|
+ <el-descriptions :column="3" border class="mb-4">
|
|
|
|
|
+ <el-descriptions-item label="市场价">
|
|
|
|
|
+ <span class="text-red-500">¥{{ baseInfo?.marketPrice ?? '-' }}</span>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="官网价">
|
|
|
|
|
+ <span class="text-red-500">¥{{ baseInfo?.memberPrice ?? '-' }}</span>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="最低销售价格">
|
|
|
|
|
+ <span class="text-red-500">¥{{ baseInfo?.minSellingPrice ?? '-' }}</span>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ </el-descriptions>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 采购信息 -->
|
|
|
|
|
+ <div class="sub-title">采购信息</div>
|
|
|
|
|
+ <el-descriptions :column="3" border class="mb-4">
|
|
|
|
|
+ <el-descriptions-item label="采购价格">
|
|
|
|
|
+ <span>¥{{ baseInfo?.purchasingPrice ?? '-' }}</span>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="暂估毛利率">
|
|
|
|
|
+ <span>{{ baseInfo?.tempGrossMargin != null ? baseInfo.tempGrossMargin + '%' : '-' }}</span>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="最高采购价">
|
|
|
|
|
+ <span>¥{{ (baseInfo as any)?.maxPurchasePrice ?? '-' }}</span>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ </el-descriptions>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 其他基础信息 -->
|
|
|
|
|
+ <el-descriptions :column="3" border class="mb-4">
|
|
|
|
|
+ <el-descriptions-item label="起订量">{{ baseInfo?.minOrderQuantity ?? '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="上下架状态">
|
|
|
|
|
+ <el-tag v-if="baseInfo?.productStatus === 1" type="success">已上架</el-tag>
|
|
|
|
|
+ <el-tag v-else-if="baseInfo?.productStatus === 0" type="warning">下架</el-tag>
|
|
|
|
|
+ <el-tag v-else-if="baseInfo?.productStatus === 2" type="info">上架中</el-tag>
|
|
|
|
|
+ <span v-else>-</span>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="主供应商">{{ (baseInfo as any)?.freightPrice ?? '-' }}</el-descriptions-item>
|
|
|
|
|
+ </el-descriptions>
|
|
|
|
|
+
|
|
|
|
|
+ <el-divider />
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 入池信息 -->
|
|
|
|
|
+ <div class="section-title">入池信息</div>
|
|
|
|
|
+ <el-descriptions :column="2" border class="mb-4">
|
|
|
|
|
+ <el-descriptions-item label="申请类型" :span="2">
|
|
|
|
|
+ <el-tag v-if="String(auditInfo?.type) === '0'" type="success">入池申请</el-tag>
|
|
|
|
|
+ <el-tag v-else-if="String(auditInfo?.type) === '1'" type="warning">出池申请</el-tag>
|
|
|
|
|
+ <span v-else>-</span>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="申请单号">{{ auditInfo?.name || auditInfo?.id || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="申请人">{{ auditInfo?.createByName || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="申请时间">{{ (auditInfo as any)?.createTime || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="备注" :span="2">{{ auditInfo?.remark || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="附件" :span="2">
|
|
|
|
|
+ <el-tag v-if="(auditInfo as any)?.attachment" type="success">已上传</el-tag>
|
|
|
|
|
+ <el-tag v-else type="info">暂无附件</el-tag>
|
|
|
|
|
+ </el-descriptions-item>
|
|
|
|
|
+ </el-descriptions>
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ <el-divider />
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 客户信息(协议池 type=2) -->
|
|
|
|
|
+ <template v-if="auditInfo && String(auditInfo.type) === '2'">
|
|
|
|
|
+ <div class="section-title">客户协议信息</div>
|
|
|
|
|
+ <el-descriptions :column="2" border class="mb-4" v-loading="extraLoading">
|
|
|
|
|
+ <el-descriptions-item label="客户编号">{{ customerInfo?.customerNo || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="客户名称">{{ customerInfo?.customerName || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="协议价格">{{ priceForm.agreementPrice || '-' }}</el-descriptions-item>
|
|
|
|
|
+ </el-descriptions>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 项目信息(项目池 type=3) -->
|
|
|
|
|
+ <template v-if="auditInfo && String(auditInfo.type) === '3'">
|
|
|
|
|
+ <div class="section-title">项目信息</div>
|
|
|
|
|
+ <el-descriptions :column="2" border class="mb-4" v-loading="extraLoading">
|
|
|
|
|
+ <el-descriptions-item label="项目名称">{{ itemInfo?.itemName || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="项目编号">{{ itemInfo?.itemKey || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="第三方价格">{{ priceForm.agreementPrice || '-' }}</el-descriptions-item>
|
|
|
|
|
+ </el-descriptions>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 营销产品池信息(营销池 type=4) -->
|
|
|
|
|
+ <template v-if="auditInfo && String(auditInfo.type) === '4'">
|
|
|
|
|
+ <div class="section-title">营销产品池信息</div>
|
|
|
|
|
+ <el-descriptions :column="2" border class="mb-4" v-loading="extraLoading">
|
|
|
|
|
+ <el-descriptions-item label="池编码">{{ poolInfo?.poolNo || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="池名称">{{ poolInfo?.name || '-' }}</el-descriptions-item>
|
|
|
|
|
+ <el-descriptions-item label="协议价格">{{ priceForm.agreementPrice || '-' }}</el-descriptions-item>
|
|
|
|
|
+ </el-descriptions>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <el-button @click="handleClose">关 闭</el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-drawer>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup lang="ts">
|
|
|
|
|
+import { getBase } from '@/api/product/base';
|
|
|
|
|
+import { getPoolAudit } from '@/api/product/poolAudit';
|
|
|
|
|
+import { getPoolLinkAudit } from '@/api/product/poolLinkAudit';
|
|
|
|
|
+import { getCustomerInfo } from '@/api/customer/customerInfo';
|
|
|
|
|
+import { getItem } from '@/api/external/item';
|
|
|
|
|
+import { getPool } from '@/api/product/pool';
|
|
|
|
|
+import { BaseVO } from '@/api/product/base/types';
|
|
|
|
|
+import { PoolAuditVO } from '@/api/product/poolAudit/types';
|
|
|
|
|
+import { PoolLinkAuditVO } from '@/api/product/poolLinkAudit/types';
|
|
|
|
|
+import { CustomerInfoVO } from '@/api/customer/customerInfo/types';
|
|
|
|
|
+import { ItemVO } from '@/api/external/item/types';
|
|
|
|
|
+import { PoolVO } from '@/api/product/pool/types';
|
|
|
|
|
+
|
|
|
|
|
+interface Props {
|
|
|
|
|
+ modelValue: boolean;
|
|
|
|
|
+ id?: string | number;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const props = withDefaults(defineProps<Props>(), {
|
|
|
|
|
+ modelValue: false
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const emit = defineEmits<{
|
|
|
|
|
+ (e: 'update:modelValue', val: boolean): void;
|
|
|
|
|
+}>();
|
|
|
|
|
+
|
|
|
|
|
+const visible = computed({
|
|
|
|
|
+ get: () => props.modelValue,
|
|
|
|
|
+ set: (val) => emit('update:modelValue', val)
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const loading = ref(false);
|
|
|
|
|
+const extraLoading = ref(false);
|
|
|
|
|
+const linkInfo = ref<PoolLinkAuditVO | null>(null);
|
|
|
|
|
+const baseInfo = ref<BaseVO | null>(null);
|
|
|
|
|
+const auditInfo = ref<PoolAuditVO | null>(null);
|
|
|
|
|
+const customerInfo = ref<CustomerInfoVO | null>(null);
|
|
|
|
|
+const itemInfo = ref<ItemVO | null>(null);
|
|
|
|
|
+const poolInfo = ref<PoolVO | null>(null);
|
|
|
|
|
+
|
|
|
|
|
+const priceForm = reactive({
|
|
|
|
|
+ discountRate: undefined as number | undefined,
|
|
|
|
|
+ agreementPrice: undefined as number | undefined
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+/** 根据池类型加载对应详情 */
|
|
|
|
|
+const loadExtraInfo = async (type: string, auditData: PoolAuditVO) => {
|
|
|
|
|
+ extraLoading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (type === '2' && auditData.customerId) {
|
|
|
|
|
+ // 协议池 → 查询客户信息
|
|
|
|
|
+ const res = await getCustomerInfo(auditData.customerId);
|
|
|
|
|
+ customerInfo.value = res.data || null;
|
|
|
|
|
+ } else if (type === '3' && auditData.itemId) {
|
|
|
|
|
+ // 项目池 → 查询项目信息
|
|
|
|
|
+ const res = await getItem(auditData.itemId);
|
|
|
|
|
+ itemInfo.value = res.data || null;
|
|
|
|
|
+ } else if (type === '4' && auditData.poolId) {
|
|
|
|
|
+ // 营销池 → 查询产品池信息
|
|
|
|
|
+ const res = await getPool(auditData.poolId);
|
|
|
|
|
+ poolInfo.value = res.data || null;
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('加载附加信息失败:', error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ extraLoading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 加载数据:先查关联审核,再并行查商品基础信息和入池单信息 */
|
|
|
|
|
+const loadData = async () => {
|
|
|
|
|
+ if (!props.id) return;
|
|
|
|
|
+ loading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ // Step 1: 查询关联审核记录,获取 productId 和 poolAuditId
|
|
|
|
|
+ const linkRes = await getPoolLinkAudit(props.id);
|
|
|
|
|
+ linkInfo.value = linkRes.data || null;
|
|
|
|
|
+
|
|
|
|
|
+ if (!linkInfo.value) return;
|
|
|
|
|
+
|
|
|
|
|
+ const { productId, poolAuditId, negotiatedPrice } = linkInfo.value;
|
|
|
|
|
+
|
|
|
|
|
+ // Step 2: 并行查商品基础信息和入池单信息
|
|
|
|
|
+ const [baseRes, auditRes] = await Promise.all([
|
|
|
|
|
+ getBase(productId),
|
|
|
|
|
+ poolAuditId ? getPoolAudit(poolAuditId) : Promise.resolve({ data: null })
|
|
|
|
|
+ ]);
|
|
|
|
|
+ baseInfo.value = baseRes.data || null;
|
|
|
|
|
+ auditInfo.value = (auditRes as any)?.data || null;
|
|
|
|
|
+
|
|
|
|
|
+ // 初始化协议价格
|
|
|
|
|
+ priceForm.agreementPrice = negotiatedPrice ?? undefined;
|
|
|
|
|
+ if (priceForm.agreementPrice && baseInfo.value?.memberPrice) {
|
|
|
|
|
+ priceForm.discountRate = Number(((priceForm.agreementPrice / baseInfo.value.memberPrice) * 100).toFixed(2));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Step 3: 根据池类型加载对应的附加信息
|
|
|
|
|
+ if (auditInfo.value?.type) {
|
|
|
|
|
+ await loadExtraInfo(String(auditInfo.value.type), auditInfo.value);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('加载产品详情失败:', error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleClose = () => {
|
|
|
|
|
+ visible.value = false;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+watch(
|
|
|
|
|
+ () => props.modelValue,
|
|
|
|
|
+ (val) => {
|
|
|
|
|
+ if (val) {
|
|
|
|
|
+ linkInfo.value = null;
|
|
|
|
|
+ baseInfo.value = null;
|
|
|
|
|
+ auditInfo.value = null;
|
|
|
|
|
+ customerInfo.value = null;
|
|
|
|
|
+ itemInfo.value = null;
|
|
|
|
|
+ poolInfo.value = null;
|
|
|
|
|
+ priceForm.discountRate = undefined;
|
|
|
|
|
+ priceForm.agreementPrice = undefined;
|
|
|
|
|
+ loadData();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+);
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
|
+.section-title {
|
|
|
|
|
+ font-size: 15px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #303133;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ padding-left: 8px;
|
|
|
|
|
+ border-left: 3px solid var(--el-color-primary);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.sub-title {
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+ padding-left: 6px;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|