|
@@ -1,11 +1,7 @@
|
|
|
<template>
|
|
|
<el-container>
|
|
|
<el-header>
|
|
|
- <el-tabs
|
|
|
- class="sa-tabs bg-#fff sa-m-t-10 z-999"
|
|
|
- v-model="activeTab"
|
|
|
- @tab-change="handleTabChange"
|
|
|
- >
|
|
|
+ <el-tabs class="sa-tabs bg-#fff sa-m-t-10 z-999" v-model="activeTab" @tab-change="handleTabChange">
|
|
|
<el-tab-pane name="basic">
|
|
|
<template #label>
|
|
|
<div class="sa-flex" :class="basicFormErrors ? 'is-error' : ''">
|
|
@@ -44,37 +40,19 @@
|
|
|
<!-- 左侧表单 -->
|
|
|
<el-col :span="14">
|
|
|
<el-form-item label="商品分类" prop="cateId" required>
|
|
|
- <el-select
|
|
|
- v-model="basicFormData.cateId"
|
|
|
- placeholder="请选择商品分类"
|
|
|
- clearable
|
|
|
- style="width: 100%"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="category in categoryOptions"
|
|
|
- :key="category.id"
|
|
|
- :label="category.name"
|
|
|
- :value="category.id"
|
|
|
- />
|
|
|
+ <el-select v-model="basicFormData.cateId" placeholder="请选择商品分类" clearable style="width: 100%">
|
|
|
+ <el-option v-for="category in categoryOptions" :key="category.id" :label="category.name"
|
|
|
+ :value="category.id" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="商品名称" prop="storeName" required>
|
|
|
- <el-input
|
|
|
- v-model="basicFormData.storeName"
|
|
|
- placeholder="请填写商品名称(限100字符)"
|
|
|
- maxlength="100"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
+ <el-input v-model="basicFormData.storeName" placeholder="请填写商品名称(限100字符)" maxlength="100"
|
|
|
+ show-word-limit />
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="副标题" prop="keyword">
|
|
|
- <el-input
|
|
|
- v-model="basicFormData.keyword"
|
|
|
- placeholder="请填写副标题(限50字符)"
|
|
|
- maxlength="50"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
+ <el-input v-model="basicFormData.keyword" placeholder="请填写副标题(限50字符)" maxlength="50" show-word-limit />
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="商品品牌" prop="itemBrand" required>
|
|
@@ -82,14 +60,8 @@
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="商品介绍" prop="storeInfo">
|
|
|
- <el-input
|
|
|
- v-model="basicFormData.storeInfo"
|
|
|
- type="textarea"
|
|
|
- :rows="4"
|
|
|
- placeholder="请填写商品介绍(限500字符)"
|
|
|
- maxlength="500"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
+ <el-input v-model="basicFormData.storeInfo" type="textarea" :rows="4" placeholder="请填写商品介绍(限500字符)"
|
|
|
+ maxlength="500" show-word-limit />
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="运费模板" prop="tempId">
|
|
@@ -98,9 +70,7 @@
|
|
|
|
|
|
<el-form-item label="商品货号" prop="itemNumber" required>
|
|
|
<el-input v-model="basicFormData.itemNumber" placeholder="请填写商品货号" />
|
|
|
- <div class="form-tip ml-10px"
|
|
|
- >如果您不输入商品货号,系统将自动生成一个唯一的货号</div
|
|
|
- >
|
|
|
+ <div class="form-tip ml-10px">如果您不输入商品货号,系统将自动生成一个唯一的货号</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="商品售价" prop="price" required>
|
|
@@ -124,24 +94,12 @@
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="商品库存" prop="stock" required>
|
|
|
- <el-input
|
|
|
- v-model="basicFormData.stock"
|
|
|
- placeholder="请输入商品库存"
|
|
|
- type="number"
|
|
|
- min="0"
|
|
|
- />
|
|
|
- <div class="form-tip ml-10px"
|
|
|
- >该设置只对单品有效,当商品存在多规格货品时为不可编辑状态,库存数值取决于货品数量</div
|
|
|
- >
|
|
|
+ <el-input v-model="basicFormData.stock" placeholder="请输入商品库存" type="number" min="0" />
|
|
|
+ <div class="form-tip ml-10px">该设置只对单品有效,当商品存在多规格货品时为不可编辑状态,库存数值取决于货品数量</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="库存预警值" prop="stockThreshold">
|
|
|
- <el-input
|
|
|
- v-model="basicFormData.stockThreshold"
|
|
|
- placeholder="请输入库存预警值"
|
|
|
- type="number"
|
|
|
- min="0"
|
|
|
- />
|
|
|
+ <el-input v-model="basicFormData.stockThreshold" placeholder="请输入库存预警值" type="number" min="0" />
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="商品状态" prop="isShow" required>
|
|
@@ -159,41 +117,20 @@
|
|
|
<!-- 右侧图片上传 -->
|
|
|
<el-col :span="10">
|
|
|
<el-form-item label="商品主图" prop="image" required>
|
|
|
- <sa-upload-image
|
|
|
- v-model="basicFormData.image"
|
|
|
- :max-count="5"
|
|
|
- :accept="['jpg', 'jpeg', 'png']"
|
|
|
- :max-size="5"
|
|
|
- :direct-upload="true"
|
|
|
- :size="100"
|
|
|
- placeholder="上传商品主图"
|
|
|
- />
|
|
|
+ <sa-upload-image v-model="basicFormData.image" :max-count="5" :accept="['jpg', 'jpeg', 'png']"
|
|
|
+ :max-size="5" :direct-upload="true" :size="100" placeholder="上传商品主图" />
|
|
|
<div class="form-tip">作用于商城列表、分享图片;建议尺寸:750*750 px</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="轮播图" prop="sliderImage">
|
|
|
- <sa-upload-image
|
|
|
- v-model="basicFormData.sliderImage"
|
|
|
- :max-count="5"
|
|
|
- :accept="['jpg', 'jpeg', 'png']"
|
|
|
- :max-size="5"
|
|
|
- :direct-upload="true"
|
|
|
- :size="100"
|
|
|
- placeholder="上传轮播图"
|
|
|
- />
|
|
|
+ <sa-upload-image v-model="basicFormData.sliderImage" :max-count="5" :accept="['jpg', 'jpeg', 'png']"
|
|
|
+ :max-size="5" :direct-upload="true" :size="100" placeholder="上传轮播图" />
|
|
|
<div class="form-tip">作用于商品详情顶部轮播显示,轮播图可以拖拽调整顺序</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="详情图" prop="flatPattern" required>
|
|
|
- <sa-upload-image
|
|
|
- v-model="basicFormData.flatPattern"
|
|
|
- :max-count="10"
|
|
|
- :accept="['jpg', 'jpeg', 'png']"
|
|
|
- :max-size="5"
|
|
|
- :direct-upload="true"
|
|
|
- :size="100"
|
|
|
- placeholder="上传详情图"
|
|
|
- />
|
|
|
+ <sa-upload-image v-model="basicFormData.flatPattern" :max-count="10" :accept="['jpg', 'jpeg', 'png']"
|
|
|
+ :max-size="5" :direct-upload="true" :size="100" placeholder="上传详情图" />
|
|
|
<div class="form-tip">详情图片,用于商品详情页展示</div>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
@@ -212,12 +149,7 @@
|
|
|
|
|
|
<!-- 有商品ID时显示属性表单 -->
|
|
|
<div>
|
|
|
- <el-form
|
|
|
- ref="attributesFormRef"
|
|
|
- :model="attributesFormData"
|
|
|
- :rules="attributesRules"
|
|
|
- label-width="120px"
|
|
|
- >
|
|
|
+ <el-form ref="attributesFormRef" :model="attributesFormData" :rules="attributesRules" label-width="120px">
|
|
|
<!-- 多规格设置 -->
|
|
|
<el-card class="spec-card">
|
|
|
<template #header>
|
|
@@ -232,12 +164,8 @@
|
|
|
<div class="sku-key sa-flex sa-row-between">
|
|
|
<div class="sa-flex">
|
|
|
<div class="sa-m-r-16">规格名称</div>
|
|
|
- <el-input
|
|
|
- v-model="s.name"
|
|
|
- placeholder="请输入规格名称"
|
|
|
- class="sku-key-input"
|
|
|
- @input="buildSkuPriceTable"
|
|
|
- ></el-input>
|
|
|
+ <el-input v-model="s.name" placeholder="请输入规格名称" class="sku-key-input"
|
|
|
+ @input="buildSkuPriceTable"></el-input>
|
|
|
</div>
|
|
|
<el-icon @click="deleteMainSku(k)" class="sku-key-icon">
|
|
|
<CircleCloseFilled />
|
|
@@ -246,20 +174,13 @@
|
|
|
<div class="sku-value sa-flex sa-flex-wrap">
|
|
|
<div class="sku-value-title sa-m-r-16 sa-m-b-16 sa-flex"> 规格值 </div>
|
|
|
<div v-for="(sc, c) in s.children" :key="c" class="sku-value-box sa-m-b-16">
|
|
|
- <el-input
|
|
|
- v-model="sc.name"
|
|
|
- placeholder="请输入规格值"
|
|
|
- class="sku-value-input"
|
|
|
- @input="buildSkuPriceTable"
|
|
|
- ></el-input>
|
|
|
+ <el-input v-model="sc.name" placeholder="请输入规格值" class="sku-value-input"
|
|
|
+ @input="buildSkuPriceTable"></el-input>
|
|
|
<el-icon @click="deleteChildrenSku(k, c)" class="sku-value-icon">
|
|
|
<CircleCloseFilled />
|
|
|
</el-icon>
|
|
|
</div>
|
|
|
- <div
|
|
|
- @click="addChildrenSku(k)"
|
|
|
- class="sku-value-add sa-m-r-24 sa-m-b-16 sa-flex cursor-pointer"
|
|
|
- >
|
|
|
+ <div @click="addChildrenSku(k)" class="sku-value-add sa-m-r-24 sa-m-b-16 sa-flex cursor-pointer">
|
|
|
添加规格值
|
|
|
</div>
|
|
|
</div>
|
|
@@ -272,24 +193,11 @@
|
|
|
<!-- 批量设置 -->
|
|
|
<div class="sa-m-t-20" v-if="attributesFormData.sku_prices.length > 0">
|
|
|
<el-form-item label="批量设置" label-width="80px">
|
|
|
- <div
|
|
|
- class="sku sa-m-r-20"
|
|
|
- v-for="(item, index) in attributesFormData.skus"
|
|
|
- :key="index"
|
|
|
- >
|
|
|
- <el-select
|
|
|
- v-model="item.batchId"
|
|
|
- placeholder="请选择规格"
|
|
|
- class="sa-w-150"
|
|
|
- clearable
|
|
|
- >
|
|
|
+ <div class="sku sa-m-r-20" v-for="(item, index) in attributesFormData.skus" :key="index">
|
|
|
+ <el-select v-model="item.batchId" placeholder="请选择规格" class="sa-w-150" clearable>
|
|
|
<template v-for="(citem, cindex) in item.children">
|
|
|
- <el-option
|
|
|
- :key="cindex"
|
|
|
- :label="citem.name"
|
|
|
- :value="citem.temp_id"
|
|
|
- v-if="citem.temp_id && citem.name"
|
|
|
- ></el-option>
|
|
|
+ <el-option :key="cindex" :label="citem.name" :value="citem.temp_id"
|
|
|
+ v-if="citem.temp_id && citem.name"></el-option>
|
|
|
</template>
|
|
|
</el-select>
|
|
|
</div>
|
|
@@ -298,35 +206,22 @@
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
<div class="sa-flex sa-flex-wrap">
|
|
|
- <el-select
|
|
|
- v-model="allEditObj.price"
|
|
|
- placeholder="请选择售价(৳)"
|
|
|
- class="sa-w-200 sa-m-r-10 sa-m-b-10"
|
|
|
- clearable
|
|
|
- >
|
|
|
+ <el-select v-model="allEditObj.price" placeholder="请选择售价(৳)" class="sa-w-200 sa-m-r-10 sa-m-b-10"
|
|
|
+ clearable>
|
|
|
<el-option :value="300" label="300৳" />
|
|
|
<el-option :value="500" label="500৳" />
|
|
|
<el-option :value="1000" label="1000৳" />
|
|
|
<el-option :value="2000" label="2000৳" />
|
|
|
<el-option :value="3000" label="3000৳" />
|
|
|
</el-select>
|
|
|
- <el-input
|
|
|
- v-model="allEditObj.stock"
|
|
|
- placeholder="请输入库存(件)"
|
|
|
- class="sa-w-200 sa-m-r-10 sa-m-b-10"
|
|
|
- >
|
|
|
+ <el-input v-model="allEditObj.stock" placeholder="请输入库存(件)" class="sa-w-200 sa-m-r-10 sa-m-b-10">
|
|
|
<template #prepend>库存(件)</template>
|
|
|
</el-input>
|
|
|
- <el-input
|
|
|
- v-model="allEditObj.stock_warning"
|
|
|
- placeholder="请输入库存预警值(件)"
|
|
|
- class="sa-w-200 sa-m-r-10 sa-m-b-10"
|
|
|
- >
|
|
|
+ <el-input v-model="allEditObj.stock_warning" placeholder="请输入库存预警值(件)"
|
|
|
+ class="sa-w-200 sa-m-r-10 sa-m-b-10">
|
|
|
<template #prepend>库存预警值(件)</template>
|
|
|
</el-input>
|
|
|
- <el-button type="primary" @click="batchEdit" class="sa-m-b-10"
|
|
|
- >批量设置</el-button
|
|
|
- >
|
|
|
+ <el-button type="primary" @click="batchEdit" class="sa-m-b-10">批量设置</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
@@ -354,25 +249,13 @@
|
|
|
</td>
|
|
|
</template>
|
|
|
<td class="image">
|
|
|
- <sa-upload-image
|
|
|
- v-model="item.imageList"
|
|
|
- :max-count="1"
|
|
|
- :accept="['jpg', 'jpeg', 'png']"
|
|
|
- :max-size="5"
|
|
|
- :direct-upload="true"
|
|
|
- :size="30"
|
|
|
- :show-tip="false"
|
|
|
- :compact="true"
|
|
|
- placeholder=""
|
|
|
- />
|
|
|
+ <sa-upload-image v-model="item.imageList" :max-count="1" :accept="['jpg', 'jpeg', 'png']"
|
|
|
+ :max-size="5" :direct-upload="true" :size="30" :show-tip="false" :compact="true"
|
|
|
+ placeholder="" />
|
|
|
</td>
|
|
|
<td>
|
|
|
- <el-select
|
|
|
- v-model="item.price"
|
|
|
- placeholder="选择价格"
|
|
|
- size="small"
|
|
|
- :class="{ 'is-error': !item.price || item.price <= 0 }"
|
|
|
- >
|
|
|
+ <el-select v-model="item.price" placeholder="选择价格" size="small"
|
|
|
+ :class="{ 'is-error': !item.price || item.price <= 0 }">
|
|
|
<el-option :value="300" label="300" />
|
|
|
<el-option :value="500" label="500" />
|
|
|
<el-option :value="1000" label="1000" />
|
|
@@ -381,37 +264,18 @@
|
|
|
</el-select>
|
|
|
</td>
|
|
|
<td class="stock">
|
|
|
- <el-input
|
|
|
- v-model="item.stock"
|
|
|
- placeholder="请输入库存"
|
|
|
- size="small"
|
|
|
- type="number"
|
|
|
- :step="1"
|
|
|
- :min="0"
|
|
|
- :class="{ 'is-error': !item.stock || item.stock < 0 }"
|
|
|
- ></el-input>
|
|
|
+ <el-input v-model="item.stock" placeholder="请输入库存" size="small" type="number" :step="1" :min="0"
|
|
|
+ :class="{ 'is-error': !item.stock || item.stock < 0 }"></el-input>
|
|
|
</td>
|
|
|
<td class="stock_warning">
|
|
|
- <el-input
|
|
|
- v-model="item.stock_warning"
|
|
|
- placeholder="请输入预警值"
|
|
|
- size="small"
|
|
|
- type="number"
|
|
|
- :step="1"
|
|
|
- :min="0"
|
|
|
- ></el-input>
|
|
|
+ <el-input v-model="item.stock_warning" placeholder="请输入预警值" size="small" type="number" :step="1"
|
|
|
+ :min="0"></el-input>
|
|
|
</td>
|
|
|
<td class="sn">
|
|
|
- <el-input
|
|
|
- v-model="item.sn"
|
|
|
- placeholder="请输入SKU编码"
|
|
|
- size="small"
|
|
|
- ></el-input>
|
|
|
+ <el-input v-model="item.sn" placeholder="请输入SKU编码" size="small"></el-input>
|
|
|
</td>
|
|
|
<td>
|
|
|
- <el-button type="danger" size="small" text @click="deleteSkuPrice(i)"
|
|
|
- >删除</el-button
|
|
|
- >
|
|
|
+ <el-button type="danger" size="small" text @click="deleteSkuPrice(i)">删除</el-button>
|
|
|
</td>
|
|
|
</tr>
|
|
|
</tbody>
|
|
@@ -436,12 +300,7 @@
|
|
|
|
|
|
<!-- 商品属性Tab的按钮 -->
|
|
|
<template v-else-if="activeTab === 'attributes'">
|
|
|
- <el-button
|
|
|
- type="primary"
|
|
|
- @click="saveAttributes"
|
|
|
- :loading="savingStates.attributes"
|
|
|
- size="large"
|
|
|
- >
|
|
|
+ <el-button type="primary" @click="saveAttributes" :loading="savingStates.attributes" size="large">
|
|
|
保存商品属性
|
|
|
</el-button>
|
|
|
</template>
|
|
@@ -455,780 +314,799 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
- import { onMounted, reactive, ref, computed, nextTick } from 'vue';
|
|
|
- import { WarningFilled, CircleCheckFilled, CircleCloseFilled } from '@element-plus/icons-vue';
|
|
|
- import { api } from '../goods.service';
|
|
|
- const emit = defineEmits(['modalCallBack']);
|
|
|
- const props = defineProps({
|
|
|
- modal: {
|
|
|
- type: Object,
|
|
|
- required: true,
|
|
|
+import { onMounted, reactive, ref, computed, nextTick } from 'vue';
|
|
|
+import { WarningFilled, CircleCheckFilled, CircleCloseFilled } from '@element-plus/icons-vue';
|
|
|
+import { api } from '../goods.service';
|
|
|
+const emit = defineEmits(['modalCallBack']);
|
|
|
+const props = defineProps({
|
|
|
+ modal: {
|
|
|
+ type: Object,
|
|
|
+ required: true,
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+// 从modal参数中获取类型和ID
|
|
|
+const type = computed(() => props.modal?.params?.type || 'add');
|
|
|
+const goodsIdFromProps = computed(() => props.modal?.params?.id || null);
|
|
|
+
|
|
|
+// 响应式数据
|
|
|
+const activeTab = ref('basic');
|
|
|
+const goodsId = ref(goodsIdFromProps.value);
|
|
|
+const isEdit = computed(() => type.value === 'edit');
|
|
|
+
|
|
|
+// 保存状态
|
|
|
+const savingStates = reactive({
|
|
|
+ basic: false,
|
|
|
+ attributes: false,
|
|
|
+ all: false,
|
|
|
+});
|
|
|
+
|
|
|
+// 保存成功状态
|
|
|
+const basicSaved = ref(false);
|
|
|
+const attributesSaved = ref(false);
|
|
|
+
|
|
|
+// 表单错误状态
|
|
|
+const basicFormErrors = ref(false);
|
|
|
+const attributesFormErrors = ref(false);
|
|
|
+
|
|
|
+// 表单引用
|
|
|
+const basicFormRef = ref(null);
|
|
|
+const attributesFormRef = ref(null);
|
|
|
+
|
|
|
+// 分类选项
|
|
|
+const categoryOptions = ref([]);
|
|
|
+
|
|
|
+// 基本信息表单数据
|
|
|
+const basicFormData = reactive({
|
|
|
+ id: '',
|
|
|
+ cateId: '',
|
|
|
+ storeName: '',
|
|
|
+ keyword: '',
|
|
|
+ itemBrand: '',
|
|
|
+ storeInfo: '',
|
|
|
+ tempId: 1,
|
|
|
+ itemNumber: '',
|
|
|
+ price: '',
|
|
|
+ otPrice: '',
|
|
|
+ stock: '',
|
|
|
+ stockThreshold: '',
|
|
|
+ isShow: 1,
|
|
|
+ itemSupplier: '',
|
|
|
+ sort: 0,
|
|
|
+ isHot: 0,
|
|
|
+ isNew: 0,
|
|
|
+ isBest: 0,
|
|
|
+ isGood: 0,
|
|
|
+ isBenefit: 0,
|
|
|
+ isPostage: 1,
|
|
|
+ cost: '',
|
|
|
+ vipPrice: '',
|
|
|
+ image: [],
|
|
|
+ sliderImage: [],
|
|
|
+ flatPattern: [],
|
|
|
+});
|
|
|
+
|
|
|
+// 商品属性表单数据
|
|
|
+const attributesFormData = reactive({
|
|
|
+ specType: 1, // 规格 0单 1多,默认多规格
|
|
|
+ skus: [
|
|
|
+ {
|
|
|
+ id: 0,
|
|
|
+ temp_id: 1,
|
|
|
+ name: '',
|
|
|
+ batchId: '',
|
|
|
+ pid: 0,
|
|
|
+ children: [],
|
|
|
},
|
|
|
- });
|
|
|
-
|
|
|
- // 从modal参数中获取类型和ID
|
|
|
- const type = computed(() => props.modal?.params?.type || 'add');
|
|
|
- const goodsIdFromProps = computed(() => props.modal?.params?.id || null);
|
|
|
-
|
|
|
- // 响应式数据
|
|
|
- const activeTab = ref('basic');
|
|
|
- const goodsId = ref(goodsIdFromProps.value);
|
|
|
- const isEdit = computed(() => type.value === 'edit');
|
|
|
-
|
|
|
- // 保存状态
|
|
|
- const savingStates = reactive({
|
|
|
- basic: false,
|
|
|
- attributes: false,
|
|
|
- all: false,
|
|
|
- });
|
|
|
-
|
|
|
- // 保存成功状态
|
|
|
- const basicSaved = ref(false);
|
|
|
- const attributesSaved = ref(false);
|
|
|
-
|
|
|
- // 表单错误状态
|
|
|
- const basicFormErrors = ref(false);
|
|
|
- const attributesFormErrors = ref(false);
|
|
|
-
|
|
|
- // 表单引用
|
|
|
- const basicFormRef = ref(null);
|
|
|
- const attributesFormRef = ref(null);
|
|
|
-
|
|
|
- // 分类选项
|
|
|
- const categoryOptions = ref([]);
|
|
|
-
|
|
|
- // 基本信息表单数据
|
|
|
- const basicFormData = reactive({
|
|
|
- id: '',
|
|
|
- cateId: '',
|
|
|
- storeName: '',
|
|
|
- keyword: '',
|
|
|
- itemBrand: '',
|
|
|
- storeInfo: '',
|
|
|
- tempId: 1,
|
|
|
- itemNumber: '',
|
|
|
- price: '',
|
|
|
- otPrice: '',
|
|
|
- stock: '',
|
|
|
- stockThreshold: '',
|
|
|
- isShow: 1,
|
|
|
- itemSupplier: '',
|
|
|
- sort: 0,
|
|
|
- isHot: 0,
|
|
|
- isNew: 0,
|
|
|
- isBest: 0,
|
|
|
- isGood: 0,
|
|
|
- isBenefit: 0,
|
|
|
- isPostage: 1,
|
|
|
- cost: '',
|
|
|
- vipPrice: '',
|
|
|
- image: [],
|
|
|
- sliderImage: [],
|
|
|
- flatPattern: [],
|
|
|
- });
|
|
|
-
|
|
|
- // 商品属性表单数据
|
|
|
- const attributesFormData = reactive({
|
|
|
- specType: 1, // 规格 0单 1多,默认多规格
|
|
|
- skus: [
|
|
|
- {
|
|
|
- id: 0,
|
|
|
- temp_id: 1,
|
|
|
- name: '',
|
|
|
- batchId: '',
|
|
|
- pid: 0,
|
|
|
- children: [],
|
|
|
- },
|
|
|
- ],
|
|
|
- sku_prices: [],
|
|
|
- });
|
|
|
+ ],
|
|
|
+ sku_prices: [],
|
|
|
+});
|
|
|
+
|
|
|
+// 基本信息验证规则
|
|
|
+const basicRules = {
|
|
|
+ cateId: [{ required: true, message: '请选择商品分类', trigger: 'change' }],
|
|
|
+ storeName: [{ required: true, message: '请填写商品名称', trigger: 'blur' }],
|
|
|
+ itemBrand: [{ required: true, message: '请填写商品品牌', trigger: 'blur' }],
|
|
|
+ itemNumber: [{ required: true, message: '请填写商品货号', trigger: 'blur' }],
|
|
|
+ price: [{ required: true, message: '请填写商品售价', trigger: 'blur' }],
|
|
|
+ stock: [{ required: true, message: '请填写商品库存', trigger: 'blur' }],
|
|
|
+ isShow: [{ required: true, message: '请选择商品状态', trigger: 'change' }],
|
|
|
+ itemSupplier: [{ required: true, message: '请填写商品供应商', trigger: 'blur' }],
|
|
|
+ image: [{ required: true, message: '请上传商品主图', trigger: 'change' }],
|
|
|
+ flatPattern: [{ required: true, message: '请上传商品详情图', trigger: 'change' }],
|
|
|
+};
|
|
|
+
|
|
|
+// 商品属性验证规则
|
|
|
+const attributesRules = {
|
|
|
+ specType: [{ required: true, message: '请选择规格类型', trigger: 'change' }],
|
|
|
+};
|
|
|
+
|
|
|
+// 图片数组转换为逗号分隔字符串的函数
|
|
|
+const convertImagesToString = (imageArray) => {
|
|
|
+ return Array.isArray(imageArray) ? imageArray.join(',') : '';
|
|
|
+};
|
|
|
+
|
|
|
+// 图片字符串转换为数组的函数
|
|
|
+const convertStringToImages = (imageString) => {
|
|
|
+ if (!imageString) return [];
|
|
|
+ return imageString.split(',').filter((img) => img.trim());
|
|
|
+};
|
|
|
+
|
|
|
+// Tab切换处理
|
|
|
+const handleTabChange = (tabName) => {
|
|
|
+ if (tabName === 'attributes' && !goodsId.value && !isEdit.value) {
|
|
|
+ nextTick(() => {
|
|
|
+ ElMessage.info('提示:保存商品属性需要先保存基本信息');
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
|
|
|
- // 基本信息验证规则
|
|
|
- const basicRules = {
|
|
|
- cateId: [{ required: true, message: '请选择商品分类', trigger: 'change' }],
|
|
|
- storeName: [{ required: true, message: '请填写商品名称', trigger: 'blur' }],
|
|
|
- itemBrand: [{ required: true, message: '请填写商品品牌', trigger: 'blur' }],
|
|
|
- itemNumber: [{ required: true, message: '请填写商品货号', trigger: 'blur' }],
|
|
|
- price: [{ required: true, message: '请填写商品售价', trigger: 'blur' }],
|
|
|
- stock: [{ required: true, message: '请填写商品库存', trigger: 'blur' }],
|
|
|
- isShow: [{ required: true, message: '请选择商品状态', trigger: 'change' }],
|
|
|
- itemSupplier: [{ required: true, message: '请填写商品供应商', trigger: 'blur' }],
|
|
|
- image: [{ required: true, message: '请上传商品主图', trigger: 'change' }],
|
|
|
- flatPattern: [{ required: true, message: '请上传商品详情图', trigger: 'change' }],
|
|
|
- };
|
|
|
+// 保存基本信息
|
|
|
+const saveBasicInfo = async () => {
|
|
|
+ savingStates.basic = true;
|
|
|
+ basicFormErrors.value = false;
|
|
|
|
|
|
- // 商品属性验证规则
|
|
|
- const attributesRules = {
|
|
|
- specType: [{ required: true, message: '请选择规格类型', trigger: 'change' }],
|
|
|
- };
|
|
|
+ const valid = await basicFormRef.value?.validate().catch(() => false);
|
|
|
+ if (!valid) {
|
|
|
+ basicFormErrors.value = true;
|
|
|
+ savingStates.basic = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- // 图片数组转换为逗号分隔字符串的函数
|
|
|
- const convertImagesToString = (imageArray) => {
|
|
|
- return Array.isArray(imageArray) ? imageArray.join(',') : '';
|
|
|
+ const submitData = {
|
|
|
+ ...basicFormData,
|
|
|
+ image: convertImagesToString(basicFormData.image),
|
|
|
+ sliderImage: convertImagesToString(basicFormData.sliderImage),
|
|
|
+ flatPattern: convertImagesToString(basicFormData.flatPattern),
|
|
|
};
|
|
|
|
|
|
- // 图片字符串转换为数组的函数
|
|
|
- const convertStringToImages = (imageString) => {
|
|
|
- if (!imageString) return [];
|
|
|
- return imageString.split(',').filter((img) => img.trim());
|
|
|
- };
|
|
|
+ const { code, data } = isEdit.value
|
|
|
+ ? await api.goods.edit(goodsId.value, submitData)
|
|
|
+ : await api.goods.add(submitData);
|
|
|
|
|
|
- // Tab切换处理
|
|
|
- const handleTabChange = (tabName) => {
|
|
|
- if (tabName === 'attributes' && !goodsId.value && !isEdit.value) {
|
|
|
- nextTick(() => {
|
|
|
- ElMessage.info('提示:保存商品属性需要先保存基本信息');
|
|
|
- });
|
|
|
+ if (code === '200') {
|
|
|
+ if (!isEdit.value) {
|
|
|
+ goodsId.value = data.id;
|
|
|
+ basicFormData.id = data.id;
|
|
|
}
|
|
|
- };
|
|
|
+ basicSaved.value = true;
|
|
|
+ savingStates.basic = false;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- // 保存基本信息
|
|
|
- const saveBasicInfo = async () => {
|
|
|
- savingStates.basic = true;
|
|
|
- basicFormErrors.value = false;
|
|
|
+ basicFormErrors.value = true;
|
|
|
+ savingStates.basic = false;
|
|
|
+ return false;
|
|
|
+};
|
|
|
|
|
|
- const valid = await basicFormRef.value?.validate().catch(() => false);
|
|
|
+// 保存商品属性(内部方法)
|
|
|
+const saveAttributesInternal = async () => {
|
|
|
+ try {
|
|
|
+ // 验证属性表单
|
|
|
+ const valid = await attributesFormRef.value?.validate().catch(() => false);
|
|
|
if (!valid) {
|
|
|
- basicFormErrors.value = true;
|
|
|
- savingStates.basic = false;
|
|
|
+ attributesFormErrors.value = true;
|
|
|
+ ElMessage.error('请完善商品属性');
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+ // 验证SKU
|
|
|
+ if (!validateSku()) {
|
|
|
+ attributesFormErrors.value = true;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 准备属性数据 - 转换为后端需要的格式
|
|
|
const submitData = {
|
|
|
- ...basicFormData,
|
|
|
- image: convertImagesToString(basicFormData.image),
|
|
|
- sliderImage: convertImagesToString(basicFormData.sliderImage),
|
|
|
- flatPattern: convertImagesToString(basicFormData.flatPattern),
|
|
|
+ goodsId: goodsId.value,
|
|
|
+ specType: attributesFormData.specType,
|
|
|
+ attrValue: generateAttrValueData(),
|
|
|
+ attr: generateAttrData(),
|
|
|
};
|
|
|
|
|
|
- const { code, data } = isEdit.value
|
|
|
- ? await api.goods.edit(goodsId.value, submitData)
|
|
|
- : await api.goods.add(submitData);
|
|
|
-
|
|
|
- if (code === '200') {
|
|
|
- if (!isEdit.value) {
|
|
|
- goodsId.value = data.id;
|
|
|
- basicFormData.id = data.id;
|
|
|
- }
|
|
|
- basicSaved.value = true;
|
|
|
- savingStates.basic = false;
|
|
|
- return true;
|
|
|
- }
|
|
|
+ // 这里调用属性保存接口(待实现)
|
|
|
+ const { code, data } = await api.rule.add(submitData);
|
|
|
+ console.log(code, data);
|
|
|
|
|
|
- basicFormErrors.value = true;
|
|
|
- savingStates.basic = false;
|
|
|
+ // 临时模拟成功
|
|
|
+ attributesSaved.value = true;
|
|
|
+ ElMessage.success(t('message.goodsAttributeSaveSuccess'));
|
|
|
+ return true;
|
|
|
+ } catch (error) {
|
|
|
+ attributesFormErrors.value = true;
|
|
|
+ ElMessage.error('保存失败:' + error.message);
|
|
|
return false;
|
|
|
- };
|
|
|
-
|
|
|
- // 保存商品属性(内部方法)
|
|
|
- const saveAttributesInternal = async () => {
|
|
|
- try {
|
|
|
- // 验证属性表单
|
|
|
- const valid = await attributesFormRef.value?.validate().catch(() => false);
|
|
|
- if (!valid) {
|
|
|
- attributesFormErrors.value = true;
|
|
|
- ElMessage.error('请完善商品属性');
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // 验证SKU
|
|
|
- if (!validateSku()) {
|
|
|
- attributesFormErrors.value = true;
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // 准备属性数据 - 转换为后端需要的格式
|
|
|
- const submitData = {
|
|
|
- goodsId: goodsId.value,
|
|
|
- specType: attributesFormData.specType,
|
|
|
- attrValue: generateAttrValueData(),
|
|
|
- attr: generateAttrData(),
|
|
|
- };
|
|
|
-
|
|
|
- // 这里调用属性保存接口(待实现)
|
|
|
- const { code, data } = await api.rule.add(submitData);
|
|
|
- console.log(code, data);
|
|
|
-
|
|
|
- // 临时模拟成功
|
|
|
- attributesSaved.value = true;
|
|
|
- ElMessage.success('商品属性保存成功');
|
|
|
- return true;
|
|
|
- } catch (error) {
|
|
|
- attributesFormErrors.value = true;
|
|
|
- ElMessage.error('保存失败:' + error.message);
|
|
|
- return false;
|
|
|
- }
|
|
|
- };
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 保存商品属性(对外方法)
|
|
|
+const saveAttributes = async () => {
|
|
|
+ try {
|
|
|
+ savingStates.attributes = true;
|
|
|
+ attributesFormErrors.value = false;
|
|
|
+
|
|
|
+ // 检查依赖
|
|
|
+ if (!goodsId.value && !isEdit.value) {
|
|
|
+ const result = await ElMessageBox.confirm(
|
|
|
+ '保存商品属性需要先保存基本信息,是否现在保存基本信息?',
|
|
|
+ '提示',
|
|
|
+ {
|
|
|
+ confirmButtonText: '保存基本信息并继续',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning',
|
|
|
+ },
|
|
|
+ );
|
|
|
+
|
|
|
+ if (result === 'confirm') {
|
|
|
+ // 先保存基本信息
|
|
|
+ const basicSaved = await saveBasicInfo();
|
|
|
|
|
|
- // 保存商品属性(对外方法)
|
|
|
- const saveAttributes = async () => {
|
|
|
- try {
|
|
|
- savingStates.attributes = true;
|
|
|
- attributesFormErrors.value = false;
|
|
|
-
|
|
|
- // 检查依赖
|
|
|
- if (!goodsId.value && !isEdit.value) {
|
|
|
- const result = await ElMessageBox.confirm(
|
|
|
- '保存商品属性需要先保存基本信息,是否现在保存基本信息?',
|
|
|
- '提示',
|
|
|
- {
|
|
|
- confirmButtonText: '保存基本信息并继续',
|
|
|
- cancelButtonText: '取消',
|
|
|
- type: 'warning',
|
|
|
- },
|
|
|
- );
|
|
|
-
|
|
|
- if (result === 'confirm') {
|
|
|
- // 先保存基本信息
|
|
|
- const basicSaved = await saveBasicInfo();
|
|
|
-
|
|
|
- if (basicSaved) {
|
|
|
- // 基本信息保存成功后,保存属性
|
|
|
- await saveAttributesInternal();
|
|
|
- }
|
|
|
+ if (basicSaved) {
|
|
|
+ // 基本信息保存成功后,保存属性
|
|
|
+ await saveAttributesInternal();
|
|
|
}
|
|
|
- return;
|
|
|
}
|
|
|
-
|
|
|
- // 直接保存属性
|
|
|
- await saveAttributesInternal();
|
|
|
- } finally {
|
|
|
- savingStates.attributes = false;
|
|
|
+ return;
|
|
|
}
|
|
|
- };
|
|
|
|
|
|
- // 保存全部
|
|
|
- const saveAll = async () => {
|
|
|
- try {
|
|
|
- savingStates.all = true;
|
|
|
-
|
|
|
- // 1. 如果没有商品ID,先保存基本信息
|
|
|
- if (!goodsId.value && !isEdit.value) {
|
|
|
- const basicSaved = await saveBasicInfo();
|
|
|
- if (!basicSaved) return;
|
|
|
- }
|
|
|
+ // 直接保存属性
|
|
|
+ await saveAttributesInternal();
|
|
|
+ } finally {
|
|
|
+ savingStates.attributes = false;
|
|
|
+ }
|
|
|
+};
|
|
|
|
|
|
- // 2. 如果属性有修改,保存属性
|
|
|
- await saveAttributesInternal();
|
|
|
+// 保存全部
|
|
|
+const saveAll = async () => {
|
|
|
+ try {
|
|
|
+ savingStates.all = true;
|
|
|
|
|
|
- ElMessage.success('保存成功');
|
|
|
- emit('modalCallBack', { event: 'confirm' });
|
|
|
- } catch (error) {
|
|
|
- ElMessage.error('保存失败:' + error.message);
|
|
|
- } finally {
|
|
|
- savingStates.all = false;
|
|
|
+ // 1. 如果没有商品ID,先保存基本信息
|
|
|
+ if (!goodsId.value && !isEdit.value) {
|
|
|
+ const basicSaved = await saveBasicInfo();
|
|
|
+ if (!basicSaved) return;
|
|
|
}
|
|
|
- };
|
|
|
|
|
|
- // 关闭对话框
|
|
|
- const closeDialog = () => {
|
|
|
- emit('modalCallBack', { event: 'close' });
|
|
|
- };
|
|
|
-
|
|
|
- // SKU相关方法
|
|
|
- const countId = ref(2);
|
|
|
- const childrenModal = [];
|
|
|
- const isResetSku = ref(0);
|
|
|
+ // 2. 如果属性有修改,保存属性
|
|
|
+ await saveAttributesInternal();
|
|
|
|
|
|
- // 批量操作相关变量
|
|
|
- const allEditObj = ref({
|
|
|
- price: 0,
|
|
|
- stock: 0,
|
|
|
- stock_warning: 0,
|
|
|
+ ElMessage.success(t('message.saveSuccess'));
|
|
|
+ emit('modalCallBack', { event: 'confirm' });
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error(t('message.saveFailed') + ':' + error.message);
|
|
|
+ } finally {
|
|
|
+ savingStates.all = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 关闭对话框
|
|
|
+const closeDialog = () => {
|
|
|
+ emit('modalCallBack', { event: 'close' });
|
|
|
+};
|
|
|
+
|
|
|
+// SKU相关方法
|
|
|
+const countId = ref(2);
|
|
|
+const childrenModal = [];
|
|
|
+const isResetSku = ref(0);
|
|
|
+
|
|
|
+// 批量操作相关变量
|
|
|
+const allEditObj = ref({
|
|
|
+ price: 0,
|
|
|
+ stock: 0,
|
|
|
+ stock_warning: 0,
|
|
|
+});
|
|
|
+
|
|
|
+// 添加主规格
|
|
|
+const addMainSku = () => {
|
|
|
+ attributesFormData.skus.push({
|
|
|
+ id: 0,
|
|
|
+ temp_id: countId.value++,
|
|
|
+ name: '',
|
|
|
+ batchId: '',
|
|
|
+ pid: 0,
|
|
|
+ children: [],
|
|
|
});
|
|
|
+ buildSkuPriceTable();
|
|
|
+};
|
|
|
|
|
|
- // 添加主规格
|
|
|
- const addMainSku = () => {
|
|
|
- attributesFormData.skus.push({
|
|
|
- id: 0,
|
|
|
- temp_id: countId.value++,
|
|
|
- name: '',
|
|
|
- batchId: '',
|
|
|
- pid: 0,
|
|
|
- children: [],
|
|
|
- });
|
|
|
- buildSkuPriceTable();
|
|
|
- };
|
|
|
+// 删除主规格
|
|
|
+const deleteMainSku = (k) => {
|
|
|
+ let data = attributesFormData.skus[k];
|
|
|
|
|
|
// 删除主规格
|
|
|
- const deleteMainSku = (k) => {
|
|
|
- let data = attributesFormData.skus[k];
|
|
|
-
|
|
|
- // 删除主规格
|
|
|
- attributesFormData.skus.splice(k, 1);
|
|
|
+ attributesFormData.skus.splice(k, 1);
|
|
|
|
|
|
- // 如果当前删除的主规格存在子规格,则清空 skuPrice
|
|
|
- if (data.children.length > 0) {
|
|
|
- attributesFormData.sku_prices = [];
|
|
|
- isResetSku.value = 1;
|
|
|
+ // 如果当前删除的主规格存在子规格,则清空 skuPrice
|
|
|
+ if (data.children.length > 0) {
|
|
|
+ attributesFormData.sku_prices = [];
|
|
|
+ isResetSku.value = 1;
|
|
|
+ }
|
|
|
+ buildSkuPriceTable();
|
|
|
+};
|
|
|
+
|
|
|
+// 添加子规格
|
|
|
+const addChildrenSku = (k) => {
|
|
|
+ let isExist = false;
|
|
|
+ attributesFormData.skus[k].children.forEach((e) => {
|
|
|
+ if (e.name == childrenModal[k] && e.name != '') {
|
|
|
+ isExist = true;
|
|
|
}
|
|
|
- buildSkuPriceTable();
|
|
|
- };
|
|
|
+ });
|
|
|
+ if (isExist) {
|
|
|
+ ElMessage.warning('子规格已存在');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- // 添加子规格
|
|
|
- const addChildrenSku = (k) => {
|
|
|
- let isExist = false;
|
|
|
- attributesFormData.skus[k].children.forEach((e) => {
|
|
|
- if (e.name == childrenModal[k] && e.name != '') {
|
|
|
- isExist = true;
|
|
|
- }
|
|
|
- });
|
|
|
- if (isExist) {
|
|
|
- ElMessage.warning('子规格已存在');
|
|
|
- return false;
|
|
|
- }
|
|
|
+ attributesFormData.skus[k].children.push({
|
|
|
+ id: 0,
|
|
|
+ temp_id: countId.value++,
|
|
|
+ name: childrenModal[k] || '',
|
|
|
+ pid: attributesFormData.skus[k].id,
|
|
|
+ });
|
|
|
+ childrenModal[k] = '';
|
|
|
|
|
|
- attributesFormData.skus[k].children.push({
|
|
|
- id: 0,
|
|
|
- temp_id: countId.value++,
|
|
|
- name: childrenModal[k] || '',
|
|
|
- pid: attributesFormData.skus[k].id,
|
|
|
+ // 如果是添加的第一个子规格,清空 skuPrice
|
|
|
+ if (attributesFormData.skus[k].children.length == 1) {
|
|
|
+ attributesFormData.sku_prices = [];
|
|
|
+ isResetSku.value = 1;
|
|
|
+ }
|
|
|
+ buildSkuPriceTable();
|
|
|
+};
|
|
|
+
|
|
|
+// 删除子规格
|
|
|
+const deleteChildrenSku = (k, i) => {
|
|
|
+ let data = attributesFormData.skus[k].children[i];
|
|
|
+ attributesFormData.skus[k].children.splice(i, 1);
|
|
|
+
|
|
|
+ // 查询 sku_prices 中包含被删除的子规格的项,然后移除
|
|
|
+ let deleteArr = [];
|
|
|
+ attributesFormData.sku_prices.forEach((item, index) => {
|
|
|
+ item.goods_sku_text.forEach((e) => {
|
|
|
+ if (e == data.name) {
|
|
|
+ deleteArr.push(index);
|
|
|
+ }
|
|
|
});
|
|
|
- childrenModal[k] = '';
|
|
|
-
|
|
|
- // 如果是添加的第一个子规格,清空 skuPrice
|
|
|
- if (attributesFormData.skus[k].children.length == 1) {
|
|
|
- attributesFormData.sku_prices = [];
|
|
|
- isResetSku.value = 1;
|
|
|
- }
|
|
|
- buildSkuPriceTable();
|
|
|
- };
|
|
|
+ });
|
|
|
+ deleteArr.sort(function (a, b) {
|
|
|
+ return b - a;
|
|
|
+ });
|
|
|
+ // 移除有相关子规格的项
|
|
|
+ deleteArr.forEach((idx) => {
|
|
|
+ attributesFormData.sku_prices.splice(idx, 1);
|
|
|
+ });
|
|
|
|
|
|
- // 删除子规格
|
|
|
- const deleteChildrenSku = (k, i) => {
|
|
|
- let data = attributesFormData.skus[k].children[i];
|
|
|
- attributesFormData.skus[k].children.splice(i, 1);
|
|
|
-
|
|
|
- // 查询 sku_prices 中包含被删除的子规格的项,然后移除
|
|
|
- let deleteArr = [];
|
|
|
- attributesFormData.sku_prices.forEach((item, index) => {
|
|
|
- item.goods_sku_text.forEach((e) => {
|
|
|
- if (e == data.name) {
|
|
|
- deleteArr.push(index);
|
|
|
- }
|
|
|
+ // 当前规格项,所有子规格都被删除,清空 sku_prices
|
|
|
+ if (attributesFormData.skus[k].children.length <= 0) {
|
|
|
+ attributesFormData.sku_prices = [];
|
|
|
+ isResetSku.value = 1;
|
|
|
+ }
|
|
|
+ buildSkuPriceTable();
|
|
|
+};
|
|
|
+
|
|
|
+// 组成新的规格
|
|
|
+const buildSkuPriceTable = () => {
|
|
|
+ let arr = [];
|
|
|
+ // 遍历sku子规格生成新数组,然后执行递归笛卡尔积
|
|
|
+ attributesFormData.skus.forEach((s1) => {
|
|
|
+ let children = s1.children;
|
|
|
+ let childrenIdArray = [];
|
|
|
+ if (children.length > 0) {
|
|
|
+ children.forEach((s2) => {
|
|
|
+ childrenIdArray.push(s2.temp_id);
|
|
|
});
|
|
|
- });
|
|
|
- deleteArr.sort(function (a, b) {
|
|
|
- return b - a;
|
|
|
- });
|
|
|
- // 移除有相关子规格的项
|
|
|
- deleteArr.forEach((idx) => {
|
|
|
- attributesFormData.sku_prices.splice(idx, 1);
|
|
|
- });
|
|
|
-
|
|
|
- // 当前规格项,所有子规格都被删除,清空 sku_prices
|
|
|
- if (attributesFormData.skus[k].children.length <= 0) {
|
|
|
- attributesFormData.sku_prices = [];
|
|
|
- isResetSku.value = 1;
|
|
|
+ // 如果 children 子规格数量为 0,则不渲染当前规格
|
|
|
+ arr.push(childrenIdArray);
|
|
|
}
|
|
|
- buildSkuPriceTable();
|
|
|
- };
|
|
|
-
|
|
|
- // 组成新的规格
|
|
|
- const buildSkuPriceTable = () => {
|
|
|
- let arr = [];
|
|
|
- // 遍历sku子规格生成新数组,然后执行递归笛卡尔积
|
|
|
- attributesFormData.skus.forEach((s1) => {
|
|
|
- let children = s1.children;
|
|
|
- let childrenIdArray = [];
|
|
|
- if (children.length > 0) {
|
|
|
- children.forEach((s2) => {
|
|
|
- childrenIdArray.push(s2.temp_id);
|
|
|
- });
|
|
|
- // 如果 children 子规格数量为 0,则不渲染当前规格
|
|
|
- arr.push(childrenIdArray);
|
|
|
- }
|
|
|
- });
|
|
|
- recursionSku(arr, 0, []);
|
|
|
- };
|
|
|
-
|
|
|
- // 递归找笛卡尔规格集合
|
|
|
- const recursionSku = (arr, k, temp) => {
|
|
|
- if (k == arr.length && k != 0) {
|
|
|
- let tempDetail = [];
|
|
|
- let tempDetailIds = [];
|
|
|
- temp.forEach((item) => {
|
|
|
- for (let sku of attributesFormData.skus) {
|
|
|
- for (let child of sku.children) {
|
|
|
- if (item == child.temp_id) {
|
|
|
- tempDetail.push(child.name);
|
|
|
- tempDetailIds.push(child.temp_id);
|
|
|
- }
|
|
|
+ });
|
|
|
+ recursionSku(arr, 0, []);
|
|
|
+};
|
|
|
+
|
|
|
+// 递归找笛卡尔规格集合
|
|
|
+const recursionSku = (arr, k, temp) => {
|
|
|
+ if (k == arr.length && k != 0) {
|
|
|
+ let tempDetail = [];
|
|
|
+ let tempDetailIds = [];
|
|
|
+ temp.forEach((item) => {
|
|
|
+ for (let sku of attributesFormData.skus) {
|
|
|
+ for (let child of sku.children) {
|
|
|
+ if (item == child.temp_id) {
|
|
|
+ tempDetail.push(child.name);
|
|
|
+ tempDetailIds.push(child.temp_id);
|
|
|
}
|
|
|
}
|
|
|
- });
|
|
|
- let flag = false; // 默认添加新的
|
|
|
- for (let i = 0; i < attributesFormData.sku_prices.length; i++) {
|
|
|
- if (
|
|
|
- attributesFormData.sku_prices[i].goods_sku_temp_ids.join(',') == tempDetailIds.join(',')
|
|
|
- ) {
|
|
|
- flag = i;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (flag === false) {
|
|
|
- attributesFormData.sku_prices.push({
|
|
|
- id: 0,
|
|
|
- temp_id: attributesFormData.sku_prices.length + 1,
|
|
|
- goods_sku_ids: '',
|
|
|
- goods_id: 0,
|
|
|
- image: '',
|
|
|
- imageList: [],
|
|
|
- price: 0,
|
|
|
- stock: 0,
|
|
|
- stock_warning: 0,
|
|
|
- sn: '',
|
|
|
- goods_sku_text: tempDetail,
|
|
|
- goods_sku_temp_ids: tempDetailIds,
|
|
|
- });
|
|
|
- } else {
|
|
|
- attributesFormData.sku_prices[flag].goods_sku_text = tempDetail;
|
|
|
- attributesFormData.sku_prices[flag].goods_sku_temp_ids = tempDetailIds;
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
- if (arr.length) {
|
|
|
- for (let i = 0; i < arr[k].length; i++) {
|
|
|
- temp[k] = arr[k][i];
|
|
|
- recursionSku(arr, k + 1, temp);
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // 批量操作
|
|
|
- const batchEdit = () => {
|
|
|
- const batchIds = attributesFormData.skus
|
|
|
- .map((item) => item.batchId)
|
|
|
- .filter((item) => Boolean(item));
|
|
|
- attributesFormData.sku_prices.forEach((item) => {
|
|
|
- if (
|
|
|
- batchIds.length ? batchIds.every((citem) => item.goods_sku_temp_ids.includes(citem)) : true
|
|
|
- ) {
|
|
|
- const { price, stock, stock_warning } = allEditObj.value;
|
|
|
- if (price) item.price = price;
|
|
|
- if (stock) item.stock = stock;
|
|
|
- if (stock_warning) item.stock_warning = stock_warning;
|
|
|
}
|
|
|
});
|
|
|
-
|
|
|
- // 清空输入框
|
|
|
- allEditObj.value = {
|
|
|
- price: 0,
|
|
|
- stock: 0,
|
|
|
- stock_warning: 0,
|
|
|
- };
|
|
|
-
|
|
|
- // 清空选择的规格
|
|
|
- attributesFormData.skus.forEach((item) => {
|
|
|
- item.batchId = '';
|
|
|
- });
|
|
|
-
|
|
|
- ElMessage.success('批量设置成功');
|
|
|
- };
|
|
|
-
|
|
|
- // 删除规格组合
|
|
|
- const deleteSkuPrice = (index) => {
|
|
|
- attributesFormData.sku_prices.splice(index, 1);
|
|
|
- ElMessage.success('删除成功');
|
|
|
- };
|
|
|
-
|
|
|
- // SKU校验
|
|
|
- const validateSku = () => {
|
|
|
- if (attributesFormData.sku_prices.length === 0) {
|
|
|
- ElMessage.error('请先添加商品规格');
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
+ let flag = false; // 默认添加新的
|
|
|
for (let i = 0; i < attributesFormData.sku_prices.length; i++) {
|
|
|
- const item = attributesFormData.sku_prices[i];
|
|
|
- if (!item.price || item.price <= 0) {
|
|
|
- ElMessage.error(`第${i + 1}个规格的销售价格不能为空且必须大于0`);
|
|
|
- return false;
|
|
|
- }
|
|
|
- if (item.stock === null || item.stock === undefined || item.stock < 0) {
|
|
|
- ElMessage.error(`第${i + 1}个规格的商品库存不能为空且不能小于0`);
|
|
|
- return false;
|
|
|
+ if (
|
|
|
+ attributesFormData.sku_prices[i].goods_sku_temp_ids.join(',') == tempDetailIds.join(',')
|
|
|
+ ) {
|
|
|
+ flag = i;
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
- return true;
|
|
|
- };
|
|
|
|
|
|
- // 生成后端需要的 attrValue 数据格式
|
|
|
- const generateAttrValueData = () => {
|
|
|
- return attributesFormData.sku_prices.map((item) => {
|
|
|
- // 构建规格属性对象,如 {"颜色": "红色", "尺寸": "S"}
|
|
|
- const attrObj = {};
|
|
|
- const attrValueObj = {};
|
|
|
-
|
|
|
- // 根据 goods_sku_text 和对应的规格名称构建属性对象
|
|
|
- item.goods_sku_text.forEach((value, index) => {
|
|
|
- const specName = attributesFormData.skus[index]?.name;
|
|
|
- if (specName) {
|
|
|
- attrObj[specName] = value;
|
|
|
- attrValueObj[specName] = value;
|
|
|
- }
|
|
|
+ if (flag === false) {
|
|
|
+ attributesFormData.sku_prices.push({
|
|
|
+ id: 0,
|
|
|
+ temp_id: attributesFormData.sku_prices.length + 1,
|
|
|
+ goods_sku_ids: '',
|
|
|
+ goods_id: 0,
|
|
|
+ image: '',
|
|
|
+ imageList: [],
|
|
|
+ price: 0,
|
|
|
+ stock: 0,
|
|
|
+ stock_warning: 0,
|
|
|
+ sn: '',
|
|
|
+ goods_sku_text: tempDetail,
|
|
|
+ goods_sku_temp_ids: tempDetailIds,
|
|
|
});
|
|
|
+ } else {
|
|
|
+ attributesFormData.sku_prices[flag].goods_sku_text = tempDetail;
|
|
|
+ attributesFormData.sku_prices[flag].goods_sku_temp_ids = tempDetailIds;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (arr.length) {
|
|
|
+ for (let i = 0; i < arr[k].length; i++) {
|
|
|
+ temp[k] = arr[k][i];
|
|
|
+ recursionSku(arr, k + 1, temp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 批量操作
|
|
|
+const batchEdit = () => {
|
|
|
+ const batchIds = attributesFormData.skus
|
|
|
+ .map((item) => item.batchId)
|
|
|
+ .filter((item) => Boolean(item));
|
|
|
+ attributesFormData.sku_prices.forEach((item) => {
|
|
|
+ if (
|
|
|
+ batchIds.length ? batchIds.every((citem) => item.goods_sku_temp_ids.includes(citem)) : true
|
|
|
+ ) {
|
|
|
+ const { price, stock, stock_warning } = allEditObj.value;
|
|
|
+ if (price) item.price = price;
|
|
|
+ if (stock) item.stock = stock;
|
|
|
+ if (stock_warning) item.stock_warning = stock_warning;
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
- return {
|
|
|
- image: item.imageList && item.imageList.length > 0 ? item.imageList[0] : '',
|
|
|
- price: item.price || '0',
|
|
|
- stock: item.stock || 0,
|
|
|
- barCode: item.sn || '',
|
|
|
- stock_warning: item.stock_warning || 0,
|
|
|
- attrValue: JSON.stringify(attrValueObj),
|
|
|
- ...attrObj, // 展开规格属性,如 "颜色": "红色", "尺寸": "S"
|
|
|
- id: 0,
|
|
|
- productId: 0,
|
|
|
- };
|
|
|
- });
|
|
|
+ // 清空输入框
|
|
|
+ allEditObj.value = {
|
|
|
+ price: 0,
|
|
|
+ stock: 0,
|
|
|
+ stock_warning: 0,
|
|
|
};
|
|
|
|
|
|
- // 生成后端需要的 attr 数据格式
|
|
|
- const generateAttrData = () => {
|
|
|
- return attributesFormData.skus
|
|
|
- .filter((sku) => sku.name && sku.children.length > 0)
|
|
|
- .map((sku) => ({
|
|
|
- attrName: sku.name,
|
|
|
- attrValues: sku.children.map((child) => child.name).join(','),
|
|
|
- }));
|
|
|
- };
|
|
|
+ // 清空选择的规格
|
|
|
+ attributesFormData.skus.forEach((item) => {
|
|
|
+ item.batchId = '';
|
|
|
+ });
|
|
|
|
|
|
- // 获取分类数据
|
|
|
- const getCategoryData = async () => {
|
|
|
- const { code, data } = await api.category.list({ size: 100 });
|
|
|
- code === '200' &&
|
|
|
- (categoryOptions.value = data.list.map((cat) => ({
|
|
|
- label: cat.name,
|
|
|
- value: cat.id,
|
|
|
- id: cat.id,
|
|
|
- name: cat.name,
|
|
|
- })));
|
|
|
- };
|
|
|
+ ElMessage.success('批量设置成功');
|
|
|
+};
|
|
|
|
|
|
- // 加载商品详情
|
|
|
- const loadGoodsDetail = async () => {
|
|
|
- if (!goodsId.value) return;
|
|
|
+// 删除规格组合
|
|
|
+const deleteSkuPrice = (index) => {
|
|
|
+ attributesFormData.sku_prices.splice(index, 1);
|
|
|
+ ElMessage.success(t('message.deleteSuccess'));
|
|
|
+};
|
|
|
|
|
|
- const { code, data } = await api.goods.detail(goodsId.value);
|
|
|
- if (code === '200') {
|
|
|
- // 转换图片字段
|
|
|
- data.image = convertStringToImages(data.image);
|
|
|
- data.sliderImage = convertStringToImages(data.sliderImage);
|
|
|
- data.flatPattern = convertStringToImages(data.flatPattern);
|
|
|
+// SKU校验
|
|
|
+const validateSku = () => {
|
|
|
+ if (attributesFormData.sku_prices.length === 0) {
|
|
|
+ ElMessage.error('请先添加商品规格');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- Object.assign(basicFormData, data);
|
|
|
- basicSaved.value = true;
|
|
|
+ for (let i = 0; i < attributesFormData.sku_prices.length; i++) {
|
|
|
+ const item = attributesFormData.sku_prices[i];
|
|
|
+ if (!item.price || item.price <= 0) {
|
|
|
+ ElMessage.error(`第${i + 1}个规格的销售价格不能为空且必须大于0`);
|
|
|
+ return false;
|
|
|
}
|
|
|
- };
|
|
|
-
|
|
|
- // 初始化
|
|
|
- const init = async () => {
|
|
|
- await getCategoryData();
|
|
|
-
|
|
|
- if (isEdit.value && goodsId.value) {
|
|
|
- await loadGoodsDetail();
|
|
|
+ if (item.stock === null || item.stock === undefined || item.stock < 0) {
|
|
|
+ ElMessage.error(`第${i + 1}个规格的商品库存不能为空且不能小于0`);
|
|
|
+ return false;
|
|
|
}
|
|
|
- };
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+};
|
|
|
+
|
|
|
+// 生成后端需要的 attrValue 数据格式
|
|
|
+const generateAttrValueData = () => {
|
|
|
+ return attributesFormData.sku_prices.map((item) => {
|
|
|
+ // 构建规格属性对象,如 {"颜色": "红色", "尺寸": "S"}
|
|
|
+ const attrObj = {};
|
|
|
+ const attrValueObj = {};
|
|
|
+
|
|
|
+ // 根据 goods_sku_text 和对应的规格名称构建属性对象
|
|
|
+ item.goods_sku_text.forEach((value, index) => {
|
|
|
+ const specName = attributesFormData.skus[index]?.name;
|
|
|
+ if (specName) {
|
|
|
+ attrObj[specName] = value;
|
|
|
+ attrValueObj[specName] = value;
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
- // 组件挂载
|
|
|
- onMounted(() => {
|
|
|
- init();
|
|
|
+ return {
|
|
|
+ image: item.imageList && item.imageList.length > 0 ? item.imageList[0] : '',
|
|
|
+ price: item.price || '0',
|
|
|
+ stock: item.stock || 0,
|
|
|
+ barCode: item.sn || '',
|
|
|
+ stock_warning: item.stock_warning || 0,
|
|
|
+ attrValue: JSON.stringify(attrValueObj),
|
|
|
+ ...attrObj, // 展开规格属性,如 "颜色": "红色", "尺寸": "S"
|
|
|
+ id: 0,
|
|
|
+ productId: 0,
|
|
|
+ };
|
|
|
});
|
|
|
+};
|
|
|
+
|
|
|
+// 生成后端需要的 attr 数据格式
|
|
|
+const generateAttrData = () => {
|
|
|
+ return attributesFormData.skus
|
|
|
+ .filter((sku) => sku.name && sku.children.length > 0)
|
|
|
+ .map((sku) => ({
|
|
|
+ attrName: sku.name,
|
|
|
+ attrValues: sku.children.map((child) => child.name).join(','),
|
|
|
+ }));
|
|
|
+};
|
|
|
+
|
|
|
+// 获取分类数据
|
|
|
+const getCategoryData = async () => {
|
|
|
+ const { code, data } = await api.category.list({ size: 100 });
|
|
|
+ code === '200' &&
|
|
|
+ (categoryOptions.value = data.list.map((cat) => ({
|
|
|
+ label: cat.name,
|
|
|
+ value: cat.id,
|
|
|
+ id: cat.id,
|
|
|
+ name: cat.name,
|
|
|
+ })));
|
|
|
+};
|
|
|
+
|
|
|
+// 加载商品详情
|
|
|
+const loadGoodsDetail = async () => {
|
|
|
+ if (!goodsId.value) return;
|
|
|
+
|
|
|
+ const { code, data } = await api.goods.detail(goodsId.value);
|
|
|
+ if (code === '200') {
|
|
|
+ // 转换图片字段
|
|
|
+ data.image = convertStringToImages(data.image);
|
|
|
+ data.sliderImage = convertStringToImages(data.sliderImage);
|
|
|
+ data.flatPattern = convertStringToImages(data.flatPattern);
|
|
|
+
|
|
|
+ Object.assign(basicFormData, data);
|
|
|
+ basicSaved.value = true;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 初始化
|
|
|
+const init = async () => {
|
|
|
+ await getCategoryData();
|
|
|
+
|
|
|
+ if (isEdit.value && goodsId.value) {
|
|
|
+ await loadGoodsDetail();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 组件挂载
|
|
|
+onMounted(() => {
|
|
|
+ init();
|
|
|
+});
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
- .goods-edit {
|
|
|
- height: 100%;
|
|
|
-
|
|
|
- .el-header {
|
|
|
- height: auto;
|
|
|
- padding: 0;
|
|
|
- }
|
|
|
+.goods-edit {
|
|
|
+ height: 100%;
|
|
|
|
|
|
- .el-main {
|
|
|
- padding: 20px;
|
|
|
- }
|
|
|
+ .el-header {
|
|
|
+ height: auto;
|
|
|
+ padding: 0;
|
|
|
}
|
|
|
|
|
|
- .tab-placeholder {
|
|
|
+ .el-main {
|
|
|
+ padding: 20px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.tab-placeholder {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ min-height: 300px;
|
|
|
+}
|
|
|
+
|
|
|
+.tab-disabled-tip {
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--el-color-info);
|
|
|
+ margin-left: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.is-error {
|
|
|
+ color: var(--el-color-danger);
|
|
|
+}
|
|
|
+
|
|
|
+.text-success {
|
|
|
+ color: var(--el-color-success);
|
|
|
+}
|
|
|
+
|
|
|
+.spec-card {
|
|
|
+ .card-header {
|
|
|
display: flex;
|
|
|
- justify-content: center;
|
|
|
+ justify-content: space-between;
|
|
|
align-items: center;
|
|
|
- min-height: 300px;
|
|
|
+ font-weight: 500;
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- .tab-disabled-tip {
|
|
|
- font-size: 12px;
|
|
|
- color: var(--el-color-info);
|
|
|
- margin-left: 4px;
|
|
|
- }
|
|
|
+.sku-wrap {
|
|
|
+ width: 100%;
|
|
|
+ border: 1px solid #d9d9d9;
|
|
|
+ padding: 8px;
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
|
- .is-error {
|
|
|
- color: var(--el-color-danger);
|
|
|
- }
|
|
|
+ .sku {
|
|
|
+ width: 100%;
|
|
|
+ min-height: 100px;
|
|
|
|
|
|
- .text-success {
|
|
|
- color: var(--el-color-success);
|
|
|
- }
|
|
|
+ .sku-key {
|
|
|
+ width: 100%;
|
|
|
+ height: 40px;
|
|
|
+ color: var(--sa-subtitle);
|
|
|
+ padding: 0 16px;
|
|
|
+ background: var(--sa-table-header-bg);
|
|
|
+ font-size: 14px;
|
|
|
|
|
|
- .spec-card {
|
|
|
- .card-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- font-weight: 500;
|
|
|
+ .sku-key-input {
|
|
|
+ width: 120px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .sku-key-icon {
|
|
|
+ color: var(--el-color-primary);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- .sku-wrap {
|
|
|
- width: 100%;
|
|
|
- border: 1px solid #d9d9d9;
|
|
|
- padding: 8px;
|
|
|
- box-sizing: border-box;
|
|
|
- .sku {
|
|
|
- width: 100%;
|
|
|
- min-height: 100px;
|
|
|
- .sku-key {
|
|
|
- width: 100%;
|
|
|
- height: 40px;
|
|
|
- color: var(--sa-subtitle);
|
|
|
- padding: 0 16px;
|
|
|
- background: var(--sa-table-header-bg);
|
|
|
- font-size: 14px;
|
|
|
- .sku-key-input {
|
|
|
- width: 120px;
|
|
|
- }
|
|
|
- .sku-key-icon {
|
|
|
- color: var(--el-color-primary);
|
|
|
- }
|
|
|
+ .sku-value {
|
|
|
+ padding: 12px 0 0 30px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: var(--sa-subtitle);
|
|
|
+
|
|
|
+ .sku-value-title {
|
|
|
+ height: 32px;
|
|
|
}
|
|
|
- .sku-value {
|
|
|
- padding: 12px 0 0 30px;
|
|
|
- font-size: 14px;
|
|
|
- color: var(--sa-subtitle);
|
|
|
- .sku-value-title {
|
|
|
- height: 32px;
|
|
|
- }
|
|
|
- .sku-value-box {
|
|
|
- position: relative;
|
|
|
- margin-right: 24px;
|
|
|
- .sku-value-input {
|
|
|
- width: 104px;
|
|
|
- }
|
|
|
- .sku-value-icon {
|
|
|
- position: absolute;
|
|
|
- right: -8px;
|
|
|
- top: -8px;
|
|
|
- width: 16px;
|
|
|
- height: 16px;
|
|
|
- color: var(--el-color-primary);
|
|
|
- }
|
|
|
- }
|
|
|
- .sku-value-add {
|
|
|
+
|
|
|
+ .sku-value-box {
|
|
|
+ position: relative;
|
|
|
+ margin-right: 24px;
|
|
|
+
|
|
|
+ .sku-value-input {
|
|
|
width: 104px;
|
|
|
- height: 32px;
|
|
|
- font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .sku-value-icon {
|
|
|
+ position: absolute;
|
|
|
+ right: -8px;
|
|
|
+ top: -8px;
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
color: var(--el-color-primary);
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- .sku-tools {
|
|
|
- width: 100%;
|
|
|
- height: 40px;
|
|
|
- color: #434343;
|
|
|
- padding-left: 16px;
|
|
|
- background: var(--sa-table-header-bg);
|
|
|
- font-size: 12px;
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- .sku-table-wrap {
|
|
|
- width: 100%;
|
|
|
- overflow: auto;
|
|
|
- margin-top: 16px;
|
|
|
- .sku-table {
|
|
|
- width: 100%;
|
|
|
- border: 1px solid var(--sa-border);
|
|
|
- tbody {
|
|
|
- font-size: 12px;
|
|
|
- }
|
|
|
- th {
|
|
|
- font-size: 12px;
|
|
|
- color: var(--subtitle);
|
|
|
+ .sku-value-add {
|
|
|
+ width: 104px;
|
|
|
height: 32px;
|
|
|
- line-height: 1;
|
|
|
- padding-left: 12px;
|
|
|
- box-sizing: border-box;
|
|
|
- text-align: left;
|
|
|
- }
|
|
|
- td {
|
|
|
- min-width: 88px;
|
|
|
- padding: 0 10px;
|
|
|
- height: 40px;
|
|
|
- box-sizing: border-box;
|
|
|
- &.image {
|
|
|
- min-width: 48px;
|
|
|
- }
|
|
|
- &.stock {
|
|
|
- min-width: 138px;
|
|
|
- }
|
|
|
- &.stock_warning {
|
|
|
- min-width: 168px;
|
|
|
- }
|
|
|
- &.sn {
|
|
|
- min-width: 116px;
|
|
|
- }
|
|
|
+ font-size: 14px;
|
|
|
+ color: var(--el-color-primary);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- :deep(.el-tabs__header) {
|
|
|
- margin: 0;
|
|
|
+ .sku-tools {
|
|
|
+ width: 100%;
|
|
|
+ height: 40px;
|
|
|
+ color: #434343;
|
|
|
+ padding-left: 16px;
|
|
|
+ background: var(--sa-table-header-bg);
|
|
|
+ font-size: 12px;
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- :deep(.el-tabs__nav-wrap::after) {
|
|
|
- height: 1px;
|
|
|
- }
|
|
|
+.sku-table-wrap {
|
|
|
+ width: 100%;
|
|
|
+ overflow: auto;
|
|
|
+ margin-top: 16px;
|
|
|
|
|
|
- :deep(.el-tabs__item) {
|
|
|
- padding: 0 20px;
|
|
|
- font-size: 14px;
|
|
|
- }
|
|
|
+ .sku-table {
|
|
|
+ width: 100%;
|
|
|
+ border: 1px solid var(--sa-border);
|
|
|
|
|
|
- :deep(.el-tabs__nav) {
|
|
|
- border: none;
|
|
|
- }
|
|
|
+ tbody {
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
|
|
|
- .form-tip {
|
|
|
- font-size: 12px;
|
|
|
- color: var(--el-color-info);
|
|
|
- margin-top: 4px;
|
|
|
- line-height: 1.4;
|
|
|
- }
|
|
|
+ th {
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--subtitle);
|
|
|
+ height: 32px;
|
|
|
+ line-height: 1;
|
|
|
+ padding-left: 12px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ text-align: left;
|
|
|
+ }
|
|
|
|
|
|
- .mt-1px {
|
|
|
- margin-top: 1px;
|
|
|
- }
|
|
|
+ td {
|
|
|
+ min-width: 88px;
|
|
|
+ padding: 0 10px;
|
|
|
+ height: 40px;
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
|
- /* 必填项样式 */
|
|
|
- .required {
|
|
|
- color: #f56c6c;
|
|
|
- margin-right: 4px;
|
|
|
- }
|
|
|
+ &.image {
|
|
|
+ min-width: 48px;
|
|
|
+ }
|
|
|
|
|
|
- /* 错误状态样式 */
|
|
|
- .is-error .el-input__wrapper {
|
|
|
- border-color: #f56c6c !important;
|
|
|
- box-shadow: 0 0 0 1px #f56c6c inset !important;
|
|
|
- }
|
|
|
+ &.stock {
|
|
|
+ min-width: 138px;
|
|
|
+ }
|
|
|
|
|
|
- .warning-title {
|
|
|
- font-size: 12px;
|
|
|
- color: #909399;
|
|
|
- }
|
|
|
+ &.stock_warning {
|
|
|
+ min-width: 168px;
|
|
|
+ }
|
|
|
|
|
|
- .th-center {
|
|
|
- text-align: center;
|
|
|
+ &.sn {
|
|
|
+ min-width: 116px;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-tabs__header) {
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-tabs__nav-wrap::after) {
|
|
|
+ height: 1px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-tabs__item) {
|
|
|
+ padding: 0 20px;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-tabs__nav) {
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+
|
|
|
+.form-tip {
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--el-color-info);
|
|
|
+ margin-top: 4px;
|
|
|
+ line-height: 1.4;
|
|
|
+}
|
|
|
+
|
|
|
+.mt-1px {
|
|
|
+ margin-top: 1px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 必填项样式 */
|
|
|
+.required {
|
|
|
+ color: #f56c6c;
|
|
|
+ margin-right: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 错误状态样式 */
|
|
|
+.is-error .el-input__wrapper {
|
|
|
+ border-color: #f56c6c !important;
|
|
|
+ box-shadow: 0 0 0 1px #f56c6c inset !important;
|
|
|
+}
|
|
|
+
|
|
|
+.warning-title {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+.th-center {
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
</style>
|