zck 1 mēnesi atpakaļ
vecāks
revīzija
bbdde1a73c

+ 1 - 1
index.html

@@ -14,7 +14,7 @@
 	 
     <meta content="vue-admin首页" name="keywords" />
     <link rel="icon" href="favicon.ico">
-    <link rel="stylesheet" type="text/css" media="print" href="./src/assets/css/print-lock.css">
+    <link rel="stylesheet" type="text/css" media="print" href="luckysheet/css/print-lock.css">
     <link rel="stylesheet" type="text/css" media="print" href="https://cdn.jsdelivr.net/npm/vue-plugin-hiprint@latest/dist/print-lock.css">
     <title></title>
 </head>

+ 2 - 0
src/api/jixiaoguanli/caiwubaobiao.js

@@ -248,3 +248,5 @@ export const CompletionWorkOrderCostList = (params) => {
     params
   })
 }
+
+

+ 10 - 0
src/api/jixiaoguanli/jitairibaobiao.js

@@ -1189,3 +1189,13 @@ export const LazhiGongData = (params) => {
     params
   })
 }
+
+
+//v23财务--按工序归结人工费统计表
+export const GetCompletionWorkOrderCostDetail = (params) => {
+  return service({
+    url:'/mes_server/Cost_Accounting/GetCompletionWorkOrderCostDetail',
+    method: 'get',
+    params
+  })
+}

+ 1 - 1
src/view/DecisionSupport/operation/operationPersonnel.vue

@@ -80,7 +80,7 @@
                   <el-table-column align="left" sortable label="计件系数" prop="工价系数"  width="110"/>
                   <el-table-column align="left" sortable label="补产标准" prop="补产标准"  width="110"/>
                   <el-table-column align="left" sortable label="实际每小时计件产量与补产标准差额" prop="实际每小时计件产量与补产标准差额"  width="110"/>
-                  <el-table-column align="left" sortable label="设备运行工时" prop="设备运行工时"  width="140"/>
+                  <el-table-column align="left" sortable label="设备通电工时" prop="设备运行工时"  width="140"/>
                   <el-table-column align="left" sortable label="保养工时" prop="保养工时"  width="110"/>
                   <el-table-column align="left" sortable label="打样总工时" prop="打样总工时"  width="140"/>
                   <el-table-column align="left" sortable label="打样补产工时" prop="打样补产工时"  width="140"/>

+ 0 - 23
src/view/DecisionSupport/productioncents/index.vue

