商品前台交互更新
This commit is contained in:
parent
ff1a8c2fca
commit
080f6d8fba
|
@ -44,9 +44,9 @@ export function delGoods(id) {
|
|||
}
|
||||
|
||||
// 商品上架/下架
|
||||
export function changeStatus(data) {
|
||||
export function changeStatusAndSort(data) {
|
||||
return request({
|
||||
url: '/bst/goods/changeStatus',
|
||||
url: '/bst/goods/changeStatusAndSort',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
|
|
|
@ -199,7 +199,7 @@
|
|||
type="primary"
|
||||
size="small"
|
||||
@click="applyBatchSetting"
|
||||
:disabled="!batchField || !batchValue || selectedSkuRows.length === 0"
|
||||
:disabled="isReadOnly || !batchField || !batchValue || selectedSkuRows.length === 0"
|
||||
>
|
||||
应用设置
|
||||
</el-button>
|
||||
|
@ -210,8 +210,12 @@
|
|||
</div>
|
||||
|
||||
<div class="sku-table">
|
||||
<el-table :data="form.skuList" style="width: 85%" :row-style="{height: '100px'}"
|
||||
@selection-change="handleSelectionChange"
|
||||
<el-table
|
||||
ref="skuTable"
|
||||
:data="form.skuList"
|
||||
style="width: 85%"
|
||||
:row-style="{height: '100px'}"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<!-- 动态生成规格列 -->
|
||||
|
@ -449,6 +453,9 @@ export default {
|
|||
});
|
||||
|
||||
this.$message.success(`已批量设置${this.selectedSkuRows.length}个值`);
|
||||
this.selectedSkuRows = [];
|
||||
this.batchValue = '';
|
||||
this.$refs.skuTable.clearSelection();
|
||||
},
|
||||
getList() {
|
||||
this.loading = true;
|
||||
|
@ -627,8 +634,7 @@ export default {
|
|||
// 失败时使用时间戳作为后备方案
|
||||
return Date.now().toString();
|
||||
}
|
||||
},
|
||||
generateSKU() {
|
||||
},generateSKU() {
|
||||
// 获取当前所有有效的规格值ID
|
||||
const currentValueIds = new Set();
|
||||
this.form.specs.forEach(spec => {
|
||||
|
@ -654,17 +660,15 @@ export default {
|
|||
const validSpecValues = (sku.specValues || sku.specs || []).filter(id =>
|
||||
currentValueIds.has(id)
|
||||
);
|
||||
const specKey = [...validSpecValues].sort().join('##');
|
||||
const specKey = validSpecValues.join('##');
|
||||
validSkuMap.set(specKey, sku);
|
||||
});
|
||||
|
||||
// 创建新的SKU列表
|
||||
// 创建新的SKU列表(不使用排序)
|
||||
this.form.skuList = combinations.map(comb => {
|
||||
// 提取并排序组合中的规格值ID
|
||||
const sortedValueIds = comb
|
||||
.map(item => item.id)
|
||||
.sort();
|
||||
const specKey = sortedValueIds.join('##');
|
||||
// 提取组合中的规格值ID(保持原始顺序)
|
||||
const specIds = comb.map(item => item.id);
|
||||
const specKey = specIds.join('##');
|
||||
|
||||
// 从映射表中获取对应的SKU
|
||||
const matchedSku = validSkuMap.get(specKey);
|
||||
|
@ -673,28 +677,29 @@ export default {
|
|||
// 保留原有SKU(含ID、价格、库存等数据)
|
||||
return {
|
||||
...matchedSku,
|
||||
// 更新规格值列表(避免包含无效ID)
|
||||
specs: sortedValueIds,
|
||||
specValues: sortedValueIds
|
||||
specs: specIds,
|
||||
specValues: specIds
|
||||
};
|
||||
} else {
|
||||
// 新建SKU
|
||||
return {
|
||||
id: undefined, // 新SKU的ID将由后端生成
|
||||
specs: sortedValueIds,
|
||||
specValues: sortedValueIds,
|
||||
specs: specIds,
|
||||
specValues: specIds,
|
||||
price: 0,
|
||||
stock: "0",
|
||||
image: ''
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 使用原始顺序更新选中的行
|
||||
const oldSelectedIds = this.selectedSkuRows.map(row =>
|
||||
row.specs ? row.specs.sort().join('##') : ''
|
||||
row.specs ? row.specs.join('##') : ''
|
||||
);
|
||||
|
||||
this.selectedSkuRows = this.form.skuList.filter(row => {
|
||||
const rowKey = row.specs ? row.specs.sort().join('##') : '';
|
||||
const rowKey = row.specs ? row.specs.join('##') : '';
|
||||
return oldSelectedIds.includes(rowKey);
|
||||
});
|
||||
},
|
||||
|
|
|
@ -1,7 +1,19 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
|
||||
<div class="app-container">
|
||||
<div v-if="showSortEditPanel" class="sort-edit-panel" :style="panelStyle">
|
||||
<el-input
|
||||
v-model="editSortValue"
|
||||
size="mini"
|
||||
@keyup.enter.native="saveSort"
|
||||
ref="sortInput"
|
||||
></el-input>
|
||||
<div class="sort-edit-buttons">
|
||||
<el-button size="mini" @click="cancelEditSort">取消</el-button>
|
||||
<el-button type="primary" size="mini" @click="saveSort">确定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="商品名称" prop="name">
|
||||
<el-input
|
||||
v-model="queryParams.name"
|
||||
|
@ -119,6 +131,17 @@
|
|||
<template v-else-if="column.key === 'status'">
|
||||
<dict-tag :value="d.row.status" :options="dict.type.goods_status"/>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'sort'">
|
||||
<div>
|
||||
{{ d.row.sort }}
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
size="mini"
|
||||
@click="startEditSort(d.row, $event)">
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'deposit'">
|
||||
<dict-tag :value="d.row.deposit" :options="dict.type.goods_deposit"/>
|
||||
</template>
|
||||
|
@ -135,7 +158,7 @@
|
|||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-top"
|
||||
@click="handleUpdate(scope.row)"
|
||||
@click="handleOnline(scope.row)"
|
||||
v-has-permi="['bst:goods:edit']"
|
||||
>上架</el-button>
|
||||
<el-button
|
||||
|
@ -143,7 +166,7 @@
|
|||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-bottom"
|
||||
@click="handleUpdate(scope.row)"
|
||||
@click="handleOffline(scope.row)"
|
||||
v-has-permi="['bst:goods:edit']"
|
||||
>下架</el-button>
|
||||
<el-button
|
||||
|
@ -183,14 +206,14 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {listGoods, getGoods, delGoods, addGoods, updateGoods, changeStatus} from "@/api/bst/goods";
|
||||
import {listGoods, getGoods, delGoods, addGoods, updateGoods, changeStatus, changeStatusAndSort} from "@/api/bst/goods";
|
||||
import { $showColumns } from '@/utils/mixins';
|
||||
import FormCol from "@/components/FormCol/index.vue";
|
||||
|
||||
// 默认排序字段
|
||||
const defaultSort = {
|
||||
prop: "createTime",
|
||||
order: "descending"
|
||||
prop: "sort",
|
||||
order: "ascending"
|
||||
}
|
||||
|
||||
export default {
|
||||
|
@ -200,6 +223,10 @@ export default {
|
|||
dicts: ['goods_deposit','goods_status'],
|
||||
data() {
|
||||
return {
|
||||
showSortEditPanel: false, // 控制面板显示
|
||||
editSortValue: null, // 编辑中的排序值
|
||||
editingRow: null, // 当前编辑的行数据
|
||||
panelPosition: { top: 0, left: 0 }, // 面板位置
|
||||
span: 24,
|
||||
// 字段列表
|
||||
columns: [
|
||||
|
@ -211,7 +238,7 @@ export default {
|
|||
// {key: 'virtualSales', visible: true, label: '虚拟销量', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'deposit', visible: true, label: '是否可存', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'status', visible: true, label: '商品状态', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'sort', visible: true, label: '排序', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
{key: 'sort', visible: true, label: '排序', minWidth: null, sortable: 'custom', overflow: false, align: 'center', width: '120'},
|
||||
{key: 'createTime', visible: true, label: '创建时间', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
//{key: 'storeId', visible: true, label: '店铺名称', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
//{key: 'categoryId', visible: true, label: '分类名称', minWidth: null, sortable: true, overflow: false, align: 'center', width: null},
|
||||
|
@ -284,19 +311,78 @@ export default {
|
|||
activated() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
mounted() {
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
methods: {startEditSort(row, event) {
|
||||
this.showSortEditPanel = false;
|
||||
this.editingRow = row;
|
||||
this.editSortValue = row.sort;
|
||||
|
||||
this.$nextTick(() => {
|
||||
// 获取触发按钮的位置
|
||||
const buttonRect = event.currentTarget.getBoundingClientRect();
|
||||
|
||||
// 设置面板位置(按钮下方10px处,水平居中)
|
||||
this.panelStyle = {
|
||||
position: 'fixed',
|
||||
top: `${buttonRect.bottom + 10}px`,
|
||||
left: `${buttonRect.left}px`,
|
||||
transform: 'translateX(-50%)',
|
||||
zIndex: 2000
|
||||
};
|
||||
|
||||
this.showSortEditPanel = true;
|
||||
this.$nextTick(() => {
|
||||
this.$refs.sortInput.focus();
|
||||
});
|
||||
});
|
||||
},
|
||||
// 新增方法:取消编辑
|
||||
cancelEditSort() {
|
||||
this.showSortEditPanel = false;
|
||||
this.editingRow = null;
|
||||
},
|
||||
|
||||
// 新增方法:保存排序
|
||||
saveSort() {
|
||||
if (!this.editingRow) return;
|
||||
|
||||
// 检查排序值是否合法
|
||||
const sortValue = parseInt(this.editSortValue);
|
||||
if (isNaN(sortValue)) {
|
||||
this.$message.error('排序值必须是数字');
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用API保存修改
|
||||
changeStatusAndSort({ id: this.editingRow.id, sort: sortValue })
|
||||
.then(response => {
|
||||
this.$modal.msgSuccess("排序更新成功");
|
||||
// 更新当前行的排序值(不刷新整个页面)
|
||||
this.editingRow.sort = sortValue;
|
||||
this.cancelEditSort();
|
||||
})
|
||||
.catch(error => {
|
||||
this.$modal.msgError("更新失败: " + (error.message || error));
|
||||
});
|
||||
this.getList()
|
||||
},
|
||||
// 上架商品
|
||||
handleOnline(row) {
|
||||
this.changeGoodsStatus(row, '1', '上架');
|
||||
this.changeStatusAndSort(row, '1', '上架');
|
||||
},
|
||||
|
||||
// 下架商品
|
||||
handleOffline(row) {
|
||||
this.changeGoodsStatus(row, '0', '下架');
|
||||
this.changeStatusAndSort(row, '0', '下架');
|
||||
},
|
||||
|
||||
// 通用的状态切换方法
|
||||
async changeGoodsStatus(row, status, actionName) {
|
||||
async changeStatusAndSort(row, status, actionName) {
|
||||
try {
|
||||
// 确认操作
|
||||
const confirmMsg = `是否确认${actionName}商品【${row.name}】?`;
|
||||
|
@ -309,7 +395,7 @@ export default {
|
|||
};
|
||||
|
||||
// 调用更新接口
|
||||
await changeStatus(updateData);
|
||||
await changeStatusAndSort(updateData);
|
||||
|
||||
// 提示成功
|
||||
this.$modal.msgSuccess(`${actionName}成功`);
|
||||
|
@ -345,6 +431,10 @@ export default {
|
|||
getList() {
|
||||
this.loading = true;
|
||||
listGoods(this.queryParams).then(response => {
|
||||
response.rows.forEach(item => {
|
||||
// 确保每行都有编辑状态
|
||||
this.$set(item, 'isEditingSort', false)
|
||||
})
|
||||
this.goodsList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
|
@ -443,3 +533,46 @@ export default {
|
|||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 新增排序编辑面板样式 */
|
||||
.sort-edit-panel {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
background: white;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.sort-edit-panel .el-input {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.sort-edit-buttons {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
/* 确保容器有相对定位 */
|
||||
.app-container {
|
||||
position: relative;
|
||||
}
|
||||
.sort-edit-panel {
|
||||
position: fixed; /* 改为固定定位 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
background: white;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
z-index: 2000;
|
||||
min-width: 150px;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue
Block a user