602 lines
21 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container customer-control">
<div class="customer-box">
<el-form ref="formRef" :model="formInline" :rules="rules" class="demo-form-inline" :label-width="'auto'">
<!-- 商品名称 -->
<el-form-item label="商品名称" prop="goodName">
<el-input v-model="formInline.goodName" clearable show-word-limit maxlength="30" placeholder="请输入商品名称"
style="width: 800px" />
</el-form-item>
<!-- 商品分类 -->
<el-form-item label="商品分类" required>
<div style="display: flex; gap: 16px;">
<el-form-item prop="categoryId1">
<el-select v-model="formInline.categoryId1" placeholder="请选择" class="my-el-select"
@change="changeCategory1($event)">
<el-option v-for="item in categoryList1" :key="item.id" :value="item.id" :label="item.name" />
</el-select>
</el-form-item>
<el-form-item prop="categoryId2">
<el-select v-model="formInline.categoryId2" placeholder="请选择" class="my-el-select"
@change="changeCategory2($event)">
<el-option v-for="item in categoryList2" :key="item.id" :value="item.id" :label="item.name" />
</el-select>
</el-form-item>
<el-form-item prop="categoryId3">
<el-select v-model="formInline.categoryId3" placeholder="请选择" class="my-el-select"
@change="changeCategory3($event)">
<el-option v-for="item in categoryList3" :key="item.id" :value="item.id" :label="item.name" />
</el-select>
</el-form-item>
</div>
</el-form-item>
<!-- 公共品牌 -->
<el-form-item label="公共品牌" prop="brandId" v-show="formInline.goodCategorySelectType == 1">
<el-input v-model="formInline.brandId" clearable placeholder="请输入公共品牌" style="width: 800px" />
</el-form-item>
<!-- 溯源编码 -->
<el-form-item label="溯源编码" prop="traceCode" v-show="formInline.goodCategorySelectType == 1">
<el-input v-model="formInline.traceCode" clearable placeholder="请输入溯源编码" style="width: 800px" />
</el-form-item>
<!-- 商品图片 -->
<el-form-item label="商品图片" prop="goodUrl" required>
<div>
<myUploadImage v-model="formInline.goodUrl"></myUploadImage>
</div>
</el-form-item>
<!-- 规格样式 -->
<el-form-item label="规格样式" prop="specStyle" required>
<el-radio-group v-model="formInline.specStyle" style="margin-top: -3px;">
<el-radio value="1" size="large">单规格</el-radio>
<el-radio value="2" size="large">多规格</el-radio>
</el-radio-group>
</el-form-item>
<div v-if="formInline.specStyle == '1'">
<el-form-item label="规格名称" prop="goodSpecs" required>
<el-input v-model="formInline.goodSpecs" class="attr-clomn" placeholder="请输入规格名称" />
</el-form-item>
<!-- 销售价格 -->
<el-form-item label="销售价格" prop="salePrice" required>
<el-input-number v-model="formInline.salePrice" :min="1" :precision="2" :controls="false"></el-input-number>
<span style="padding: 0 10px;">元</span>
</el-form-item>
<!-- 库存数量 -->
<el-form-item label="库存数量" prop="stock" required>
<el-input-number v-model="formInline.stock" :min="1" :controls="false" />
</el-form-item>
<!-- 净含量 -->
<el-form-item label="净含量" prop="netContent" required>
<el-input-number v-model="formInline.netContent" :min="1" :controls="false" />
<el-select v-model="formInline.unit" style="width: 80px; margin-left: 10px">
<el-option label="kg" value="kg" />
<el-option label="g" value="g" />
<el-option label="L" value="L" />
<el-option label="ml" value="ml" />
<el-option label="棵" value="棵" />
<el-option label="袋" value="袋" />
<el-option label="瓶" value="瓶" />
<el-option label="件" value="件" />
</el-select>
</el-form-item>
</div>
<!-- 多规格 -->
<div v-else>
<el-form-item label="商品规格" prop="netWeight" required>
<div v-for="(item, index) in formInline.netWeight" :key="index" class="attr-item">
<el-input v-model="item.goodSpecs" :value="item.goodSpecs" class="attr-clomn" placeholder="请输入规格名称" />
<el-icon size="20px" v-if="index !== 0" @click="deleteSpecs(index)" style="cursor: pointer;">
<Delete />
</el-icon>
</div>
<el-button icon="plus" type="primary" plain style="margin: 0" @click="addSpecs">添加属性</el-button>
</el-form-item>
<!-- 价格库存 -->
<el-form-item label="价格库存" prop="netWeight" required>
<div class="attr-box">
<div class="attr-row">
<div class="attr-clomn color-gray">商品规格</div>
<div class="attr-clomn200 color-gray">销售价格</div>
<div class="attr-clomn color-gray">库存数量</div>
<div class="attr-clomn220 color-gray">净含量</div>
</div>
<div v-for="(item, index) in formInline.netWeight" :key="index" class="attr-row">
<div class="attr-clomn">{{ item.goodSpecs }}</div>
<div class="attr-clomn200 flex-left-top">
<el-input-number v-model="item.goodPrice" :min="1" :precision="2" :controls="false"></el-input-number>
<span style="padding: 0 10px;">元</span>
</div>
<div class="attr-clomn">
<el-input-number v-model="item.goodStock" :min="1" :controls="false" />
</div>
<div class="attr-clomn220 flex-left-top">
<el-input-number v-model="item.netContent" :min="1" :controls="false" />
<el-select v-model="item.unit" style="width: 80px; margin-left: 10px">
<el-option label="kg" value="kg" />
<el-option label="g" value="g" />
<el-option label="L" value="L" />
<el-option label="ml" value="ml" />
<el-option label="棵" value="棵" />
<el-option label="袋" value="袋" />
<el-option label="瓶" value="瓶" />
<el-option label="件" value="件" />
</el-select>
</div>
</div>
</div>
</el-form-item>
</div>
<!-- 商品属性 -->
<el-form-item label="商品属性" prop="attribute" required>
<div v-for="(item, index) in formInline.attribute" :key="index" class="attr-item">
<el-input v-model="item.name" :value="item.name" class="attr-input" placeholder="请输入属性名称" />
<el-icon size="20px" v-if="index !== 0" @click="deleteAttr(index)" style="cursor: pointer;">
<Delete />
</el-icon>
</div>
<el-button icon="plus" type="primary" plain style="margin: 0" @click="addAttr">添加规格</el-button>
</el-form-item>
<!-- 属性内容 -->
<el-form-item label="属性内容" prop="attribute" required>
<div class="attr-box">
<div class="attr-row">
<div class="attr-input color-gray">属性名称</div>
<div class="attr-input color-gray">属性内容</div>
</div>
<div v-for="(item, index) in formInline.attribute" :key="index" class="attr-row">
<div class="attr-input">{{ item.name }}</div>
<el-input v-model="item.value" class="attr-input" />
</div>
</div>
</el-form-item>
<!-- 发货地址 -->
<el-form-item label="发货地址" required>
<div style="display: flex; gap: 16px;">
<el-form-item prop="selectedAddress">
<!-- 区域级联选择器 -->
<el-cascader v-model="formInline.selectedAddress" :options="addressOptions" :props="cascaderProps"
placeholder="请选择区域" clearable style="width: 400px;" />
</el-form-item>
<el-form-item prop="detailAddress">
<!-- 详细地址输入框 -->
<el-input v-model="formInline.detailAddress" placeholder="详细地址(如街道、门牌号等)" style="width: 220px;" />
</el-form-item>
</div>
</el-form-item>
<!-- 保障服务 -->
<el-form-item label="保障服务" prop="safeguard" required style="margin-bottom: 10px;">
<el-checkbox v-model="isSafeguardSelected" size="large" style="margin-top: -3px;">
<div style="color: #333;" v-for="(item) in formInline.safeguard.options" :key="item.id">服务承诺:{{ item.text }}
</div>
</el-checkbox>
</el-form-item>
<!-- 优惠折扣 -->
<el-form-item label="优惠折扣" style="margin-bottom: 10px;">
<div style="width: 100%;">
<el-checkbox v-model="isDiscountSettings" size="large" style="margin-top: -3px;">
<div style="color: #333;" v-for="(item) in formInline.discountSettings.options" :key="item.id">
优惠设置:{{
item.text }}</div>
</el-checkbox>
</div>
<div style="width: 100%;">
<el-checkbox v-model="isDiscountRebate" size="large" style="margin-top: -3px;">
<div style="color: #333;" v-for="(item) in formInline.discountSettings.options" :key="item.id">
折扣设置:{{
item.text }}</div>
</el-checkbox>
</div>
</el-form-item>
<!-- 商品详情 -->
<el-form-item label="商品详情" prop="detailUrl">
<div>
<myUploadImage v-model="formInline.detailUrl" :isShowSubscript="false"></myUploadImage>
</div>
</el-form-item>
<!-- 商品视频 -->
<el-form-item label="商品视频" prop="videoUrl">
<div>
<myUploadVideo v-model="formInline.videoUrl"></myUploadVideo>
</div>
</el-form-item>
</el-form>
<el-button type="primary" @click="onSubmit" style="margin: 10px 0 0 80px;width: 150px;">确认新增</el-button>
</div>
</div>
</template>
<script setup name="addGoods">
import { ca } from "element-plus/es/locales.mjs";
import { ref, reactive, nextTick, onMounted } from "vue";
import myUploadImage from "@/components/myUploadImage.vue";
import myUploadVideo from "@/components/myUploadVideo.vue";
import { getGoodType, goodAdd, getActiveInfos } from "@/api/goods/info";
import { getRegion } from "@/api/common";
import { ElMessage } from "element-plus";
import areaList from "./areaList";
const formRef = ref(null)
const formInline = reactive({
goodName: "",
categoryId: "", //给后端的最后一级,
categoryId1: "", //一级,
categoryId2: "", //二级
categoryId3: "", //三级
goodUrl: "", //逗号分割的多个图片地址字符串
goodCategorySelectType: 2, // 商品分类一级选项
brandId: "", //品牌
traceCode: "", //溯源码
specStyle: "1",//规格样式 1单规格 2多规格
salePrice: 1,//销售价格-单规格
stock: 1,//库存数量-单规格
netContent: 1,//净含量-单规格
unit: "kg",//净含量单位-单规格
netWeight: [ //多规格集合
{
goodSpecs: "",
goodPrice: 1,
goodStock: 1,
netContent: 1,
unit: "kg"
}
], //规格
attribute: [
{
name: '', //属性
value: '', //内容
},
],
selectedAddress: [], //选中的区域编码数组
areaAddress: '', //区域地址
detailAddress: "", //详细地址
sendAddress: "",
safeguard: {
isSelected: 1, //0未选中 1选中
options: [
// { id: 10, text: '该商品,支持【七天无理由退货】服务' },
]
}, //保障服务
discountSettings: {
isSelected: 0, //0未选中 1选中
options: [
// { id: 11, text: '支持【满100减10元】优惠活动' },
// { id: 13, text: '支持【满200减20元】优惠活动' },
]
}, //优惠设置
discountRebate: {
isSelected: 0, //0未选中 1选中
options: [
// { id: 12, text: '支持【满两件-打8折】优惠活动' },
// { id: 14, text: '支持【单件-打905折】优惠活动' },
]
}, //优惠折扣
detailUrl: "",
brandId: "",
traceCode: "",
videoUrl: "",
});
const rules = reactive({
goodName: [
{
required: true,
message: '请输入商品名称',
trigger: 'blur'
},
],
categoryId1: [
{
required: true,
message: '请选择',
trigger: 'change',
},
],
categoryId2: [
{
required: true,
message: '请选择',
trigger: 'change',
},
],
categoryId3: [
{
required: true,
message: '请选择',
trigger: 'change',
},
],
goodUrl: [
{
validator: (rule, value, callback) => {
if (value === "" || value.trim() === "") {
callback(new Error('请至少上传一张商品图片'))
} else {
callback()
}
},
trigger: 'change'
}
],
specStyle: [
{ required: true, message: '请选择规格样式', trigger: 'change' }
],
salePrice: formInline.specStyle == '1' ? [
{
validator: (rule, value, callback) => {
if (!value || Number(value) <= 0) {
callback(new Error('请输入销售价格'))
} else {
callback()
}
},
trigger: ['blur', 'change']
},
] : [],
stock: formInline.specStyle == '1' ? [
{
validator: (rule, value, callback) => {
if (!value || Number(value) <= 0) {
callback(new Error('请输入库存数量'))
} else {
callback()
}
},
trigger: ['blur', 'change']
},
] : [],
netContent: formInline.specStyle == '1' ? [
{
validator: (rule, value, callback) => {
if (!value || Number(value) <= 0) {
callback(new Error('请输入净含量'))
} else {
callback()
}
},
trigger: ['blur', 'change']
},
] : [],
netWeight: [
{
validator: (rule, value, callback) => {
// 检查是否至少有一个属性
if (!value || value.length === 0) {
return callback(new Error('至少需要添加一个属性'))
}
// 检查每个属性名称是否已填写
const emptyNames = value.filter(item => !item.goodSpecs?.trim())
if (emptyNames.length > 0) {
return callback(new Error('请填写所有商品规格'))
}
callback()
},
trigger: 'blur'
}
],
attribute: [
{
validator: (rule, value, callback) => {
// 检查是否至少有一个属性
if (!value || value.length === 0) {
return callback(new Error('至少需要添加一个属性'))
}
// 检查每个属性名称是否已填写
const emptyNames = value.filter(item => !item.name?.trim())
if (emptyNames.length > 0) {
return callback(new Error('请填写所有属性名称和内容'))
}
callback()
},
trigger: 'blur'
}
],
selectedAddress: [
{
required: true,
validator: (rule, value, callback) => {
if (!value || value.length < 3) {
callback(new Error('请选择完整的区域'));
} else {
callback();
}
},
trigger: 'blur'
}
],
detailAddress: [
{ required: true, message: '请输入详细地址', trigger: 'blur' }
],
safeguard: [
{
validator: (rule, value, callback) => {
if (value.isSelected !== 1) { // 如果值不是 1未选中
callback(new Error('必须选择保障服务')); // 报错
} else {
callback(); // 校验通过
}
},
trigger: 'change', // 触发时机
},
],
});
const addSpecs = () => {
formInline.netWeight.push({
goodSpecs: "",
goodPrice: 1.00,
goodStock: 1,
netContent: 1,
unit: "kg"
})
}
const deleteSpecs = (index) => {
formInline.netWeight.splice(index, 1)
}
const addAttr = () => {
formInline.attribute.push({
name: '',
value: '',
})
}
const deleteAttr = (index) => {
formInline.attribute.splice(index, 1)
}
// 选中的省市区编码数组(如:['云南省', '昆明市', '呈贡区']
const selectedAddress = ref([]);
const detailAddress = ref('');
// 级联选择器配置
const cascaderProps = ref({
label: 'areaName', // 选项标签字段名
value: 'areaCode', // 选项值字段名
children: 'areaChildVOS', // 子选项字段名
emitPath: true,
expandTrigger: 'hover',
});
// 省市区数据(示例)
const addressOptions = ref([]);
addressOptions.value = areaList.data;
// 保障服务
const isSafeguardSelected = computed({
get: () => formInline.safeguard.isSelected === 1,
set: (val) => {
formInline.safeguard.isSelected = val ? 1 : 0
}
})
// 优惠设置
const isDiscountSettings = computed({
get: () => formInline.discountSettings.isSelected === 1,
set: (val) => {
formInline.discountSettings.isSelected = val ? 1 : 0
}
})
// 优惠折扣
const isDiscountRebate = computed({
get: () => formInline.discountRebate.isSelected === 1,
set: (val) => {
formInline.discountRebate.isSelected = val ? 1 : 0
}
})
const categoryList1 = ref([]);
const categoryList2 = ref([]);
const categoryList3 = ref([]);
const getGoodTypeList = async () => {
try {
let response = await getGoodType();
if (response.code == 200) {
categoryList1.value = response.data;
}
} catch (error) {
}
};
const changeCategory1 = (id) => {
formInline.categoryId1 = id;
formInline.categoryId2 = "";
categoryList2.value = categoryList1.value.filter((item) => item.id == id)[0].children;
formInline.categoryId3 = "";
formInline.categoryId = "";
categoryList3.value = [];
if (id == 70) {
// 选择产出品
formInline.goodCategorySelectType = 1;
} else {
// 选择投入品
formInline.goodCategorySelectType = 2;
}
};
const changeCategory2 = (id) => {
formInline.categoryId2 = id;
categoryList3.value = categoryList2.value.filter((item) => item.id == id)[0].children;
formInline.categoryId3 = "";
formInline.categoryId = "";
};
const changeCategory3 = (id) => {
formInline.categoryId3 = id;
formInline.categoryId = id;
};
const onSubmit = async () => {
try {
await formRef.value.validate()
// 整理提交的参数
let params = { ...formInline };
if (formInline.specStyle == '1') {
params.netWeight = [
{
goodSpecs: formInline.goodSpecs,
goodPrice: formInline.salePrice,
goodStock: formInline.stock,
netContent: formInline.netContent,
unit: formInline.unit
}
];
} else {
params.netWeight = formInline.netWeight
}
params.areaAddress = params.selectedAddress.join(',');
params.safeguardSelected = formInline.safeguard.isSelected; //保障服务
params.discountSettingsSelected = formInline.discountSettings.isSelected; //优惠设置
params.discountRebateSelected = formInline.discountRebate.isSelected; //优惠折扣
// 调用接口提交
onGoodSave(params)
} catch (error) {
console.log('验证失败', error)
}
};
const onGoodSave = async (params) => {
let response = await goodAdd(params);
if (response.code === 200) {
ElMessage.success("新增成功!");
formRef.value.resetFields();
router.go(-1);
} else {
ElMessage.error(response.message);
}
}
const getArea = async () => {
const res = await getRegion();
if (res.code === 200) {
addressOptions.value = res.data;
} else {
ElMessage.error(res.message);
}
};
const activeInfoList = ref([]);
// 获取商品优惠信息配置项
const getActiveInfo = async () => {
const res = await getActiveInfos();
if (res.code === 200) {
activeInfoList.value = res.data;
formInline.safeguard.options = [...activeInfoList.value.safeguard.options];
formInline.discountSettings.options = [...activeInfoList.value.discountSettings.options];
formInline.discountRebate.options = [...activeInfoList.value.discountRebate.options];
} else {
ElMessage.error(res.message);
}
};
onMounted(() => {
getActiveInfo();
getGoodTypeList();
getArea();
});
</script>
<style lang="scss" scoped></style>