|
|
@@ -4,11 +4,12 @@
|
|
|
<el-table v-loading="loading" :data="tableData" border @selection-change="handleSelectionChange"
|
|
|
@sort-change="handleSortChange" class="shift-schedule-table" ref="tableRef" :row-class-name="getRowClassName">
|
|
|
<el-table-column type="selection" width="55" fixed="left" :selectable="isSelectable" />
|
|
|
+ <el-table-column type="index" label="序号" width="65" align="center" fixed="left" />
|
|
|
<el-table-column label="日期" prop="date" width="170" align="center" fixed="left" sortable>
|
|
|
<template #default="{ row }">
|
|
|
<div class="date-cell">
|
|
|
<el-date-picker v-model="row.date" type="date" value-format="YYYY-MM-DD" placeholder="选择日期"
|
|
|
- :clearable="false" class="!w-120px" :disabled="!canEdit(row)" @change="handleDateChange(row)" />
|
|
|
+ :clearable="false" class="!w-120px" :disabled="!canEditDate(row)" @change="handleDateChange(row)" />
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
@@ -20,13 +21,14 @@
|
|
|
<template #default="{ row }">
|
|
|
<div>
|
|
|
<!-- 不可编辑状态:只显示检验员名称 -->
|
|
|
- <div v-if="!canEdit(row)" class="checker-display">
|
|
|
+ <div v-if="!canEditCheckers(row)" class="checker-display">
|
|
|
{{ getCheckerNames(row) || '-' }}
|
|
|
</div>
|
|
|
|
|
|
<!-- 可编辑状态:使用Popover -->
|
|
|
<el-popover v-else placement="bottom-start" :width="600" trigger="click"
|
|
|
- popper-class="checker-select-popover" @show="() => handlePopoverShow(row)">
|
|
|
+ popper-class="checker-select-popover" @show="() => handlePopoverShow(row)"
|
|
|
+ @hide="() => handlePopoverHide(row)">
|
|
|
<template #reference>
|
|
|
<div class="checker-trigger" :class="{ 'has-checkers': getCheckerNames(row) }" @click.stop>
|
|
|
<span class="checker-text">{{ getCheckerNames(row) || '请选择检验员' }}</span>
|
|
|
@@ -109,6 +111,14 @@
|
|
|
<span class="status-dot" style="background-color: #f56c6c;"></span>
|
|
|
<span>检测中</span>
|
|
|
</div>
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="status-dot" style="background-color: #909399;"></span>
|
|
|
+ <span>部分办结</span>
|
|
|
+ </div>
|
|
|
+ <div class="legend-item">
|
|
|
+ <span class="status-dot" style="background-color: #303133;"></span>
|
|
|
+ <span>已办结</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
<div class="flex items-center justify-center gap-6px cursor-help">
|
|
|
@@ -130,7 +140,7 @@
|
|
|
<template #default="{ row }">
|
|
|
<el-tag v-if="row.isCopied && !row.submitted" type="warning" size="small">已复制</el-tag>
|
|
|
<el-button v-else size="small" :type="row.modified ? 'success' : 'primary'"
|
|
|
- :disabled="row.status === 100 || !canEdit(row)" @click="handleCopy(row)">
|
|
|
+ :disabled="!canEditCheckers(row)" @click="handleCopy(row)">
|
|
|
复制
|
|
|
</el-button>
|
|
|
</template>
|
|
|
@@ -190,6 +200,7 @@ interface ScheduleRow {
|
|
|
status?: number // 状态, 100 已排期 200 待约检 300 已受理 400 检测中
|
|
|
isCopied?: boolean // 是否为复制的行
|
|
|
submitted?: boolean // 是否已提交
|
|
|
+ sourceId?: string
|
|
|
}
|
|
|
|
|
|
const loading = ref(false)
|
|
|
@@ -277,13 +288,48 @@ const setCheckerSelectRef = (el: any, rowId: string) => {
|
|
|
}
|
|
|
}
|
|
|
const inspectors = ref()
|
|
|
+// 从 teamList 重新构建 inspectors,保证是最新数据
|
|
|
+const buildInspectorsFromTeamList = (teamList: any[]): any[] => {
|
|
|
+ if (!teamList) return []
|
|
|
+ return teamList.flatMap(team => {
|
|
|
+ const teamMembers: any[] = []
|
|
|
+ if (team.leaders && team.leaders.length > 0) {
|
|
|
+ team.leaders.forEach((leader: any) => {
|
|
|
+ if (leader) {
|
|
|
+ teamMembers.push({
|
|
|
+ memberId: leader.id,
|
|
|
+ groupTeamId: team.groupTeamId,
|
|
|
+ leaderId: leader.id,
|
|
|
+ member: leader,
|
|
|
+ isLeader: true
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ if (team.members && team.members.length > 0) {
|
|
|
+ team.members.forEach((member: any) => {
|
|
|
+ if (member) {
|
|
|
+ teamMembers.push({
|
|
|
+ memberId: member.id,
|
|
|
+ groupTeamId: team.groupTeamId,
|
|
|
+ leaderId: team.leaders?.[0]?.id || '',
|
|
|
+ member: member,
|
|
|
+ isLeader: false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return teamMembers
|
|
|
+ })
|
|
|
+}
|
|
|
// 处理 Popover 显示
|
|
|
const handlePopoverShow = async (row: ScheduleRow) => {
|
|
|
if (!canEdit(row)) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
- inspectors.value = row.inspectors
|
|
|
+ // 从当前 teamList 重新构建 inspectors,确保拿到最新数据
|
|
|
+ inspectors.value = buildInspectorsFromTeamList(row.teamList)
|
|
|
currentEditingRow.value = row
|
|
|
|
|
|
const checkerSelectRef = checkerSelectRefs.value[row.id]
|
|
|
@@ -291,12 +337,6 @@ const handlePopoverShow = async (row: ScheduleRow) => {
|
|
|
// 加载检验员列表
|
|
|
const deptId = userStore.getUser.deptId?.toString() || props.relateDepartment
|
|
|
await checkerSelectRef.getCheckerList(deptId)
|
|
|
- console.log(row.inspectors)
|
|
|
-}
|
|
|
-
|
|
|
-// 关闭Popover
|
|
|
-const closePopover = () => {
|
|
|
- currentEditingRow.value = null
|
|
|
}
|
|
|
|
|
|
// 处理检验员选择变化
|
|
|
@@ -332,8 +372,13 @@ const handleCheckerSelectChange = (selectedCheckers: CheckerItem[], row: Schedul
|
|
|
}
|
|
|
})
|
|
|
row.teamList = Array.from(teamMap.values())
|
|
|
- // 标记为已修改并自动保存
|
|
|
+ // 标记为已修改,Popover 关闭时保存
|
|
|
row.modified = true
|
|
|
+}
|
|
|
+
|
|
|
+// Popover 关闭时保存
|
|
|
+const handlePopoverHide = (row: ScheduleRow) => {
|
|
|
+ if (!row || !row.modified) return
|
|
|
autoSaveRow(row)
|
|
|
}
|
|
|
|
|
|
@@ -358,14 +403,14 @@ const calculateWeek = (dateStr: string): string => {
|
|
|
|
|
|
// 获取状态文本
|
|
|
const getStatusText = (status: number | string | null | undefined): string => {
|
|
|
- if (status === null || status === undefined) {
|
|
|
- return '未知'
|
|
|
- }
|
|
|
+ if (status === null || status === undefined) return '未知'
|
|
|
const statusMap: Record<number, string> = {
|
|
|
100: '已排期',
|
|
|
200: '待约检',
|
|
|
300: '已受理',
|
|
|
- 400: '检测中'
|
|
|
+ 400: '检测中',
|
|
|
+ 500: '部分办结',
|
|
|
+ 600: '已办结'
|
|
|
}
|
|
|
return statusMap[Number(status)] || '未知'
|
|
|
}
|
|
|
@@ -380,26 +425,35 @@ const formatPipeLength = (val: string | undefined): string => {
|
|
|
|
|
|
// 获取状态样式类
|
|
|
const getStatusClass = (status: number | string | null | undefined): string => {
|
|
|
- if (status === null || status === undefined) {
|
|
|
- return ''
|
|
|
- }
|
|
|
+ if (status === null || status === undefined) return ''
|
|
|
const classMap: Record<number, string> = {
|
|
|
100: 'dot-scheduled',
|
|
|
200: 'dot-pending-appointment',
|
|
|
300: 'dot-accepted',
|
|
|
- 400: 'dot-testing'
|
|
|
+ 400: 'dot-testing',
|
|
|
+ 500: 'dot-partial-done',
|
|
|
+ 600: 'dot-done'
|
|
|
}
|
|
|
return classMap[Number(status)] || ''
|
|
|
}
|
|
|
|
|
|
-// 判断是否可以编辑
|
|
|
+// 复制行(有 sourceId)在办结前不限制修改
|
|
|
+const isCopyNotDone = (row: ScheduleRow): boolean => {
|
|
|
+ return !!row.sourceId && (row.status === undefined || row.status < 500)
|
|
|
+}
|
|
|
+
|
|
|
+const canEditDate = (row: ScheduleRow): boolean => {
|
|
|
+ if (isCopyNotDone(row)) return true
|
|
|
+ return row.status === 100 || row.status === 200
|
|
|
+}
|
|
|
+
|
|
|
+const canEditCheckers = (row: ScheduleRow): boolean => {
|
|
|
+ if (isCopyNotDone(row)) return true
|
|
|
+ return row.status === 100 || row.status === 200 || row.status === 300 || row.status === 400
|
|
|
+}
|
|
|
+
|
|
|
const canEdit = (row: ScheduleRow): boolean => {
|
|
|
- // 受理前(状态为 100 已排期或 200 待约检)的行可以编辑
|
|
|
- if (row.status === 100 || row.status === 200) {
|
|
|
- return true
|
|
|
- }
|
|
|
- // 其他行不可编辑
|
|
|
- return false
|
|
|
+ return canEditDate(row) || canEditCheckers(row)
|
|
|
}
|
|
|
|
|
|
// 获取行类名
|
|
|
@@ -415,11 +469,6 @@ const getRowClassName = ({ row }: { row: ScheduleRow }): string => {
|
|
|
|
|
|
// 复制行
|
|
|
const handleCopy = (row: ScheduleRow) => {
|
|
|
- // 限制只有有 confirmOrderId 的情况下才能复制
|
|
|
- if (!row.confirmOrderId) {
|
|
|
- ElMessage.warning('只有已确认的订单才能复制')
|
|
|
- return
|
|
|
- }
|
|
|
|
|
|
// 计算下一天的日期
|
|
|
let nextDate = ''
|
|
|
@@ -433,6 +482,7 @@ const handleCopy = (row: ScheduleRow) => {
|
|
|
const newRow: ScheduleRow = {
|
|
|
...row,
|
|
|
sourceIndex: row.index,
|
|
|
+ sourceId: row.sourceId || row.id,
|
|
|
date: nextDate, // 设置为下一天
|
|
|
week: nextWeek, // 设置对应的星期
|
|
|
isCopied: true, // 标记为复制的行
|
|
|
@@ -497,44 +547,8 @@ const handleQuery = async () => {
|
|
|
isCopied: false,
|
|
|
submitted: true
|
|
|
}))
|
|
|
- tableData.value.forEach((row, index) => {
|
|
|
- const inspectors = row.teamList?.flatMap(team => {
|
|
|
- const teamMembers = []
|
|
|
-
|
|
|
- // 处理组长
|
|
|
- if (team.leaders && team.leaders.length > 0) {
|
|
|
- team.leaders.forEach(leader => {
|
|
|
- if (leader) {
|
|
|
- teamMembers.push({
|
|
|
- memberId: leader.id,
|
|
|
- groupTeamId: team.groupTeamId,
|
|
|
- leaderId: leader.id,
|
|
|
- member: leader,
|
|
|
- isLeader: true
|
|
|
- })
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- // 处理组员
|
|
|
- if (team.members && team.members.length > 0) {
|
|
|
- team.members.forEach(member => {
|
|
|
- if (member) {
|
|
|
- teamMembers.push({
|
|
|
- memberId: member.id,
|
|
|
- groupTeamId: team.groupTeamId,
|
|
|
- leaderId: team.leaders?.[0]?.id || '',
|
|
|
- member: member,
|
|
|
- isLeader: false
|
|
|
- })
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- return teamMembers
|
|
|
- }) || []
|
|
|
- row.inspectors = inspectors
|
|
|
- console.log('inspectors', inspectors)
|
|
|
+ tableData.value.forEach((row) => {
|
|
|
+ row.inspectors = buildInspectorsFromTeamList(row.teamList)
|
|
|
})
|
|
|
loading.value = false
|
|
|
}
|
|
|
@@ -549,12 +563,13 @@ const autoSaveRow = async (row: ScheduleRow) => {
|
|
|
if (!row.checkers || row.checkers.length === 0) {
|
|
|
return
|
|
|
}
|
|
|
- // 校验:同 confirmOrderId 日期不能重复
|
|
|
- if (row.confirmOrderId) {
|
|
|
- const sameGroup = tableData.value.filter(r => r.confirmOrderId === row.confirmOrderId)
|
|
|
+ // 校验:同源排期(sourceId 或 id)的日期不能重复
|
|
|
+ const sourceOrId = row.sourceId || row.id
|
|
|
+ if (sourceOrId) {
|
|
|
+ const sameGroup = tableData.value.filter(r => (r.sourceId === sourceOrId || r.id === sourceOrId))
|
|
|
const duplicate = sameGroup.some(item => item.date === row.date && item !== row)
|
|
|
if (duplicate) {
|
|
|
- ElMessage.warning('同一个约检确认单下日期不能重复')
|
|
|
+ ElMessage.warning('同一源排期下日期不能重复')
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
@@ -891,6 +906,14 @@ onMounted(async () => {
|
|
|
.dot-testing {
|
|
|
background: #f56c6c;
|
|
|
}
|
|
|
+
|
|
|
+.dot-partial-done {
|
|
|
+ background: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+.dot-done {
|
|
|
+ background: #303133;
|
|
|
+}
|
|
|
</style>
|
|
|
|
|
|
<style lang="scss">
|