|
|
@@ -1,14 +1,41 @@
|
|
|
<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 @keyup.enter="handleSearch">
|
|
|
- <el-input
|
|
|
- v-model="searchForm.workorder"
|
|
|
- placeholder="请输入订单编号"
|
|
|
- clearable
|
|
|
- style="width: 200px"
|
|
|
- />
|
|
|
- <el-button type="primary" icon="search" :loading="loading" @click="handleSearch">
|
|
|
+ <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>
|
|
|
@@ -88,9 +115,9 @@
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="完工数量" prop="数量" width="90" align="center" />
|
|
|
- <el-table-column v-if="!hideAmountColumns" label="金额" prop="金额" width="90" align="center" />
|
|
|
- <el-table-column v-if="!hideAmountColumns" label="工时" prop="工时" width="90" align="center" />
|
|
|
- <el-table-column v-if="!hideAmountColumns" 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" />
|
|
|
<el-table-column label="完工日期" prop="完工日期" width="110" align="center" />
|
|
|
<template #empty>
|
|
|
@@ -107,7 +134,7 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { computed, reactive, ref, watch } from 'vue'
|
|
|
+import { computed, reactive, ref, watch, onMounted, onUnmounted } from 'vue'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
import { checkProcessProduction, WorkOrderList } from '@/api/mes/job'
|
|
|
|
|
|
@@ -118,7 +145,7 @@ const props = defineProps({
|
|
|
initialWorkorder: { type: String, default: '' },
|
|
|
/** 嵌入订单资料弹窗时使用 */
|
|
|
inDialog: { type: Boolean, default: false },
|
|
|
- /** 为 true 时不显示金额、工时、工资列(如样衣批核页) */
|
|
|
+ /** 为 true 时不显示工分、工时、工资列(如样衣批核页) */
|
|
|
hideAmountColumns: { type: Boolean, default: false },
|
|
|
/** 嵌入工分报工页 Tab:隐藏搜索栏与订单摘要,固定表格高度 */
|
|
|
embeddedInTab: { type: Boolean, default: false },
|
|
|
@@ -149,7 +176,7 @@ const formatSummaryValue = (total, prop) => {
|
|
|
const tableSummaryMethod = ({ columns, data }) => {
|
|
|
const summaryProps = props.hideAmountColumns
|
|
|
? ['数量']
|
|
|
- : ['数量', '金额', '工时', '工资']
|
|
|
+ : ['数量', '工分', '工时', '工资']
|
|
|
|
|
|
return columns.map((column, index) => {
|
|
|
if (index === 0) return '合计'
|
|
|
@@ -185,9 +212,9 @@ const emptyDescription = computed(() => {
|
|
|
return pageHint.value || '暂无数据'
|
|
|
})
|
|
|
|
|
|
-const searchForm = reactive({
|
|
|
- workorder: '',
|
|
|
-})
|
|
|
+const searchKeyword = ref('')
|
|
|
+const searchWrapRef = ref(null)
|
|
|
+const workOrderDropdownVisible = ref(false)
|
|
|
|
|
|
const orderSummary = reactive({})
|
|
|
|
|
|
@@ -210,7 +237,7 @@ const flattenProcessList = (processList = []) => {
|
|
|
数量: '',
|
|
|
开工日期: '',
|
|
|
完工日期: '',
|
|
|
- 金额: '',
|
|
|
+ 工分: '',
|
|
|
工时: '',
|
|
|
工资: '',
|
|
|
_processRowSpan: 1,
|
|
|
@@ -226,7 +253,7 @@ const flattenProcessList = (processList = []) => {
|
|
|
数量: staff.数量 ?? '',
|
|
|
开工日期: staff.开工日期 ?? '',
|
|
|
完工日期: staff.完工日期 ?? '',
|
|
|
- 金额: staff.金额 ?? '',
|
|
|
+ 工分: staff.工分 ?? '',
|
|
|
工时: staff.工时 ?? '',
|
|
|
工资: staff.工资 ?? '',
|
|
|
_processRowSpan: index === 0 ? staffs.length : 0,
|
|
|
@@ -363,15 +390,104 @@ const loadOrderSummaryFromWorkOrderList = async (workorder) => {
|
|
|
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
|
|
|
- searchForm.workorder = w
|
|
|
- await handleSearch()
|
|
|
+ searchKeyword.value = w
|
|
|
+ await executeProductionSearch(w)
|
|
|
}
|
|
|
|
|
|
-const handleSearch = async () => {
|
|
|
- const workorder = String(searchForm.workorder || '').trim()
|
|
|
+const executeProductionSearch = async (orderNo) => {
|
|
|
+ const workorder = String(orderNo || '').trim()
|
|
|
if (!workorder) {
|
|
|
ElMessage.warning('请输入订单编号')
|
|
|
return
|
|
|
@@ -405,7 +521,6 @@ const handleSearch = async () => {
|
|
|
resetOrderSummary(workorder)
|
|
|
} finally {
|
|
|
loading.value = false
|
|
|
- searchForm.workorder = ''
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -459,6 +574,93 @@ defineExpose({ loadByWorkorder })
|
|
|
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;
|