liuhairui 3 дней назад
Родитель
Сommit
8014ef2a3c
1 измененных файлов с 345 добавлено и 72 удалено
  1. 345 72
      src/view/yunyin/shengchanguanli/dahuobaobiao.vue

+ 345 - 72
src/view/yunyin/shengchanguanli/dahuobaobiao.vue

@@ -3,13 +3,21 @@
     <layout>
       <layout-header>
         <div class="top-action-bar action-buttons">
-           <el-button type="primary" icon="download" @click="exportMonthlyData">导出出货大货生产进度表</el-button>
+          <el-input
+            v-model="searchInfo"
+            placeholder="搜索"
+            clearable
+            style="width: 200px;"
+            @keyup.enter="onSearch"
+          />
+          <el-button type="primary" icon="search" @click="onSearch">查询</el-button>
+          <el-button type="primary" icon="download" @click="exportMonthlyData">导出出货大货生产进度表</el-button>
         </div>
       </layout-header>
 
-      <layout>
+      <layout class="dahuobaobiao-body-layout">
         <!-- 左侧日期菜单 -->
-        <layout-sider :resize-directions="['right']" :width="190" style="margin-right: 10px;">
+        <layout-sider :resize-directions="['right']" :width="140" class="dahuobaobiao-sider">
           <div class="JKWTree-tree treecolor">
             <h3>出货月份选择</h3>
             <el-tree class="treecolor" :data="treeData" :props="defaultProps" node-key="id" highlight-current @node-click="handleNodeClick"></el-tree>
@@ -17,8 +25,8 @@
         </layout-sider>
 
         <!-- 右侧表格区域 -->
-        <layout-content>
-          <el-main>
+        <layout-content class="dahuobaobiao-content">
+          <el-main class="dahuobaobiao-main">
             <div class="gva-table-box">
               <!-- 表格数据 -->
               <el-table ref="multipleTable" style="width: 100%; height: 40vh" tooltip-effect="dark"
@@ -35,7 +43,28 @@
                 <el-table-column sortable align="center" label="下单日期" prop="下单日期" width="100" />
                 <el-table-column sortable align="center" label="货期" prop="货期" width="100" />
                 <el-table-column sortable align="center" label="款号" prop="款号" width="150" />
-                <el-table-column sortable align="center" label="生产组别" prop="生产组别" width="100" />
+                <el-table-column align="center" label="计划生产小组" width="140">
+                  <template #default="{ row }">
+                    <el-select
+                      v-model="row['计划生产小组']"
+                      clearable
+                      filterable
+                      allow-create
+                      default-first-option
+                      size="small"
+                      style="width: 100%"
+                      @change="(val) => handlePlanGroupSelectChange(row, val)"
+                    >
+                      <el-option
+                        v-for="opt in planGroupSelectOptions"
+                        :key="opt.value"
+                        :label="opt.label"
+                        :value="opt.value"
+                      />
+                    </el-select>
+                  </template>
+                </el-table-column>
+                <el-table-column align="center" label="实际生产小组" prop="实际生产小组" width="110" show-overflow-tooltip />
                 <el-table-column sortable align="center" label="面料入库时间" prop="面料入库时间" width="140" />
                 <el-table-column  align="center" label="辅料计划入库时间" prop="辅料计划入库时间" width="140">
                   <template #default="{ row }">
@@ -74,14 +103,21 @@
 
               <!-- 分页 -->
               <div class="gva-pagination">
-                <el-pagination layout="total" :current-page="page" :page-size="pageSize"
-                               :total="total" @current-change="handleCurrentChange" @size-change="handleSizeChange" />
+                <el-pagination
+                  layout="total, sizes, prev, pager, next, jumper"
+                  :current-page="page"
+                  :page-size="pageSize"
+                  :page-sizes="[10, 30, 50, 100]"
+                  :total="total"
+                  @current-change="handleCurrentChange"
+                  @size-change="handleSizeChange"
+                />
               </div>
             </div>
-            
+
             <!-- 下方BOM表格 -->
-            <div class="gva-table-box" >
-              <h3 style="margin: 10px 0;">订单开工详情</h3>
+            <div class="gva-table-box dahuobaobiao-detail-box">
+              <h3 class="dahuobaobiao-detail-title">订单开工详情</h3>
               <el-table ref="bomTable" style="width: 100%; height: 30vh" tooltip-effect="dark"
                         :row-style="{ height: '25px' }" :header-cell-style="{ padding: '0px' }"
                         :cell-style="{ padding: '0px' }" :header-row-style="{ height: '20px' }"
