新增商品关联商品静态部分

This commit is contained in:
gyq
2025-12-24 16:13:43 +08:00
parent 1d7ba844f6
commit bf35a1b35b
3 changed files with 265 additions and 15 deletions

View File

@@ -222,7 +222,6 @@
<el-form-item label="库存数量">
<el-input-number v-model="ruleForm.stockNumber" :min="0" />
</el-form-item>
<el-form-item label="打包费" prop="delivery">
<div style="display: block;">
<el-input-number v-model="ruleForm.packFee" controls-position="right"
@@ -230,6 +229,41 @@
<div style="color: #999;">单份商品打包费店铺开启外卖模式下该数据才生效</div>
</div>
</el-form-item>
<el-form-item label="关联推荐商品">
<div class="column">
<div class="row">
<div class="center">
<el-button type="primary" @click="selecProductDialogRef?.show()"
:disabled="goodsList.length >= goodsListMax">添加商品</el-button>
<div class="tips">设置商品后用户可以在商品详情页中看到推荐商品可拖动调整顺序最多设置{{ goodsListMax }}个商品</div>
</div>
</div>
<div class="row">
<div id="goods_table_drag">
<el-table :data="goodsList" border stripe style="width: 500px;" row-key="id">
<!-- 拖拽列 -->
<el-table-column label="排序" width="60">
<template v-slot="scope">
<div class="drag-handle"></div>
</template>
</el-table-column>
<el-table-column label="商品图片" prop="coverImg" width="90">
<template v-slot="scope">
<el-image :src="scope.row.coverImg" style="width: 50px;height: 50px;border-radius: 4px;"
fit="cover"></el-image>
</template>
</el-table-column>
<el-table-column label="商品名称" prop="name"></el-table-column>
<el-table-column label="操作" width="100">
<template v-slot="scope">
<el-button link type="danger" @click="goodsList.splice(scope.$index, 1)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(ruleFormRef)">确定</el-button>
<el-button @click="resetForm(ruleFormRef)">取消</el-button>
@@ -256,11 +290,13 @@
</span>
</template>
</el-dialog>
<!-- 选择商品弹窗 -->
<selecProductDialog ref="selecProductDialogRef" @success="selecProductSuccess" />
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from "vue";
import { reactive, ref, onMounted, nextTick } from "vue";
import type { FormInstance, FormRules } from "element-plus";
// 规格属性
import SpecificationAttribute from "./SpecificationAttribute.vue";
@@ -272,7 +308,65 @@ import UserAPI4 from "@/api/product/specificationsconfig";
import shopList from "@/components/mycomponents/shopList.vue";
import AddImg from "@/components/mycomponents/addImg.vue";
import { useRouter } from "vue-router";
import Sortable from "sortablejs";
import { useTagsViewStore } from "@/store";
import selecProductDialog from "@/views/marketing_center/group_booking/components/selecProductDialog.vue";
const selecProductDialogRef = ref(null)
const goodsListMax = ref(9)
const goodsList = ref<any[]>([]);
onMounted(() => {
// Sortable 需要在 el-table 渲染 tbody 后初始化,尝试多次以确保 DOM 可用
const initSortable = async () => {
await nextTick();
let attempts = 0;
const maxAttempts = 8;
const tryInit = () => {
const el = document.querySelector("#goods_table_drag .el-table__body-wrapper tbody");
if (!el) {
attempts++;
if (attempts < maxAttempts) {
setTimeout(tryInit, 80);
}
return;
}
// 已找到表体,初始化 Sortable
new Sortable(el as HTMLElement, {
animation: 150,
handle: ".drag-handle",
ghostClass: "sortable-ghost",
chosenClass: "sortable-chosen",
onEnd: (e) => {
if (e.oldIndex == null || e.newIndex == null) return;
if (e.oldIndex === e.newIndex) return;
const from = e.oldIndex;
const to = e.newIndex;
const item = goodsList.value.splice(from, 1)[0];
goodsList.value.splice(to, 0, item);
// 触发响应式更新
goodsList.value = goodsList.value.slice();
console.log("排序后的数据", goodsList.value);
},
});
};
tryInit();
};
initSortable();
});
// 已选择的商品
function selecProductSuccess(res: any) {
let obj = goodsList.value.find((item) => item.id == res.id);
if (obj && obj.id) {
ElMessage.error("该商品已选择");
return;
}
goodsList.value.push({ ...res });
}
const tagsViewStore = useTagsViewStore();
const router = useRouter();
let list = ref<any[]>([
@@ -915,6 +1009,27 @@ const resetForm = (formEl: FormInstance | undefined) => {
margin-bottom: 20px;
}
.drag-handle {
cursor: move;
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
background: #f0f0f0;
}
/* SortableJS classes */
.sortable-ghost {
opacity: 0.6;
}
.sortable-chosen {
background: #f5f7ff !important;
}
.el-table__body-wrapper tbody tr {
transition: transform 150ms ease, background-color 150ms ease;
}
.showStyle:hover>.buttonstyle {
display: block;
}
@@ -942,4 +1057,26 @@ const resetForm = (formEl: FormInstance | undefined) => {
top: -10px;
z-index: 10;
}
</style>
.column {
flex: 1;
display: flex;
flex-direction: column;
.row {
flex: 1;
margin-bottom: 10px;
}
}
.center {
display: flex;
align-items: center;
gap: 10px;
.tips {
color: #999;
font-size: 14px;
}
}
</style>