java-mall-admin/src/views/product/goodsTool/GoodsItem.vue

449 lines
12 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>
<el-drawer
:before-close="handleClose"
direction="rtl"
size="50%"
:title="mode === 'add' ? '批量新增商品配置' : '编辑商品配置'"
:visible.sync="drawerVisible"
>
<div class="goodst_fixed_header">
<el-button
v-if="mode === 'add'"
icon="el-icon-plus"
type="primary"
@click="addNewItem"
>
添加组
</el-button>
</div>
<div class="scrollable-content">
<el-form ref="batchFormRef" label-width="80px" :model="batchForm">
<div
v-for="(item, index) in batchForm.items"
:key="index"
class="product-card"
>
<div class="card-header">
<span>组{{ index + 1 }}</span>
<el-button
v-if="mode === 'add' || batchForm.items.length > 1"
size="small"
type="danger"
@click="removeItem(index)"
>
删除
</el-button>
</div>
<div class="form-row">
<el-form-item
label="店铺"
:prop="'items.' + index + '.storeId'"
:rules="rules.storeId"
>
<el-select
v-model="item.storeId"
clearable
filterable
placeholder="选择店铺"
style="width: 100%"
>
<el-option
v-for="item in shopListData"
:key="item.store_id"
:label="item.store_name"
:value="item.store_id"
/>
</el-select>
</el-form-item>
<el-form-item
label="商品名称"
:prop="'items.' + index + '.productName'"
:rules="rules.productName"
>
<el-input
v-model="item.productName"
placeholder="请输入商品名称"
/>
</el-form-item>
</div>
<div class="form-row">
<el-form-item
label="规格值"
:prop="'items.' + index + '.specValue'"
:rules="rules.specValue"
>
<el-input
v-model.number="item.specValue"
placeholder="请输入规格值"
type="number"
/>
</el-form-item>
<el-form-item
label="商品货号"
:prop="'items.' + index + '.productNumber'"
:rules="rules.productNumber"
>
<el-input
v-model.number="item.productNumber"
placeholder="请输入商品货号"
type="number"
/>
</el-form-item>
</div>
<div class="form-row">
<el-form-item
label="规格单位"
:prop="'items.' + index + '.specUnit'"
:rules="rules.specUnit"
>
<el-input
v-model="item.specUnit"
placeholder="请输入规格单位"
/>
</el-form-item>
<el-form-item
label="排序"
:prop="'items.' + index + '.sortOrder'"
:rules="rules.sortOrder"
>
<el-input
v-model.number="item.sortOrder"
placeholder="请输入排序"
type="number"
/>
</el-form-item>
</div>
<div class="form-row">
<el-form-item
label="商品溢价率"
:prop="'items.' + index + '.premiumRate'"
>
<el-input
v-model.number="item.premiumRate"
placeholder="商品溢价率(%)"
type="number"
/>
</el-form-item>
</div>
<div class="form-row">
<el-form-item
label="描述"
:prop="'items.' + index + '.description'"
:rules="rules.description"
>
<el-input
v-model="item.description"
placeholder="请输入描述"
:rows="1"
style="display: block"
type="textarea"
/>
</el-form-item>
</div>
</div>
</el-form>
</div>
<div class="goodst_fixed_footer">
<el-button @click="drawerVisible = false">取消</el-button>
<el-button :loading="loading" type="primary" @click="submitForm">
{{ mode === 'add' ? '提交' : '保存' }}
</el-button>
</div>
</el-drawer>
</div>
</template>
<script>
import GoodsToolApi from '@/api/goodsTool'
export default {
name: 'BatchProductForm',
props: {
mode: {
type: String,
default: 'add',
validator: (value) => ['add', 'edit'].includes(value),
},
initialData: {
type: Array,
default: () => [],
},
shopListData: {
type: Array,
default: () => [],
},
},
data() {
return {
drawerVisible: false,
loading: false,
batchForm: {
items: [],
},
rules: {
productName: [
{ required: true, message: '请输入商品名称', trigger: 'blur' },
],
storeId: [
{ required: true, message: '请选择店铺', trigger: 'change' },
],
specValue: [
{ required: true, message: '请输入规格值', trigger: 'blur' },
{ type: 'number', message: '规格值必须为数字', trigger: 'blur' },
],
specUnit: [
{ required: true, message: '请输入规格单位', trigger: 'blur' },
],
sortOrder: [
{ required: true, message: '请输入排序', trigger: 'blur' },
],
productNumber: [
{ required: true, message: '请输入商品货号', trigger: 'blur' },
],
},
}
},
watch: {
// 监听props变化更新表单数据
initialData: {
handler(newVal) {
if (this.mode === 'edit' && newVal && newVal.length > 0) {
// 深拷贝初始数据,避免修改原始数据
this.batchForm.items = JSON.parse(JSON.stringify(newVal))
}
},
immediate: true,
deep: true,
},
},
methods: {
// 打开抽屉
open() {
this.drawerVisible = true
// 如果是新增模式,确保有一个空项
if (this.mode === 'add' && this.batchForm.items.length === 0) {
this.addNewItem()
}
},
// 关闭抽屉前的确认
handleClose(done) {
if (this.hasUnsavedChanges()) {
this.$confirm('确定要关闭吗?未保存的数据将会丢失。', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
done()
})
.catch(() => {
// 取消关闭
})
} else {
done()
}
},
// 检查是否有未保存的更改
hasUnsavedChanges() {
if (this.mode === 'add') {
return this.batchForm.items.some(
(item) =>
item.productName ||
item.storeId ||
item.specValue ||
item.specUnit
)
}
// 编辑模式下的比较逻辑
if (this.initialData && this.initialData.length > 0) {
return (
JSON.stringify(this.batchForm.items) !==
JSON.stringify(this.initialData)
)
}
return false
},
// 添加新项目
addNewItem() {
this.batchForm.items.push({
productName: '',
storeId: '',
specValue: '',
specUnit: '',
description: '',
sortOrder: '',
})
// 滚动到底部
this.$nextTick(() => {
const container = document.querySelector('.scrollable-content')
if (container) {
container.scrollTop = container.scrollHeight
}
})
},
// 删除项目
removeItem(index) {
if (this.mode === 'add' && this.batchForm.items.length > 1) {
console.log(111)
this.batchForm.items.splice(index, 1)
} else {
this.$message.warning('至少保留一个商品组配置')
}
},
// 提交表单
submitForm() {
this.$refs.batchFormRef.validate(async (valid) => {
if (valid) {
this.loading = true
// 准备提交数据
const submitData = this.batchForm.items.map((item) => ({
productName: item.productName,
storeId: item.storeId,
specValue: item.specValue,
specUnit: item.specUnit,
description: item.description,
sortOrder: item.sortOrder,
productNumber:item.productNumber,
premiumRate:item.premiumRate
}))
// 过滤掉空项(新增模式下)
const filteredData =
this.mode === 'add'
? submitData.filter(
(item) =>
item.productName ||
item.storeId ||
item.specValue ||
item.specUnit
)
: submitData
if (filteredData.length === 0) {
this.$message.warning('请添加商品配置组数据')
this.loading = false
return
}
try {
let res = null;
if (this.mode === 'add') {
res = await GoodsToolApi.batchCreateGoods(submitData);
} else {
res = await GoodsToolApi.updateGoods({
...submitData[0],
id: this.batchForm.items[0].id,
});
}
if (res.status === 200) {
this.$message.success('操作成功');
this.$emit('refresh'); //刷新
this.drawerVisible = false; // 关闭抽屉
} else {
this.$message.error('操作失败: ' + res.msg);
}
} catch (error) {
console.error('提交错误:', error);
this.$message.error('提交时发生错误');
} finally {
this.loading = false; // 确保无论成功或失败都重置 loading
}
} else {
this.$message.error('请完善表单信息');
return false;
}
})
},
},
}
</script>
<style lang="scss" scoped>
.goodst_fixed_header {
padding: 0 12px 12px;
border-bottom: 1px solid #ebeef5;
display: flex;
justify-content: flex-end;
}
.scrollable-content {
padding: 12px;
height: calc(100vh - 195px);
overflow-y: auto;
}
.goodst_fixed_footer {
display: flex;
justify-content: flex-start;
padding: 12px;
border-top: 1px solid #ebeef5;
background-color: #fff;
}
.product-card {
width: 100%;
margin-bottom: 12px;
padding: 12px 12px 0;
border: 1px solid #dcdfe6;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
background-color: #fff;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding-bottom: 10px;
border-bottom: 1px solid #ebeef5;
}
.form-row {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 15px;
}
.form-row .el-form-item {
flex: 1 1 calc(33.33% - 12px);
margin-bottom: 0;
}
.form-row .el-form-item:last-child {
flex: 1 1 calc(33.34% - 12px);
}
.form-row .el-form-item:nth-child(3n) {
flex: 1 1 100%;
}
.form-row .el-input__inner {
height: 32px;
}
.form-row .el-input--textarea .el-input__inner {
height: auto;
}
</style>