@@ -114,12 +150,13 @@
   </div>
 </template>
   <script setup>
-  import {ref, reactive, onMounted} from 'vue'
+  import { ref, reactive, onMounted, computed } from 'vue'
   import { Layout, LayoutSider, LayoutContent, LayoutHeader } from '@arco-design/web-vue'
   import {
     orderBomList, FabricEdit, Approval, AccessoriesInboundTime,
     getWorkOrderDates, getWorkOrdersByMonth,
   } from '@/api/mes/job'
+  import { GetDeviceNameList } from '@/api/yunyin/yunying'
 
 
   import { ElMessage } from 'element-plus'
@@ -141,8 +178,206 @@
   const tableData = reactive([])
   const page = ref(1)
   const total = ref(0)
-  const pageSize = ref(10)
+  const pageSize = ref(30)
+  /** 列表查询方式:month 按月份 / search 按关键字 */
+  const listQueryMode = ref('month')
+
+  const parseWorkOrdersPayload = (data) => {
+    if (Array.isArray(data)) {
+      return { list: data, total: data.length }
+    }
+    if (data && typeof data === 'object') {
+      const list = data.data ?? data.list ?? data.table ?? []
+      const totalCount =
+        data.total ?? data.count ?? (Array.isArray(list) ? list.length : 0)
+      return {
+        list: Array.isArray(list) ? list : [],
+        total: Number(totalCount) || 0,
+      }
+    }
+    return { list: [], total: 0 }
+  }
+
+  const applyTableDataFromResponse = (list, totalCount, rowOffset = 0) => {
+    const sortedData = [...(list || [])].sort((a, b) => {
+      return (a['货期'] || '').localeCompare(b['货期'] || '')
+    })
+    const formattedData = sortedData.map((item, index) =>
+      initRowPlanGroupPath({
+        ID: rowOffset + index + 1,
+        ...item,
+        '下单日期': formatDate(item['下单日期']),
+        '货期': formatDate(item['货期']),
+        '面料入库时间': formatDate(item['面料入库时间']),
+        '开裁日期': formatDate(item['开裁日期']),
+        '上车位日期': formatDate(item['上车位日期']),
+        '车位完成日期': formatDate(item['车位完成日期']),
+        '后道完成日期': formatDate(item['后道完成日期']),
+      })
+    )
+    tableData.splice(0, tableData.length, ...formattedData)
+    total.value = totalCount
+    bomData.value = []
+  }
+
+  /** 请求列表(服务端分页:page + limit) */
+  const fetchTableList = async ({ resetPage = false } = {}) => {
+    if (resetPage) {
+      page.value = 1
+    }
+    const params = {
+      page: page.value,
+      limit: pageSize.value,
+    }
+    if (listQueryMode.value === 'search') {
+      const keyword = (searchInfo.value || '').trim()
+      if (!keyword) {
+        tableData.splice(0, tableData.length)
+        total.value = 0
+        bomData.value = []
+        return
+      }
+      params.search = keyword
+    } else if (selectedDate.value) {
+      params.rq = selectedDate.value
+    } else {
+      return
+    }
+    try {
+      const response = await getWorkOrdersByMonth(params)
+      if (response.code === 0) {
+        const { list, total: totalCount } = parseWorkOrdersPayload(response.data)
+        const rowOffset = (page.value - 1) * pageSize.value
+        applyTableDataFromResponse(list, totalCount, rowOffset)
+      } else {
+        ElMessage.error('获取工单数据失败')
+      }
+    } catch (error) {
+      console.error('获取工单数据失败:', error)
+      ElMessage.error('获取工单数据失败')
+    }
+  }
   
