|
@@ -213,6 +213,7 @@
|
|
|
placeholder="请输入UPC(69)条码"
|
|
placeholder="请输入UPC(69)条码"
|
|
|
maxlength="20"
|
|
maxlength="20"
|
|
|
show-word-limit
|
|
show-word-limit
|
|
|
|
|
+ @input="handleUpcInput"
|
|
|
/>
|
|
/>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
@@ -245,16 +246,23 @@
|
|
|
<!-- 商品品牌 -->
|
|
<!-- 商品品牌 -->
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-form-item label="商品品牌:" prop="brandId" required>
|
|
<el-form-item label="商品品牌:" prop="brandId" required>
|
|
|
- <el-select-v2
|
|
|
|
|
|
|
+ <el-select
|
|
|
v-model="productForm.brandId"
|
|
v-model="productForm.brandId"
|
|
|
- :options="brandOptionsFormatted"
|
|
|
|
|
- placeholder="请选择商品品牌"
|
|
|
|
|
- clearable
|
|
|
|
|
|
|
+ placeholder="请输入品牌名称搜索"
|
|
|
filterable
|
|
filterable
|
|
|
- class="w-full"
|
|
|
|
|
|
|
+ remote
|
|
|
|
|
+ clearable
|
|
|
|
|
+ :remote-method="handleBrandSearch"
|
|
|
:loading="brandLoading"
|
|
: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-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
|
|
|
|
@@ -277,7 +285,14 @@
|
|
|
<el-row :gutter="20">
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-form-item label="税率:" required>
|
|
<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-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
@@ -373,7 +388,7 @@
|
|
|
<el-option
|
|
<el-option
|
|
|
v-for="option in supplierOptions"
|
|
v-for="option in supplierOptions"
|
|
|
:key="option.id"
|
|
:key="option.id"
|
|
|
- :label="option.enterpriseName"
|
|
|
|
|
|
|
+ :label="`${option.supplierNo},${option.enterpriseName}`"
|
|
|
:value="String(option.id)"
|
|
:value="String(option.id)"
|
|
|
/>
|
|
/>
|
|
|
</el-select>
|
|
</el-select>
|
|
@@ -426,6 +441,7 @@
|
|
|
v-model="productForm.midRangePrice"
|
|
v-model="productForm.midRangePrice"
|
|
|
type="number"
|
|
type="number"
|
|
|
placeholder="请输入市场价"
|
|
placeholder="请输入市场价"
|
|
|
|
|
+ @blur="formatPrice('midRangePrice')"
|
|
|
/>
|
|
/>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
@@ -435,6 +451,7 @@
|
|
|
v-model="productForm.standardPrice"
|
|
v-model="productForm.standardPrice"
|
|
|
type="number"
|
|
type="number"
|
|
|
placeholder="请输入平台售价"
|
|
placeholder="请输入平台售价"
|
|
|
|
|
+ @blur="formatPrice('standardPrice')"
|
|
|
/>
|
|
/>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
@@ -444,6 +461,7 @@
|
|
|
v-model="productForm.certificatePrice"
|
|
v-model="productForm.certificatePrice"
|
|
|
type="number"
|
|
type="number"
|
|
|
placeholder="请输入最低售价"
|
|
placeholder="请输入最低售价"
|
|
|
|
|
+ @blur="formatPrice('certificatePrice')"
|
|
|
/>
|
|
/>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
@@ -482,6 +500,7 @@
|
|
|
v-model="productForm.purchasePrice"
|
|
v-model="productForm.purchasePrice"
|
|
|
type="number"
|
|
type="number"
|
|
|
placeholder="请输入采购价"
|
|
placeholder="请输入采购价"
|
|
|
|
|
+ @blur="formatPrice('purchasePrice')"
|
|
|
/>
|
|
/>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
@@ -491,6 +510,7 @@
|
|
|
v-model="productForm.estimatedPurchasePrice"
|
|
v-model="productForm.estimatedPurchasePrice"
|
|
|
type="number"
|
|
type="number"
|
|
|
placeholder="请输入暂估采购价"
|
|
placeholder="请输入暂估采购价"
|
|
|
|
|
+ @blur="formatPrice('estimatedPurchasePrice')"
|
|
|
/>
|
|
/>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
@@ -507,11 +527,14 @@
|
|
|
<el-form ref="purchaseInfoFormRef" :model="productForm" :rules="productRules" 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-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
<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-select>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
@@ -521,7 +544,7 @@
|
|
|
<el-option
|
|
<el-option
|
|
|
v-for="option in staffOptions"
|
|
v-for="option in staffOptions"
|
|
|
:key="option.staffId"
|
|
:key="option.staffId"
|
|
|
- :label="option.staffName"
|
|
|
|
|
|
|
+ :label="`${option.staffCode},${option.staffName}`"
|
|
|
:value="String(option.staffId)"
|
|
:value="String(option.staffId)"
|
|
|
/>
|
|
/>
|
|
|
</el-select>
|
|
</el-select>
|
|
@@ -622,6 +645,27 @@
|
|
|
</div>
|
|
</div>
|
|
|
</el-form-item>
|
|
</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-form-item label="商品详情:">
|
|
|
<el-tabs v-model="activeDetailTab" type="border-card">
|
|
<el-tabs v-model="activeDetailTab" type="border-card">
|
|
@@ -770,6 +814,14 @@
|
|
|
title="选择商品主图"
|
|
title="选择商品主图"
|
|
|
@confirm="handleMainImageSelected"
|
|
@confirm="handleMainImageSelected"
|
|
|
/>
|
|
/>
|
|
|
|
|
+ <!-- 轮播图文件选择器 -->
|
|
|
|
|
+ <FileSelector
|
|
|
|
|
+ v-model="carouselImageSelectorVisible"
|
|
|
|
|
+ :allowed-types="[1]"
|
|
|
|
|
+ :multiple="true"
|
|
|
|
|
+ title="选择商品轮播图"
|
|
|
|
|
+ @confirm="handleCarouselImagesSelected"
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -784,7 +836,8 @@ import { categoryTreeVO } from '@/api/product/category/types';
|
|
|
import { BrandVO } from '@/api/product/brand/types';
|
|
import { BrandVO } from '@/api/product/brand/types';
|
|
|
import { BaseForm } from '@/api/product/base/types';
|
|
import { BaseForm } from '@/api/product/base/types';
|
|
|
import { AttributesVO } from '@/api/product/attributes/types';
|
|
import { AttributesVO } from '@/api/product/attributes/types';
|
|
|
-import { addBase, updateBase, getBase, brandList, categoryTree, categoryAttributeList, getAfterSaleList, getServiceList, getUnitList } from '@/api/product/base';
|
|
|
|
|
|
|
+import { addBase, updateBase, getBase, categoryTree, categoryAttributeList, getAfterSaleList, getServiceList, getUnitList, getTaxRateList } from '@/api/product/base';
|
|
|
|
|
+import { listBrand } from '@/api/product/brand';
|
|
|
import { listInfo } from '@/api/customer/supplierInfo';
|
|
import { listInfo } from '@/api/customer/supplierInfo';
|
|
|
import { InfoVO } from '@/api/customer/supplierInfo/types';
|
|
import { InfoVO } from '@/api/customer/supplierInfo/types';
|
|
|
import { listComStaff } from '@/api/system/comStaff';
|
|
import { listComStaff } from '@/api/system/comStaff';
|
|
@@ -807,6 +860,13 @@ const activeDetailTab = ref('pc');
|
|
|
|
|
|
|
|
// 文件选择器相关
|
|
// 文件选择器相关
|
|
|
const mainImageSelectorVisible = ref(false);
|
|
const mainImageSelectorVisible = ref(false);
|
|
|
|
|
+const carouselImageSelectorVisible = ref(false);
|
|
|
|
|
+
|
|
|
|
|
+// 轮播图URL数组(UI管理用)
|
|
|
|
|
+const carouselImages = ref<string[]>([]);
|
|
|
|
|
+
|
|
|
|
|
+// 税率选项
|
|
|
|
|
+const taxRateOptions = ref<any[]>([]);
|
|
|
|
|
|
|
|
// 定制说明表单
|
|
// 定制说明表单
|
|
|
const customForm = reactive({
|
|
const customForm = reactive({
|
|
@@ -943,6 +1003,7 @@ const productForm = reactive<BaseForm>({
|
|
|
bottomCategoryId: undefined,
|
|
bottomCategoryId: undefined,
|
|
|
unitId: undefined,
|
|
unitId: undefined,
|
|
|
productImage: undefined,
|
|
productImage: undefined,
|
|
|
|
|
+ imageUrl: undefined,
|
|
|
isSelf: 0,
|
|
isSelf: 0,
|
|
|
productReviewStatus: 0,
|
|
productReviewStatus: 0,
|
|
|
homeRecommended: 0,
|
|
homeRecommended: 0,
|
|
@@ -993,9 +1054,9 @@ const productRules = {
|
|
|
standardPrice: [{ required: true, message: '平台售价不能为空', trigger: 'blur' }],
|
|
standardPrice: [{ required: true, message: '平台售价不能为空', trigger: 'blur' }],
|
|
|
certificatePrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
|
|
certificatePrice: [{ required: true, message: '最低售价不能为空', trigger: 'blur' }],
|
|
|
purchasePrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
|
|
purchasePrice: [{ required: true, message: '采购价不能为空', trigger: 'blur' }],
|
|
|
- productNature: [{ required: true, message: '产品性质不能为空', trigger: 'change' }],
|
|
|
|
|
|
|
+ productNature: [{ required: true, message: '产品经理不能为空', trigger: 'change' }],
|
|
|
purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
|
|
purchasingPersonnel: [{ required: true, message: '采购人员不能为空', trigger: 'change' }],
|
|
|
- taxRate: [{ required: true, message: '税率不能为空', trigger: 'blur' }],
|
|
|
|
|
|
|
+ taxRate: [{ required: true, message: '税率不能为空', trigger: 'change' }],
|
|
|
minOrderQuantity: [{ required: true, message: '最低起订量不能为空', trigger: 'blur' }],
|
|
minOrderQuantity: [{ required: true, message: '最低起订量不能为空', trigger: 'blur' }],
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -1003,12 +1064,7 @@ const productRules = {
|
|
|
const categoryOptions = ref<categoryTreeVO[]>([]);
|
|
const categoryOptions = ref<categoryTreeVO[]>([]);
|
|
|
const brandOptions = ref<BrandVO[]>([]);
|
|
const brandOptions = ref<BrandVO[]>([]);
|
|
|
const brandLoading = ref(false);
|
|
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[]>([]);
|
|
const attributesList = ref<AttributesVO[]>([]);
|
|
@@ -1186,6 +1242,8 @@ const handleSubmit = async () => {
|
|
|
...productForm,
|
|
...productForm,
|
|
|
// 将服务保障ID数组转换为逗号分隔字符串
|
|
// 将服务保障ID数组转换为逗号分隔字符串
|
|
|
serviceGuarantee: serviceGuarantees.value.map(id => String(id)).join(','),
|
|
serviceGuarantee: serviceGuarantees.value.map(id => String(id)).join(','),
|
|
|
|
|
+ // 轮播图URL逗号分隔
|
|
|
|
|
+ imageUrl: carouselImages.value.join(','),
|
|
|
// 将商品属性值转换为JSON字符串
|
|
// 将商品属性值转换为JSON字符串
|
|
|
attributesList: JSON.stringify(productAttributesValues.value),
|
|
attributesList: JSON.stringify(productAttributesValues.value),
|
|
|
customizable: customForm.customizable,
|
|
customizable: customForm.customizable,
|
|
@@ -1238,6 +1296,45 @@ const clearMainImage = () => {
|
|
|
productForm.productImage = undefined;
|
|
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 () => {
|
|
const getCategoryTree = async () => {
|
|
|
try {
|
|
try {
|
|
@@ -1248,27 +1345,31 @@ const getCategoryTree = async () => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-// 获取品牌列表(实时请求,每次只加载500条)
|
|
|
|
|
-const getBrandList = async () => {
|
|
|
|
|
|
|
+// 加载品牌选项(默认100条)
|
|
|
|
|
+const loadBrandOptions = async (keyword?: string) => {
|
|
|
|
|
+ brandLoading.value = true;
|
|
|
try {
|
|
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) {
|
|
} catch (error) {
|
|
|
- console.error('获取品牌列表失败:', error);
|
|
|
|
|
|
|
+ console.error('加载品牌列表失败:', error);
|
|
|
} finally {
|
|
} finally {
|
|
|
brandLoading.value = false;
|
|
brandLoading.value = false;
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// 品牌远程搜索(防抖)
|
|
|
|
|
+const handleBrandSearch = (query: string) => {
|
|
|
|
|
+ if (brandSearchTimer) clearTimeout(brandSearchTimer);
|
|
|
|
|
+ brandSearchTimer = setTimeout(() => {
|
|
|
|
|
+ loadBrandOptions(query || undefined);
|
|
|
|
|
+ }, 300);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// 处理品牌下拉框显示/隐藏
|
|
// 处理品牌下拉框显示/隐藏
|
|
|
const handleBrandVisibleChange = (visible: boolean) => {
|
|
const handleBrandVisibleChange = (visible: boolean) => {
|
|
|
if (visible && brandOptions.value.length === 0) {
|
|
if (visible && brandOptions.value.length === 0) {
|
|
|
- getBrandList();
|
|
|
|
|
|
|
+ loadBrandOptions();
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -1350,6 +1451,16 @@ const getStaffOptions = async () => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// 获取税率列表
|
|
|
|
|
+const getTaxRateOptions = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await getTaxRateList();
|
|
|
|
|
+ taxRateOptions.value = res.rows || [];
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取税率列表失败:', error);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// 加载分类属性列表
|
|
// 加载分类属性列表
|
|
|
const loadCategoryAttributes = async (categoryId: string | number) => {
|
|
const loadCategoryAttributes = async (categoryId: string | number) => {
|
|
|
try {
|
|
try {
|
|
@@ -1407,6 +1518,13 @@ const loadProductDetail = async () => {
|
|
|
const res = await getBase(id as string);
|
|
const res = await getBase(id as string);
|
|
|
Object.assign(productForm, res.data);
|
|
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.topCategoryId = res.data.topCategoryId;
|
|
|
categoryForm.mediumCategoryId = res.data.mediumCategoryId;
|
|
categoryForm.mediumCategoryId = res.data.mediumCategoryId;
|
|
@@ -1474,11 +1592,13 @@ onMounted(async () => {
|
|
|
await getUnitOptions();
|
|
await getUnitOptions();
|
|
|
await getAfterSalesOptions();
|
|
await getAfterSalesOptions();
|
|
|
await getServiceGuaranteeOptions();
|
|
await getServiceGuaranteeOptions();
|
|
|
|
|
+ await getTaxRateOptions();
|
|
|
// 先加载商品详情(如果是编辑模式)
|
|
// 先加载商品详情(如果是编辑模式)
|
|
|
await loadProductDetail();
|
|
await loadProductDetail();
|
|
|
// 再加载下拉选项,这样如果详情中没有值,会自动设置第一个
|
|
// 再加载下拉选项,这样如果详情中没有值,会自动设置第一个
|
|
|
await getSupplierOptions();
|
|
await getSupplierOptions();
|
|
|
await getStaffOptions();
|
|
await getStaffOptions();
|
|
|
|
|
+ loadBrandOptions();
|
|
|
});
|
|
});
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
@@ -1587,35 +1707,35 @@ onMounted(async () => {
|
|
|
gap: 8px;
|
|
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;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1625,6 +1745,40 @@ onMounted(async () => {
|
|
|
flex-wrap: wrap;
|
|
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 {
|
|
.custom-table {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
margin-top: 10px;
|
|
margin-top: 10px;
|