|
|
@@ -213,6 +213,7 @@
|
|
|
placeholder="请输入UPC(69)条码"
|
|
|
maxlength="20"
|
|
|
show-word-limit
|
|
|
+ @input="handleUpcInput"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
@@ -245,16 +246,23 @@
|
|
|
<!-- 商品品牌 -->
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="商品品牌:" prop="brandId" required>
|
|
|
- <el-select-v2
|
|
|
+ <el-select
|
|
|
v-model="productForm.brandId"
|
|
|
- :options="brandOptionsFormatted"
|
|
|
- placeholder="请选择商品品牌"
|
|
|
- clearable
|
|
|
+ placeholder="请输入品牌名称搜索"
|
|
|
filterable
|
|
|
- class="w-full"
|
|
|
+ remote
|
|
|
+ clearable
|
|
|
+ :remote-method="handleBrandSearch"
|
|
|
:loading="brandLoading"
|
|
|
- @visible-change="handleBrandVisibleChange"
|
|
|
- />
|
|
|
+ class="w-full"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in brandOptions"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.brandName"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
|
|
|
@@ -277,7 +285,14 @@
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="税率:" required>
|
|
|
- <el-input v-model="productForm.taxRate" placeholder="请输入商品税率" type="number" />
|
|
|
+ <el-select v-model="productForm.taxRate" placeholder="请选择税率" clearable class="w-full">
|
|
|
+ <el-option
|
|
|
+ v-for="option in taxRateOptions"
|
|
|
+ :key="option.id"
|
|
|
+ :label="option.taxrateName"
|
|
|
+ :value="option.taxrate"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
@@ -367,12 +382,15 @@
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
|
|
|
- <!-- 主库简介 -->
|
|
|
+ <!-- 主供应商 -->
|
|
|
<el-form-item label="主供应商:" prop="mainLibraryIntro" required>
|
|
|
- <el-select v-model="productForm.mainLibraryIntro" placeholder="请选择" clearable class="w-full">
|
|
|
- <el-option label="选项1" value="1" />
|
|
|
- <el-option label="选项2" value="2" />
|
|
|
- <el-option label="选项3" value="3" />
|
|
|
+ <el-select v-model="productForm.mainLibraryIntro" placeholder="请选择" clearable class="w-full" value-key="id">
|
|
|
+ <el-option
|
|
|
+ v-for="option in supplierOptions"
|
|
|
+ :key="option.id"
|
|
|
+ :label="`${option.supplierNo},${option.enterpriseName}`"
|
|
|
+ :value="String(option.id)"
|
|
|
+ />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
|
|
|
@@ -415,7 +433,7 @@
|
|
|
<span class="text-lg font-bold">销售价格</span>
|
|
|
</template>
|
|
|
|
|
|
- <el-form ref="priceFormRef" :model="productForm" label-width="120px" class="product-info-form">
|
|
|
+ <el-form ref="priceFormRef" :model="productForm" :rules="productRules" label-width="120px" class="product-info-form">
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="8">
|
|
|
<el-form-item label="市场价:" prop="midRangePrice" required>
|
|
|
@@ -423,6 +441,7 @@
|
|
|
v-model="productForm.midRangePrice"
|
|
|
type="number"
|
|
|
placeholder="请输入市场价"
|
|
|
+ @blur="formatPrice('midRangePrice')"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
@@ -432,6 +451,7 @@
|
|
|
v-model="productForm.standardPrice"
|
|
|
type="number"
|
|
|
placeholder="请输入平台售价"
|
|
|
+ @blur="formatPrice('standardPrice')"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
@@ -441,6 +461,7 @@
|
|
|
v-model="productForm.certificatePrice"
|
|
|
type="number"
|
|
|
placeholder="请输入最低售价"
|
|
|
+ @blur="formatPrice('certificatePrice')"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
@@ -471,7 +492,7 @@
|
|
|
<span class="text-lg font-bold">采购价格</span>
|
|
|
</template>
|
|
|
|
|
|
- <el-form ref="purchasePriceFormRef" :model="productForm" label-width="120px" class="product-info-form">
|
|
|
+ <el-form ref="purchasePriceFormRef" :model="productForm" :rules="productRules" label-width="120px" class="product-info-form">
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="采购价:" prop="purchasePrice" required>
|
|
|
@@ -479,6 +500,7 @@
|
|
|
v-model="productForm.purchasePrice"
|
|
|
type="number"
|
|
|
placeholder="请输入采购价"
|
|
|
+ @blur="formatPrice('purchasePrice')"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
@@ -488,6 +510,7 @@
|
|
|
v-model="productForm.estimatedPurchasePrice"
|
|
|
type="number"
|
|
|
placeholder="请输入暂估采购价"
|
|
|
+ @blur="formatPrice('estimatedPurchasePrice')"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
@@ -501,23 +524,29 @@
|
|
|
<span class="text-lg font-bold">采购信息</span>
|
|
|
</template>
|
|
|
|
|
|
- <el-form ref="purchaseInfoFormRef" :model="productForm" label-width="120px" class="product-info-form">
|
|
|
+ <el-form ref="purchaseInfoFormRef" :model="productForm" :rules="productRules" label-width="120px" class="product-info-form">
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
|
- <el-form-item label="产品性质:" prop="productNature" required>
|
|
|
- <el-select v-model="productForm.productNature" placeholder="请选择" clearable class="w-full">
|
|
|
- <el-option label="自营" value="1" />
|
|
|
- <el-option label="代销" value="2" />
|
|
|
- <el-option label="定制" value="3" />
|
|
|
+ <el-form-item label="产品经理:" prop="productNature" required>
|
|
|
+ <el-select v-model="productForm.productNature" placeholder="请选择" clearable class="w-full" value-key="staffId">
|
|
|
+ <el-option
|
|
|
+ v-for="option in staffOptions"
|
|
|
+ :key="option.staffId"
|
|
|
+ :label="`${option.staffCode},${option.staffName}`"
|
|
|
+ :value="String(option.staffId)"
|
|
|
+ />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="采购人员:" prop="purchasingPersonnel" required>
|
|
|
- <el-select v-model="productForm.purchasingPersonnel" placeholder="请选择" clearable class="w-full">
|
|
|
- <el-option label="采购员1" value="1" />
|
|
|
- <el-option label="采购员2" value="2" />
|
|
|
- <el-option label="采购员3" value="3" />
|
|
|
+ <el-select v-model="productForm.purchasingPersonnel" placeholder="请选择" clearable class="w-full" value-key="staffId">
|
|
|
+ <el-option
|
|
|
+ v-for="option in staffOptions"
|
|
|
+ :key="option.staffId"
|
|
|
+ :label="`${option.staffCode},${option.staffName}`"
|
|
|
+ :value="String(option.staffId)"
|
|
|
+ />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
@@ -616,6 +645,27 @@
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
+ <!-- 商品轮播图 -->
|
|
|
+ <el-form-item label="商品轮播图:">
|
|
|
+ <div class="carousel-images-container">
|
|
|
+ <div class="carousel-image-list">
|
|
|
+ <div v-for="(imgUrl, index) in carouselImages" :key="index" class="carousel-image-item">
|
|
|
+ <img :src="imgUrl" class="carousel-preview-image" />
|
|
|
+ <div class="carousel-image-actions">
|
|
|
+ <el-button size="small" type="danger" @click="removeCarouselImage(index)">删除</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="image-upload-placeholder carousel-add-btn" @click="openCarouselImageSelector">
|
|
|
+ <el-icon class="upload-icon"><Plus /></el-icon>
|
|
|
+ <div class="upload-text">添加图片</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="form-item-tip">
|
|
|
+ 从图片库选择,支持多选,建议尺寸300*300px
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
<!-- 商品详情 -->
|
|
|
<el-form-item label="商品详情:">
|
|
|
<el-tabs v-model="activeDetailTab" type="border-card">
|
|
|
@@ -764,6 +814,14 @@
|
|
|
title="选择商品主图"
|
|
|
@confirm="handleMainImageSelected"
|
|
|
/>
|
|
|
+ <!-- 轮播图文件选择器 -->
|
|
|
+ <FileSelector
|
|
|
+ v-model="carouselImageSelectorVisible"
|
|
|
+ :allowed-types="[1]"
|
|
|
+ :multiple="true"
|
|
|
+ title="选择商品轮播图"
|
|
|
+ @confirm="handleCarouselImagesSelected"
|
|
|
+ />
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
@@ -774,11 +832,16 @@ import { ElMessage } from 'element-plus';
|
|
|
import { Warning, ArrowRight, Check, Plus, CircleCheck } from '@element-plus/icons-vue';
|
|
|
import Editor from '@/components/Editor/index.vue';
|
|
|
import FileSelector from '@/components/FileSelector/index.vue';
|
|
|
-import { categoryTreeVO } from '@/api/pmsProduct/category/types';
|
|
|
-import { BrandVO } from '@/api/pmsProduct/brand/types';
|
|
|
-import { BaseForm } from '@/api/pmsProduct/base/types';
|
|
|
-import { AttributesVO } from '@/api/pmsProduct/attributes/types';
|
|
|
-import { addBase, updateBase, getBase, brandList, categoryTree, categoryAttributeList, getAfterSaleList, getServiceList, getUnitList } from '@/api/pmsProduct/base';
|
|
|
+import { categoryTreeVO } from '@/api/product/category/types';
|
|
|
+import { BrandVO } from '@/api/product/brand/types';
|
|
|
+import { BaseForm } from '@/api/product/base/types';
|
|
|
+import { AttributesVO } from '@/api/product/attributes/types';
|
|
|
+import { addBase, updateBase, getBase, categoryTree, categoryAttributeList, getAfterSaleList, getServiceList, getUnitList, getTaxRateList } from '@/api/product/base/index';
|
|
|
+import { listBrand } from '@/api/product/brand';
|
|
|
+import { listInfo } from '@/api/customer/supplierInfo';
|
|
|
+import { InfoVO } from '@/api/customer/supplierInfo/types';
|
|
|
+import { listComStaff } from '@/api/system/comStaff';
|
|
|
+import { ComStaffVO } from '@/api/system/comStaff/types';
|
|
|
|
|
|
const route = useRoute();
|
|
|
const router = useRouter();
|
|
|
@@ -797,6 +860,13 @@ const activeDetailTab = ref('pc');
|
|
|
|
|
|
// 文件选择器相关
|
|
|
const mainImageSelectorVisible = ref(false);
|
|
|
+const carouselImageSelectorVisible = ref(false);
|
|
|
+
|
|
|
+// 轮播图URL数组(UI管理用)
|
|
|
+const carouselImages = ref<string[]>([]);
|
|
|
+
|
|
|
+// 税率选项
|
|
|
+const taxRateOptions = ref<any[]>([]);
|
|
|
|
|
|
// 定制说明表单
|
|
|
const customForm = reactive({
|
|
|
@@ -933,6 +1003,7 @@ const productForm = reactive<BaseForm>({
|
|
|
bottomCategoryId: undefined,
|
|
|
unitId: undefined,
|
|
|
productImage: undefined,
|
|
|
+ imageUrl: undefined,
|
|
|
isSelf: 0,
|
|
|
productReviewStatus: 0,
|
|
|
homeRecommended: 0,
|
|
|
@@ -954,7 +1025,7 @@ const productForm = reactive<BaseForm>({
|
|
|
weightUnit: 'kg',
|
|
|
volume: undefined,
|
|
|
volumeUnit: 'm3',
|
|
|
- mainLibraryIntro: '1',
|
|
|
+ mainLibraryIntro: undefined,
|
|
|
afterSalesService: undefined,
|
|
|
serviceGuarantee: undefined, // 服务保障ID列表,逗号分隔
|
|
|
freeInstallation: '0',
|
|
|
@@ -975,30 +1046,25 @@ const productForm = reactive<BaseForm>({
|
|
|
|
|
|
// 表单验证规则
|
|
|
const productRules = {
|
|
|
- productNo: [{ required: true, message: '请输入商品编号', trigger: 'blur' }],
|
|
|
- itemName: [{ required: true, message: '请输入商品名称', trigger: 'blur' }],
|
|
|
- brandId: [{ required: true, message: '请选择商品品牌', trigger: 'change' }],
|
|
|
- mainLibraryIntro: [{ required: true, message: '请选择主库简介', trigger: 'change' }],
|
|
|
- midRangePrice: [{ required: true, message: '请输入市场价', trigger: 'blur' }],
|
|
|
- standardPrice: [{ required: true, message: '请输入平档价', trigger: 'blur' }],
|
|
|
- certificatePrice: [{ required: true, message: '请输入最低售价', trigger: 'blur' }],
|
|
|
- purchasePrice: [{ required: true, message: '请输入采购价', trigger: 'blur' }],
|
|
|
- productNature: [{ required: true, message: '请选择产品性质', trigger: 'change' }],
|
|
|
- purchasingPersonnel: [{ required: true, message: '请选择采购人员', trigger: 'change' }],
|
|
|
- taxRate: [{ required: true, message: '请输入税率', trigger: 'blur' }],
|
|
|
- minOrderQuantity: [{ required: true, message: '请输入最低起订量', trigger: 'blur' }],
|
|
|
+ productNo: [{ required: true, message: '商品编号不能为空', trigger: 'blur' }],
|
|
|
+ itemName: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }],
|
|
|
+ brandId: [{ required: true, message: '商品品牌不能为空', trigger: 'change' }],
|
|
|
+ mainLibraryIntro: [{ required: true, message: '主供应商不能为空', trigger: 'change' }],
|
|
|
+ midRangePrice: [{ required: true, message: '市场价不能为空', trigger: 'blur' }],
|
|
|
+ standardPrice: [{ required: true, message: '平台售价不能为空', trigger: 'blur' }],
|
|
|
+ certificatePrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
|
|
|
+ purchasePrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
|
|
|
+ productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
|
|
|
+ purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
|
|
|
+ taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
|
|
|
+ minOrderQuantity: [{ required: true, message: '最低起订量不能为空', trigger: 'blur' }],
|
|
|
};
|
|
|
|
|
|
// 分类和品牌选项
|
|
|
const categoryOptions = ref<categoryTreeVO[]>([]);
|
|
|
const brandOptions = ref<BrandVO[]>([]);
|
|
|
const brandLoading = ref(false);
|
|
|
-const brandOptionsFormatted = computed(() => {
|
|
|
- return brandOptions.value.slice(0, 500).map(item => ({
|
|
|
- label: item.brandName,
|
|
|
- value: item.id
|
|
|
- }));
|
|
|
-});
|
|
|
+let brandSearchTimer: ReturnType<typeof setTimeout> | null = null;
|
|
|
|
|
|
// 商品属性列表
|
|
|
const attributesList = ref<AttributesVO[]>([]);
|
|
|
@@ -1011,6 +1077,12 @@ const serviceGuaranteeOptions = ref<any[]>([]);
|
|
|
// 单位选项
|
|
|
const unitOptions = ref<any[]>([]);
|
|
|
|
|
|
+// 主供应商选项
|
|
|
+const supplierOptions = ref<InfoVO[]>([]);
|
|
|
+
|
|
|
+// 采购人员选项
|
|
|
+const staffOptions = ref<ComStaffVO[]>([]);
|
|
|
+
|
|
|
// 搜索关键词
|
|
|
const searchLevel1 = ref('');
|
|
|
const searchLevel2 = ref('');
|
|
|
@@ -1138,7 +1210,7 @@ const nextStep = async () => {
|
|
|
productForm.topCategoryId = categoryForm.topCategoryId;
|
|
|
productForm.mediumCategoryId = categoryForm.mediumCategoryId;
|
|
|
productForm.bottomCategoryId = categoryForm.bottomCategoryId;
|
|
|
-
|
|
|
+
|
|
|
currentStep.value++;
|
|
|
} else if (currentStep.value === 1) {
|
|
|
// 验证商品信息表单并提交
|
|
|
@@ -1170,6 +1242,8 @@ const handleSubmit = async () => {
|
|
|
...productForm,
|
|
|
// 将服务保障ID数组转换为逗号分隔字符串
|
|
|
serviceGuarantee: serviceGuarantees.value.map(id => String(id)).join(','),
|
|
|
+ // 轮播图URL逗号分隔
|
|
|
+ imageUrl: carouselImages.value.join(','),
|
|
|
// 将商品属性值转换为JSON字符串
|
|
|
attributesList: JSON.stringify(productAttributesValues.value),
|
|
|
customizable: customForm.customizable,
|
|
|
@@ -1222,6 +1296,45 @@ const clearMainImage = () => {
|
|
|
productForm.productImage = undefined;
|
|
|
};
|
|
|
|
|
|
+// 打开轮播图选择器
|
|
|
+const openCarouselImageSelector = () => {
|
|
|
+ carouselImageSelectorVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+// 处理轮播图选择(多选)
|
|
|
+const handleCarouselImagesSelected = (files: any[]) => {
|
|
|
+ if (files && files.length > 0) {
|
|
|
+ files.forEach(file => {
|
|
|
+ if (!carouselImages.value.includes(file.url)) {
|
|
|
+ carouselImages.value.push(file.url);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 删除轮播图
|
|
|
+const removeCarouselImage = (index: number) => {
|
|
|
+ carouselImages.value.splice(index, 1);
|
|
|
+};
|
|
|
+
|
|
|
+// UPC(69)条码只允许输入数字
|
|
|
+const handleUpcInput = () => {
|
|
|
+ if (productForm.upcBarcode) {
|
|
|
+ productForm.upcBarcode = productForm.upcBarcode.replace(/\D/g, '');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 格式化价格为两位小数
|
|
|
+const formatPrice = (field: string) => {
|
|
|
+ const val = (productForm as any)[field];
|
|
|
+ if (val !== undefined && val !== null && val !== '') {
|
|
|
+ const num = parseFloat(String(val));
|
|
|
+ if (!isNaN(num)) {
|
|
|
+ (productForm as any)[field] = parseFloat(num.toFixed(2));
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
// 获取分类树
|
|
|
const getCategoryTree = async () => {
|
|
|
try {
|
|
|
@@ -1232,27 +1345,31 @@ const getCategoryTree = async () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// 获取品牌列表(实时请求,每次只加载500条)
|
|
|
-const getBrandList = async () => {
|
|
|
+// 加载品牌选项(默认100条)
|
|
|
+const loadBrandOptions = async (keyword?: string) => {
|
|
|
+ brandLoading.value = true;
|
|
|
try {
|
|
|
- brandLoading.value = true;
|
|
|
- const res = await brandList({ pageNum: 1, pageSize: 500 });
|
|
|
- brandOptions.value = res.data || [];
|
|
|
- // 如果是新增模式且有选项,设置第一个为默认值
|
|
|
- if (!route.params.id && brandOptions.value.length > 0 && !productForm.brandId) {
|
|
|
- productForm.brandId = brandOptions.value[0].id;
|
|
|
- }
|
|
|
+ const res = await listBrand({ pageNum: 1, pageSize: 100, brandName: keyword });
|
|
|
+ brandOptions.value = res.rows || [];
|
|
|
} catch (error) {
|
|
|
- console.error('获取品牌列表失败:', error);
|
|
|
+ console.error('加载品牌列表失败:', error);
|
|
|
} finally {
|
|
|
brandLoading.value = false;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+// 品牌远程搜索(防抖)
|
|
|
+const handleBrandSearch = (query: string) => {
|
|
|
+ if (brandSearchTimer) clearTimeout(brandSearchTimer);
|
|
|
+ brandSearchTimer = setTimeout(() => {
|
|
|
+ loadBrandOptions(query || undefined);
|
|
|
+ }, 300);
|
|
|
+};
|
|
|
+
|
|
|
// 处理品牌下拉框显示/隐藏
|
|
|
const handleBrandVisibleChange = (visible: boolean) => {
|
|
|
if (visible && brandOptions.value.length === 0) {
|
|
|
- getBrandList();
|
|
|
+ loadBrandOptions();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
@@ -1298,6 +1415,52 @@ const getUnitOptions = async () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+// 获取主供应商列表
|
|
|
+const getSupplierOptions = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listInfo();
|
|
|
+ console.log('供应商接口返回:', res);
|
|
|
+ // 处理可能的数据结构: res.data 或 res.rows
|
|
|
+ const dataList = res.data || res.rows || [];
|
|
|
+ supplierOptions.value = dataList;
|
|
|
+ console.log('供应商列表:', supplierOptions.value);
|
|
|
+ // 如果有选项且当前没有选中值,设置第一个为默认值
|
|
|
+ if (supplierOptions.value.length > 0 && !productForm.mainLibraryIntro) {
|
|
|
+ productForm.mainLibraryIntro = String(supplierOptions.value[0].id);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取主供应商列表失败:', error);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 获取采购人员列表
|
|
|
+const getStaffOptions = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listComStaff();
|
|
|
+ console.log('采购人员接口返回:', res);
|
|
|
+ // 处理可能的数据结构: res.data 或 res.rows
|
|
|
+ const dataList = res.data || res.rows || [];
|
|
|
+ staffOptions.value = dataList;
|
|
|
+ console.log('采购人员列表:', staffOptions.value);
|
|
|
+ // 如果有选项且当前没有选中值,设置第一个为默认值
|
|
|
+ if (staffOptions.value.length > 0 && !productForm.purchasingPersonnel) {
|
|
|
+ productForm.purchasingPersonnel = String(staffOptions.value[0].staffId);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取采购人员列表失败:', error);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 获取税率列表
|
|
|
+const getTaxRateOptions = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getTaxRateList();
|
|
|
+ taxRateOptions.value = res.rows || [];
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取税率列表失败:', error);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
// 加载分类属性列表
|
|
|
const loadCategoryAttributes = async (categoryId: string | number) => {
|
|
|
try {
|
|
|
@@ -1355,6 +1518,13 @@ const loadProductDetail = async () => {
|
|
|
const res = await getBase(id as string);
|
|
|
Object.assign(productForm, res.data);
|
|
|
|
|
|
+ // 回显轮播图
|
|
|
+ if (res.data.imageUrl) {
|
|
|
+ carouselImages.value = res.data.imageUrl.split(',').filter((url: string) => url.trim());
|
|
|
+ } else {
|
|
|
+ carouselImages.value = [];
|
|
|
+ }
|
|
|
+
|
|
|
// 回显分类选择
|
|
|
categoryForm.topCategoryId = res.data.topCategoryId;
|
|
|
categoryForm.mediumCategoryId = res.data.mediumCategoryId;
|
|
|
@@ -1422,7 +1592,13 @@ onMounted(async () => {
|
|
|
await getUnitOptions();
|
|
|
await getAfterSalesOptions();
|
|
|
await getServiceGuaranteeOptions();
|
|
|
+ await getTaxRateOptions();
|
|
|
+ // 先加载商品详情(如果是编辑模式)
|
|
|
await loadProductDetail();
|
|
|
+ // 再加载下拉选项,这样如果详情中没有值,会自动设置第一个
|
|
|
+ await getSupplierOptions();
|
|
|
+ await getStaffOptions();
|
|
|
+ loadBrandOptions();
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
@@ -1515,7 +1691,7 @@ onMounted(async () => {
|
|
|
|
|
|
.image-preview {
|
|
|
position: relative;
|
|
|
-
|
|
|
+
|
|
|
.preview-image {
|
|
|
width: 178px;
|
|
|
height: 178px;
|
|
|
@@ -1531,35 +1707,35 @@ onMounted(async () => {
|
|
|
gap: 8px;
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- .image-upload-placeholder {
|
|
|
- width: 178px;
|
|
|
- height: 178px;
|
|
|
- border: 1px dashed #d9d9d9;
|
|
|
- border-radius: 6px;
|
|
|
- cursor: pointer;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- transition: all 0.3s;
|
|
|
- background-color: #fafafa;
|
|
|
+ .image-upload-placeholder {
|
|
|
+ width: 178px;
|
|
|
+ height: 178px;
|
|
|
+ border: 1px dashed #d9d9d9;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ transition: all 0.3s;
|
|
|
+ background-color: #fafafa;
|
|
|
|
|
|
- &:hover {
|
|
|
- border-color: #409eff;
|
|
|
- background-color: #f5f7fa;
|
|
|
- }
|
|
|
+ &:hover {
|
|
|
+ border-color: #409eff;
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ }
|
|
|
|
|
|
- .upload-icon {
|
|
|
- font-size: 28px;
|
|
|
- color: #8c939d;
|
|
|
- margin-bottom: 8px;
|
|
|
- }
|
|
|
+ .upload-icon {
|
|
|
+ font-size: 28px;
|
|
|
+ color: #8c939d;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
|
|
|
- .upload-text {
|
|
|
- color: #8c939d;
|
|
|
- font-size: 14px;
|
|
|
- }
|
|
|
+ .upload-text {
|
|
|
+ color: #8c939d;
|
|
|
+ font-size: 14px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1569,6 +1745,40 @@ onMounted(async () => {
|
|
|
flex-wrap: wrap;
|
|
|
}
|
|
|
|
|
|
+ .carousel-images-container {
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ .carousel-image-list {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 10px;
|
|
|
+
|
|
|
+ .carousel-image-item {
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ .carousel-preview-image {
|
|
|
+ width: 120px;
|
|
|
+ height: 120px;
|
|
|
+ display: block;
|
|
|
+ object-fit: cover;
|
|
|
+ border-radius: 6px;
|
|
|
+ border: 1px solid #dcdfe6;
|
|
|
+ }
|
|
|
+
|
|
|
+ .carousel-image-actions {
|
|
|
+ margin-top: 6px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .carousel-add-btn {
|
|
|
+ width: 120px;
|
|
|
+ height: 120px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
.custom-table {
|
|
|
width: 100%;
|
|
|
margin-top: 10px;
|