+  // 搜索关键字
+  const searchInfo = ref('')
+
+  /** 计划小组:GetDeviceNameList,一级生产工序、二级设备编组(表格列内选择) */
+  const deviceNameList = ref([])
+
+  /** 计划生产小组下拉仅展示「车缝」工序下的设备编组;选项只显示编组名 */
+  const PLAN_GROUP_PROCESS = '车缝'
+
+  const planGroupSelectOptions = computed(() => {
+    const list = deviceNameList.value
+    if (!Array.isArray(list) || list.length === 0) return []
+    const byTeam = new Map()
+    for (const r of list) {
+      const gx = String(r['生产工序'] ?? '').trim()
+      if (gx !== PLAN_GROUP_PROCESS) continue
+      const team = String(r['设备编组'] ?? '').trim()
+      if (!team || byTeam.has(team)) continue
+      const uid = r.UniqId ?? r.uniqId ?? r.uniq_id
+      byTeam.set(team, {
+        value: team,
+        label: team,
+        生产工序: gx,
+        UniqId: uid,
+      })
+    }
+    return Array.from(byTeam.values()).sort((a, b) => {
+      const ua = Number(a.UniqId)
+      const ub = Number(b.UniqId)
+      if (!Number.isNaN(ua) && !Number.isNaN(ub) && ua !== ub) return ua - ub
+      return a.value.localeCompare(b.value, 'zh-CN', { numeric: true })
+    })
+  })
+
+  const syncPlanGroupMetaFromTeam = (row, team) => {
+    const name = String(team ?? '').trim()
+    if (!name) {
+      row['计划生产工序'] = ''
+      row['计划小组UniqId'] = undefined
+      return
+    }
+    const hit =
+      deviceNameList.value.find(
+        (r) =>
+          String(r['生产工序'] ?? '').trim() === PLAN_GROUP_PROCESS &&
+          String(r['设备编组'] ?? '').trim() === name
+      ) ??
+      deviceNameList.value.find((r) => String(r['设备编组'] ?? '').trim() === name)
+    row['计划生产工序'] = hit ? String(hit['生产工序'] ?? '').trim() : ''
+    row['计划小组UniqId'] = hit?.UniqId ?? hit?.uniqId ?? hit?.uniq_id
+  }
+
+  /** 回显计划生产小组(与 生产组别 无关) */
+  const initRowPlanGroupPath = (item) => {
+    const team = String(item['计划生产小组'] ?? item['计划小组'] ?? item['计划设备编组'] ?? '').trim()
+    item['计划生产小组'] = team
+    syncPlanGroupMetaFromTeam(item, team)
+    return item
+  }
+
+  /** 计划生产小组:无 rq;有值传编组名,清空传空字符串 */
+  const submitPlanProductionGroup = async (row, team) => {
+    if (!row?.Uniqid) {
+      ElMessage.error('操作失败')
+      return false
+    }
+    const groupName = team == null ? '' : String(team).trim()
+    const operator = userStore.userInfo.nickName
+    try {
+      const response = await AccessoriesInboundTime({
+        Uniqid: row.Uniqid,
+        计划生产小组: groupName,
+        sys_id: operator,
+      })
+      if (response.code === 0) {
+        row['计划生产小组'] = groupName
+        row['计划生产小组操作人'] = groupName ? operator : ''
+        row['计划生产小组时间'] = groupName
+          ? (response.data?.['计划生产小组时间'] ?? row['计划生产小组时间'])
+          : ''
+        row['计划生产工序'] = groupName ? row['计划生产工序'] : ''
+        if (!groupName) {
+          row['计划小组UniqId'] = undefined
+        }
+        ElMessage.success('操作成功')
+        return true
+      }
+      ElMessage.error('操作失败')
+      return false
+    } catch (error) {
+      console.error('保存失败:', error)
+      ElMessage.error('操作失败')
+      return false
+    }
+  }
+
+  const handlePlanGroupSelectChange = async (row, val) => {
+    const team = val == null ? '' : String(val).trim()
+    row['计划生产小组'] = team
+    syncPlanGroupMetaFromTeam(row, team)
+    await submitPlanProductionGroup(row, team)
+  }
+
+  const loadPlanGroupOptions = async () => {
+    try {
+      const res = await GetDeviceNameList()
+      if (res?.code === 0) {
+        const raw = res.data
+        deviceNameList.value = Array.isArray(raw) ? raw : raw?.list ?? []
+        tableData.forEach((row) => initRowPlanGroupPath(row))
+      } else {
+        deviceNameList.value = []
+      }
+    } catch (e) {
+      console.error(e)
+      deviceNameList.value = []
+      ElMessage.error('加载失败')
+    }
+  }
+
   // 选中的日期
   const selectedDate = ref('')
   
@@ -213,45 +448,32 @@
     }
   }
   