@@ -171,30 +171,7 @@ const cp_gdprintonClick = () => {
 
 
 
-  //=========工序产量核查===========
 
-
-  // 工序产量核查按钮
-const gd_gxclhconClick = async () => {
-  // if(_Gd_gdbh.value === '' || _Gd_gdbh.value === null){
-  //   ElMessage({type: 'warning',message: '请选择具体的工单,在进行操作'})
-  //   return false;
-  // }
-  // gxclhcformData['gdbh'] = _Gd_gdbh.value;
-  // gxclhcformData['yjno'] = 1;
-  // gd_gxclhclist.value = true;
-  // const response = await PrintDetailList ({workOrder:_Gd_gdbh.value});
-  // console.log(response)
-  // gdwhformData.yjno = response.data[0].no
-  // inputCpmc.value = response.data[0].name
-  // if (response.code === 0) {
-	//   const noFields = response.data.map(item => item.no);
-	//   gdwhformData.yinjian = noFields
-	// } else {
-	//   console.error('查询失败:', response.msg);
-	// }
-  // _getOrderProcessCount();
-};
   // =========== 获取左侧树侧形结构 ===========
   
   const AttendanceVisible=ref(false)

+ 1 - 19
src/view/DecisionSupport/shengchanzhouqi/shengchanzhouqitongji.vue

@@ -352,29 +352,11 @@ const cp_gdprintonClick = () => {
   const dialogexportToExcel = ref(false)
   
   
-  //=========工序产量核查===========
 
 
   // 工序产量核查按钮
 const gd_gxclhconClick = async () => {
-  // if(_Gd_gdbh.value === '' || _Gd_gdbh.value === null){
-  //   ElMessage({type: 'warning',message: '请选择具体的工单,在进行操作'})
-  //   return false;
-  // }
-  // gxclhcformData['gdbh'] = _Gd_gdbh.value;
-  // gxclhcformData['yjno'] = 1;
-  // gd_gxclhclist.value = true;
-  // const response = await PrintDetailList ({workOrder:_Gd_gdbh.value});
-  // console.log(response)
-  // gdwhformData.yjno = response.data[0].no
-  // inputCpmc.value = response.data[0].name
-  // if (response.code === 0) {
-	//   const noFields = response.data.map(item => item.no);
-	//   gdwhformData.yinjian = noFields
-	// } else {
-	//   console.error('查询失败:', response.msg);
-	// }
-  // _getOrderProcessCount();
+
 };
   // =========== 获取左侧树侧形结构 ===========
   

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1218
src/view/job/processSheet/processSheet.vue


+ 275 - 2
src/view/performance/yuangongrigongzi.vue

@@ -42,8 +42,9 @@
 			  <!-- <el-button type="primary" :icon="Search">查改</el-button> -->
 			  <el-button type="primary"  class="bt" @click="handlePrint">员工计件明细</el-button>
               <div style="margin-left: auto;">
+                <!-- <el-button type="primary" :icon="Download" class="bt" @click="gxexportExcel">导出按工序归结人工费统计表</el-button> -->
                 <el-button type="primary" :icon="Download" class="bt" @click="exportExcel">导出到Excel(汇总)</el-button>
-				<el-button type="primary" :icon="Download" class="bt" @click="exportExcel2">导出到Excel(明细)</el-button>
+				        <el-button type="primary" :icon="Download" class="bt" @click="exportExcel2">导出到Excel(明细)</el-button>
               </div>
             </div>
             <!-- 数据展示 -->
@@ -331,6 +332,26 @@
           			</el-card>
           			<el-button type="primary" @click="enterpositioning">确 定</el-button>
           </el-dialog>
+
+
+          <el-dialog v-model="ongxrgf"  title="导出工序归结人工费统计表" destroy-on-close style="height: 20%;width: 20%;">
+  <el-form-item label="选择年份" label-width="100px">
+    <el-date-picker
+			    v-model="gxrgfrq"
+			    type="year"
+			    placeholder="选择年份"
+			    :default-value="new Date()"
+          @change="onchange_data"
+			    style="width: 200px;" 
+			  />
+  </el-form-item>
+        <template #footer>
+		    <div class="dialog-footer" style="text-align: right;">
+		      <el-button @click="gxrgfcloseDialog">取消</el-button>
+		      <el-button type="primary" @click="gxrgfonDialog">确定</el-button>
+		    </div>
+		  </template>
+            </el-dialog>
          
         </el-main>
       </el-container>
@@ -346,6 +367,8 @@
         <Ygjjmx :ygbh="currentRow?.['bh']" />
       </el-dialog>
 
+      
+
   </div>
 </template>
 
@@ -358,7 +381,8 @@ import {
   dailygetAllList,
   dailygetDetail,
   dailysearch,
-  getYg
+  getYg,
+  GetCompletionWorkOrderCostDetail
 } from '@/api/jixiaoguanli/jitairibaobiao'
 
 // 全量引入格式化工具 请按需保留
@@ -368,6 +392,8 @@ import { Search, Refresh, Download } from '@element-plus/icons-vue'
 import { ref, reactive, onMounted, nextTick, onBeforeMount } from 'vue'
 import Ygjjmx from './printYgjjmx.vue'
 import * as XLSX from "xlsx";
+import ExcelJS from 'exceljs';
+import { saveAs } from 'file-saver'; 
 import { useUserStore } from '@/pinia/modules/user'
 const userStore = useUserStore() 
 const sys_id='['+userStore.userInfo.userName+'/'+userStore.userInfo.nickName+']'
@@ -848,6 +874,253 @@ function doubleClick(row, column, event) {
 }
 
 // 导出excel
+const ongxrgf =ref(false)
+const gxrgfrq = ref('')
+
+//打开弹窗
+const gxexportExcel = async () => { 
+  ongxrgf.value = true
+}
+
+
+
+
+// 确定导出(ExcelJS版)
+const gxrgfonDialog = async () => { 
+  try {
+    // 1. 接口数据获取+处理
+    const response = await GetCompletionWorkOrderCostDetail({ year: gxrgfrq.value});
+    const originalData = response.data;
+    if (!originalData || Object.keys(originalData).length === 0) {
+      ElMessage.warning('暂无数据可导出');
+      return;
+    }
+
+    // 核心配置
+    const PROCESS_ORDER = ['胶印','卷凹','圆烫','圆切','单凹','丝印','喷码','覆膜','裁切','切废','烫金','模切','机检','手检'];
+    const PROCESS_REMARK = {
+      胶印: '按所有胶印机台',卷凹: '按所有卷凹机台',圆烫: '按所有圆压圆烫金机台',圆切: '按所有圆压圆模切机台',
+      单凹: '按所有单凹机台',丝印: '按所有丝印机台',喷码: '按所有喷码机台',覆膜: '按所有覆膜机台',
+      裁切: '按所有切纸机台(仅为裁切工序,不含切废工序)',切废: '按所有切纸机台(仅为切废工序,不含裁切工序)',
+      烫金: '按所有烫金机台',模切: '按所有模切机台',机检: '按所有检品机台(不含圆压圆模切配套的检品机)',
+      手检: '按工序--手检'
+    };
+    const MONTH_KEYS = ['车头产量','补产产量','核算产量','计件工资','加班工资','产量工资合计'];
+    const YEAR = gxrgfrq.value || new Date().getFullYear();
+    const totalCol = 1 + 12*6 + 1; // 总列数:工序+12*6指标+备注
+
+    // 2. 数据分组
+    const processGroup = {};
+    Object.entries(originalData).forEach(([process, monthList]) => {
+      if (!Array.isArray(monthList) || monthList.length === 0) return;
+      processGroup[process] = monthList.reduce((obj, item) => {
+        const monthStr = String(item.年月).slice(-2);
+        const formatItem = {
+          车头产量: Number(item.车头产量) || 0,补产产量: Number(item.补产产量) || 0,核算产量: Number(item.核算产量) || 0,
+          计件工资: Number(item.计件工资) || 0,加班工资: Number(item.加班工资) || 0,产量工资合计: Number(item.产量工资合计) || 0
+        };
+        obj[monthStr] = formatItem;
+        return obj;
+      }, {});
+    });
+
+    // 3. 构建数据行
+    // 表头行:标题行、月份行、指标行
+    const titleRow = [`${YEAR}年按工序归结人工费统计表`];
+    const monthRow = ['工序'];
+    const indexRow = [''];
+    titleRow.push(...Array(totalCol-1).fill('')); // 标题行补空
+    for (let m = 1; m <= 12; m++) {
+      monthRow.push(`${m}月`);
+      // 为每个月添加5个空白单元格,确保每个月占6列
+      monthRow.push(...Array(5).fill(''));
+      indexRow.push(...MONTH_KEYS);
+    }
+    monthRow.push('备注');
+    indexRow.push('');
+
+    // 数据行:14个工序的所有数据+备注
+    const dataRows = PROCESS_ORDER.map(process => {
+      const row = [process];
+      const monthDataMap = processGroup[process] || {};
+      for (let m = 1; m <= 12; m++) {
+        const month = m.toString().padStart(2, '0');
+        const currentMonth = monthDataMap[month] || {车头产量:0,补产产量:0,核算产量:0,计件工资:0,加班工资:0,产量工资合计:0};
+        row.push(...MONTH_KEYS.map(key => currentMonth[key].toFixed(1)));
+      }
+      row.push(PROCESS_REMARK[process] || '');
+      return row;
+    });
+
+    // ============== ExcelJS 核心:创建工作簿+设置样式 ==============
+    // 4. 创建工作簿和工作表
+    const workbook = new ExcelJS.Workbook();
+    const worksheet = workbook.addWorksheet('Sheet1'); // 工作表名与原Excel一致
+
+    // 5. 写入数据(按行写入:标题行→月份行→指标行→数据行)
+    worksheet.addRow(titleRow);
+    worksheet.addRow(monthRow);
+    worksheet.addRow(indexRow);
+    dataRows.forEach(row => worksheet.addRow(row));
+
+    // 辅助函数:将列索引转换为Excel列字母(如1→A, 2→B, 26→Z, 27→AA)
+    const getColumnLetter = (colIndex) => {
+      let letter = '';
+      let num = colIndex;
+      while (num > 0) {
+        const remainder = (num - 1) % 26;
+        letter = String.fromCharCode(65 + remainder) + letter;
+        num = Math.floor((num - 1) / 26);
+      }
+      return letter;
+    };
+
+    // 6. 样式配置:合并单元格+边框+底色+居中+列宽
+    // 6.1 合并单元格
+    const mergeRange = (range) => worksheet.mergeCells(range);
+    // 合并1:标题行(A1到最后一列1)
+    mergeRange(`A1:${getColumnLetter(totalCol)}1`);
+    // 合并2:工序列(A2:A4)
+    mergeRange('A2:A3');
+    // 合并3:每个月的月份行(1月B2:G2、2月H2:M2...)
+    let startCol = 2; // 从B列开始
+    for (let m = 1; m <= 12; m++) {
+      const endCol = startCol + 5;
+      mergeRange(`${getColumnLetter(startCol)}2:${getColumnLetter(endCol)}2`);
+      startCol = endCol + 1;
+    }
+    // 合并4:备注列(最后一列2:最后一列4)
+    mergeRange(`${getColumnLetter(totalCol)}2:${getColumnLetter(totalCol)}4`);
+
+    // 6.2 定义样式模板
+    const commonStyle = { // 所有单元格公共样式:边框+居中+自动换行
+      border: {
+        top: { style: 'thin', color: { argb: 'FF000000' } },
+        bottom: { style: 'thin', color: { argb: 'FF000000' } },
+        left: { style: 'thin', color: { argb: 'FF000000' } },
+        right: { style: 'thin', color: { argb: 'FF000000' } }
+      },
+      alignment: { horizontal: 'center', vertical: 'middle', wrapText: true },
+      font: { size: 11, color: { argb: 'FF000000' } }
+    };
+    const titleStyle = { // 标题行样式:浅灰底+14号字+加粗
+      ...commonStyle,
+      font: { size: 14, bold: true, color: { argb: 'FF000000' } },
+      fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE6E6E6' } }
+    };
+    const headerStyle = { // 表头行样式:深灰底+12号字+加粗
+      ...commonStyle,
+      font: { size: 12, bold: true, color: { argb: 'FF000000' } },
+      fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFC0C0C0' } }
+    };
+
+    // 6.3 应用样式到单元格
+    const lastRow = 4 + dataRows.length; // 最后一行:3行表头+数据行
+    
+    // 定义特殊列的样式(黄色背景)
+    const yellowBgStyle = {
+      ...commonStyle,
+      fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFF00' } }
+    };
+    
+    // 标题行(第1行):应用标题样式
+    worksheet.getRow(1).eachCell(cell => cell.style = titleStyle);
+    
+    // 表头行(第2-3行):应用表头样式
+    worksheet.getRow(2).eachCell(cell => cell.style = headerStyle);
+    
+    // 指标行(第3行):特殊处理核算产量和产量工资合计列
+    const indexRowObject = worksheet.getRow(3);
+    indexRowObject.eachCell((cell, colIndex) => {
+      // 跳过A列(工序列)
+      if (colIndex === 1) {
+        cell.style = headerStyle;
+        return;
+      }
+      // 检查是否是核算产量或产量工资合计列
+      const cellValue = cell.value;
+      if (cellValue === '核算产量' || cellValue === '产量工资合计') {
+        cell.style = {
+          ...headerStyle,
+          fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFF00' } }
+        };
+      } else {
+        cell.style = headerStyle;
+      }
+    });
+    
+    // 数据行(第4行到最后一行):特殊处理核算产量和产量工资合计列
+    for (let row = 4; row <= lastRow; row++) {
+      const currentRow = worksheet.getRow(row);
+      currentRow.eachCell((cell, colIndex) => {
+        // 跳过A列(工序列)和最后一列(备注列)
+        if (colIndex === 1 || colIndex === totalCol) {
+          cell.style = commonStyle;
+          return;
+        }
+        
+        // 计算当前列属于第几个月的第几个指标
+        const monthColIndex = colIndex - 2; // 减去A列
+        const monthIndex = Math.floor(monthColIndex / 6);
+        const metricIndex = monthColIndex % 6;
+        
+        // 核算产量是每个月的第3个指标(索引2),产量工资合计是每个月的第6个指标(索引5)
+        if (metricIndex === 2 || metricIndex === 5) {
+          cell.style = yellowBgStyle;
+        } else {
+          cell.style = commonStyle;
+        }
+      });
+    }
+
+    // 6.4 设置列宽(与原Excel一致,像素适配)
+    const colWidths = [120]; // A列(工序):120px
+    for (let m = 1; m <= 12; m++) {
+      colWidths.push(...Array(6).fill(80)); // 12个月×6列:80px/列
+    }
+    colWidths.push(200); // 最后一列(备注):200px
+    // ExcelJS列宽单位为「字符」,px转字符按 1px ≈ 0.14 换算(精准适配)
+    worksheet.columns = colWidths.map((width, index) => ({
+      key: index+1,
+      width: width * 0.14
+    }));
+
+    // 6.5 调整行高(可选,适配表头文字,避免遮挡)
+    worksheet.getRow(1).height = 30; // 标题行高
+    worksheet.getRow(2).height = 25; // 月份行高
+    worksheet.getRow(3).height = 25; // 指标行高
+
+    // ============== 导出Excel文件 ==============
+    // 7. 生成blob并下载
+    const buffer = await workbook.xlsx.writeBuffer();
+    const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+    saveAs(blob, `按工序归结人工费统计表${YEAR}年.xlsx`);
+
+    ElMessage.success('导出成功!');
+  } catch (error) {
+    console.error('Excel导出失败:', error);
+    ElMessage.error('导出数据失败,请重试');
+  }
+};
+
+//选择日期
+const onchange_data = (val) => {
+  if (val) {
+    // 将日期对象转换为本地时间的年月格式
+    const year = val.getFullYear()
+    gxrgfrq.value = `${year}`
+    console.log(gxrgfrq.value)
+  } else {
+    gxrgfrq.value = ''
+  }
+  
+}
+
+//关闭弹窗
+const gxrgfcloseDialog = () => {ongxrgf.value = false}
+
+
+
 
 function exportExcel() {
  if(tableData.length<1){

+ 557 - 0
src/view/v26financial/gxgz.vue

@@ -0,0 +1,557 @@
+<template>
+  <div style="border: 1px black solid; width: 40%; height: 30%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 20px;">
+    <div style="display: flex; align-items: center; gap: 10px;">
+      <el-form-item label="选择年份:" class="mab" prop="keyOrder" label-width="100">
+        <el-date-picker
+          v-model="selectedYear"
+          type="year"
+          placeholder="选择年份"
+          :default-value="new Date()"
+          @change="onYearChange"
+          style="width: 130px;"
+        />
+      </el-form-item>
+      <el-button type="primary" @click="exportYearlyData">导出年度数据</el-button>
+    </div>
+    
+    <div style="display: flex; align-items: center; gap: 10px;">
+      <el-form-item label="选择月份:" class="mab" prop="keyOrder" label-width="100">
+        <el-date-picker
+          v-model="selectedMonth"
+          type="month"
+          placeholder="选择月份"
+          :default-value="new Date()"
+          @change="onMonthChange"
+          style="width: 150px;"
+        />
+      </el-form-item>
+      <el-button type="success" @click="exportMonthlyData">导出月份数据</el-button>
+    </div>
+  </div>
+</template>
+<script setup>
+import {ref, reactive} from 'vue'
+import {
+  staffSalaryCount,
+} from '@/api/yunyin/yunying'
+import {
+  GetCompletionWorkOrderCostDetail,
+} from '@/api/jixiaoguanli/jitairibaobiao'
+import { ElMessage } from 'element-plus'
+import { useUserStore } from '@/pinia/modules/user'
+import * as ExcelJS from 'exceljs'
+import { saveAs } from 'file-saver'
+const userStore = useUserStore()
+const _username = ref('')
+_username.value = userStore.userInfo.userName + '/' + userStore.userInfo.nickName
+
+const form = reactive({})
+const visible = ref(true)
+const selectedYear = ref('')
+const yearValue = ref('')
+const selectedMonth = ref('')
+const monthValue = ref('')
+
+// 获取当前日期
+const currentDate = new Date();
+// 获取当前年份和月份
+const currentYear = currentDate.getFullYear();
+const currentMonth = currentDate.getMonth();
+// 设置默认年份和月份
+selectedYear.value = new Date(currentYear, 0, 1);
+yearValue.value = currentYear.toString();
+selectedMonth.value = new Date(currentYear, currentMonth, 1);
+monthValue.value = `${currentYear}${String(currentMonth + 1).padStart(2, '0')}`;
+
+// 年份变化时处理
+const onYearChange = (val) => {
+  if (val) {
+    const year = val.getFullYear();
+    yearValue.value = year.toString();
+    console.log('Selected year:', yearValue.value);
+  } else {
+    yearValue.value = '';
+  }
+};
+
+// 月份变化时处理
+const onMonthChange = (val) => {
+  if (val) {
+    const year = val.getFullYear();
+    const month = val.getMonth() + 1;
+    monthValue.value = `${year}${String(month).padStart(2, '0')}`;
+    console.log('Selected month:', monthValue.value);
+  } else {
+    monthValue.value = '';
+  }
+};
+
+// 导出年度数据
+const exportYearlyData = async () => {
+  if (!yearValue.value) {
+    ElMessage.warning('请选择年份');
+    return;
+  }
+  
+  try {
+    // 1. 接口数据获取+处理
+    const response = await GetCompletionWorkOrderCostDetail({ year: yearValue.value});
+    const originalData = response.data;
+    if (!originalData || Object.keys(originalData).length === 0) {
+      ElMessage.warning('暂无数据可导出');
+      return;
+    }
+
+    // 核心配置
+    const PROCESS_ORDER = ['胶印','卷凹','圆烫','圆切','单凹','丝印','喷码','覆膜','裁切','切废','烫金','模切','机检','手检'];
+    const PROCESS_REMARK = {
+      胶印: '按所有胶印机台',卷凹: '按所有卷凹机台',圆烫: '按所有圆压圆烫金机台',圆切: '按所有圆压圆模切机台',
+      单凹: '按所有单凹机台',丝印: '按所有丝印机台',喷码: '按所有喷码机台',覆膜: '按所有覆膜机台',
+      裁切: '按所有切纸机台(仅为裁切工序,不含切废工序)',切废: '按所有切纸机台(仅为切废工序,不含裁切工序)',
+      烫金: '按所有烫金机台',模切: '按所有模切机台',机检: '按所有检品机台(不含圆压圆模切配套的检品机)',
+      手检: '按工序--手检'
+    };
+    const MONTH_KEYS = ['车头产量','补产产量','核算产量','计件工资','加班工资','产量工资合计'];
+    const YEAR = yearValue.value || new Date().getFullYear();
+    const totalCol = 1 + 12*6 + 1; // 总列数:工序+12*6指标+备注
+
+    // 2. 数据分组
+    const processGroup = {};
+    Object.entries(originalData).forEach(([process, monthList]) => {
+      if (!Array.isArray(monthList) || monthList.length === 0) return;
+      processGroup[process] = monthList.reduce((obj, item) => {
+        const monthStr = String(item.年月).slice(-2);
+        const formatItem = {
+          车头产量: Number(item.车头产量) || 0,补产产量: Number(item.补产产量) || 0,核算产量: Number(item.核算产量) || 0,
+          计件工资: Number(item.计件工资) || 0,加班工资: Number(item.加班工资) || 0,产量工资合计: Number(item.产量工资合计) || 0
+        };
+        obj[monthStr] = formatItem;
+        return obj;
+      }, {});
+    });
+
+    // 3. 构建数据行
+    // 表头行:标题行、月份行、指标行
+    const titleRow = [`${YEAR}年按工序归结人工费统计表`];
+    const monthRow = ['工序'];
+    const indexRow = [''];
+    titleRow.push(...Array(totalCol-1).fill('')); // 标题行补空
+    for (let m = 1; m <= 12; m++) {
+      monthRow.push(`${m}月`);
+      // 为每个月添加5个空白单元格,确保每个月占6列
+      monthRow.push(...Array(5).fill(''));
+      indexRow.push(...MONTH_KEYS);
+    }
+    monthRow.push('备注');
+    indexRow.push('');
+
+    // 数据行:14个工序的所有数据+备注
+    const dataRows = PROCESS_ORDER.map(process => {
+      const row = [process];
+      const monthDataMap = processGroup[process] || {};
+      for (let m = 1; m <= 12; m++) {
+        const month = m.toString().padStart(2, '0');
+        const currentMonth = monthDataMap[month] || {车头产量:0,补产产量:0,核算产量:0,计件工资:0,加班工资:0,产量工资合计:0};
+        row.push(...MONTH_KEYS.map(key => currentMonth[key].toFixed(1)));
+      }
+      row.push(PROCESS_REMARK[process] || '');
+      return row;
+    });
+
+    // ============== ExcelJS 核心:创建工作簿+设置样式 ==============
+    // 4. 创建工作簿和工作表
+    const workbook = new ExcelJS.Workbook();
+    const worksheet = workbook.addWorksheet('Sheet1'); // 工作表名与原Excel一致
+
+    // 5. 写入数据(按行写入:标题行→月份行→指标行→数据行)
+    worksheet.addRow(titleRow);
+    worksheet.addRow(monthRow);
+    worksheet.addRow(indexRow);
+    dataRows.forEach(row => worksheet.addRow(row));
+
+    // 辅助函数:将列索引转换为Excel列字母(如1→A, 2→B, 26→Z, 27→AA)
+    const getColumnLetter = (colIndex) => {
+      let letter = '';
+      let num = colIndex;
+      while (num > 0) {
+        const remainder = (num - 1) % 26;
+        letter = String.fromCharCode(65 + remainder) + letter;
+        num = Math.floor((num - 1) / 26);
+      }
+      return letter;
+    };
+
+    // 6. 样式配置:合并单元格+边框+底色+居中+列宽
+    // 6.1 合并单元格
+    const mergeRange = (range) => worksheet.mergeCells(range);
+    // 合并1:标题行(A1到最后一列1)
+    mergeRange(`A1:${getColumnLetter(totalCol)}1`);
+    // 合并2:工序列(A2:A4)
+    mergeRange('A2:A3');
+    // 合并3:每个月的月份行(1月B2:G2、2月H2:M2...)
+    let startCol = 2; // 从B列开始
+    for (let m = 1; m <= 12; m++) {
+      const endCol = startCol + 5;
+      mergeRange(`${getColumnLetter(startCol)}2:${getColumnLetter(endCol)}2`);
+      startCol = endCol + 1;
+    }
+    // 合并4:备注列(最后一列2:最后一列4)
+    mergeRange(`${getColumnLetter(totalCol)}2:${getColumnLetter(totalCol)}4`);
+
+    // 6.2 定义样式模板
+    const commonStyle = { // 所有单元格公共样式:边框+居中+自动换行
+      border: {
+        top: { style: 'thin', color: { argb: 'FF000000' } },
+        bottom: { style: 'thin', color: { argb: 'FF000000' } },
+        left: { style: 'thin', color: { argb: 'FF000000' } },
+        right: { style: 'thin', color: { argb: 'FF000000' } }
+      },
+      alignment: { horizontal: 'center', vertical: 'middle', wrapText: true },
+      font: { size: 11, color: { argb: 'FF000000' } }
+    };
+    const titleStyle = { // 标题行样式:浅灰底+14号字+加粗
+      ...commonStyle,
+      font: { size: 14, bold: true, color: { argb: 'FF000000' } },
+      fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE6E6E6' } }
+    };
+    const headerStyle = { // 表头行样式:深灰底+12号字+加粗
+      ...commonStyle,
+      font: { size: 12, bold: true, color: { argb: 'FF000000' } },
+      fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFC0C0C0' } }
+    };
+
+    // 6.3 应用样式到单元格
+    const lastRow = 4 + dataRows.length; // 最后一行:3行表头+数据行
+    
+    // 定义特殊列的样式(黄色背景)
+    const yellowBgStyle = {
+      ...commonStyle,
+      fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFF00' } }
+    };
+    
+    // 标题行(第1行):应用标题样式
+    worksheet.getRow(1).eachCell(cell => cell.style = titleStyle);
+    
+    // 表头行(第2-3行):应用表头样式
+    worksheet.getRow(2).eachCell(cell => cell.style = headerStyle);
+    
+    // 指标行(第3行):特殊处理核算产量和产量工资合计列
+    const indexRowObject = worksheet.getRow(3);
+    indexRowObject.eachCell((cell, colIndex) => {
+      // 跳过A列(工序列)
+      if (colIndex === 1) {
+        cell.style = headerStyle;
+        return;
+      }
+      // 检查是否是核算产量或产量工资合计列
+      const cellValue = cell.value;
+      if (cellValue === '核算产量' || cellValue === '产量工资合计') {
+        cell.style = {
+          ...headerStyle,
+          fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFF00' } }
+        };
+      } else {
+        cell.style = headerStyle;
+      }
+    });
+    
+    // 数据行(第4行到最后一行):特殊处理核算产量和产量工资合计列
+    for (let row = 4; row <= lastRow; row++) {
+      const currentRow = worksheet.getRow(row);
+      currentRow.eachCell((cell, colIndex) => {
+        // 跳过A列(工序列)和最后一列(备注列)
+        if (colIndex === 1 || colIndex === totalCol) {
+          cell.style = commonStyle;
+          return;
+        }
+        
+        // 计算当前列属于第几个月的第几个指标
+        const monthColIndex = colIndex - 2; // 减去A列
+        const monthIndex = Math.floor(monthColIndex / 6);
+        const metricIndex = monthColIndex % 6;
+        
+        // 核算产量是每个月的第3个指标(索引2),产量工资合计是每个月的第6个指标(索引5)
+        if (metricIndex === 2 || metricIndex === 5) {
+          cell.style = yellowBgStyle;
+        } else {
+          cell.style = commonStyle;
+        }
+      });
+    }
+
+    // 6.4 设置列宽(与原Excel一致,像素适配)
+    const colWidths = [120]; // A列(工序):120px
+    for (let m = 1; m <= 12; m++) {
+      colWidths.push(...Array(6).fill(80)); // 12个月×6列:80px/列
+    }
+    colWidths.push(200); // 最后一列(备注):200px
+    // ExcelJS列宽单位为「字符」,px转字符按 1px ≈ 0.14 换算(精准适配)
+    worksheet.columns = colWidths.map((width, index) => ({
+      key: index+1,
+      width: width * 0.14
+    }));
+
+    // 6.5 调整行高(可选,适配表头文字,避免遮挡)
+    worksheet.getRow(1).height = 30; // 标题行高
+    worksheet.getRow(2).height = 25; // 月份行高
+    worksheet.getRow(3).height = 25; // 指标行高
+
+    // ============== 导出Excel文件 ==============
+    // 7. 生成blob并下载
+    const buffer = await workbook.xlsx.writeBuffer();
+    const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+    saveAs(blob, `按工序归结人工费统计表${YEAR}年.xlsx`);
+
+    ElMessage.success('导出成功!');
+  } catch (error) {
+    console.error('Excel导出失败:', error);
+    ElMessage.error('导出数据失败,请重试');
+  }
+};
+
+// 导出月份数据
+const exportMonthlyData = async () => {
+  if (!monthValue.value) {
+    ElMessage.warning('请选择月份');
+    return;
+  }
+  
+  try {
+    // 1. 接口数据获取+处理
+    const year = monthValue.value.substring(0, 4);
+    const month = monthValue.value.substring(4, 6);
+    const response = await GetCompletionWorkOrderCostDetail({ year: year, month: month });
+    const originalData = response.data;
+    if (!originalData || Object.keys(originalData).length === 0) {
+      ElMessage.warning('暂无数据可导出');
+      return;
+    }
+
+    // 核心配置
+    const PROCESS_ORDER = ['胶印','卷凹','圆烫','圆切','单凹','丝印','喷码','覆膜','裁切','切废','烫金','模切','机检','手检'];
+    const PROCESS_REMARK = {
+      胶印: '按所有胶印机台',卷凹: '按所有卷凹机台',圆烫: '按所有圆压圆烫金机台',圆切: '按所有圆压圆模切机台',
+      单凹: '按所有单凹机台',丝印: '按所有丝印机台',喷码: '按所有喷码机台',覆膜: '按所有覆膜机台',
+      裁切: '按所有切纸机台(仅为裁切工序,不含切废工序)',切废: '按所有切纸机台(仅为切废工序,不含裁切工序)',
+      烫金: '按所有烫金机台',模切: '按所有模切机台',机检: '按所有检品机台(不含圆压圆模切配套的检品机)',
+      手检: '按工序--手检'
+    };
+    const MONTH_KEYS = ['车头产量','补产产量','核算产量','计件工资','加班工资','产量工资合计'];
+    const YEAR = year;
+    const MONTH = monthValue.value.substring(4, 6);
+    const totalCol = 1 + 6 + 1; // 总列数:工序+6指标+备注
+
+    // 2. 数据处理
+    const processData = {};
+    Object.entries(originalData).forEach(([process, data]) => {
+      if (!Array.isArray(data) || data.length === 0) {
+        processData[process] = {车头产量:0,补产产量:0,核算产量:0,计件工资:0,加班工资:0,产量工资合计:0};
+      } else {
+        // 直接使用返回的数据,因为接口已经按月份过滤
+        const item = data[0];
+        processData[process] = {
+          车头产量: Number(item.车头产量) || 0,
+          补产产量: Number(item.补产产量) || 0,
+          核算产量: Number(item.核算产量) || 0,
+          计件工资: Number(item.计件工资) || 0,
+          加班工资: Number(item.加班工资) || 0,
+          产量工资合计: Number(item.产量工资合计) || 0
+        };
+      }
+    });
+
+    // 3. 构建数据行
+    // 表头行:标题行、月份行、指标行
+    const titleRow = [`${YEAR}年${MONTH}月按工序归结人工费统计表`];
+    const monthRow = ['工序'];
+    const indexRow = [''];
+    titleRow.push(...Array(totalCol-1).fill('')); // 标题行补空
+    monthRow.push(`${MONTH}月`);
+    // 为月份添加5个空白单元格,确保占6列
+    monthRow.push(...Array(5).fill(''));
+    indexRow.push(...MONTH_KEYS);
+    monthRow.push('备注');
+    indexRow.push('');
+
+    // 数据行:14个工序的所有数据+备注
+    const dataRows = PROCESS_ORDER.map(process => {
+      const row = [process];
+      const currentData = processData[process] || {车头产量:0,补产产量:0,核算产量:0,计件工资:0,加班工资:0,产量工资合计:0};
+      row.push(...MONTH_KEYS.map(key => currentData[key].toFixed(1)));
+      row.push(PROCESS_REMARK[process] || '');
+      return row;
+    });
+
+    // ============== ExcelJS 核心:创建工作簿+设置样式 ==============
+    // 4. 创建工作簿和工作表
+    const workbook = new ExcelJS.Workbook();
+    const worksheet = workbook.addWorksheet('Sheet1'); // 工作表名与原Excel一致
+
+    // 5. 写入数据(按行写入:标题行→月份行→指标行→数据行)
+    worksheet.addRow(titleRow);
+    worksheet.addRow(monthRow);
+    worksheet.addRow(indexRow);
+    dataRows.forEach(row => worksheet.addRow(row));
+
+    // 辅助函数:将列索引转换为Excel列字母(如1→A, 2→B, 26→Z, 27→AA)
+    const getColumnLetter = (colIndex) => {
+      let letter = '';
+      let num = colIndex;
+      while (num > 0) {
+        const remainder = (num - 1) % 26;
+        letter = String.fromCharCode(65 + remainder) + letter;
+        num = Math.floor((num - 1) / 26);
+      }
+      return letter;
+    };
+
+    // 6. 样式配置:合并单元格+边框+底色+居中+列宽
+    // 6.1 合并单元格
+    const mergeRange = (range) => worksheet.mergeCells(range);
+    // 合并1:标题行(A1到最后一列1)
+    mergeRange(`A1:${getColumnLetter(totalCol)}1`);
+    // 合并2:工序列(A2:A4)
+    mergeRange('A2:A3');
+    // 合并3:月份行(B2:G2)
+    mergeRange(`B2:G2`);
+    // 合并4:备注列(最后一列2:最后一列4)
+    mergeRange(`${getColumnLetter(totalCol)}2:${getColumnLetter(totalCol)}3`);
+
+    // 6.2 定义样式模板
+    const commonStyle = { // 所有单元格公共样式:边框+居中+自动换行
+      border: {
+        top: { style: 'thin', color: { argb: 'FF000000' } },
+        bottom: { style: 'thin', color: { argb: 'FF000000' } },
+        left: { style: 'thin', color: { argb: 'FF000000' } },
+        right: { style: 'thin', color: { argb: 'FF000000' } }
+      },
+      alignment: { horizontal: 'center', vertical: 'middle', wrapText: true },
+      font: { size: 11, color: { argb: 'FF000000' } }
+    };
+    const titleStyle = { // 标题行样式:浅灰底+14号字+加粗
+      ...commonStyle,
+      font: { size: 14, bold: true, color: { argb: 'FF000000' } },
+      fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE6E6E6' } }
+    };
+    const headerStyle = { // 表头行样式:深灰底+12号字+加粗
+      ...commonStyle,
+      font: { size: 12, bold: true, color: { argb: 'FF000000' } },
+      fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFC0C0C0' } }
+    };
+
+    // 6.3 应用样式到单元格
+    const lastRow = 3 + dataRows.length; // 最后一行:3行表头+数据行
+    
+    // 定义特殊列的样式(黄色背景)
+    const yellowBgStyle = {
+      ...commonStyle,
+      fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFF00' } }
+    };
+    
+    // 标题行(第1行):应用标题样式
+    worksheet.getRow(1).eachCell(cell => cell.style = titleStyle);
+    
+    // 表头行(第2行):应用表头样式
+    worksheet.getRow(2).eachCell(cell => cell.style = headerStyle);
+    
+    // 指标行(第3行):特殊处理核算产量和产量工资合计列
+    const indexRowObject = worksheet.getRow(3);
+    indexRowObject.eachCell((cell, colIndex) => {
+      // 跳过A列(工序列)
+      if (colIndex === 1) {
+        cell.style = headerStyle;
+        return;
+      }
+      // 检查是否是核算产量或产量工资合计列
+      const cellValue = cell.value;
+      if (cellValue === '核算产量' || cellValue === '产量工资合计') {
+        cell.style = {
+          ...headerStyle,
+          fill: { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFF00' } }
+        };
+      } else {
+        cell.style = headerStyle;
+      }
+    });
+    
+    // 数据行(第4行到最后一行):特殊处理核算产量和产量工资合计列
+    for (let row = 4; row <= lastRow; row++) {
+      const currentRow = worksheet.getRow(row);
+      currentRow.eachCell((cell, colIndex) => {
+        // 跳过A列(工序列)和最后一列(备注列)
+        if (colIndex === 1 || colIndex === totalCol) {
+          cell.style = commonStyle;
+          return;
+        }
+        
+        // 计算当前列属于第几个指标
+        const metricIndex = colIndex - 2; // 减去A列
+        
+        // 核算产量是第3个指标(索引2),产量工资合计是第6个指标(索引5)
+        if (metricIndex === 2 || metricIndex === 5) {
+          cell.style = yellowBgStyle;
+        } else {
+          cell.style = commonStyle;
+        }
+      });
+    }
+
+    // 6.4 设置列宽(与原Excel一致,像素适配)
+    const colWidths = [120]; // A列(工序):120px
+    colWidths.push(...Array(6).fill(80)); // 6列指标:80px/列
+    colWidths.push(200); // 最后一列(备注):200px
+    // ExcelJS列宽单位为「字符」,px转字符按 1px ≈ 0.14 换算(精准适配)
+    worksheet.columns = colWidths.map((width, index) => ({
+      key: index+1,
+      width: width * 0.14
+    }));
+
+    // 6.5 调整行高(可选,适配表头文字,避免遮挡)
+    worksheet.getRow(1).height = 30; // 标题行高
+    worksheet.getRow(2).height = 25; // 月份行高
+    worksheet.getRow(3).height = 25; // 指标行高
+
+    // ============== 导出Excel文件 ==============
+    // 7. 生成blob并下载
+    const buffer = await workbook.xlsx.writeBuffer();
+    const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
+    saveAs(blob, `按工序归结人工费统计表${YEAR}年${MONTH}月.xlsx`);
+
+    ElMessage.success('导出成功!');
+  } catch (error) {
+    console.error('Excel导出失败:', error);
+    ElMessage.error('导出数据失败,请重试');
+  }
+};
+
+</script>
+<style scoped>
+:deep(.el-table td .cell) {
+  line-height: 20px !important;
+}
+:deep(.el-tabs__header){
+  margin-bottom: 0;
+}
+.search{
+  margin-left: 0px !important;
+  margin-right: 10px !important;
+}
+.bt{
+  margin-left: 2px !important;
+  padding: 3px !important;
+  font-size: 12px;
+}
+.el-tabs__header{
+  margin: 0px !important;
+}
+.gva-table-box{
+  padding: 0px !important;
+}
+.el-pagination{
+  margin-top: 0px !important;
+}
+.mab{
+  margin-bottom: 5px;
+}
+</style>
+

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels