request->isGet()) { $this->error('请求方法错误'); } $params = $this->request->param(); if (empty($params['workorder'])) { $this->error('工单编号不能为空'); } $list = db('工单_工艺资料') ->where('订单编号', $params['workorder']) ->field('工序编号,工序名称,工序备注') ->distinct('工序名称') ->select(); if(empty($list)){ $this->error('该工单没有大工序'); } $this->success('成功', $list); } /** * 工单部件列表 * @param workorder 工单编号 */ public function PartList() { if (!$this->request->isGet()) { $this->error('请求方法错误'); } $params = $this->request->param(); if (empty($params['workorder'])) { $this->error('工单编号不能为空'); } $list = db('工单_部件资料') ->where('work_order', $params['workorder']) ->where('del_rq', null) ->field('part_code as 部件编号,part_name as 部件名称,remark as 部件备注,part_type as 部件类型,status as 状态, sys_id as 操作人,sys_rq as 操作时间,mod_rq as 修改时间,mod_id as 修改人,id as 部件ID') ->order('part_code') ->select(); if(empty($list)){ // $this->error('该工单没有部件,请先添加部件'); } $this->success('成功', $list); } /** * 新增工单部件 * @param workorder 工单编号 * @param part_code 部件编号 * @param part_name 部件名称 * @param remark 部件备注 * @param part_type 部件类型 * @param sys_id 操作人 */ public function AddPart() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params['workorder'])) { $this->error('工单编号不能为空'); } if (empty($params['part_name'])) { $this->error('部件名称不能为空'); } // 检查是否传入了part_code if (!empty($params['part_code'])) { $code = $params['part_code']; // 检查是否存在冲突 $exists = db('工单_部件资料') ->where('work_order', $params['workorder']) ->where('part_code', '>=', $code) ->count(); if ($exists > 0) { // 如果存在冲突,将后续编号自动加1 db('工单_部件资料') ->where('work_order', $params['workorder']) ->where('part_code', '>=', $code) ->setInc('part_code'); } } else { // 如果没有传入part_code,按照原来的逻辑生成 $code = db('工单_部件资料') ->where('work_order', $params['workorder']) ->max('part_code'); $code = $code ? $code + 1 : 1; } $data = [ 'work_order' => $params['workorder'], 'part_code' => $code, 'part_name' => $params['part_name'], 'remark' => $params['remark'], 'part_type' => $params['part_type'], 'status' => 1, 'sys_id' => $params['sys_id'], 'sys_rq' => date('Y-m-d H:i:s'), ]; $result = db('工单_部件资料')->insert($data); if (!$result) { $this->error('新增失败'); } $this->success('新增成功'); } /** * 修改部件状态 * @param id 部件ID * @param status 状态 */ public function UpdatePartStatus() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params['id'])) { $this->error('部件ID不能为空'); } if (!isset($params['status'])) { $this->error('状态不能为空'); } $result = db('工单_部件资料') ->where('id', $params['id']) ->update(['status' => $params['status']]); if (!$result) { $this->error('修改失败'); } $this->success('修改成功'); } /** * 修改部件信息 * @param workorder 工单编号 * @param part_code 部件编号 * @param part_name 部件名称 * @param remark 部件备注 * @param part_type 部件类型 */ public function UpdatePartInfo() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params['part_name'])) { $this->error('部件名称不能为空'); } if (empty($params['remark'])) { $this->error('部件备注不能为空'); } if (empty($params['part_type'])) { $this->error('部件类型不能为空'); } if(empty($params['mod_id'])){ $this->error('修改人不能为空'); } if(empty($params['id'])){ $this->error('部件ID不能为空'); } $result = db('工单_部件资料') ->where('id', $params['id']) ->update([ 'part_name' => $params['part_name'], 'remark' => $params['remark'], 'part_type' => $params['part_type'], 'mod_id' => $params['mod_id'], 'mod_rq' => date('Y-m-d H:i:s'), ]); if (!$result) { $this->error('修改失败'); } $this->success('修改成功'); } /** 软删除部件信息 * @param id 部件ID */ public function DeletePart() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params['id'])) { $this->error('部件ID不能为空'); } $ids = explode(',', $params['id']); $ids = array_filter(array_map('intval', $ids)); if (empty($ids)) { $this->error('无效的部件ID'); } $result = db('工单_部件资料') ->whereIn('id', $ids) ->whereNull('del_rq') ->update(['del_rq' => date('Y-m-d H:i:s')]); if ($result === false) { $this->error('删除失败'); } if ($result === 0) { $this->error('未找到可删除的部件'); } $this->success('删除成功'); } /** * 工单工艺列表 * @param workorder 工单编号 */ public function GetProcessList() { if (!$this->request->isGet()) { $this->error('请求方法错误'); } $params = $this->request->param(); if (empty($params['workorder'])) { $this->error('工单编号不能为空'); } $list = db('工单_基础工艺资料') ->alias('a') ->join('工单_部件资料 b', 'a.part_code = b.part_code and a.work_order = b.work_order', 'LEFT') ->where('a.del_rq', null) ->where('a.work_order', $params['workorder']) ->where('b.del_rq', null) ->field('a.id,a.part_code as 部件编号, IFNULL(b.part_name, "") as 部件名称, a.process_code as 工艺编号, a.process_name as 工艺名称, a.big_process as 大工艺, a.standard_hour as 标准工时, a.standard_score as 标准公分, a.remark as 备注, a.coefficient as 系数, a.sys_id as 系统人, a.sys_rq as 系统时间, a.mod_id as 修改人, a.mod_rq as 修改时间') ->order('a.id') ->select(); $this->success('成功', $list); } /** * 工单工艺列表 * @param workorder 工单编号 */ // public function GetProcessList() // { // if (!$this->request->isGet()) { // $this->error('请求方法错误'); // } // $params = $this->request->param(); // if (empty($params['workorder'])) { // $this->error('工单编号不能为空'); // } // $list = db('工单_基础工艺资料') // ->alias('a') // ->join('工单_部件资料 b', 'a.part_code = b.part_code and a.work_order = b.work_order') // ->where('a.del_rq', null) // ->where('a.work_order', $params['workorder']) // ->where('b.del_rq', null) // ->field('a.id,a.part_code as 部件编号,b.part_name as 部件名称,a.process_code as 序号, // a.process_name as 工序名称,a.big_process as 大工艺,a.standard_hour as 秒,a.standard_minutes as 分钟, // a.standard_score as 标准公分,a.money as 金额,a.remark as 备注,a.coefficient as 难度系数,a.sys_id as 操作人员, // a.sys_rq as 系统时间,a.mod_id as 修改人,a.mod_rq as 修改时间') // ->order('process_code') // ->select(); // $this->success('成功', $list); // } /** * 获取部件列表 * @param workorder 工单编号 */ public function getpartlist() { if(!$this->request->isGet()){ $this->error('请求方法错误'); } $params = $this->request->get(); if (empty($params['workorder'])) { $this->error('工单编号不能为空'); } $list = db('工单_部件资料') ->where('work_order', $params['workorder']) ->where('del_rq', null) ->field('part_code as 部件编号,part_name as 部件名称') ->order('part_code') ->select(); if(empty($list)){ $this->error('该工单没有部件,请先添加部件'); } $this->success('成功', $list); } /** * 新增工单工艺资料 * @param workorder 工单编号 * @param part_code 部件编号 * @param process_code 工艺编号 * @param process_name 工艺名称 * @param big_process 大工艺 * @param standard_hour 标准工时 * @param standard_score 标准公分 * @param sys_id 系统人 * @param coefficient 系数 * @param remark 备注 */ public function AddProcess() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params['workorder'])) { $this->error('工单编号不能为空'); } if (empty($params['part_code'])) { $this->error('部件编号不能为空'); } if (empty($params['process_name'])) { $this->error('工艺名称不能为空'); } if (empty($params['big_process'])) { $this->error('大工艺不能为空'); } // if (empty($params['standard_hour'])) { // $this->error('标准工时不能为空'); // } // if (empty($params['standard_score'])) { // $this->error('标准公分不能为空'); // // } // if (empty($params['coefficient'])) { // $params['coefficient'] = 'C'; // } if (empty($params['sys_id'])) { $this->error('系统人不能为空'); } // 检查是否传入了process_code if (!empty($params['process_code'])) { $code = $params['process_code']; // 检查是否存在冲突 $exists = db('工单_基础工艺资料') ->where('work_order', $params['workorder']) ->where('part_code', $params['part_code']) ->where('process_code', '>=', $code) ->count(); if ($exists > 0) { // 如果存在冲突,将后续编号自动加1 db('工单_基础工艺资料') ->where('work_order', $params['workorder']) ->where('part_code', $params['part_code']) ->where('process_code', '>=', $code) ->setInc('process_code'); } } else { // 如果没有传入process_code,按照原来的逻辑生成 $code = db('工单_基础工艺资料') ->where('work_order', $params['workorder']) ->where('part_code', $params['part_code']) ->max('process_code'); $code = $code ? $code + 1 : 1; } $data = [ 'work_order' => $params['workorder'], 'part_code' => $params['part_code'], 'part_name' => $params['part_name'], 'process_code' => $code, 'process_name' => $params['process_name'], 'big_process' => $params['big_process'], 'standard_hour' => $params['standard_hour'], 'standard_score' => $params['standard_score'], 'coefficient' => $params['coefficient'], 'remark' => $params['remark'], 'sys_id' => $params['sys_id'], 'sys_rq' => date('Y-m-d H:i:s'), ]; $result = db('工单_基础工艺资料')->insert($data); if ($result === false) { $this->error('新增失败'); } $this->success('新增成功'); } /** * 更新工单工艺资料 * @param id 工艺ID * @param mod_id 修改人 * @param process_name 工艺名称 * @param big_process 大工艺 * @param standard_hour 标准工时 * @param standard_score 标准公分 * @param coefficient 系数 * @param remark 备注 */ public function UpdateProcess() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params['id'])) { $this->error('工艺ID不能为空'); } if (empty($params['mod_id'])) { $this->error('修改人不能为空'); } if (empty($params['process_name'])) { $this->error('工艺名称不能为空'); } if (empty($params['big_process'])) { $this->error('大工艺不能为空'); } if (!isset($params['coefficient']) || $params['coefficient'] === '') { $params['coefficient'] = 'C'; } $process = Db::table('工单_基础工艺资料') ->where('id', intval($params['id'])) ->whereNull('del_rq') ->find(); if (empty($process)) { $this->error('工艺不存在'); } $data = [ 'part_code' => $params['part_code'], 'part_name' => $params['part_name'], 'standard_minutes' => $params['standard_minutes'], 'money' => $params['money'], 'remark' => $params['remark'], 'process_name' => $params['process_name'], 'big_process' => $params['big_process'], 'standard_hour' => $params['standard_hour'], 'standard_score' => $params['standard_score'], 'coefficient' => $params['coefficient'], 'mod_id' => $params['mod_id'], 'mod_rq' => date('Y-m-d H:i:s'), ]; $fieldLabels = [ 'part_code' => '部件编号', 'part_name' => '部件名称', 'standard_minutes' => '分', 'money' => '金额', 'remark' => '备注', 'process_name' => '工序名称', 'big_process' => '大工序', 'standard_hour' => '秒', 'standard_score' => '定额分', 'coefficient' => '难度系数', ]; $operTime = date('Y-m-d H:i:s'); $logList = []; foreach ($fieldLabels as $field => $label) { $oldValue = isset($process[$field]) ? $process[$field] : ''; $newValue = $data[$field]; if ((string)$oldValue === (string)$newValue) { continue; } $logList[] = [ 'order_no' => $process['work_order'], 'process_code' => $params['process_code'], 'change_field' => $label, 'old_value' => $oldValue === null ? '' : (string)$oldValue, 'new_value' => (string)$newValue, 'oper_type' => '修改工单工艺', 'oper_user_name' => $params['mod_id'], 'oper_time' => $operTime, ]; } if (empty($logList)) { $this->error('未找到可更新的工艺或数据无变化'); } $standardScoreChanged = (string)$process['standard_score'] !== (string)$params['standard_score']; if ($standardScoreChanged && (string)$process['status'] === '0') { $workOrder = Db::table('工单_基本资料') ->where('订单编号', $process['work_order']) ->where('Mod_rq', null) ->field('计划制造工分') ->find(); if (empty($workOrder)) { $this->error('工单不存在'); } $totalStandardScore = Db::table('工单_基础工艺资料') ->where('work_order', $process['work_order']) ->where('status', 0) ->whereNull('del_rq') ->sum('standard_score'); $totalStandardScore = $totalStandardScore ? floatval($totalStandardScore) : 0; $newTotal = $totalStandardScore - floatval($process['standard_score']) + floatval($params['standard_score']); if ($newTotal > floatval($workOrder['计划制造工分'])) { $this->error('工序定额分和大于制造工分,请确认之后再修改'); } } Db::startTrans(); try { $updateResult = Db::table('工单_基础工艺资料') ->where('id', intval($params['id'])) ->whereNull('del_rq') ->update($data); if ($updateResult === false) { $dbError = Db::getError(); $detail = is_array($dbError) && !empty($dbError) ? json_encode($dbError, JSON_UNESCAPED_UNICODE) : ''; throw new \Exception('更新工艺失败' . ($detail !== '' ? ':' . $detail : '')); } if ($updateResult === 0) { throw new \Exception('未找到可更新的工艺'); } $logResult = Db::name('work_order_operation_log')->insertAll($logList); if ($logResult === false || $logResult === 0) { $dbError = Db::getError(); $detail = is_array($dbError) && !empty($dbError) ? json_encode($dbError, JSON_UNESCAPED_UNICODE) : ''; throw new \Exception('写入操作日志失败' . ($detail !== '' ? ':' . $detail : '')); } Db::commit(); } catch (\think\exception\HttpResponseException $e) { throw $e; } catch (\Exception $e) { Db::rollback(); $msg = trim($e->getMessage()); $this->error('更新失败:' . ($msg !== '' ? $msg : '未知错误')); } $this->success('更新成功'); } /** * 工单工艺资料软删除 * @param id 工艺ID */ public function DeleteProcess() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params['id'])) { $this->error('工艺ID不能为空'); } $ids = explode(',', $params['id']); $ids = array_filter(array_map('intval', $ids)); if (empty($ids)) { $this->error('无效的工艺ID'); } $result = db('工单_基础工艺资料') ->whereIn('id', $ids) ->whereNull('del_rq') ->update(['del_rq' => date('Y-m-d H:i:s')]); if ($result === false) { $this->error('删除失败'); } if ($result === 0) { $this->error('未找到可删除的工艺'); } $this->success('删除成功'); } /** * 工单工艺复制 * @param workorder 工单编号 * @param product_code 产品编号 * @param sys_id 操作人 * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException * @throws \think\exception\PDOException */ public function workorderprocessCopy() { if (!$this->request->isGet()) { $this->error('请求方法错误'); } $params = $this->request->param(); if (empty($params['workorder'])) { $this->error('工单编号不能为空'); } if (empty($params['product_code'])) { $this->error('产品编号不能为空'); } if (empty($params['sys_id'])) { $this->error('操作人不能为空'); } $now = date('Y-m-d H:i:s'); $productParts = db('产品_部件资料') ->where('product_code', $params['product_code']) ->where('mod_rq', null) ->field('part_sort as part_code,part_name') ->select(); if (empty($productParts)) { $this->error('该产品没有有效的部件'); } $productProcesses = db('产品_工艺资料') ->where('product_code', $params['product_code']) ->field('part_sort as part_code,part_name,gy_sort as process_code,gy_name as process_name, big_process,standard_hour,standard_score,difficulty_coef as coefficient') ->select(); if (empty($productProcesses)) { $this->error('该产品没有工艺'); } $workOrderParts = []; //配置工单部件数据 foreach ($productParts as $value) { $workOrderParts[] = [ 'work_order' => $params['workorder'], 'part_code' => $value['part_code'], 'part_name' => $value['part_name'], 'part_type' => '', 'remark' => '', 'status' => 1, 'sys_id' => $params['sys_id'], 'sys_rq' => $now, ]; } $workOrderProcesses = []; //配置工单工艺数据 foreach ($productProcesses as $value) { $workOrderProcesses[] = [ 'work_order' => $params['workorder'], 'part_code' => $value['part_code'], 'part_name' => $value['part_name'], 'process_code' => $value['process_code'], 'process_name' => $value['process_name'], 'big_process' => $value['big_process'], 'standard_hour' => $value['standard_hour'], 'standard_score' => $value['standard_score'], 'coefficient' => $value['coefficient'], 'remark' => '', 'sys_id' => $params['sys_id'], 'sys_rq' => $now, ]; } Db::startTrans(); try { //删除数据库现有的工单部件数据 Db::name('工单_部件资料')->where('work_order', $params['workorder'])->delete(); //删除数据库现有的工单工艺数据 Db::name('工单_基础工艺资料')->where('work_order', $params['workorder'])->delete(); //插入工单部件数据 $partInsertCount = Db::name('工单_部件资料')->insertAll($workOrderParts); if ($partInsertCount === false) { throw new \Exception('工单部件复制失败'); } //插入工单工艺数据 $processInsertCount = Db::name('工单_基础工艺资料')->insertAll($workOrderProcesses); if ($processInsertCount === false) { throw new \Exception('工单工艺复制失败'); } //提交事务 Db::commit(); } catch (\Exception $e) { Db::rollback(); $this->error('复制失败'); } $this->success('复制成功'); } /** * 查询产品类型 * @ApiMethod (GET) * @param string $workorder 工单编号 * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function getproducttype() { if(!$this->request->isGet()){ $this->error('请求方法错误'); } $params = $this->request->get(); if (empty($params['product'])) { $this->error('产品类型不能为空'); } $list = db('产品_基本资料') ->where('product_type', $params['product']) ->where('status', 1) ->field('product_code as 产品编号,product_type as 产品类型,product_name as 产品名称') ->select(); if(empty($list)){ $this->error('该产品类型没有产品'); } $this->success('成功', $list); } /** * 工单工艺排序 * @param workorder 工单编号 * @param part_code 部件编号 * @param process_code 工艺编号 * @param process_name 工艺名称 * @param big_process 大工艺 * @param standard_hour 标准工时 * @param standard_score 标准公分 * @param coefficient 系数 * @param remark 备注 */ public function sortProcess() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params)) { $this->error('参数不能为空'); } if (!is_array($params)) { $this->error('参数格式错误'); } Db::startTrans(); try { foreach ($params as $value) { if (empty($value['id'])) { throw new \Exception('缺少工艺ID'); } if (!isset($value['process_code']) || $value['process_code'] === '') { throw new \Exception('缺少工艺编号'); } $result = db('工单_基础工艺资料') ->where('id', intval($value['id'])) ->whereNull('del_rq') ->update(['process_code' => intval($value['process_code'])]); if ($result === false) { throw new \Exception('排序失败'); } } Db::commit(); } catch (\Exception $e) { Db::rollback(); $this->error($e->getMessage()); } $this->success('排序成功'); } /** * 工单工艺excel导入 * @param workorder 工单编号 * */ public function importProcess() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params['workorder'])) { $this->error('工单编号不能为空'); } if (empty($params['sys_id'])) { $this->error('操作人不能为空'); } $file = $this->request->file('file'); if (!$file) { $this->error('文件不能为空'); } $uploadDir = ROOT_PATH . 'public' . DS . 'uploads'; $info = $file->validate(['size' => 1024 * 1024 * 10, 'ext' => 'xlsx,xls,csv,txt']) ->move($uploadDir); if (!$info) { $this->error($file->getError()); } $filePath = $uploadDir . DS . $info->getSaveName(); // 定额表:上方为标题与元数据,第 5 行表头,第 6 行起为数据 $data = $this->readExcel($filePath, 5, 6); if (empty($data)) { $this->error('文件内容为空'); } $seenSeq = []; foreach ($data as $row) { $seq = isset($row['序号']) ? $row['序号'] : null; if ($seq === null || $seq === '') { continue; } $seqKey = is_scalar($seq) ? (string)$seq : $seq; if (isset($seenSeq[$seqKey])) { $this->error('工序序号重复,请重新调整之后再上传'); } $seenSeq[$seqKey] = true; } $now = date('Y-m-d H:i:s'); $partMap = []; $nextPartCode = 0; foreach ($data as $row) { $partName = isset($row['部件名称']) ? trim((string)$row['部件名称']) : ''; if ($partName === '') { continue; } $partType = isset($row['生产工序']) ? trim((string)$row['生产工序']) : ''; if (!isset($partMap[$partName])) { $partMap[$partName] = [ 'part_code' => ++$nextPartCode, 'part_type' => $partType, ]; } elseif ($partType !== '' && $partMap[$partName]['part_type'] === '') { $partMap[$partName]['part_type'] = $partType; } } $workOrderParts = []; foreach ($partMap as $partName => $partInfo) { $workOrderParts[] = [ 'work_order' => $params['workorder'], 'part_name' => $partName, 'part_code' => $partInfo['part_code'], 'part_type' => $partInfo['part_type'], 'remark' => '', 'status' => 1, 'sys_id' => $params['sys_id'], 'sys_rq' => $now, ]; } $workOrderProcesses = []; foreach ($data as $value) { $seq = isset($value['序号']) ? $value['序号'] : null; if ($seq === null || $seq === '') { continue; } $name = isset($value['部件名称']) ? trim((string)$value['部件名称']) : ''; $partCode = ($name !== '' && isset($partMap[$name])) ? $partMap[$name]['part_code'] : ''; $workOrderProcesses[] = [ 'work_order' => $params['workorder'], 'part_code' => $partCode, 'part_name' => $name, 'process_code' => $seq, 'process_name' => $value['工序名称'], 'big_process' => $value['生产工序'], 'standard_hour' => $value['秒'], 'standard_minutes' => $value['分'], 'standard_score' => $value['定额分'], 'money' => $value['金额'], 'coefficient' => $value['难度系数'], 'remark' => isset($value['备注']) ? $value['备注'] : '', 'sys_id' => $params['sys_id'], 'sys_rq' => $now, ]; } Db::startTrans(); try { Db::name('工单_部件资料')->where('work_order', $params['workorder'])->delete(); if (!empty($workOrderParts)) { $partInsertCount = Db::name('工单_部件资料')->insertAll($workOrderParts); if ($partInsertCount === false || $partInsertCount === 0) { throw new \Exception('工单部件导入失败'); } } Db::name('工单_基础工艺资料')->where('work_order', $params['workorder'])->delete(); if (empty($workOrderProcesses)) { throw new \Exception('没有可导入的工序数据'); } $processInsertCount = Db::name('工单_基础工艺资料')->insertAll($workOrderProcesses); if ($processInsertCount === false || $processInsertCount === 0) { throw new \Exception('工单工艺导入失败'); } Db::commit(); } catch (\think\exception\HttpResponseException $e) { throw $e; } catch (\Exception $e) { Db::rollback(); $this->error('导入失败:' . $e->getMessage()); } $this->success('导入成功', [ 'part_count' => count($workOrderParts), 'process_count' => count($workOrderProcesses), ]); } /** * 读取 Excel/CSV(PhpSpreadsheet) * * @param string $filePath * @param int $headerRowNum 表头所在行(1 起计,如定额表为第 5 行) * @param int $dataStartRowNum 首条数据行(1 起计,须大于表头行,如第 6 行) * @return array 每行一条关联数组,键为表头单元格文本 */ public function readExcel($filePath, $headerRowNum = 5, $dataStartRowNum = 6) { if (!is_file($filePath) || !is_readable($filePath)) { return []; } if ($dataStartRowNum <= $headerRowNum) { return []; } $spreadsheet = IOFactory::load($filePath); $sheet = $spreadsheet->getActiveSheet(); $rows = $sheet->toArray(); if (empty($rows)) { return []; } $headerIdx = $headerRowNum - 1; $dataStartIdx = $dataStartRowNum - 1; if (!isset($rows[$headerIdx])) { return []; } $headers = array_map(function ($cell) { return is_string($cell) ? trim($cell) : $cell; }, $rows[$headerIdx]); $data = []; $rowCount = count($rows); for ($r = $dataStartIdx; $r < $rowCount; $r++) { $row = $rows[$r]; $hasCell = false; foreach ($row as $cell) { if ($cell !== null && $cell !== '') { $hasCell = true; break; } } if (!$hasCell) { continue; } $assoc = []; foreach ($headers as $i => $key) { if ($key === '' || $key === null) { continue; } $assoc[$key] = array_key_exists($i, $row) ? $row[$i] : null; } $data[] = $assoc; } return $data; } /** * 获取工单工艺信息 * @param workorder 工单编号 * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function getWorkOrderProcess() { if (!$this->request->isGet()) { $this->error('请求方法错误'); } $params = $this->request->param(); if (empty($params['workorder'])) { $this->error('工单编号不能为空'); } $where = [ 'work_order' => $params['workorder'], 'del_rq' => null, ]; $workOrderProcess = Db::table('工单_基础工艺资料') ->where($where) ->field('id,part_code as 部件编号,part_name as 部件名称,process_code as 工序编号,process_name as 工序名称, big_process as 大工序,standard_hour as 秒,standard_minutes as 分,standard_score as 定额分,money as 金额, coefficient as 难度系数,remark as 备注,status as 状态,pid') ->select(); if (empty($workOrderProcess)) { $this->error('工单工艺不存在'); } $pidList = []; foreach ($workOrderProcess as $row) { if (!empty($row['pid'])) { $pidList[(int)$row['pid']] = true; } } $parentCodeMap = []; if (!empty($pidList)) { $parentCodeMap = Db::table('工单_基础工艺资料') ->whereIn('id', array_keys($pidList)) ->column('process_code', 'id'); } foreach ($workOrderProcess as &$row) { $row['母工序编号'] = !empty($row['pid']) && isset($parentCodeMap[(int)$row['pid']]) ? $parentCodeMap[(int)$row['pid']] : ''; } unset($row); $this->success('成功', $workOrderProcess); } /** * 修改工单计划制造工分 * @param id 工单Uniqid或订单编号 * @param number 计划制造工分 * @param sys_id 操作人 */ public function updateWorkOrderPlanManufacture() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params['id'])) { $this->error('工单ID不能为空'); } if (!isset($params['number']) || $params['number'] === '') { $this->error('制造工分不能为空'); } if (empty($params['sys_id'])) { $this->error('操作人不能为空'); } $workOrder = Db::table('工单_基本资料') ->where('Uniqid|订单编号', $params['id']) ->where('Mod_rq', null) ->field('Uniqid,订单编号,计划制造工分') ->find(); if (empty($workOrder)) { $this->error('工单不存在'); } $oldValue = $workOrder['计划制造工分']; $newValue = $params['number']; if ((string)$oldValue === (string)$newValue) { $this->error('计划制造工分未发生变化'); } $totalStandardScore = Db::table('工单_基础工艺资料') ->where('work_order', $workOrder['订单编号']) ->where('status', 0) ->whereNull('del_rq') ->sum('standard_score'); $totalStandardScore = $totalStandardScore ? floatval($totalStandardScore) : 0; if ($totalStandardScore > floatval($newValue)) { $this->error('工序定额分和大于制造工分,请确认之后再修改'); } $operTime = date('Y-m-d H:i:s'); $logData = [ 'order_no' => $workOrder['订单编号'], 'change_field' => '计划制造工分', 'old_value' => $oldValue === null ? '' : (string)$oldValue, 'new_value' => (string)$newValue, 'oper_type' => '修改工单计划制造工分', 'oper_user_name' => $params['sys_id'], 'oper_time' => $operTime, ]; Db::startTrans(); try { $updateResultSql = Db::table('工单_基本资料') ->where('Uniqid', $workOrder['Uniqid']) ->fetchSql(true) ->update(['计划制造工分' => $newValue]); $updateResult = Db::query($updateResultSql); if ($updateResult === false) { throw new \Exception('更新工单失败'); } $logResult = Db::name('work_order_operation_log')->insert($logData); if ($logResult === false) { throw new \Exception('写入操作日志失败'); } Db::commit(); } catch (\Exception $e) { Db::rollback(); $this->error('修改失败'); } $this->success('修改成功'); } /** * 拆分工序时判断工序是否存在报工 * @param workorder 工单编号 * @param process_code 工艺编号 * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function checkProcessReport() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params['workorder'])) { $this->error('工单编号不能为空'); } if (empty($params['process_code'])) { $this->error('工艺编号不能为空'); } $process = db('设备_工分计酬') ->where('work_order', $params['workorder']) ->where('process_code', $params['process_code']) ->find(); if (!empty($process)) { $this->error(''); } $this->success('工序不存在报工,可以拆分'); } /** * 确认拆分工序:number>0 时母工序置为已拆分并生成子工序(子工序 pid 为母工序 id); * number=0 时恢复母工序 status=0 并软删除其子工序 * @param id 工艺ID * @param number 拆分数量(0 表示取消拆分) * @param sys_id 操作人员 * @param sys_rq 操作时间(可选,默认当前时间) */ public function confirmProcessSplit() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params['id'])) { $this->error('工艺ID不能为空'); } if (!isset($params['number']) || $params['number'] === '' || $params['number'] === null) { $this->error('拆分工序数量不能为空'); } if (empty($params['sys_id'])) { $this->error('操作人不能为空'); } $splitCount = intval($params['number']); $operTime = !empty($params['sys_rq']) ? $params['sys_rq'] : date('Y-m-d H:i:s'); $processId = intval($params['id']); $process = Db::table('工单_基础工艺资料') ->where('id', $processId) ->whereNull('del_rq') ->find(); if (empty($process)) { $this->error('工序不存在'); } $workorder = $process['work_order']; if ($splitCount === 0) { $children = Db::table('工单_基础工艺资料') ->where('pid', $processId) ->whereNull('del_rq') ->field('id,process_code') ->select(); $logList = [ [ 'order_no' => $workorder, 'process_code' => $process['process_code'], 'change_field' => '状态', 'old_value' => '1', 'new_value' => '0', 'oper_type' => '取消拆分工序', 'oper_user_name' => $params['sys_id'], 'oper_time' => $operTime, ], ]; foreach ($children as $child) { $logList[] = [ 'order_no' => $workorder, 'process_code' => $child['process_code'], 'change_field' => '工序拆分', 'old_value' => (string)$process['process_code'], 'new_value' => '删除子工序', 'oper_type' => '取消拆分工序', 'oper_user_name' => $params['sys_id'], 'oper_time' => $operTime, ]; } Db::startTrans(); try { if (!empty($children)) { $deleteResult = Db::table('工单_基础工艺资料') ->where('pid', $processId) ->whereNull('del_rq') ->update(['del_rq' => $operTime]); if ($deleteResult === false) { throw new \Exception('删除子工序失败'); } } $updateResult = Db::table('工单_基础工艺资料') ->where('id', $processId) ->whereNull('del_rq') ->update(['status' => 0]); if ($updateResult === false) { throw new \Exception('恢复母工序状态失败'); } if (!empty($logList)) { $logResult = Db::name('work_order_operation_log')->insertAll($logList); if ($logResult === false || $logResult === 0) { throw new \Exception('写入操作日志失败'); } } Db::commit(); } catch (\think\exception\HttpResponseException $e) { throw $e; } catch (\Exception $e) { Db::rollback(); $this->error('取消拆分失败:' . $e->getMessage()); } $this->success('取消拆分工序成功', ['count' => count($children)]); return; } if ($splitCount < 1) { $this->error('拆分工序数量必须大于0'); } if (!in_array($process['status'], [0, '0'], true)) { $this->error('工序不存在或已确认拆分'); } $processCodes = Db::table('工单_基础工艺资料') ->where('work_order', $workorder) ->whereNull('del_rq') ->column('process_code'); $maxNumeric = 0; foreach ($processCodes as $code) { if (preg_match('/^(\d+)/', (string)$code, $match)) { $num = intval($match[1]); if ($num > $maxNumeric) { $maxNumeric = $num; } } } $baseCode = $maxNumeric + 1; $splitFields = ['standard_hour', 'standard_minutes', 'standard_score', 'money']; $splitValues = []; foreach ($splitFields as $field) { $splitValues[$field] = $this->splitNumericValue($process[$field], $splitCount); } $insertList = []; for ($i = 1; $i <= $splitCount; $i++) { $newProcessCode = $baseCode + $i - 1; $exists = Db::table('工单_基础工艺资料') ->where('work_order', $workorder) ->where('process_code', $newProcessCode) ->whereNull('del_rq') ->count(); if ($exists > 0) { $this->error('工序编号已存在:' . $newProcessCode); } $insertList[] = [ 'work_order' => $workorder, 'part_code' => $process['part_code'], 'part_name' => isset($process['part_name']) ? $process['part_name'] : '', 'process_code' => $newProcessCode, 'process_name' => $process['process_name'] . '-' . $i, 'big_process' => $process['big_process'], 'standard_hour' => $splitValues['standard_hour'][$i - 1], 'standard_minutes' => $splitValues['standard_minutes'][$i - 1], 'standard_score' => $splitValues['standard_score'][$i - 1], 'money' => $splitValues['money'][$i - 1], 'coefficient' => isset($process['coefficient']) && $process['coefficient'] !== '' && $process['coefficient'] !== null ? $process['coefficient'] : 'C', 'remark' => isset($process['remark']) && $process['remark'] !== null ? $process['remark'] : '', 'status' => 0, 'pid' => $processId, 'sys_id' => $params['sys_id'], 'sys_rq' => $operTime, ]; } $logList = [ [ 'order_no' => $workorder, 'process_code' => $process['process_code'], 'change_field' => '状态', 'old_value' => '0', 'new_value' => '1', 'oper_type' => '确认拆分工序', 'oper_user_name' => $params['sys_id'], 'oper_time' => $operTime, ], ]; foreach ($insertList as $row) { $logList[] = [ 'order_no' => $workorder, 'process_code' => $row['process_code'], 'change_field' => '工序拆分', 'old_value' => (string)$process['process_code'], 'new_value' => sprintf( '秒:%s,分:%s,定额分:%s,金额:%s', $row['standard_hour'], $row['standard_minutes'], $row['standard_score'], $row['money'] ), 'oper_type' => '确认拆分工序', 'oper_user_name' => $params['sys_id'], 'oper_time' => $operTime, ]; } Db::startTrans(); try { $updateResult = Db::table('工单_基础工艺资料') ->where('id', $process['id']) ->where('status', 'in', [0, '0']) ->update(['status' => 1]); if ($updateResult === false) { throw new \Exception('更新母工序状态失败'); } if ($updateResult === 0) { throw new \Exception('母工序状态已变更,请刷新后重试'); } $insertResult = Db::name('工单_基础工艺资料')->insertAll($insertList); if ($insertResult === false || $insertResult === 0) { throw new \Exception('拆分工序新增失败'); } $logResult = Db::name('work_order_operation_log')->insertAll($logList); if ($logResult === false || $logResult === 0) { throw new \Exception('写入操作日志失败,请确认日志表已包含 process_code 字段'); } Db::commit(); } catch (\think\exception\HttpResponseException $e) { throw $e; } catch (\Exception $e) { Db::rollback(); $this->error('修改失败:' . $e->getMessage()); } $this->success('确认拆分工序成功', ['count' => $splitCount]); } /** * 按拆分数量分配数值:不能整除时第一条为剩余后的最大值,其余为向下取整的平均值 * @param mixed $total * @param int $count * @return array */ private function splitNumericValue($total, $count) { $count = intval($count); if ($count <= 0) { return []; } $total = floatval($total); $avg = floor($total / $count * 100) / 100; $first = round($total - $avg * ($count - 1), 2); $values = [$first]; for ($i = 1; $i < $count; $i++) { $values[] = $avg; } return $values; } /** * 根据款号查询工单信息 * @param search 搜索内容 * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function getWorkOrderInfoByStyle() { if (!$this->request->isGet()) { $this->error('请求方法错误'); } $params = $this->request->param(); if (empty($params['search'])) { $this->error('搜索内容不能为空'); } $where = [ 'a.订单编号|a.生产款号|a.款式' => ['like', '%' . $params['search'] . '%'], 'a.Mod_rq' => null, ]; $workOrder = db('工单_基本资料')->alias('a') ->join('工单_基础工艺资料 b', 'a.订单编号 = b.work_order') ->field('a.订单编号,a.生产款号,a.款式,a.客户编号') ->where($where) ->group('a.订单编号') ->select(); if (empty($workOrder)) { $this->error('未找到工单信息'); } $this->success('成功', $workOrder); } /** * 复制目标工单的部件与工艺到当前工单 * @param target_workorder 目标工单编号 * @param current_workorder 当前工单编号 * @param sys_id 操作人 */ public function copyProcessToCurrentWorkOrder() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $params = $this->request->post(); if (empty($params['target_workorder'])) { $this->error('目标工单编号不能为空'); } if (empty($params['current_workorder'])) { $this->error('当前工单编号不能为空'); } if (empty($params['sys_id'])) { $this->error('操作人不能为空'); } if ($params['target_workorder'] === $params['current_workorder']) { $this->error('目标工单与当前工单不能相同'); } if (!$this->workOrderExists($params['target_workorder'])) { $this->error('目标工单不存在'); } if (!$this->workOrderExists($params['current_workorder'])) { $this->error('当前工单不存在'); } $targetWorkOrderInfo = $this->getWorkOrderInfo($params['target_workorder']); if (empty($targetWorkOrderInfo['partInfo']) && empty($targetWorkOrderInfo['processInfo'])) { $this->error('目标工单没有可复制的部件或工艺'); } $currentWorkOrderInfo = $this->getWorkOrderInfo($params['current_workorder']); $oldPartCount = count($currentWorkOrderInfo['partInfo']); $oldProcessCount = count($currentWorkOrderInfo['processInfo']); $now = date('Y-m-d H:i:s'); $partInsertList = $this->buildWorkOrderPartCopyRows( $targetWorkOrderInfo['partInfo'], $params['current_workorder'], $params['sys_id'], $now ); $processInsertList = $this->buildWorkOrderProcessCopyRows( $targetWorkOrderInfo['processInfo'], $params['current_workorder'], $params['sys_id'], $now ); $logData = [ 'order_no' => $params['current_workorder'], 'change_field' => $params['target_workorder'], 'old_value' => sprintf('部件%d条,工艺%d条', $oldPartCount, $oldProcessCount), 'new_value' => sprintf('部件%d条,工艺%d条', count($partInsertList), count($processInsertList)), 'oper_type' => '复制工单工艺', 'oper_user_name' => $params['sys_id'], 'oper_time' => $now, ]; Db::startTrans(); try { if ($oldPartCount > 0 || $oldProcessCount > 0) { $partDeleteResult = Db::table('工单_部件资料') ->where('work_order', $params['current_workorder']) ->whereNull('del_rq') ->update(['del_rq' => $now]); if ($partDeleteResult === false) { throw new \Exception('清除当前工单部件失败'); } $processDeleteResult = Db::table('工单_基础工艺资料') ->where('work_order', $params['current_workorder']) ->whereNull('del_rq') ->update(['del_rq' => $now]); if ($processDeleteResult === false) { throw new \Exception('清除当前工单工艺失败'); } } if (!empty($partInsertList)) { $partInsertResult = Db::name('工单_部件资料')->insertAll($partInsertList); if ($partInsertResult === false || $partInsertResult === 0) { throw new \Exception('复制部件失败'); } } if (!empty($processInsertList)) { $processInsertResult = Db::name('工单_基础工艺资料')->insertAll($processInsertList); if ($processInsertResult === false || $processInsertResult === 0) { throw new \Exception('复制工艺失败'); } } $logResult = Db::name('work_order_operation_log')->insert($logData); if ($logResult === false || $logResult === 0) { throw new \Exception('写入操作日志失败'); } Db::commit(); } catch (\think\exception\HttpResponseException $e) { throw $e; } catch (\Exception $e) { Db::rollback(); $this->error('复制失败:' . $e->getMessage()); } $this->success('复制成功', [ 'part_count' => count($partInsertList), 'process_count' => count($processInsertList), ]); } /** * 判断工单是否存在 * @param string $workorder * @return bool */ private function workOrderExists($workorder) { return Db::table('工单_基本资料') ->where('订单编号', $workorder) ->whereNull('Mod_rq') ->count() > 0; } /** * 查询工单部件与工艺(未删除、工艺仅 status=0) * @param string $workorder * @return array */ private function getWorkOrderInfo($workorder) { $partInfo = db('工单_部件资料') ->where('work_order', $workorder) ->whereNull('del_rq') ->field('part_code,part_name,remark,part_type,status') ->order('part_code') ->select(); $processInfo = db('工单_基础工艺资料') ->where('work_order', $workorder) ->whereNull('del_rq') ->where('status', 0) ->field('part_code,part_name,process_code,process_name,standard_hour,standard_minutes, standard_score,money,coefficient,remark,big_process') ->order('process_code') ->select(); return [ 'partInfo' => $partInfo ?: [], 'processInfo' => $processInfo ?: [], ]; } /** * 组装待复制的部件数据 */ private function buildWorkOrderPartCopyRows($partList, $workOrder, $sysId, $operTime) { $rows = []; foreach ($partList as $part) { $rows[] = [ 'work_order' => $workOrder, 'part_code' => $part['part_code'], 'part_name' => $part['part_name'], 'remark' => isset($part['remark']) ? $part['remark'] : '', 'part_type' => isset($part['part_type']) ? $part['part_type'] : '', 'status' => 0, 'sys_id' => $sysId, 'sys_rq' => $operTime, ]; } return $rows; } /** * 组装待复制的工艺数据 */ private function buildWorkOrderProcessCopyRows($processList, $workOrder, $sysId, $operTime) { $rows = []; foreach ($processList as $process) { $rows[] = [ 'work_order' => $workOrder, 'part_code' => $process['part_code'], 'part_name' => isset($process['part_name']) ? $process['part_name'] : '', 'process_code' => $process['process_code'], 'process_name' => $process['process_name'], 'big_process' => $process['big_process'], 'standard_hour' => $process['standard_hour'], 'standard_minutes' => $process['standard_minutes'], 'standard_score' => $process['standard_score'], 'money' => $process['money'], 'coefficient' => $process['coefficient'], 'remark' => isset($process['remark']) ? $process['remark'] : '', 'status' => 0, 'pid' => 0, 'sys_id' => $sysId, 'sys_rq' => $operTime, ]; } return $rows; } /** * 批量新增工序资料(请求体为 JSON 数组,每条含 work_order 等字段) * @param processList 工序信息 * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException **/ public function batchAddProcess() { if (!$this->request->isPost()) { $this->error('请求方法错误'); } $processList = $this->parseBatchProcessList(); if (empty($processList)) { $this->error('工艺数据不能为空'); } $requiredFields = [ 'work_order' => '工单编号', 'part_code' => '部件编号', 'part_name' => '部件名称', 'process_code' => '工序编号', 'process_name' => '工序名称', 'big_process' => '大工序', 'standard_hour' => '秒', 'standard_score' => '定额分', 'coefficient' => '难度系数', 'standard_minutes' => '分', 'money' => '金额', 'remark' => '备注', 'sys_id' => '操作人员', ]; $workorder = ''; $now = date('Y-m-d H:i:s'); $insertList = []; $processCodeMap = []; $newBatchStatus0Sum = 0; foreach ($processList as $index => $process) { $rowNo = $index + 1; if (!is_array($process)) { $this->error('第' . $rowNo . '条工艺数据格式错误'); } // foreach ($requiredFields as $field => $label) { // if (!isset($process[$field]) || $process[$field] === '' || $process[$field] === null) { // $this->error('第' . $rowNo . '条' . $label . '不能为空'); // } // } $itemWorkOrder = trim($process['work_order']); if ($workorder === '') { $workorder = $itemWorkOrder; } elseif ($itemWorkOrder !== $workorder) { $this->error('第' . $rowNo . '条工单编号与其它数据不一致'); } $processCode = (string)$process['process_code']; if (isset($processCodeMap[$processCode])) { $this->error('批量数据中存在重复的工序编号:' . $processCode); } $processCodeMap[$processCode] = true; $status = isset($process['status']) ? $process['status'] : 0; if (in_array($status, [0, '0'], true)) { $newBatchStatus0Sum += floatval($process['standard_score']); } $insertList[] = [ 'work_order' => $workorder, 'part_code' => $process['part_code'], 'part_name' => $process['part_name'], 'process_code' => $processCode, 'process_name' => $process['process_name'], 'big_process' => $process['big_process'], 'standard_hour' => $process['standard_hour'], 'standard_minutes' => $process['standard_minutes'], 'standard_score' => $process['standard_score'], 'coefficient' => $process['coefficient'], 'money' => $process['money'], 'remark' => $process['remark'], 'status' => $status, 'sys_id' => $process['sys_id'], 'sys_rq' => $now, ]; } $existingCodes = Db::table('工单_基础工艺资料') ->where('work_order', $workorder) ->whereIn('process_code', array_keys($processCodeMap)) ->whereNull('del_rq') ->column('process_code'); if (!empty($existingCodes)) { $this->error('工序编号已存在:' . $existingCodes[0]); } $workOrder = Db::table('工单_基本资料') ->where('订单编号', $workorder) ->where('Mod_rq', null) ->field('订单编号,计划制造工分') ->find(); if (empty($workOrder)) { $this->error('工单不存在'); } $existingTotal = Db::table('工单_基础工艺资料') ->where('work_order', $workorder) ->where('status', 0) ->whereNull('del_rq') ->sum('standard_score'); $existingTotal = $existingTotal ? floatval($existingTotal) : 0; if ($existingTotal + $newBatchStatus0Sum > floatval($workOrder['计划制造工分'])) { $this->error('工序定额分和大于制造工分,请确认之后再修改'); } Db::startTrans(); try { $insertResult = Db::name('工单_基础工艺资料')->insertAll($insertList); if ($insertResult === false || $insertResult === 0) { throw new \Exception('批量新增工序失败'); } Db::commit(); } catch (\think\exception\HttpResponseException $e) { throw $e; } catch (\Exception $e) { Db::rollback(); $this->error('批量新增工序资料失败'); } $this->success('批量新增工序资料成功', ['count' => count($insertList)]); } /** * 解析批量工序请求体(form 数组 / JSON 数组 / 单字段 JSON 字符串) * @return array */ private function parseBatchProcessList() { $params = $this->request->post(); if (isset($params[0]) && is_array($params[0])) { return $params; } $decoded = json_decode($this->request->getInput(), true); if (is_array($decoded) && isset($decoded[0]) && is_array($decoded[0])) { return $decoded; } $jsonStr = is_string($params) ? $params : (count($params) === 1 ? reset($params) : null); if (is_string($jsonStr)) { $decoded = json_decode($jsonStr, true); return is_array($decoded) ? $decoded : []; } return []; } /** * 工序产量核查:按工单查询报工汇总(工单信息 / 工序列表 / 人员报工明细) * @param workorder 工单编号 * @return array */ public function checkProcessProduction() { if (!$this->request->isGet()) { $this->error('请求方法错误'); } $params = $this->request->param(); if (empty($params['workorder'])) { $this->error('工单编号不能为空'); } $list = Db::name('设备_工分计酬')->alias('a') ->join('工单_基本资料 b', 'a.work_order = b.订单编号 AND b.Mod_rq IS NULL', 'LEFT') ->where('a.work_order', $params['workorder']) ->whereNull('a.del_rq') ->field('b.订单编号,b.生产款号,b.款式,a.process_code as 工序号,a.process_name as 工序名称,a.staff_name as 员工姓名, SUM(a.number) as 数量,MIN(a.date) as 开工日期,MAX(a.date) as 完工日期, SUM(a.standard_score) as 工分,SUM(a.production_score) as 工时,SUM(a.salary) as 工资') ->group('b.订单编号,b.生产款号,b.款式,a.process_code,a.process_name,a.staff_no,a.staff_name') ->order('a.process_code asc,a.staff_no asc') ->select(); if (empty($list)) { $this->error('未找到报工数据'); } $data = [ '订单编号' => $list[0]['订单编号'], '生产款号' => $list[0]['生产款号'], '款式' => $list[0]['款式'], '工序列表' => [], ]; $processMap = []; foreach ($list as $row) { $processKey = (string)$row['工序号'] . '|' . (string)$row['工序名称']; if (!isset($processMap[$processKey])) { $processMap[$processKey] = [ '工序号' => $row['工序号'], '工序名称' => $row['工序名称'], 'staffs' => [], ]; } $startDate = !empty($row['开工日期']) ? date('Y-m-d', strtotime($row['开工日期'])) : ''; $endDate = !empty($row['完工日期']) ? date('Y-m-d', strtotime($row['完工日期'])) : ''; $processMap[$processKey]['staffs'][] = [ '员工姓名' => $row['员工姓名'], '数量' => floatval($row['数量']), '开工日期' => $startDate, '完工日期' => $endDate, '工分' => round(floatval($row['工分']), 4), '工时' => round(floatval($row['工时']), 4), '工资' => round(floatval($row['工资']), 4), ]; } $data['工序列表'] = array_values($processMap); $this->success('成功', $data); } }