liuhairui hai 1 semana
pai
achega
bdc42021ad
Modificáronse 1 ficheiros con 226 adicións e 24 borrados
  1. 226 24
      src/view/SalaryManage/ProcessProduction.vue

+ 226 - 24
src/view/SalaryManage/ProcessProduction.vue

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