|
@@ -87,6 +87,31 @@
|
|
|
show-summary
|
|
show-summary
|
|
|
show-overflow-tooltip
|
|
show-overflow-tooltip
|
|
|
>
|
|
>
|
|
|
|
|
+ <el-table-column label="小组" prop="小组" width="100" align="center">
|
|
|
|
|
+ <template #header>
|
|
|
|
|
+ <div class="process-production-col-header">
|
|
|
|
|
+ <span>小组</span>
|
|
|
|
|
+ <el-popover trigger="click" placement="bottom-start" :width="180" :teleported="true" :z-index="10050" append-to-body popper-class="gy-detail-filter-popper">
|
|
|
|
|
+ <template #reference>
|
|
|
|
|
+ <span class="gy-detail-filter-btn" :class="{ 'is-active': isGroupFilterActive }" @click.stop>
|
|
|
|
|
+ <svg viewBox="0 0 1024 1024" width="14" height="14" aria-hidden="true"><path fill="currentColor" d="M880.1 154H143.9c-24.5 0-39.9 26.7-27.6 48L349 597.4V838c0 17.7 14.2 32 31.8 32h262.4c17.6 0 31.8-14.3 31.8-32V597.4L907.7 202c12.2-21.3-3.1-48-27.6-48z"/></svg>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <div class="gy-detail-filter-panel">
|
|
|
|
|
+ <div class="gy-detail-filter-options">
|
|
|
|
|
+ <el-checkbox-group v-model="groupFilter">
|
|
|
|
|
+ <el-checkbox v-for="item in groupFilterOptions" :key="item.value" :label="item.value">{{ item.text }}</el-checkbox>
|
|
|
|
|
+ </el-checkbox-group>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="gy-detail-filter-actions">
|
|
|
|
|
+ <span class="gy-detail-filter-link" @click.stop="clearGroupFilter">取消全选</span>
|
|
|
|
|
+ <span class="gy-detail-filter-link" @click.stop="selectAllGroupFilter">全选</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-popover>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
<el-table-column label="工序编号" prop="工序号" width="100" align="center" />
|
|
<el-table-column label="工序编号" prop="工序号" width="100" align="center" />
|
|
|
<el-table-column label="工序名称" prop="工序名称" min-width="280" align="left" show-overflow-tooltip />
|
|
<el-table-column label="工序名称" prop="工序名称" min-width="280" align="left" show-overflow-tooltip />
|
|
|
<el-table-column label="员工姓名" prop="员工姓名" width="120" align="left">
|
|
<el-table-column label="员工姓名" prop="员工姓名" width="120" align="left">
|
|
@@ -118,8 +143,56 @@
|
|
|
<el-table-column v-if="!hideAmountColumns" label="工分" prop="工分" width="100" align="center" />
|
|
<el-table-column v-if="!hideAmountColumns" label="工分" prop="工分" width="100" align="center" />
|
|
|
<el-table-column v-if="!hideAmountColumns" label="工时" prop="工时" width="100" align="center" />
|
|
<el-table-column v-if="!hideAmountColumns" label="工时" prop="工时" width="100" align="center" />
|
|
|
<el-table-column v-if="!hideAmountColumns" label="工资" prop="工资" width="100" align="center" />
|
|
<el-table-column v-if="!hideAmountColumns" label="工资" prop="工资" width="100" align="center" />
|
|
|
- <el-table-column label="开工日期" prop="开工日期" width="110" align="center" />
|
|
|
|
|
- <el-table-column label="完工日期" prop="完工日期" width="110" align="center" />
|
|
|
|
|
|
|
+ <el-table-column label="开工日期" prop="开工日期" width="110" align="center">
|
|
|
|
|
+ <template #header>
|
|
|
|
|
+ <div class="process-production-col-header">
|
|
|
|
|
+ <span>开工日期</span>
|
|
|
|
|
+ <el-popover trigger="click" placement="bottom-start" :width="180" :teleported="true" :z-index="10050" append-to-body popper-class="gy-detail-filter-popper">
|
|
|
|
|
+ <template #reference>
|
|
|
|
|
+ <span class="gy-detail-filter-btn" :class="{ 'is-active': isStartDateFilterActive }" @click.stop>
|
|
|
|
|
+ <svg viewBox="0 0 1024 1024" width="14" height="14" aria-hidden="true"><path fill="currentColor" d="M880.1 154H143.9c-24.5 0-39.9 26.7-27.6 48L349 597.4V838c0 17.7 14.2 32 31.8 32h262.4c17.6 0 31.8-14.3 31.8-32V597.4L907.7 202c12.2-21.3-3.1-48-27.6-48z"/></svg>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <div class="gy-detail-filter-panel">
|
|
|
|
|
+ <div class="gy-detail-filter-options">
|
|
|
|
|
+ <el-checkbox-group v-model="startDateFilter">
|
|
|
|
|
+ <el-checkbox v-for="item in startDateFilterOptions" :key="item.value" :label="item.value">{{ item.text }}</el-checkbox>
|
|
|
|
|
+ </el-checkbox-group>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="gy-detail-filter-actions">
|
|
|
|
|
+ <span class="gy-detail-filter-link" @click.stop="clearStartDateFilter">取消全选</span>
|
|
|
|
|
+ <span class="gy-detail-filter-link" @click.stop="selectAllStartDateFilter">全选</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-popover>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column label="完工日期" prop="完工日期" width="110" align="center">
|
|
|
|
|
+ <template #header>
|
|
|
|
|
+ <div class="process-production-col-header">
|
|
|
|
|
+ <span>完工日期</span>
|
|
|
|
|
+ <el-popover trigger="click" placement="bottom-start" :width="180" :teleported="true" :z-index="10050" append-to-body popper-class="gy-detail-filter-popper">
|
|
|
|
|
+ <template #reference>
|
|
|
|
|
+ <span class="gy-detail-filter-btn" :class="{ 'is-active': isFinishDateFilterActive }" @click.stop>
|
|
|
|
|
+ <svg viewBox="0 0 1024 1024" width="14" height="14" aria-hidden="true"><path fill="currentColor" d="M880.1 154H143.9c-24.5 0-39.9 26.7-27.6 48L349 597.4V838c0 17.7 14.2 32 31.8 32h262.4c17.6 0 31.8-14.3 31.8-32V597.4L907.7 202c12.2-21.3-3.1-48-27.6-48z"/></svg>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <div class="gy-detail-filter-panel">
|
|
|
|
|
+ <div class="gy-detail-filter-options">
|
|
|
|
|
+ <el-checkbox-group v-model="finishDateFilter">
|
|
|
|
|
+ <el-checkbox v-for="item in finishDateFilterOptions" :key="item.value" :label="item.value">{{ item.text }}</el-checkbox>
|
|
|
|
|
+ </el-checkbox-group>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="gy-detail-filter-actions">
|
|
|
|
|
+ <span class="gy-detail-filter-link" @click.stop="clearFinishDateFilter">取消全选</span>
|
|
|
|
|
+ <span class="gy-detail-filter-link" @click.stop="selectAllFinishDateFilter">全选</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-popover>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
<template #empty>
|
|
<template #empty>
|
|
|
<el-empty
|
|
<el-empty
|
|
|
v-if="!loading"
|
|
v-if="!loading"
|
|
@@ -222,7 +295,17 @@ const isScalarSummaryValue = (val) =>
|
|
|
val == null || (typeof val !== 'object' && typeof val !== 'function')
|
|
val == null || (typeof val !== 'object' && typeof val !== 'function')
|
|
|
|
|
|
|
|
const processListRaw = ref([])
|
|
const processListRaw = ref([])
|
|
|
-const staffNameFilter = ref([])
|
|
|
|
|
|
|
+
|
|
|
|
|
+const normalizeTableDate = (val) => {
|
|
|
|
|
+ const s = String(val ?? '').trim()
|
|
|
|
|
+ if (!s) return ''
|
|
|
|
|
+ return s.replace(/\s+\d{2}:\d{2}(:\d{2})?$/, '').split('T')[0].split(' ')[0]
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const pickGroupFromStaff = (staff) =>
|
|
|
|
|
+ String(
|
|
|
|
|
+ staff?.小组 ?? staff?.group ?? staff?.['设备编组'] ?? staff?.['设备编号'] ?? staff?.team_name ?? ''
|
|
|
|
|
+ ).trim()
|
|
|
|
|
|
|
|
const flattenProcessList = (processList = []) => {
|
|
const flattenProcessList = (processList = []) => {
|
|
|
const rows = []
|
|
const rows = []
|
|
@@ -231,6 +314,7 @@ const flattenProcessList = (processList = []) => {
|
|
|
if (!staffs.length) {
|
|
if (!staffs.length) {
|
|
|
rows.push({
|
|
rows.push({
|
|
|
rowKey: `${proc.工序号}-empty`,
|
|
rowKey: `${proc.工序号}-empty`,
|
|
|
|
|
+ 小组: '',
|
|
|
工序号: proc.工序号 ?? '',
|
|
工序号: proc.工序号 ?? '',
|
|
|
工序名称: proc.工序名称 ?? '',
|
|
工序名称: proc.工序名称 ?? '',
|
|
|
员工姓名: '',
|
|
员工姓名: '',
|
|
@@ -247,6 +331,7 @@ const flattenProcessList = (processList = []) => {
|
|
|
staffs.forEach((staff, index) => {
|
|
staffs.forEach((staff, index) => {
|
|
|
rows.push({
|
|
rows.push({
|
|
|
rowKey: `${proc.工序号}-${index}-${staff.员工姓名 || ''}`,
|
|
rowKey: `${proc.工序号}-${index}-${staff.员工姓名 || ''}`,
|
|
|
|
|
+ 小组: pickGroupFromStaff(staff),
|
|
|
工序号: proc.工序号 ?? '',
|
|
工序号: proc.工序号 ?? '',
|
|
|
工序名称: proc.工序名称 ?? '',
|
|
工序名称: proc.工序名称 ?? '',
|
|
|
员工姓名: staff.员工姓名 ?? '',
|
|
员工姓名: staff.员工姓名 ?? '',
|
|
@@ -265,58 +350,105 @@ const flattenProcessList = (processList = []) => {
|
|
|
|
|
|
|
|
const flatTableRows = computed(() => flattenProcessList(processListRaw.value || []))
|
|
const flatTableRows = computed(() => flattenProcessList(processListRaw.value || []))
|
|
|
|
|
|
|
|
-const staffNameFilterOptions = computed(() => {
|
|
|
|
|
- const names = [...new Set(
|
|
|
|
|
- flatTableRows.value
|
|
|
|
|
- .map(row => String(row.员工姓名 || '').trim())
|
|
|
|
|
- .filter(Boolean)
|
|
|
|
|
- )]
|
|
|
|
|
- return names.map(name => ({ text: name, value: name }))
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const isStaffNameFilterActive = computed(() => {
|
|
|
|
|
- const allValues = staffNameFilterOptions.value.map(item => item.value)
|
|
|
|
|
- const selected = staffNameFilter.value
|
|
|
|
|
- if (!allValues.length) return false
|
|
|
|
|
- return selected.length < allValues.length
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-const selectAllStaffNameFilter = () => {
|
|
|
|
|
- staffNameFilter.value = staffNameFilterOptions.value.map(item => item.value)
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-const clearStaffNameFilter = () => {
|
|
|
|
|
- staffNameFilter.value = []
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-const syncStaffNameFilterAfterDataChange = () => {
|
|
|
|
|
- const allValues = staffNameFilterOptions.value.map(item => item.value)
|
|
|
|
|
- const selected = staffNameFilter.value
|
|
|
|
|
|
|
+const syncCheckboxFilterAfterDataChange = (options, selectedRef) => {
|
|
|
|
|
+ const allValues = options.map((item) => item.value)
|
|
|
|
|
+ const selected = selectedRef.value
|
|
|
if (!selected.length) {
|
|
if (!selected.length) {
|
|
|
- staffNameFilter.value = [...allValues]
|
|
|
|
|
|
|
+ selectedRef.value = [...allValues]
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- const wasAllSelected = allValues.length > 0 && allValues.every(v => selected.includes(v))
|
|
|
|
|
|
|
+ const wasAllSelected = allValues.length > 0 && allValues.every((v) => selected.includes(v))
|
|
|
if (wasAllSelected) {
|
|
if (wasAllSelected) {
|
|
|
- staffNameFilter.value = [...allValues]
|
|
|
|
|
|
|
+ selectedRef.value = [...allValues]
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- staffNameFilter.value = selected.filter(v => allValues.includes(v))
|
|
|
|
|
|
|
+ selectedRef.value = selected.filter((v) => allValues.includes(v))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const applyStaffNameFilter = (rows) => {
|
|
|
|
|
- const options = staffNameFilterOptions.value
|
|
|
|
|
- const selected = staffNameFilter.value
|
|
|
|
|
|
|
+const applyCheckboxColumnFilter = (rows, options, selected, getValue) => {
|
|
|
if (!selected.length) return []
|
|
if (!selected.length) return []
|
|
|
if (!options.length || selected.length >= options.length) return rows
|
|
if (!options.length || selected.length >= options.length) return rows
|
|
|
const set = new Set(selected)
|
|
const set = new Set(selected)
|
|
|
return rows.filter((row) => {
|
|
return rows.filter((row) => {
|
|
|
- const name = String(row.员工姓名 || '').trim()
|
|
|
|
|
- if (!name) return true
|
|
|
|
|
- return set.has(name)
|
|
|
|
|
|
|
+ const val = getValue(row)
|
|
|
|
|
+ if (!val) return true
|
|
|
|
|
+ return set.has(val)
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function createColumnFilter(getValue, { sortDesc = false } = {}) {
|
|
|
|
|
+ const selected = ref([])
|
|
|
|
|
+ const options = computed(() => {
|
|
|
|
|
+ const values = [...new Set(flatTableRows.value.map(getValue).filter(Boolean))]
|
|
|
|
|
+ if (sortDesc) values.sort((a, b) => b.localeCompare(a))
|
|
|
|
|
+ else values.sort((a, b) => a.localeCompare(b, 'zh-CN'))
|
|
|
|
|
+ return values.map((v) => ({ text: v, value: v }))
|
|
|
|
|
+ })
|
|
|
|
|
+ const isActive = computed(() => {
|
|
|
|
|
+ const allValues = options.value.map((item) => item.value)
|
|
|
|
|
+ if (!allValues.length) return false
|
|
|
|
|
+ return selected.value.length < allValues.length
|
|
|
})
|
|
})
|
|
|
|
|
+ return {
|
|
|
|
|
+ selected,
|
|
|
|
|
+ options,
|
|
|
|
|
+ isActive,
|
|
|
|
|
+ selectAll: () => {
|
|
|
|
|
+ selected.value = options.value.map((item) => item.value)
|
|
|
|
|
+ },
|
|
|
|
|
+ clear: () => {
|
|
|
|
|
+ selected.value = []
|
|
|
|
|
+ },
|
|
|
|
|
+ sync: () => syncCheckboxFilterAfterDataChange(options.value, selected),
|
|
|
|
|
+ apply: (rows) => applyCheckboxColumnFilter(rows, options.value, selected.value, getValue),
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+const groupFilterCtrl = createColumnFilter((row) => String(row.小组 || '').trim())
|
|
|
|
|
+const staffNameFilterCtrl = createColumnFilter((row) => String(row.员工姓名 || '').trim())
|
|
|
|
|
+const startDateFilterCtrl = createColumnFilter((row) => normalizeTableDate(row.开工日期), { sortDesc: true })
|
|
|
|
|
+const finishDateFilterCtrl = createColumnFilter((row) => normalizeTableDate(row.完工日期), { sortDesc: true })
|
|
|
|
|
+
|
|
|
|
|
+const {
|
|
|
|
|
+ selected: groupFilter,
|
|
|
|
|
+ options: groupFilterOptions,
|
|
|
|
|
+ isActive: isGroupFilterActive,
|
|
|
|
|
+ selectAll: selectAllGroupFilter,
|
|
|
|
|
+ clear: clearGroupFilter,
|
|
|
|
|
+ sync: syncGroupFilterAfterDataChange,
|
|
|
|
|
+ apply: applyGroupFilter,
|
|
|
|
|
+} = groupFilterCtrl
|
|
|
|
|
+
|
|
|
|
|
+const {
|
|
|
|
|
+ selected: staffNameFilter,
|
|
|
|
|
+ options: staffNameFilterOptions,
|
|
|
|
|
+ isActive: isStaffNameFilterActive,
|
|
|
|
|
+ selectAll: selectAllStaffNameFilter,
|
|
|
|
|
+ clear: clearStaffNameFilter,
|
|
|
|
|
+ sync: syncStaffNameFilterAfterDataChange,
|
|
|
|
|
+ apply: applyStaffNameFilter,
|
|
|
|
|
+} = staffNameFilterCtrl
|
|
|
|
|
+
|
|
|
|
|
+const {
|
|
|
|
|
+ selected: startDateFilter,
|
|
|
|
|
+ options: startDateFilterOptions,
|
|
|
|
|
+ isActive: isStartDateFilterActive,
|
|
|
|
|
+ selectAll: selectAllStartDateFilter,
|
|
|
|
|
+ clear: clearStartDateFilter,
|
|
|
|
|
+ sync: syncStartDateFilterAfterDataChange,
|
|
|
|
|
+ apply: applyStartDateFilter,
|
|
|
|
|
+} = startDateFilterCtrl
|
|
|
|
|
+
|
|
|
|
|
+const {
|
|
|
|
|
+ selected: finishDateFilter,
|
|
|
|
|
+ options: finishDateFilterOptions,
|
|
|
|
|
+ isActive: isFinishDateFilterActive,
|
|
|
|
|
+ selectAll: selectAllFinishDateFilter,
|
|
|
|
|
+ clear: clearFinishDateFilter,
|
|
|
|
|
+ sync: syncFinishDateFilterAfterDataChange,
|
|
|
|
|
+ apply: applyFinishDateFilter,
|
|
|
|
|
+} = finishDateFilterCtrl
|
|
|
|
|
+
|
|
|
const recomputeProcessRowSpan = (rows) => {
|
|
const recomputeProcessRowSpan = (rows) => {
|
|
|
const result = []
|
|
const result = []
|
|
|
let i = 0
|
|
let i = 0
|
|
@@ -337,12 +469,19 @@ const recomputeProcessRowSpan = (rows) => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const displayTableData = computed(() => {
|
|
const displayTableData = computed(() => {
|
|
|
- const filtered = applyStaffNameFilter(flatTableRows.value)
|
|
|
|
|
|
|
+ let filtered = flatTableRows.value
|
|
|
|
|
+ filtered = applyGroupFilter(filtered)
|
|
|
|
|
+ filtered = applyStaffNameFilter(filtered)
|
|
|
|
|
+ filtered = applyStartDateFilter(filtered)
|
|
|
|
|
+ filtered = applyFinishDateFilter(filtered)
|
|
|
return recomputeProcessRowSpan(filtered)
|
|
return recomputeProcessRowSpan(filtered)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
watch(flatTableRows, () => {
|
|
watch(flatTableRows, () => {
|
|
|
|
|
+ syncGroupFilterAfterDataChange()
|
|
|
syncStaffNameFilterAfterDataChange()
|
|
syncStaffNameFilterAfterDataChange()
|
|
|
|
|
+ syncStartDateFilterAfterDataChange()
|
|
|
|
|
+ syncFinishDateFilterAfterDataChange()
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
const tableSpanMethod = ({ row, column }) => {
|
|
const tableSpanMethod = ({ row, column }) => {
|