|
|
@@ -42,7 +42,7 @@
|
|
|
@selection-change="handleSelectionChange"
|
|
|
@cell-click="handleTableCellClick"
|
|
|
@row-dblclick="handleRowDblclick">
|
|
|
- <el-table-column sortable align="center" label="客户编号" prop="客户编号" width="120">
|
|
|
+ <el-table-column sortable align="center" label="客户编号" prop="客户编号" width="100">
|
|
|
<template #default="{ row }">
|
|
|
<el-input v-if="isEditing(row, '客户编号')"
|
|
|
v-model="row.客户编号"
|
|
|
@@ -62,7 +62,7 @@
|
|
|
<div v-else class="cell-span">{{ row.款号 || '\u00A0' }}</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column sortable align="center" label="款式" prop="款式" width="120">
|
|
|
+ <el-table-column sortable align="center" label="款式" prop="款式" width="90">
|
|
|
<template #default="{ row }">
|
|
|
<el-input v-if="isEditing(row, '款式')"
|
|
|
v-model="row.款式"
|
|
|
@@ -72,7 +72,7 @@
|
|
|
<div v-else class="cell-span">{{ row.款式 || '\u00A0' }}</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column sortable align="center" label="样办种类" prop="样办种类" width="120">
|
|
|
+ <el-table-column sortable align="center" label="样办种类" prop="样办种类" width="100">
|
|
|
<template #default="{ row }">
|
|
|
<el-input v-if="isEditing(row, '样办种类')"
|
|
|
v-model="row.样办种类"
|
|
|
@@ -82,7 +82,7 @@
|
|
|
<div v-else class="cell-span">{{ row.样办种类 || '\u00A0' }}</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column sortable align="center" label="做办部门" prop="做办部门" width="120">
|
|
|
+ <el-table-column sortable align="center" label="做办部门" prop="做办部门" width="100">
|
|
|
<template #default="{ row }">
|
|
|
<el-input v-if="isEditing(row, '做办部门')"
|
|
|
v-model="row.做办部门"
|
|
|
@@ -92,7 +92,7 @@
|
|
|
<div v-else class="cell-span">{{ row.做办部门 || '\u00A0' }}</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column sortable align="center" label="数量" prop="数量" width="100">
|
|
|
+ <el-table-column sortable align="center" label="数量" prop="数量" width="90">
|
|
|
<template #default="{ row }">
|
|
|
<el-input v-if="isEditing(row, '数量')"
|
|
|
v-model="row.数量"
|
|
|
@@ -110,28 +110,40 @@
|
|
|
value-format="YYYY-MM-DD"
|
|
|
placeholder="选择日期"
|
|
|
style="width: 100%"
|
|
|
+ teleported
|
|
|
@blur="handleCellBlur(row, '下单日期')"
|
|
|
- @change="handleCellBlur(row, '下单日期')" />
|
|
|
+ @change="handleCellBlur(row, '下单日期')"
|
|
|
+ @visible-change="(v) => handleDatePickerVisibleChange(v, row, '下单日期')" />
|
|
|
<div v-else class="cell-span">{{ row.下单日期 || '\u00A0' }}</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column sortable align="center" label="面料进度" prop="面料进度" width="120">
|
|
|
+ <el-table-column sortable align="center" label="面料进度" prop="面料进度" width="140">
|
|
|
<template #default="{ row }">
|
|
|
- <el-input v-if="isEditing(row, '面料进度')"
|
|
|
- v-model="row.面料进度"
|
|
|
- @blur="handleCellBlur(row, '面料进度')"
|
|
|
- @keyup.enter="handleCellBlur(row, '面料进度')"
|
|
|
- :ref="el => { if (el) el.focus() }" />
|
|
|
+ <el-date-picker v-if="isEditing(row, '面料进度')"
|
|
|
+ v-model="row.面料进度"
|
|
|
+ type="date"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ placeholder="选择日期"
|
|
|
+ style="width: 100%"
|
|
|
+ teleported
|
|
|
+ @blur="handleCellBlur(row, '面料进度')"
|
|
|
+ @change="handleCellBlur(row, '面料进度')"
|
|
|
+ @visible-change="(v) => handleDatePickerVisibleChange(v, row, '面料进度')" />
|
|
|
<div v-else class="cell-span">{{ row.面料进度 || '\u00A0' }}</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column sortable align="center" label="辅料进度" prop="辅料进度" width="120">
|
|
|
+ <el-table-column sortable align="center" label="辅料进度" prop="辅料进度" width="140">
|
|
|
<template #default="{ row }">
|
|
|
- <el-input v-if="isEditing(row, '辅料进度')"
|
|
|
- v-model="row.辅料进度"
|
|
|
- @blur="handleCellBlur(row, '辅料进度')"
|
|
|
- @keyup.enter="handleCellBlur(row, '辅料进度')"
|
|
|
- :ref="el => { if (el) el.focus() }" />
|
|
|
+ <el-date-picker v-if="isEditing(row, '辅料进度')"
|
|
|
+ v-model="row.辅料进度"
|
|
|
+ type="date"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ placeholder="选择日期"
|
|
|
+ style="width: 100%"
|
|
|
+ teleported
|
|
|
+ @blur="handleCellBlur(row, '辅料进度')"
|
|
|
+ @change="handleCellBlur(row, '辅料进度')"
|
|
|
+ @visible-change="(v) => handleDatePickerVisibleChange(v, row, '辅料进度')" />
|
|
|
<div v-else class="cell-span">{{ row.辅料进度 || '\u00A0' }}</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
@@ -143,8 +155,10 @@
|
|
|
value-format="YYYY-MM-DD"
|
|
|
placeholder="选择日期"
|
|
|
style="width: 100%"
|
|
|
+ teleported
|
|
|
@blur="handleCellBlur(row, '计划交办日期')"
|
|
|
- @change="handleCellBlur(row, '计划交办日期')" />
|
|
|
+ @change="handleCellBlur(row, '计划交办日期')"
|
|
|
+ @visible-change="(v) => handleDatePickerVisibleChange(v, row, '计划交办日期')" />
|
|
|
<div v-else class="cell-span">{{ row.计划交办日期 || '\u00A0' }}</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
@@ -156,8 +170,10 @@
|
|
|
value-format="YYYY-MM-DD"
|
|
|
placeholder="选择日期"
|
|
|
style="width: 100%"
|
|
|
+ teleported
|
|
|
@blur="handleCellBlur(row, '实际交办日期')"
|
|
|
- @change="handleCellBlur(row, '实际交办日期')" />
|
|
|
+ @change="handleCellBlur(row, '实际交办日期')"
|
|
|
+ @visible-change="(v) => handleDatePickerVisibleChange(v, row, '实际交办日期')" />
|
|
|
<div v-else class="cell-span">{{ row.实际交办日期 || '\u00A0' }}</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
@@ -225,6 +241,7 @@ const defaultProps = {
|
|
|
}
|
|
|
|
|
|
const tableData = ref([])
|
|
|
+const multipleTable = ref(null)
|
|
|
const _noderq = ref('')
|
|
|
const _nodecode = ref('')
|
|
|
const page = ref(1)
|
|
|
@@ -313,13 +330,16 @@ const buildTreeData = (data) => {
|
|
|
id: `m-${yearMonth}`,
|
|
|
label: `${yearMonth}`,
|
|
|
yearMonth,
|
|
|
- children: (data[yearMonth] || []).map((customer) => ({
|
|
|
- id: `c-${yearMonth}-${customer.客户编号}`,
|
|
|
- label: `${customer.客户编号} (${customer.total}条)`,
|
|
|
- yearMonth,
|
|
|
- customerCode: customer.客户编号,
|
|
|
- total: customer.total,
|
|
|
- })),
|
|
|
+ children: (data[yearMonth] || []).map((customer) => {
|
|
|
+ const code = customer.客户编号 || '暂无客户'
|
|
|
+ return {
|
|
|
+ id: `c-${yearMonth}-${customer.客户编号 || 'empty'}`,
|
|
|
+ label: `${code} (${customer.total}条)`,
|
|
|
+ yearMonth,
|
|
|
+ customerCode: customer.客户编号,
|
|
|
+ total: customer.total,
|
|
|
+ }
|
|
|
+ }),
|
|
|
}))
|
|
|
}
|
|
|
|
|
|
@@ -362,7 +382,9 @@ const handleNodeClick = async (node) => {
|
|
|
return
|
|
|
}
|
|
|
if (node.yearMonth) {
|
|
|
- await loadListByMonth(node.yearMonth, node.customerCode || '')
|
|
|
+ // 空客户编号节点传 '__EMPTY__' 特殊标记
|
|
|
+ const customer = node.customerCode ? node.customerCode : '__EMPTY__'
|
|
|
+ await loadListByMonth(node.yearMonth, customer)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -464,18 +486,54 @@ const handleTableCellClick = (row, column) => {
|
|
|
handleCellClick(row, prop)
|
|
|
}
|
|
|
|
|
|
-const refreshData = async () => {
|
|
|
- const keepRq = _noderq.value
|
|
|
- const keepCode = _nodecode.value
|
|
|
+// 日期选择器面板关闭时,若值未改变则退出编辑态
|
|
|
+// 解决 el-date-picker 点击空白区域不会像 el-input 那样自然 blur 的问题
|
|
|
+const handleDatePickerVisibleChange = (visible, row, prop) => {
|
|
|
+ if (!visible) {
|
|
|
+ // 面板关闭了,如果当前还在编辑这个单元格,且值没变化,清除编辑态
|
|
|
+ if (editingCell.rowId === rowKeyOf(row) && editingCell.prop === prop) {
|
|
|
+ if (isCellUnchanged(row, prop)) {
|
|
|
+ clearEditingCell()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const refreshTreePreserveSelection = async () => {
|
|
|
+ const prevKey = currentTreeKey.value
|
|
|
try {
|
|
|
const response = await getDateTree()
|
|
|
treeData.value = buildTreeData(response.data || {})
|
|
|
+ await nextTick()
|
|
|
+ if (prevKey) {
|
|
|
+ menuTreeRef.value?.setCurrentKey?.(prevKey)
|
|
|
+ }
|
|
|
} catch (e) {
|
|
|
console.error(e)
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+const refreshData = async () => {
|
|
|
+ const keepRq = _noderq.value
|
|
|
+ const keepCode = _nodecode.value
|
|
|
+ await refreshTreePreserveSelection()
|
|
|
await loadListByMonth(keepRq, keepCode)
|
|
|
}
|
|
|
|
|
|
+// 保存/修改后定位回刚操作的行,避免整表刷新后跳到第一行
|
|
|
+const restoreEditedRow = async (uniqId) => {
|
|
|
+ if (!uniqId) return
|
|
|
+ await nextTick()
|
|
|
+ const target = tableData.value.find((item) => item.UniqId === uniqId)
|
|
|
+ if (!target) return
|
|
|
+ multipleTable.value?.setCurrentRow?.(target)
|
|
|
+ const idx = tableData.value.indexOf(target)
|
|
|
+ if (idx < 0) return
|
|
|
+ const bodyWrapper = multipleTable.value?.$el?.querySelector?.('.el-table__body-wrapper')
|
|
|
+ const rowEl = bodyWrapper?.querySelector?.(`tbody tr:nth-child(${idx + 1})`)
|
|
|
+ rowEl?.scrollIntoView?.({ block: 'nearest' })
|
|
|
+}
|
|
|
+
|
|
|
const handleCellBlur = async (row, prop) => {
|
|
|
// 已退出编辑态,忽略重复 blur/change
|
|
|
if (editingCell.rowId !== rowKeyOf(row) || editingCell.prop !== prop) {
|
|
|
@@ -499,6 +557,7 @@ const handleCellBlur = async (row, prop) => {
|
|
|
|
|
|
try {
|
|
|
if (row.UniqId) {
|
|
|
+ const editedId = row.UniqId
|
|
|
const res = await updateMonthlyGarments({
|
|
|
UniqId: row.UniqId,
|
|
|
nickName: userStore.userInfo.nickName,
|
|
|
@@ -519,7 +578,9 @@ const handleCellBlur = async (row, prop) => {
|
|
|
ElMessage.error('修改失败')
|
|
|
return
|
|
|
}
|
|
|
- await refreshData()
|
|
|
+ // 修改成功:只刷新左侧树,不重载表格,避免跳到第一行,方便继续改同一行
|
|
|
+ await refreshTreePreserveSelection()
|
|
|
+ await restoreEditedRow(editedId)
|
|
|
} else if (row.tempId) {
|
|
|
const res = await saveMonthlyGarments({
|
|
|
客户编号: row['客户编号'],
|
|
|
@@ -536,9 +597,21 @@ const handleCellBlur = async (row, prop) => {
|
|
|
备注: row['备注']
|
|
|
})
|
|
|
if (res.code === 0) {
|
|
|
- row.UniqId = parseInt(res.data.id)
|
|
|
+ const newId = parseInt(res.data.id)
|
|
|
+ row.UniqId = newId
|
|
|
delete row.tempId
|
|
|
- await refreshData()
|
|
|
+
|
|
|
+ // 先刷新列表(保留当前筛选条件),确保新数据立即可见
|
|
|
+ await loadListByMonth(_noderq.value, _nodecode.value)
|
|
|
+ // 安全网:如果刚保存的行不在刷新后的列表中(说明当前筛选看不到它),手动补到顶部
|
|
|
+ const exists = tableData.value.some((item) => item.UniqId === newId)
|
|
|
+ if (!exists) {
|
|
|
+ tableData.value.unshift(row)
|
|
|
+ }
|
|
|
+ // 再刷新树(保留当前选中状态)
|
|
|
+ await refreshTreePreserveSelection()
|
|
|
+ // 定位回刚新增的行,而不是停在第一行
|
|
|
+ await restoreEditedRow(newId)
|
|
|
} else {
|
|
|
ElMessage.error('保存失败')
|
|
|
return
|