-  // 获取工单数据
-const getWorkOrderData = async (rq) => {
-  try {
-    const response = await getWorkOrdersByMonth({ rq: rq });
-    if (response.code === 0) {
-      const formatDate = (dateStr) => {
-        if (!dateStr) return '';
-        const date = new Date(dateStr);
-        return `${date.getMonth() + 1}月${date.getDate()}日`;
-      };
-      
-      // 按货期字符串排序(YYYY-MM-DD格式可以直接字符串排序)
-      const sortedData = [...response.data].sort((a, b) => {
-        return a['货期'].localeCompare(b['货期']);
-      });
-      
-      // 处理数据
-      const formattedData = sortedData.map((item, index) => ({
-        ID: index + 1,
-        ...item,
-        '下单日期': formatDate(item['下单日期']),
-        '货期': formatDate(item['货期']),
-        '面料入库时间': formatDate(item['面料入库时间']),
-        '开裁日期': formatDate(item['开裁日期']),
-        '上车位日期': formatDate(item['上车位日期']),
-        '车位完成日期': formatDate(item['车位完成日期']),
-        '后道完成日期': formatDate(item['后道完成日期'])
-      }));
-      
-      tableData.splice(0, tableData.length, ...formattedData);
-      total.value = formattedData.length;
-    } else {
-      ElMessage.error('获取工单数据失败');
+  const formatDate = (dateStr) => {
+    if (!dateStr) return '';
+    const date = new Date(dateStr);
+    return `${date.getMonth() + 1}月${date.getDate()}日`;
+  }
+
+  // 搜索:传 search + page + limit
+  const onSearch = async () => {
+    const keyword = (searchInfo.value || '').trim()
+    if (!keyword) {
+      tableData.splice(0, tableData.length)
+      total.value = 0
+      page.value = 1
+      bomData.value = []
+      return
     }
-  } catch (error) {
-    console.error('获取工单数据失败:', error);
-    ElMessage.error('获取工单数据失败');
+    listQueryMode.value = 'search'
+    await fetchTableList({ resetPage: true })
+  }
+
+  // 按月份获取工单数据
+  const getWorkOrderData = async (rq) => {
+    selectedDate.value = rq
+    listQueryMode.value = 'month'
+    await fetchTableList({ resetPage: true })
   }
-}
   
   // 表格行点击
   const tableRowClick = async (row) => {
@@ -279,12 +501,13 @@ const getWorkOrderData = async (rq) => {
   
   // 分页处理
   const handleCurrentChange = (val) => {
-    page.value = val;
+    page.value = val
+    fetchTableList()
   }
-  
+
   const handleSizeChange = (val) => {
-    pageSize.value = val;
-    page.value = 1;
+    pageSize.value = val
+    fetchTableList({ resetPage: true })
   }
   
   // 样衣核批相关
@@ -412,6 +635,7 @@ const getWorkOrderData = async (rq) => {
   // 生命周期
   onMounted(() => {
     getDateList();
+    loadPlanGroupOptions();
   })
 
   // 计划入库时间编辑相关
@@ -479,7 +703,7 @@ const getWorkOrderData = async (rq) => {
     }
   };
 
-  // 辅料入库时间编辑相关
+  /** 辅料计划入库时间:AccessoriesInboundTime 传 Uniqid + rq(日期) + sys_id(不传 计划生产小组) */
   const handleAccessoryDateChange = async (row, newDate) => {
     try {
       if (!row.Uniqid) {
@@ -490,20 +714,20 @@ const getWorkOrderData = async (rq) => {
       const formattedDate = row.辅料计划入库时间 ? row.辅料计划入库时间 : getTodayYmd();
       const operator = userStore.userInfo.nickName;
 
-      const response = await AccessoriesInboundTime({ 
-        Uniqid: row.Uniqid, 
-        rq: formattedDate, 
-        sys_id: operator 
+      const response = await AccessoriesInboundTime({
+        Uniqid: row.Uniqid,
+        rq: formattedDate,
+        sys_id: operator,
       });
-      
+
       if (response.code === 0) {
-        ElMessage.success('辅料入库时间修改成功');
+        ElMessage.success('辅料计划入库时间修改成功');
       } else {
-        ElMessage.error('辅料入库时间修改失败');
+        ElMessage.error('辅料计划入库时间修改失败');
       }
     } catch (error) {
-      console.error('辅料入库时间修改失败:', error);
-      ElMessage.error('辅料入库时间修改失败');
+      console.error('辅料计划入库时间修改失败:', error);
+      ElMessage.error('辅料计划入库时间修改失败');
     }
   };
   
@@ -520,8 +744,8 @@ const getWorkOrderData = async (rq) => {
       const year = rq.substring(0, 4);
       const month = rq.substring(5);
       // 调用实际的大货生产进度表接口
-      const response = await getWorkOrdersByMonth({ rq: rq });
-      const originalData = response.data;
+      const response = await getWorkOrdersByMonth({ rq: rq, page: 1, limit: 99999 });
+      const { list: originalData } = parseWorkOrdersPayload(response.data);
       if (!originalData || originalData.length === 0) {
         ElMessage.warning('暂无数据可导出');
         return;
@@ -531,7 +755,7 @@ const getWorkOrderData = async (rq) => {
       const YEAR = year;
       const MONTH = month;
       // 表头字段
-      const HEADER_FIELDS = ['款式', '客人编号', '下单日期', '货期', '款号', '生产组', '订单数量', '实裁数量', '已完成数量', '入库数量', '面料入库时间', '辅料入库时间', '产前样批核', '开裁日期', '上车位日期', '台产', '车位完成日期', '后道完成日期', '备注'];
+      const HEADER_FIELDS = ['款式', '客人编号', '下单日期', '货期', '款号','计划生产小组', '实际生产组', '订单数量', '实裁数量', '已完成数量', '入库数量', '面料入库时间', '辅料入库时间', '产前样批核', '开裁日期', '上车位日期', '台产', '车位完成日期', '后道完成日期', '备注'];
       const totalCol = HEADER_FIELDS.length;
 
       // 2. 数据处理 - 根据实际接口返回的数据结构进行调整
@@ -552,7 +776,8 @@ const getWorkOrderData = async (rq) => {
           formatDate(item['下单日期']),
           formatDate(item['货期']),
           item['款号'] || '',
-          item['生产组别'] || '', // 接口返回中没有生产组别,默认为空
+          item['计划生产小组'] || '',
+          item['实际生产小组'] || '',
           item['订单数量'] || '',
           item['实裁数量'] || '',
           item['已完成数量'] || '',
@@ -713,12 +938,61 @@ const getWorkOrderData = async (rq) => {
     flex-wrap: wrap;
   }
 
-  /* 左侧树状图区域 */
-  .JKWTree-tree {
+  /* 左右栏底部对齐:侧栏与右侧双表区域同高 */
+  .dahuobaobiao-body-layout {
+    align-items: stretch !important;
+  }
+
+  .dahuobaobiao-sider {
+    margin-right: 0 !important;
+    align-self: stretch !important;
+  }
+
+  .dahuobaobiao-body-layout :deep(.arco-layout-sider-children) {
     height: 100%;
-    padding: 10px;
+    display: flex;
+    flex-direction: column;
+    padding-bottom: 10px !important;
+    box-sizing: border-box;
+  }
+
+  .dahuobaobiao-content {
+    padding-left: 0 !important;
+  }
+
+  .dahuobaobiao-body-layout :deep(.arco-layout-content) {
+    padding-bottom: 0 !important;
+  }
+
+  .dahuobaobiao-main {
+    padding: 0 10px 10px 0 !important;
+    box-sizing: border-box;
+  }
+
+  .dahuobaobiao-detail-box {
+    margin-top: 6px;
+  }
+
+  .dahuobaobiao-detail-title {
+    font-size: 15px;
+    font-weight: 700;
+    margin: 0 0 6px;
+    padding: 0;
+    line-height: 1.4;
+  }
+
+  /* 左侧树状图区域:高度与右侧 40vh+30vh 及分页、标题区一致 */
+  .dahuobaobiao-sider .JKWTree-tree {
+    flex: 1;
+    min-height: calc(70vh + 72px);
+    height: calc(70vh + 72px);
+    max-height: calc(70vh + 72px);
+    overflow-x: hidden;
+    overflow-y: auto;
+    padding: 10px 6px 10px 10px;
     background: #fff;
     border-right: 1px solid #e8e8e8;
+    box-sizing: border-box;
   }
 
   .JKWTree-tree h3 {
@@ -733,7 +1007,6 @@ const getWorkOrderData = async (rq) => {
   }
 
   .gva-pagination {
-    margin-top: 10px;
     text-align: right;
   }