| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909 |
- <template>
- <div class="process-production-page" :class="{ 'in-dialog': inDialog, 'embedded-in-tab': embeddedInTab }">
- <div class="process-production-inner">
- <el-form v-if="!embeddedInTab" class="process-production-search" inline @submit.prevent="handleQueryClick">
- <div ref="searchWrapRef" class="workorder-search-wrap">
- <el-input
- v-model="searchKeyword"
- clearable
- placeholder="请输入订单编号/生产款号/款式"
- style="width: 360px"
- @keyup.enter="handleQueryClick"
- @input="onSearchKeywordInput"
- @clear="closeWorkOrderDropdown"
- />
- <div
- v-show="workOrderDropdownVisible && workOrderOptions.length"
- class="workorder-dropdown-panel"
- >
- <div class="workorder-suggest-header">
- <span>订单编号</span>
- <span>生产款号</span>
- <span>款式</span>
- </div>
- <div class="workorder-dropdown-list">
- <div
- v-for="item in workOrderOptions"
- :key="item.订单编号"
- class="workorder-suggest-row"
- @click="onPickWorkOrder(item)"
- >
- <span class="workorder-suggest-no" :title="item.订单编号">{{ item.订单编号 }}</span>
- <span class="workorder-suggest-style" :title="item.生产款号">{{ item.生产款号 }}</span>
- <span class="workorder-suggest-name" :title="item.款式">{{ item.款式 }}</span>
- </div>
- </div>
- </div>
- </div>
- <el-button type="primary" icon="search" :loading="workOrderSuggestLoading" @click="handleQueryClick">
- 查询
- </el-button>
- </el-form>
- <el-alert
- v-if="pageHint"
- class="process-production-hint"
- :title="pageHint"
- type="warning"
- show-icon
- :closable="false"
- />
- <!-- 订单摘要:新增字段只在此处数组里加一行,key 与 WorkOrderList 返回字段一致 -->
- <el-descriptions
- v-if="!embeddedInTab"
- class="order-summary-desc"
- :column="5"
- border
- >
- <el-descriptions-item
- v-for="field in [
- { label: '客户编号', key: '客户编号' },
- { label: '订单编号', key: '订单编号' },
- { label: '生产款号', key: '生产款号' },
- { label: '款式', key: '款式' },
- { label: '订单数量', key: '订单数量' },
- ]"
- :key="field.key"
- :label="field.label"
- >
- {{ orderSummary[field.key] }}
- </el-descriptions-item>
- </el-descriptions>
- <div class="process-production-table-wrap">
- <el-table
- v-loading="loading"
- :data="displayTableData"
- :height="tableHeight"
- border
- stripe
- row-key="rowKey"
- style="width: 100%"
- :row-style="{ height: '32px' }"
- :header-row-style="{ height: '36px' }"
- :span-method="tableSpanMethod"
- :summary-method="tableSummaryMethod"
- show-summary
- 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="工序名称" min-width="280" align="left" show-overflow-tooltip />
- <el-table-column label="员工姓名" prop="员工姓名" width="120" align="left">
- <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': isStaffNameFilterActive }" @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="staffNameFilter">
- <el-checkbox v-for="item in staffNameFilterOptions" :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="clearStaffNameFilter">取消全选</span>
- <span class="gy-detail-filter-link" @click.stop="selectAllStaffNameFilter">全选</span>
- </div>
- </div>
- </el-popover>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="完工数量" prop="数量" width="90" 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">
- <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>
- <el-empty
- v-if="!loading"
- :description="emptyDescription"
- :image-size="100"
- />
- </template>
- </el-table>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import { computed, reactive, ref, watch, onMounted, onUnmounted } from 'vue'
- import { ElMessage } from 'element-plus'
- import { checkProcessProduction, WorkOrderList } from '@/api/mes/job'
- defineOptions({ name: 'ProcessProduction' })
- const props = defineProps({
- /** 弹窗打开时传入的订单编号,会自动查询 */
- initialWorkorder: { type: String, default: '' },
- /** 嵌入订单资料弹窗时使用 */
- inDialog: { type: Boolean, default: false },
- /** 为 true 时不显示工分、工时、工资列(如样衣批核页) */
- hideAmountColumns: { type: Boolean, default: false },
- /** 嵌入工分报工页 Tab:隐藏搜索栏与订单摘要,固定表格高度 */
- embeddedInTab: { type: Boolean, default: false },
- })
- /** 主页面表格高度:改此值即可 */
- const MAIN_TABLE_HEIGHT = 'calc(100vh - 300px)'
- /** 弹窗内表格最大高度(距视口顶部的预留像素,含标题/搜索/订单信息栏) */
- const DIALOG_TABLE_OFFSET = 220
- const DIALOG_TABLE_EMPTY_HEIGHT = 320
- const TABLE_SUMMARY_ROW_HEIGHT = 40
- const sumTableColumn = (data, prop) => {
- return data.reduce((sum, row) => {
- const n = Number(row[prop])
- return sum + (Number.isFinite(n) ? n : 0)
- }, 0)
- }
- const formatSummaryValue = (total, prop) => {
- if (!Number.isFinite(total)) return ''
- if (prop === '数量') {
- return Number.isInteger(total) ? String(total) : total.toFixed(2)
- }
- return total.toFixed(2)
- }
- const tableSummaryMethod = ({ columns, data }) => {
- const summaryProps = props.hideAmountColumns
- ? ['数量']
- : ['数量', '工分', '工时', '工资']
- return columns.map((column, index) => {
- if (index === 0) return '合计'
- const prop = column.property
- if (!summaryProps.includes(prop)) return ''
- return formatSummaryValue(sumTableColumn(data, prop), prop)
- })
- }
- /** 嵌入 Tab 时与工分报工记录表同高 */
- const EMBEDDED_TAB_TABLE_HEIGHT = '52vh'
- /** 弹窗按行数自适应高度,避免数据少时底部大块空白;主页面固定高度 */
- const tableHeight = computed(() => {
- if (props.embeddedInTab) return EMBEDDED_TAB_TABLE_HEIGHT
- if (!props.inDialog) return MAIN_TABLE_HEIGHT
- const rows = displayTableData.value.length
- const maxH = Math.max(200, window.innerHeight - DIALOG_TABLE_OFFSET)
- if (!rows) return Math.min(DIALOG_TABLE_EMPTY_HEIGHT, maxH)
- const needH = rows * 32 + 36 + 12 + TABLE_SUMMARY_ROW_HEIGHT
- return Math.min(Math.max(needH, 200), maxH)
- })
- const loading = ref(false)
- const searched = ref(false)
- /** 查询结果页内提示(如:未找到报工数据),不用 ElMessage 弹窗 */
- const pageHint = ref('')
- const emptyDescription = computed(() => {
- if (!searched.value) {
- return props.embeddedInTab ? '请先查询订单' : '请输入订单编号后查询'
- }
- return pageHint.value || '暂无数据'
- })
- const searchKeyword = ref('')
- const searchWrapRef = ref(null)
- const workOrderDropdownVisible = ref(false)
- const orderSummary = reactive({})
- const isScalarSummaryValue = (val) =>
- val == null || (typeof val !== 'object' && typeof val !== 'function')
- const processListRaw = 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 rows = []
- for (const proc of processList) {
- const staffs = Array.isArray(proc.staffs) ? proc.staffs : []
- if (!staffs.length) {
- rows.push({
- rowKey: `${proc.工序号}-empty`,
- 小组: '',
- 工序号: proc.工序号 ?? '',
- 工序名称: proc.工序名称 ?? '',
- 员工姓名: '',
- 数量: '',
- 开工日期: '',
- 完工日期: '',
- 工分: '',
- 工时: '',
- 工资: '',
- _processRowSpan: 1,
- })
- continue
- }
- staffs.forEach((staff, index) => {
- rows.push({
- rowKey: `${proc.工序号}-${index}-${staff.员工姓名 || ''}`,
- 小组: pickGroupFromStaff(staff),
- 工序号: proc.工序号 ?? '',
- 工序名称: proc.工序名称 ?? '',
- 员工姓名: staff.员工姓名 ?? '',
- 数量: staff.数量 ?? '',
- 开工日期: staff.开工日期 ?? '',
- 完工日期: staff.完工日期 ?? '',
- 工分: staff.工分 ?? '',
- 工时: staff.工时 ?? '',
- 工资: staff.工资 ?? '',
- _processRowSpan: index === 0 ? staffs.length : 0,
- })
- })
- }
- return rows
- }
- const flatTableRows = computed(() => flattenProcessList(processListRaw.value || []))
- const syncCheckboxFilterAfterDataChange = (options, selectedRef) => {
- const allValues = options.map((item) => item.value)
- const selected = selectedRef.value
- if (!selected.length) {
- selectedRef.value = [...allValues]
- return
- }
- const wasAllSelected = allValues.length > 0 && allValues.every((v) => selected.includes(v))
- if (wasAllSelected) {
- selectedRef.value = [...allValues]
- return
- }
- selectedRef.value = selected.filter((v) => allValues.includes(v))
- }
- const applyCheckboxColumnFilter = (rows, options, selected, getValue) => {
- if (!selected.length) return []
- if (!options.length || selected.length >= options.length) return rows
- const set = new Set(selected)
- return rows.filter((row) => {
- 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 result = []
- let i = 0
- while (i < rows.length) {
- const processNo = rows[i].工序号
- const processName = rows[i].工序名称
- let j = i
- while (j < rows.length && rows[j].工序号 === processNo && rows[j].工序名称 === processName) {
- j++
- }
- const group = rows.slice(i, j)
- group.forEach((row, idx) => {
- result.push({ ...row, _processRowSpan: idx === 0 ? group.length : 0 })
- })
- i = j
- }
- return result
- }
- const displayTableData = computed(() => {
- let filtered = flatTableRows.value
- filtered = applyGroupFilter(filtered)
- filtered = applyStaffNameFilter(filtered)
- filtered = applyStartDateFilter(filtered)
- filtered = applyFinishDateFilter(filtered)
- return recomputeProcessRowSpan(filtered)
- })
- watch(flatTableRows, () => {
- syncGroupFilterAfterDataChange()
- syncStaffNameFilterAfterDataChange()
- syncStartDateFilterAfterDataChange()
- syncFinishDateFilterAfterDataChange()
- })
- const tableSpanMethod = ({ row, column }) => {
- if (column.property !== '工序号' && column.property !== '工序名称') {
- return { rowspan: 1, colspan: 1 }
- }
- const rowspan = row._processRowSpan || 0
- if (rowspan > 0) {
- return { rowspan, colspan: 1 }
- }
- return { rowspan: 0, colspan: 0 }
- }
- const resetOrderSummary = (workorder = '') => {
- Object.keys(orderSummary).forEach((key) => {
- orderSummary[key] = ''
- })
- orderSummary.订单编号 = workorder
- }
- const applyOrderSummaryFromWorkOrder = (data, workorder) => {
- Object.keys(orderSummary).forEach((key) => {
- orderSummary[key] = ''
- })
- for (const [key, val] of Object.entries(data || {})) {
- if (isScalarSummaryValue(val)) {
- orderSummary[key] = val ?? ''
- }
- }
- orderSummary.订单编号 = orderSummary.订单编号 || workorder
- }
- const loadOrderSummaryFromWorkOrderList = async (workorder) => {
- resetOrderSummary(workorder)
- try {
- const res = await WorkOrderList({ search: workorder, page: 1, limit: 1 })
- const list = res?.data?.data
- if (res?.code === 0 && Array.isArray(list) && list.length) {
- applyOrderSummaryFromWorkOrder(list[0], workorder)
- return true
- }
- } catch (error) {
- console.error(error)
- }
- return false
- }
- let workOrderSuggestSeq = 0
- const workOrderOptions = ref([])
- const workOrderSuggestLoading = ref(false)
- let searchInputTimer = null
- const closeWorkOrderDropdown = () => {
- workOrderDropdownVisible.value = false
- workOrderOptions.value = []
- }
- const onSearchKeywordInput = () => {
- clearTimeout(searchInputTimer)
- searchInputTimer = setTimeout(async () => {
- const q = String(searchKeyword.value || '').trim()
- if (!q) {
- closeWorkOrderDropdown()
- return
- }
- await remoteSearchWorkOrder(q)
- workOrderDropdownVisible.value = workOrderOptions.value.length > 0
- }, 300)
- }
- const onDocClick = (event) => {
- if (!searchWrapRef.value?.contains(event.target)) {
- workOrderDropdownVisible.value = false
- }
- }
- onMounted(() => {
- document.addEventListener('click', onDocClick)
- })
- onUnmounted(() => {
- document.removeEventListener('click', onDocClick)
- clearTimeout(searchInputTimer)
- })
- const remoteSearchWorkOrder = async (query) => {
- const q = String(query || '').trim()
- if (!q) {
- workOrderOptions.value = []
- return
- }
- const seq = ++workOrderSuggestSeq
- workOrderSuggestLoading.value = true
- try {
- const res = await WorkOrderList({ search: q, page: 1, limit: 20 })
- if (seq !== workOrderSuggestSeq) return
- workOrderOptions.value = res?.code === 0 && Array.isArray(res.data?.data) ? res.data.data : []
- } catch (error) {
- console.error(error)
- workOrderOptions.value = []
- } finally {
- if (seq === workOrderSuggestSeq) {
- workOrderSuggestLoading.value = false
- }
- }
- }
- const onPickWorkOrder = async (item) => {
- const no = String(item?.订单编号 || '').trim()
- if (!no) return
- applyOrderSummaryFromWorkOrder(item, no)
- workOrderDropdownVisible.value = false
- await executeProductionSearch(no)
- searchKeyword.value = ''
- }
- /** 点击查询 / 回车:仅 1 条则直接查,多条则展开下拉;查询前不清空输入框 */
- const handleQueryClick = async () => {
- const q = String(searchKeyword.value || '').trim()
- if (!q) {
- ElMessage.warning('请输入订单编号/生产款号/款式')
- return
- }
- await remoteSearchWorkOrder(q)
- if (!workOrderOptions.value.length) {
- ElMessage.warning('未找到匹配订单')
- workOrderDropdownVisible.value = false
- return
- }
- if (workOrderOptions.value.length === 1) {
- await onPickWorkOrder(workOrderOptions.value[0])
- return
- }
- workOrderDropdownVisible.value = true
- }
- const loadByWorkorder = async (workorder) => {
- const w = String(workorder || '').trim()
- if (!w) return
- searchKeyword.value = w
- await executeProductionSearch(w)
- }
- const executeProductionSearch = async (orderNo) => {
- const workorder = String(orderNo || '').trim()
- if (!workorder) {
- ElMessage.warning('请输入订单编号')
- return
- }
- loading.value = true
- searched.value = true
- pageHint.value = ''
- try {
- const [, res] = await Promise.all([
- loadOrderSummaryFromWorkOrderList(workorder),
- checkProcessProduction({ workorder }),
- ])
- if (res?.code !== 0) {
- processListRaw.value = []
- pageHint.value = res?.msg || '未找到报工数据'
- return
- }
- const data = res.data || {}
- processListRaw.value = data.工序列表 || []
- if (!processListRaw.value.length) {
- pageHint.value = '未找到报工数据'
- }
- } catch (error) {
- console.error(error)
- pageHint.value = ''
- ElMessage.error('查询失败,请稍后重试')
- processListRaw.value = []
- resetOrderSummary(workorder)
- } finally {
- loading.value = false
- }
- }
- watch(
- () => props.initialWorkorder,
- (val) => {
- if (val) loadByWorkorder(val)
- },
- { immediate: true }
- )
- defineExpose({ loadByWorkorder })
- </script>
- <style scoped>
- .process-production-page {
- height: 100%;
- background: transparent;
- }
- .process-production-page.in-dialog {
- min-height: 0;
- }
- /* 主页面:右侧与左侧留白一致(左侧由布局已有间距,此处补右侧) */
- .process-production-page:not(.in-dialog) {
- padding-right: 16px;
- box-sizing: border-box;
- }
- .process-production-inner {
- padding: 0 16px 12px;
- box-sizing: border-box;
- max-width: 100%;
- }
- .process-production-page.embedded-in-tab .process-production-inner {
- padding: 0;
- }
- .process-production-search {
- margin-bottom: 8px;
- }
- .process-production-hint {
- margin-bottom: 10px;
- }
- .process-production-search :deep(.el-form-item) {
- margin-bottom: 0;
- margin-right: 12px;
- }
- .workorder-search-wrap {
- position: relative;
- display: inline-block;
- vertical-align: middle;
- }
- .workorder-dropdown-panel {
- position: absolute;
- top: calc(100% + 4px);
- left: 0;
- z-index: 3000;
- width: 680px;
- max-width: min(920px, 96vw);
- background: #fff;
- border: 1px solid #e4e7ed;
- border-radius: 4px;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
- box-sizing: border-box;
- overflow: hidden;
- }
- .workorder-dropdown-panel .workorder-suggest-header {
- padding: 8px 12px 6px;
- border-bottom: 1px solid #ebeef5;
- background: #fafafa;
- }
- .workorder-dropdown-list {
- max-height: 280px;
- overflow-y: auto;
- }
- .workorder-suggest-row {
- display: grid;
- grid-template-columns: 118px minmax(220px, 1fr) minmax(140px, 180px);
- gap: 10px;
- align-items: center;
- padding: 8px 12px;
- line-height: 1.4;
- font-size: 13px;
- cursor: pointer;
- box-sizing: border-box;
- }
- .workorder-suggest-row:hover {
- background: #f5f7fa;
- }
- .workorder-suggest-header,
- .workorder-suggest-row {
- display: grid;
- grid-template-columns: 118px minmax(220px, 1fr) minmax(140px, 180px);
- gap: 10px;
- align-items: center;
- line-height: 1.4;
- font-size: 13px;
- box-sizing: border-box;
- }
- .workorder-suggest-header {
- font-weight: 600;
- color: #909399;
- font-size: 12px;
- }
- .workorder-suggest-no {
- color: #303133;
- font-weight: 500;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .workorder-suggest-style {
- color: #606266;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .workorder-suggest-name {
- color: #303133;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .order-summary-desc {
- width: 100%;
- margin-bottom: 10px;
- }
- .order-summary-desc :deep(.el-descriptions__label) {
- width: 100px;
- font-weight: normal;
- color: #606266;
- background: #f5f7fa;
- }
- .order-summary-desc :deep(.el-descriptions__content) {
- color: #303133;
- }
- /* 不用 gva-table-box,避免全局白底卡片(main.scss: bg-white p-6 rounded) */
- .process-production-table-wrap {
- width: 100%;
- padding: 0;
- background: transparent;
- border-radius: 0;
- }
- .process-production-table-wrap :deep(.el-table__footer-wrapper td) {
- font-weight: 600;
- color: #303133;
- background: #fafafa;
- }
- .process-production-col-header {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: 4px;
- }
- .gy-detail-filter-btn {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- width: 22px;
- height: 22px;
- cursor: pointer;
- color: #909399;
- border-radius: 2px;
- }
- .gy-detail-filter-btn:hover,
- .gy-detail-filter-btn.is-active {
- color: var(--el-color-primary);
- background: #ecf5ff;
- }
- .gy-detail-filter-options {
- max-height: 220px;
- overflow-x: hidden;
- overflow-y: auto;
- margin-bottom: 4px;
- }
- .gy-detail-filter-panel :deep(.el-checkbox) {
- display: flex;
- margin-right: 0;
- margin-bottom: 6px;
- }
- .gy-detail-filter-actions {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-top: 4px;
- padding-top: 8px;
- border-top: 1px solid #ebeef5;
- }
- .gy-detail-filter-link {
- color: var(--el-color-primary);
- font-size: 12px;
- line-height: 1;
- cursor: pointer;
- user-select: none;
- padding: 4px 2px;
- }
- .gy-detail-filter-link:hover {
- opacity: 0.85;
- }
- </style>
- <style>
- .gy-detail-filter-popper {
- z-index: 10050 !important;
- pointer-events: auto;
- padding: 8px 10px !important;
- }
- .gy-detail-filter-popper .gy-detail-filter-panel {
- pointer-events: auto;
- }
- .gy-detail-filter-popper .gy-detail-filter-panel .el-checkbox {
- display: flex;
- margin-right: 0;
- margin-bottom: 6px;
- }
- </style>
|