Browse Source

序号拖拽排序

java8
han\hanst 10 months ago
parent
commit
9b4dc81d02
  1. 1
      package.json
  2. 216
      src/views/modules/part/bom_create.vue

1
package.json

@ -40,6 +40,7 @@
"pubsub-js": "^1.9.3", "pubsub-js": "^1.9.3",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
"sass-loader": "6.0.6", "sass-loader": "6.0.6",
"sortablejs": "^1.15.0",
"svg-sprite-loader": "3.7.3", "svg-sprite-loader": "3.7.3",
"v-viewer": "^1.6.4", "v-viewer": "^1.6.4",
"vue": "2.6.10", "vue": "2.6.10",

216
src/views/modules/part/bom_create.vue

@ -92,6 +92,7 @@
<div class="rq "> <div class="rq ">
<el-table <el-table
:data="subDetailList" :data="subDetailList"
:key="tableKey"
height="320px" height="320px"
border border
@selection-change="componentSelectionChange" @selection-change="componentSelectionChange"
@ -886,6 +887,8 @@ import BomComponentUpload from "./bom_component_upload.vue"
import {partFamilyInformationSearch} from "../../../api/part/partFamilyInformation"; import {partFamilyInformationSearch} from "../../../api/part/partFamilyInformation";
import {bomSearchHeader, getComponentPartList} from "../../../api/part/bomSearch3"; import {bomSearchHeader, getComponentPartList} from "../../../api/part/bomSearch3";
import {getSiteAndBuByUserName} from "@/api/eam/eam.js" import {getSiteAndBuByUserName} from "@/api/eam/eam.js"
import Sortable from 'sortablejs'
export default { export default {
components: { components: {
BomComponentUpload, BomComponentUpload,
@ -1673,7 +1676,7 @@ export default {
sortLv: 0, sortLv: 0,
status: true, status: true,
fixed: '', fixed: '',
columnWidth: 200
columnWidth: 120
}, },
{ {
userId: this.$store.state.user.name, userId: this.$store.state.user.name,
@ -2599,13 +2602,198 @@ export default {
materialWeightFamily: ['RFID018', 'RFID019'], materialWeightFamily: ['RFID018', 'RFID019'],
materialLength2Family: ['RFID018', 'RFID019'], materialLength2Family: ['RFID018', 'RFID019'],
unitConversionFamily: ['RFID018', 'RFID019'], unitConversionFamily: ['RFID018', 'RFID019'],
sortableInstance: null, // 保存 Sortable 实例
isDragging: false, // 标记是否正在拖拽,避免重复初始化
tableKey: 0 // 表格的 key,用于强制刷新表格
} }
}, },
created () { created () {
// 获取用户的 site 和 bu // 获取用户的 site 和 bu
this.getSiteAndBuByUserName() this.getSiteAndBuByUserName()
}, },
mounted() {
// 初始化表格行拖拽排序功能
this.$nextTick(() => {
this.initTableRowDrag()
})
},
updated() {
// 组件更新后重新初始化拖拽功能
// 只在非拖拽状态下初始化,避免拖拽操作触发重复初始化
if (!this.isDragging) {
this.$nextTick(() => {
this.initTableRowDrag()
})
}
},
methods: { methods: {
/**
* 初始化表格行拖拽排序功能
* 拖拽后自动重新计算序号并保存到数据库
*/
initTableRowDrag() {
// 如果正在拖拽,不重新初始化
if (this.isDragging) {
return
}
// 销毁旧的 Sortable 实例
if (this.sortableInstance) {
this.sortableInstance.destroy()
this.sortableInstance = null
}
const el = document.querySelector('.rq .el-table__body-wrapper tbody')
if (!el) {
console.warn('未找到表格DOM元素,拖拽功能初始化失败')
return
}
// 创建新的 Sortable 实例
this.sortableInstance = Sortable.create(el, {
animation: 150,
handle: 'tr', // 整行可拖拽
ghostClass: 'sortable-ghost',
chosenClass: 'sortable-chosen',
dragClass: 'sortable-drag',
onStart: () => {
this.isDragging = true
},
onEnd: (evt) => {
const { oldIndex, newIndex } = evt
this.isDragging = false
if (oldIndex === newIndex) return
console.log(`🔄 拖拽: 从位置 ${oldIndex} (序号${this.subDetailList[oldIndex].lineSequence}) 移动到位置 ${newIndex}`)
// 1. 更新本地数据顺序
const movedItem = this.subDetailList.splice(oldIndex, 1)[0]
this.subDetailList.splice(newIndex, 0, movedItem)
// 2. 重新计算所有序号(从1开始)- 使用 Vue.set 确保响应式更新
this.subDetailList.forEach((item, index) => {
this.$set(item, 'lineSequence', index + 1)
})
console.log('📝 拖拽后新序号:', this.subDetailList.map((item, idx) =>
`位置${idx}: ${item.componentPart} (序号${item.lineSequence})`
).join(', '))
// 3. 强制刷新视图 - 使用多种方式确保更新
this.tableKey++ // 强制刷新表格
this.$forceUpdate()
// 4. 使用 nextTick 确保 DOM 更新后再保存
this.$nextTick(() => {
// 5. 保存到数据库
this.saveBomComponentSequence()
})
}
})
console.log('✅ 拖拽功能初始化成功')
},
/**
* 保存BOM子物料序号到数据库
* 将整个列表的数据(包含新序号)提交到后端保存
*/
saveBomComponentSequence() {
if (this.subDetailList.length === 0) {
return
}
console.log('💾 === 拖拽排序保存开始 ===')
console.log('准备保存的数据:')
this.subDetailList.forEach((item, index) => {
console.log(` 位置${index}: ${item.componentPart} → 新序号 ${item.lineSequence}`)
})
// 构建保存数据
const tempData = {
site: this.modalData.site,
buNo: this.modalData.buNo,
partNo: this.modalData.partNo,
partDesc: this.modalData.partDesc,
engChgLevel: this.modalData.engChgLevel,
bomType: this.modalData.bomType,
noteText: this.modalData.noteText,
effPhaseInDate: this.modalData.effPhaseInDate,
effPhaseOutDate: this.modalData.effPhaseOutDate,
engRevision: this.modalData.engRevision,
typeFlag: this.modalData.typeFlag,
netWeight: this.modalData.netWeight,
alternativeNo: this.detailData.alternativeNo,
alternativeDescription: this.detailData.alternativeDescription,
minLotQty: this.detailData.minLotQty,
defaultFlag: this.detailData.defaultFlag,
detailNoteText: this.detailData.detailNoteText,
status: this.detailData.status,
createBy: this.$store.state.user.name,
updateBy: this.$store.state.user.name,
informationList: this.subDetailList,
processUnit: this.modalData.processUnit
}
// 显示loading
const loadingInstance = this.$loading({
lock: true,
text: '正在保存序号排序...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.3)'
})
// 调用保存API
bomManagementSave(tempData).then(({data}) => {
loadingInstance.close()
if (data && data.code === 0) {
this.$message({
message: '序号排序保存成功',
type: 'success',
duration: 1500
})
// ✅ 保存成功后,保持前端已排序的数据,不使用后端返回的数据
// 因为后端返回的数据是按旧的 line_sequence 排序的,会覆盖我们的新顺序
console.log('✅ 序号保存成功,当前顺序:', this.subDetailList.map(item => ({
componentPart: item.componentPart,
lineSequence: item.lineSequence
})))
// 如果需要更新其他字段(如计算字段),可以从后端数据中提取并合并
if (data.rows && data.rows.subDetailList) {
const backendList = data.rows.subDetailList
// 按照前端的顺序,更新后端返回的其他字段
this.subDetailList = this.subDetailList.map(frontItem => {
const backendItem = backendList.find(b =>
b.componentPart === frontItem.componentPart &&
b.lineItemNo === frontItem.lineItemNo
)
// 保留前端的 lineSequence,更新其他字段
return backendItem ? {
...backendItem,
lineSequence: frontItem.lineSequence
} : frontItem
})
}
// 强制刷新表格显示
this.tableKey++
this.$forceUpdate()
} else {
this.$message.error(data.msg || '保存失败')
// 保存失败时刷新数据,恢复原序号
this.alternativeChange()
}
}).catch((error) => {
loadingInstance.close()
console.error('保存失败:', error)
this.$message.error('保存失败,请重试')
// 保存失败时刷新数据,恢复原序号
this.alternativeChange()
})
},
// 初始化组件的参数 // 初始化组件的参数
async init (tempData) { async init (tempData) {
await getBomInformationByPartNo(tempData).then(({data}) => { await getBomInformationByPartNo(tempData).then(({data}) => {
@ -4277,6 +4465,32 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/* 拖拽排序样式 */
.sortable-ghost {
opacity: 0.5;
background: #f0f9ff;
}
.sortable-chosen {
background: #e0f2fe;
cursor: move;
}
.sortable-drag {
opacity: 0.8;
background: #bae6fd;
}
/* 为表格行添加拖拽指示 */
/deep/ .rq .el-table__body-wrapper tbody tr {
cursor: move;
user-select: none;
}
/deep/ .rq .el-table__body-wrapper tbody tr:hover {
background-color: #f5f7fa;
}
/deep/ .detail-tab .el-tabs__content { /deep/ .detail-tab .el-tabs__content {
height: 165px; height: 165px;
padding: 15px 0px 0px 0px; padding: 15px 0px 0px 0px;

Loading…
Cancel
Save