Browse Source

Merge branch 'master' of https://git.7in6.com/liuhairui/mes-dc-server-api

zck 2 weeks ago
parent
commit
b20dd55460

+ 0 - 678
application/api/controller/EmployeeDailySalary.php

@@ -1,678 +0,0 @@
-<?php
-
-namespace app\api\controller;
-
-use app\common\controller\Api;
-use \think\Request;
-use \think\Db;
-/**
- * 员工日工资查询接口
- */
-class EmployeeDailySalary extends Api
-{
-    protected $noNeedLogin = ['*'];
-    protected $noNeedRight = ['*'];
-
-    /**
-     * 首页
-     *
-     */
-    public function index()
-    {
-        $this->success('请求成功');
-    }
-
-    /**
-     * 员工日工资查询侧边栏
-     * @ApiMethod (GET)
-     */
-    public function getTab()
-    {
-        //get请求
-        if(!$this->request->isGet()){
-            $this->error('请求方式错误');
-        }
-        $res=db('绩效工资汇总')
-            ->field('DATE_FORMAT(`sczl_rq`, "%Y%m") as sys_ny,bh')
-            ->group('DATE_FORMAT(`sczl_rq`, "%Y%m"),bh')
-            ->whereTime('sczl_rq', '>=', strtotime('-14 months'))
-            ->where('bh','<>','000000')
-            ->order('sczl_rq desc')
-            ->select();
-        foreach($res as $v){
-            $arr[$v['sys_ny'].'-'][]=$v['bh'];
-        }
-        $rs = db('人事_基本资料')->column('员工编号,所在部门');
-        foreach($arr as $k=>$v){
-            foreach($v as $key=>$value){
-                if(array_key_exists($value,$rs)){
-                    $data[$k][$key]=rtrim($rs[$value]);
-                }
-            }
-            $data[$k]=array_unique($data[$k]);
-            usort($data[$k], function($a, $b) {
-                $order = array(
-                    '胶印车间',
-                    '凹印车间',
-                    '丝印车间',
-                    '模切车间',
-                    '检验车间',
-                    '精品试验车间',
-                    '品保部',
-                    '人力资源部',
-                    '生产部',
-                    '营销部'
-                );
-                $a_index = array_search($a, $order);
-                $b_index = array_search($b, $order);
-                return $a_index - $b_index;
-            });
-        }
-        $i=0;
-        foreach($data as $k=>$v){
-            $datas[$i]['label']=str_replace('-','',$k);
-            foreach($v as $value){
-                $datas[$i]['children'][]['label']=$value;
-            }
-            $i++;
-        }
-        $this->success('成功',$datas);
-    }
-    
-
-    /**
-     * 员工日工资查询上侧列表
-     * @ApiMethod (GET)
-     * @param string $date 年月
-     * @param string $department 部门
-     */
-    public function getList()
-    {
-        //get请求
-        if(!$this->request->isGet()){
-            $this->error('请求方式错误');
-        }
-        $req = $this->request->param();
-        //获取工资汇总表数据
-        $res=db('绩效工资汇总')
-            ->join('人事_基本资料','人事_基本资料.员工编号=绩效工资汇总.bh')
-            ->group('绩效工资汇总.bh,LEFT(sczl_rq, 10)')
-            ->where('sys_ny',$req['date'])
-            ->where(['人事_基本资料.所在部门'=>['like',$req['department'].'%']])
-            ->column('CONCAT(bh, "-", DATE_FORMAT(sczl_rq,"%Y.%m.%d")) AS rq_bh,bh,rtrim(xm) as 员工姓名,DATE_FORMAT(sczl_rq,"%Y.%m.%d") as sczl_rq,sum(个人计件工资) as 计件工资,
-            sum(个人加班工资) as 加班工资,sum(异常停机工时) as 计时时数');
-
-        $year=substr($req['date'],0,4);
-        $month=substr($req['date'],-2);
-        $start_time = $year . '-' . $month . '-01 00:00:00';
-        $end_time = date('Y-m-t', strtotime("$year-$month-01")) . ' 23:59:59';
-        
-        //查询wgjs表获取数据,以供后续计算
-        $arr = [];
-        $columns = ['wgjs_bh1', 'wgjs_bh2', 'wgjs_bh3', 'wgjs_bh4', 'wgjs_bh5', 'wgjs_bh6'];
-        for ($i = 1; $i <= 6; $i++) {
-            $column = $columns[$i-1];
-            $r = db('db_wgjs')
-                ->field("DATE_FORMAT(wgjs_rq,'%Y.%m.%d') as wgjs_rq, $column as wgjs_bh, trim(员工姓名) as 员工姓名, wgjs_js$i as wgjs_js, wgjs_冲定额$i as wgjs_冲定额")
-                ->join('人事_基本资料', "人事_基本资料.员工编号=db_wgjs.$column")
-                ->where(['wgjs_rq' => ['between', "$start_time,$end_time"], '人事_基本资料.所在部门' => ['like', $req['department'] . '%']])
-                ->select();
-
-            $arr = array_merge($arr, $r);
-        }
-        
-        //计算wgjs总计时时数
-        $list = [];
-        foreach($arr as $v){
-            if(isset($list[$v['wgjs_bh'].'-'.$v['wgjs_rq']])){
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计时时数']+=$v['wgjs_js'];
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计时工资']=floatval(number_format($list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计时时数']*10,2, '.', ''));
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['日工资合计']=floatval(number_format($list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计时时数']*10,2, '.', ''));
-            }else{
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['bh']=$v['wgjs_bh'];
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['员工姓名']=$v['员工姓名'];
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['sczl_rq']=$v['wgjs_rq'];
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计件工资']=0;
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['加班工资']=0;
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计时时数']=$v['wgjs_js'];
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计时工资']=floatval(number_format($v['wgjs_js']*10,2, '.', ''));
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['日工资合计']=floatval(number_format($v['wgjs_js']*10,2, '.', ''));
-            }
-        };
-
-        //计算当月冲定额时长
-        $list1 = [];
-        foreach($arr as $v){
-            if(isset($list1[$v['wgjs_bh']])){
-                if($v['wgjs_冲定额']=='是'){
-                    $list1[$v['wgjs_bh']]['计时时数']+=$v['wgjs_js'];
-                }
-            }else{
-                if($v['wgjs_冲定额']=='是'){
-                    $list1[$v['wgjs_bh']]['计时时数']=$v['wgjs_js'];
-                }else{
-                    $list1[$v['wgjs_bh']]['计时时数']=0;
-                }
-            }
-        };
-
-        //获取每个员工计时补差天数
-        $arr1 = db('绩效工资汇总')->alias('j')
-            ->field('j.bh,j.sczl_rq')
-            ->join('人事_基本资料 r','r.员工编号=j.bh')
-            ->group('j.bh,j.sczl_rq')
-            ->where('j.sys_ny',$req['date'])
-            // ->where('j.达标定额','<>',0)
-            ->where(['r.所在部门'=>['like',$req['department'].'%']])
-            ->buildSql();
-        $arr1 = db()->table($arr1 . ' t')
-            ->group('t.bh, LEFT(t.sczl_rq, 7)')
-            ->column('t.bh,count(LEFT(t.sczl_rq, 7)) as num');
-
-        //查询该员工当月停机工时
-        $res1=db('绩效工资汇总')
-            ->join('人事_基本资料','人事_基本资料.员工编号=绩效工资汇总.bh')
-            ->group('绩效工资汇总.bh,LEFT(sczl_rq, 7)')
-            ->where('sys_ny',$req['date'])
-            ->where(['人事_基本资料.所在部门'=>['like',$req['department'].'%']])
-            ->column('bh,rtrim(xm) as 员工姓名,DATE_FORMAT(sczl_rq,"%Y.%m.%d") as sczl_rq,
-            sum(异常停机工时) as 计时时数');
-
-        //查询每条记录
-        $arr2 = db('绩效工资汇总')->alias('j')
-            ->field('j.bh, DATE_FORMAT(j.sczl_rq,"%Y.%m.%d") as sczl_rq,
-            sum(j.达标定额) as 达标定额, j.Rate, j.千件工价, sum(j.异常停机工时) as 异常停机工时')
-            ->join('人事_基本资料 r','r.员工编号=j.bh')
-            ->where('j.sys_ny',$req['date'])
-            // ->where('j.达标定额','<>',0)
-            ->where(['r.所在部门'=>['like',$req['department'].'%']])
-            ->group('j.bh,j.sczl_rq,j.sczl_gdbh')
-            ->select();
-        //计算每条记录的计时补差
-        $brr = [];
-        foreach($arr2 as $v){
-            $yjsss1 = array_key_exists($v['bh'],$list1) ? $list1[$v['bh']]['计时时数'] : 0;
-            $yjsss2 = array_key_exists($v['bh'],$res1) ? $res1[$v['bh']]['计时时数'] : 0;
-            $yjsss = $yjsss1 + $yjsss2;
-
-            $a = $yjsss/$arr1[$v['bh']]/11*0.6*$v['达标定额']*$v['Rate']*0.5/1000*$v['千件工价'];
-                
-            if(array_key_exists($v['bh'].'-'.$v['sczl_rq'],$brr)){
-                $brr[$v['bh'].'-'.$v['sczl_rq']] += $a;
-            }else{
-                $brr[$v['bh'].'-'.$v['sczl_rq']] = $a;
-            }
-        }
-
-        //工资汇总表和wgjs表中共有数据汇总 
-        foreach($res as $k=>&$v){
-            if(array_key_exists($k,$list)){
-                $v['计时时数'] += $list[$k]['计时时数'];
-                unset($list[$k]);
-            }
-            $v['计时工资'] = array_key_exists($k,$brr) ? floatval(number_format($v['计时时数']*10+$brr[$k],2, '.', '')) : floatval(number_format($v['计时时数']*10,2, '.', ''));
-            $v['日工资合计'] = floatval(number_format($v['计件工资'] + $v['加班工资'] + $v['计时工资'],2, '.', ''));
-            
-            unset($v['rq_bh']);
-        }
-
-        //工资汇总表和wgjs表中不共有数据合并 
-        $rows = array_merge($res,$list);
-        ksort($rows);
-        $rows = array_values($rows);
-        $this->success('成功',$rows);
-    }
-    /**
-     * 员工日工资查询下侧列表
-     * @ApiMethod (GET)
-     * @param string $date 年月
-     * @param string $code 员工编号
-     */
-    public function getAllList()
-    {
-        //get请求
-        if(!$this->request->isGet()){
-            $this->error('请求方式错误');
-        }
-        $req = $this->request->param();
-        $res = db('绩效工资汇总')
-            ->field('LEFT(sczl_rq, 10) as sczl_rq, sczl_gdbh, rtrim(g.yj_yjmc) as Gd_cpmc, 
-            sczl_yjno, sczl_gxh, sczl_type, sczl_jtbh,sum(班组车头产量) as 班组车头产量, 
-            sum(班组换算产量) as 班组换算产量, 工序难度系数, sum(个人计件工资) as 个人计件工资,
-            sum(个人加班工资) as 个人加班工资, sum(装版工时) as 装版工时, 
-            sum(保养工时) as 保养工时, sum(打样工时) as 打样工时, 
-            sum(异常停机工时) as 异常停机工时, sum(车头产量占用机时) as 车头产量占用机时, 日定额,
-            sum(达标定额) as 达标定额, 千件工价, 补产标准, bh, rtrim(xm) as xm, Rate')
-            ->join('工单_印件资料 g','g.Yj_Gdbh = 绩效工资汇总.sczl_gdbh AND g.yj_Yjno = 绩效工资汇总.sczl_yjno','LEFT')
-            ->group('LEFT(sczl_rq, 10),sczl_gdbh,CONCAT(sczl_yjno, "-", sczl_gxh, "-", sczl_type),千件工价')
-            ->where(['sys_ny'=>$req['date'],'bh'=>$req['code']])
-            ->select();
-        if(!$res){
-            $this->error('失败');
-        }
-        foreach($res as &$v){
-            $v['sczl_rq']=str_replace('-','.',$v['sczl_rq']);
-            if($v['sczl_yjno']>9){
-                $sczl_yjno=$v['sczl_yjno'];
-            }else{
-                $sczl_yjno='0'.$v['sczl_yjno'];
-            }
-            unset($v['sczl_yjno']);
-            if($v['sczl_gxh']>9){
-                $sczl_gxh=$v['sczl_gxh'];
-            }else{
-                $sczl_gxh='0'.$v['sczl_gxh'];
-            }
-            unset($v['sczl_gxh']);
-            $v['sczl_type']=$sczl_yjno.'-'.$sczl_gxh.'-->'.$v['sczl_type'];
-        }
-        $this->success('成功',$res);
-    }
-     /**
-     * 员工日工资查询详情
-     * @ApiMethod (GET)
-     * @param string $date 日期
-     * @param string $code 员工编号
-     */
-    public function getDetail()
-    {
-        //get请求
-        if(!$this->request->isGet()){
-            $this->error('请求方式错误');
-        }
-        $req = $this->request->param();
-        $start_time=$req['date'].' 00:00:00';
-        $end_time=$req['date'].' 23:59:59';
-        $res=db('绩效工资汇总')
-            ->field('LEFT(sczl_rq, 10) as sczl_rq,sczl_gdbh,rtrim(g.yj_yjmc) as Gd_cpmc,sczl_yjno,sczl_gxh,sczl_type,
-            sczl_jtbh,sum(班组车头产量) as 班组车头产量,sum(班组换算产量) as 班组换算产量,工序难度系数,sum(个人计件工资)
-            as 个人计件工资,sum(个人加班工资) as 个人加班工资,sum(装版工时) as 装版工时,sum(保养工时) as 保养工时,
-            sum(打样工时) as 打样工时,sum(异常停机工时) as 异常停机工时,sum(车头产量占用机时) as 车头产量占用机时,日定额,
-            sum(达标定额) as 达标定额,千件工价,补产标准,bh,rtrim(xm) as xm,Rate')
-            ->join('工单_印件资料 g','g.Yj_Gdbh = 绩效工资汇总.sczl_gdbh AND g.yj_Yjno = 绩效工资汇总.sczl_yjno','LEFT')
-            ->group('LEFT(sczl_rq, 10),sczl_gdbh')
-            ->where(['sczl_rq'=>['between',"$start_time,$end_time"],'bh'=>$req['code']])
-            ->select();
-        if(!$res){
-            $this->error('失败');
-        }
-        foreach($res as &$v){
-            $v['sczl_rq']=str_replace('-','.',$v['sczl_rq']);
-            if($v['sczl_yjno']>9){
-                $sczl_yjno=$v['sczl_yjno'];
-            }else{
-                $sczl_yjno='0'.$v['sczl_yjno'];
-            }
-            unset($v['sczl_yjno']);
-            if($v['sczl_gxh']>9){
-                $sczl_gxh=$v['sczl_gxh'];
-            }else{
-                $sczl_gxh='0'.$v['sczl_gxh'];
-            }
-            unset($v['sczl_gxh']);
-            $v['sczl_type']=$sczl_yjno.'-'.$sczl_gxh.'-->'.$v['sczl_type'];
-        }
-        $this->success('成功',$res);
-    }
-    /**
-     * 定位
-     * @ApiMethod GET
-    */
-    public function search(){
-        
-        //get请求
-        if(!$this->request->isGet()){
-            $this->error('请求方式错误');
-        }
-        $req = $this->request->param();
-        $yg = db('人事_基本资料')->where('员工姓名',$req['search'])->value('员工编号');
-        if($yg){
-            $req['search']=$yg;
-        }
-        $res=db('绩效工资汇总')
-            ->join('人事_基本资料','人事_基本资料.员工编号=绩效工资汇总.bh')
-            ->group('绩效工资汇总.bh,LEFT(sczl_rq, 10)')
-            ->where('sys_ny',$req['date'])
-            ->where('bh',$req['search'])
-            // ->where(['人事_基本资料.所在部门'=>['like',$req['department'].'%']])
-            ->column('CONCAT(bh, "-", DATE_FORMAT(sczl_rq,"%Y.%m.%d")) AS rq_bh,bh,rtrim(xm) as 员工姓名,DATE_FORMAT(sczl_rq,"%Y.%m.%d") as sczl_rq,sum(个人计件工资) as 计件工资,
-            sum(个人加班工资) as 加班工资,sum(异常停机工时) as 计时时数');
-
-        $year=substr($req['date'],0,4);
-        $month=substr($req['date'],-2);
-        $start_time = $year . '-' . $month . '-01 00:00:00';
-        $end_time = date('Y-m-t', strtotime("$year-$month-01")) . ' 23:59:59';
-        
-        $arr = [];
-        $columns = ['wgjs_bh1', 'wgjs_bh2', 'wgjs_bh3', 'wgjs_bh4', 'wgjs_bh5', 'wgjs_bh6'];
-        for ($i = 1; $i <= 6; $i++) {
-            $column = $columns[$i-1];
-            $r = db('db_wgjs')
-                ->field("DATE_FORMAT(wgjs_rq,'%Y.%m.%d') as wgjs_rq, $column as wgjs_bh, trim(员工姓名) as 员工姓名, wgjs_js$i as wgjs_js, wgjs_冲定额$i as wgjs_冲定额")
-                ->join('人事_基本资料', "人事_基本资料.员工编号=db_wgjs.$column")
-                ->where($column,$req['search'])
-                ->where(['wgjs_rq' => ['between', "$start_time,$end_time"]])
-                ->select();
-
-            $arr = array_merge($arr, $r);
-        }
-        
-        $list = [];
-        foreach($arr as $v){
-            if(isset($list[$v['wgjs_bh'].'-'.$v['wgjs_rq']])){
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计时时数']+=$v['wgjs_js'];
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计时工资']=floatval(number_format($list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计时时数']*10,2, '.', ''));
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['日工资合计']=floatval(number_format($list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计时时数']*10,2, '.', ''));
-            }else{
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['bh']=$v['wgjs_bh'];
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['员工姓名']=$v['员工姓名'];
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['sczl_rq']=$v['wgjs_rq'];
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计件工资']=0;
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['加班工资']=0;
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计时时数']=$v['wgjs_js'];
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['计时工资']=floatval(number_format($v['wgjs_js']*10,2, '.', ''));
-                $list[$v['wgjs_bh'].'-'.$v['wgjs_rq']]['日工资合计']=floatval(number_format($v['wgjs_js']*10,2, '.', ''));
-            }
-        };
-        $list1 = [];
-        foreach($arr as $v){
-            if(isset($list1[$v['wgjs_bh']])){
-                if($v['wgjs_冲定额']=='是'){
-                    $list1[$v['wgjs_bh']]['计时时数']+=$v['wgjs_js'];
-                }
-            }else{
-                if($v['wgjs_冲定额']=='是'){
-                    $list1[$v['wgjs_bh']]['计时时数']=$v['wgjs_js'];
-                }else{
-                    $list1[$v['wgjs_bh']]['计时时数']=0;
-                }
-            }
-        };
-
-        //获取每个员工计时补差天数
-        $arr1 = db('绩效工资汇总')->alias('j')
-            ->field('j.bh,j.sczl_rq')
-            ->join('人事_基本资料 r','r.员工编号=j.bh')
-            ->group('j.bh,j.sczl_rq')
-            ->where('j.sys_ny',$req['date'])
-            // ->where('j.达标定额','<>',0)
-            ->where('j.bh',$req['search'])
-            // ->where(['r.所在部门'=>['like',$req['department'].'%']])
-            ->buildSql();
-        $arr1 = db()->table($arr1 . ' t')
-            ->group('t.bh, LEFT(t.sczl_rq, 7)')
-            ->column('t.bh,count(LEFT(t.sczl_rq, 7)) as num');
-
-        //查询该员工当月停机工时
-        $res1=db('绩效工资汇总')
-            ->join('人事_基本资料','人事_基本资料.员工编号=绩效工资汇总.bh')
-            ->group('绩效工资汇总.bh,LEFT(sczl_rq, 7)')
-            ->where('sys_ny',$req['date'])
-            ->where('bh',$req['search'])
-            // ->where(['人事_基本资料.所在部门'=>['like',$req['department'].'%']])
-            ->column('bh,rtrim(xm) as 员工姓名,DATE_FORMAT(sczl_rq,"%Y.%m.%d") as sczl_rq,
-            sum(异常停机工时) as 计时时数');
-
-        //查询每条记录
-        $arr2 = db('绩效工资汇总')->alias('j')
-            ->field('j.bh, DATE_FORMAT(j.sczl_rq,"%Y.%m.%d") as sczl_rq,
-            sum(j.达标定额) as 达标定额, j.Rate, j.千件工价, sum(j.异常停机工时) as 异常停机工时')
-            ->join('人事_基本资料 r','r.员工编号=j.bh')
-            ->where('j.sys_ny',$req['date'])
-            // ->where('j.达标定额','<>',0)
-            ->where('j.bh',$req['search'])
-            // ->where(['r.所在部门'=>['like',$req['department'].'%']])
-            ->group('j.bh,j.sczl_rq,j.sczl_gdbh')
-            ->select();
-        //计算每条记录的计时补差
-        $brr = [];
-        foreach($arr2 as $v){
-            $yjsss1 = array_key_exists($v['bh'],$list1) ? $list1[$v['bh']]['计时时数'] : 0;
-            $yjsss2 = array_key_exists($v['bh'],$res1) ? $res1[$v['bh']]['计时时数'] : 0;
-            $yjsss = $yjsss1 + $yjsss2;
-
-            $a = $yjsss/$arr1[$v['bh']]/11*0.6*$v['达标定额']*$v['Rate']*0.5/1000*$v['千件工价'];
-                
-            if(array_key_exists($v['bh'].'-'.$v['sczl_rq'],$brr)){
-                $brr[$v['bh'].'-'.$v['sczl_rq']] += $a;
-            }else{
-                $brr[$v['bh'].'-'.$v['sczl_rq']] = $a;
-            }
-        }
-
-        foreach($res as $k=>&$v){
-            if(array_key_exists($k,$list)){
-                $v['计时时数'] += $list[$k]['计时时数'];
-                unset($list[$k]);
-            }
-            $v['计时工资'] = array_key_exists($k,$brr) ? floatval(number_format($v['计时时数']*10+$brr[$k],2, '.', '')) : floatval(number_format($v['计时时数']*10,2, '.', ''));
-            $v['日工资合计'] = floatval(number_format($v['计件工资'] + $v['加班工资'] + $v['计时工资'],2, '.', ''));
-            
-            unset($v['rq_bh']);
-        }
-
-        $rows = array_merge($res,$list);
-        ksort($rows);
-        $rows = array_values($rows);
-        $this->success('成功',$rows);
-    }
-     /**
-     * 员工计件明细
-     * @ApiMethod (GET)
-     * @param string $start_time
-     * @param string $end_time
-     * @param string $code 员工编号
-     */
-    public function getPieceDetail()
-    {
-        //get请求
-        if(!$this->request->isGet()){
-            $this->error('请求方式错误');
-        }
-        $req = $this->request->param();
-        $req['start_time']=str_replace('.','-',$req['start_time']);
-        $req['end_time']=str_replace('.','-',$req['end_time']);
-        $start_time=$req['start_time'].' 00:00:00';
-        $end_time=$req['end_time'].' 23:59:59';
-        $res=db('绩效工资汇总')
-           ->field('LEFT(sczl_rq, 10) as sczl_rq,sczl_gdbh,rtrim(g.员工姓名) as 员工资料,sczl_yjno,sczl_gxh,sczl_type,
-            sczl_jtbh,班组车头产量,保养工时,装版工时,打样工时,异常停机工时,补产标准,计时补差额工资 as 班组补产,日定额,达标定额,千件工价,
-            个人计件工资,个人加班工资,Rate as 个人比例')
-            ->join('人事_基本资料 g','人事_基本资料.员工编号=绩效工资汇总.bh','LEFT')
-            ->where(['sczl_rq'=>['between',"$start_time,$end_time"],'bh'=>$req['code']])
-            ->select();
-        if(!$res){
-            $this->error('失败');
-        }
-        foreach($res as &$v){
-            $v['sczl_rq']=str_replace('-','.',$v['sczl_rq']);
-            if($v['sczl_yjno']>9){
-                $sczl_yjno=$v['sczl_yjno'];
-            }else{
-                $sczl_yjno='0'.$v['sczl_yjno'];
-            }
-            unset($v['sczl_yjno']);
-            if($v['sczl_gxh']>9){
-                $sczl_gxh=$v['sczl_gxh'];
-            }else{
-                $sczl_gxh='0'.$v['sczl_gxh'];
-            }
-            unset($v['sczl_gxh']);
-            $v['sczl_type']=$sczl_yjno.'-'.$sczl_gxh.'-->'.$v['sczl_type'];
-            $v['班组补产']=$v['补产标准']*($v['保养工时']+$v['装版工时']+$v['打样工时']+$v['异常停机工时']);
-        }
-        $this->success('成功',$res);
-    }
-     /**
-     * 每日工资统计
-     * @ApiMethod (GET)
-     * @param string $date 年月
-     * @param string $department 部门
-     */
-    public function statistics()
-    {
-        //get请求
-        if(!$this->request->isGet()){
-            $this->error('请求方式错误');
-        }
-        $req = $this->request->param();
-        $res=db('绩效工资汇总')
-            ->join('人事_基本资料','人事_基本资料.员工编号=绩效工资汇总.bh','LEFT')
-            ->field('bh,rtrim(xm) as 员工姓名,LEFT(sczl_rq, 10) as sczl_rq,sum(个人计件工资) as 计件工资,
-            sum(个人加班工资) as 加班工资')
-            ->group('绩效工资汇总.bh,LEFT(sczl_rq, 10)')
-            ->where('sys_ny',$req['date'])
-            ->where(['人事_基本资料.所在部门'=>['like',$req['department'].'%']])
-            ->select();
-        if(!$res){
-            $this->error('失败');
-        }
-        $year=substr($req['date'],0,4);
-        $month=substr($req['date'],-2);
-        $start_time = $year . '-' . $month . '-01 00:00:00';
-        $end_time = date('Y-m-t', strtotime("$year-$month-01")) . ' 23:59:59';
-        $res1=db('db_wgjs')->cache(true,86400)
-        ->field('LEFT(wgjs_rq, 10) as wgjs_rq,wgjs_bh1 as wgjs_bh,wgjs_js1 as wgjs_js')
-        ->join('人事_基本资料','人事_基本资料.员工编号=db_wgjs.wgjs_bh1','LEFT')
-        ->where(['wgjs_rq'=>['between',"$start_time,$end_time"],'人事_基本资料.所在部门'=>['like',$req['department'].'%']])
-        ->select();
-        $res2=db('db_wgjs')->cache(true,86400)
-        ->field('LEFT(wgjs_rq, 10) as wgjs_rq,wgjs_bh2 as wgjs_bh,wgjs_js2 as wgjs_js')
-        ->join('人事_基本资料','人事_基本资料.员工编号=db_wgjs.wgjs_bh2','LEFT')
-        ->where(['wgjs_rq'=>['between',"$start_time,$end_time"],'人事_基本资料.所在部门'=>['like',$req['department'].'%']])
-        ->select();
-        $res3=db('db_wgjs')->cache(true,86400)
-        ->field('LEFT(wgjs_rq, 10) as wgjs_rq,wgjs_bh3 as wgjs_bh,wgjs_js3 as wgjs_js')
-        ->join('人事_基本资料','人事_基本资料.员工编号=db_wgjs.wgjs_bh3','LEFT')
-        ->where(['wgjs_rq'=>['between',"$start_time,$end_time"],'人事_基本资料.所在部门'=>['like',$req['department'].'%']])
-        ->select();
-        $res4=db('db_wgjs')->cache(true,86400)
-        ->field('LEFT(wgjs_rq, 10) as wgjs_rq,wgjs_bh4 as wgjs_bh,wgjs_js4 as wgjs_js')
-        ->join('人事_基本资料','人事_基本资料.员工编号=db_wgjs.wgjs_bh4','LEFT')
-        ->where(['wgjs_rq'=>['between',"$start_time,$end_time"],'人事_基本资料.所在部门'=>['like',$req['department'].'%']])
-        ->select();
-        $res5=db('db_wgjs')->cache(true,86400)
-        ->field('LEFT(wgjs_rq, 10) as wgjs_rq,wgjs_bh5 as wgjs_bh,wgjs_js5  as wgjs_js')
-        ->join('人事_基本资料','人事_基本资料.员工编号=db_wgjs.wgjs_bh5','LEFT')
-        ->where(['wgjs_rq'=>['between',"$start_time,$end_time"],'人事_基本资料.所在部门'=>['like',$req['department'].'%']])
-        ->select();
-        $res6=db('db_wgjs')->cache(true,86400)
-        ->field('LEFT(wgjs_rq, 10) as wgjs_rq,wgjs_bh6 as wgjs_bh,wgjs_js6 as wgjs_js')
-        ->join('人事_基本资料','人事_基本资料.员工编号=db_wgjs.wgjs_bh6','LEFT')
-        ->where(['wgjs_rq'=>['between',"$start_time,$end_time"],'人事_基本资料.所在部门'=>['like',$req['department'].'%']])
-        ->select();
-        $arr=array_merge($res1,$res2,$res3,$res4,$res5,$res6);
-        foreach($arr as $v){
-            if(isset($list[$v['wgjs_rq']][$v['wgjs_bh']])){
-                $list[$v['wgjs_rq']][$v['wgjs_bh']]+=$v['wgjs_js'];
-            }else{
-                $list[$v['wgjs_rq']][$v['wgjs_bh']]=$v['wgjs_js'];
-            }
-        }
-        foreach($res as &$v){
-            if(isset($list[$v['sczl_rq']][$v['bh']])){
-                $v['计时工资']=$list[$v['sczl_rq']][$v['bh']];
-            }else{
-                $v['计时工资']='';
-            } 
-            $v['部门']=$req['department']; 
-            $v['sczl_rq']=str_replace('-','.',$v['sczl_rq']);
-        }
-        $this->success('成功',$res);
-    }
-       /**
-     * 月度计时工资调整
-     * @ApiMethod (GET)
-     * @param string $date 年月
-     * @param string $code 员工编号
-     */
-    public function wageAdjustment()
-    {
-        //get请求
-        if(!$this->request->isGet()){
-            $this->error('请求方式错误');
-        }
-        $req = $this->request->param();
-        $res=db('绩效加班工资月度修正')->cache(true,86400)
-            ->field('人事_基本资料.所在部门,bh,rtrim(xm) as xm,月计时时数,DATE_FORMAT(sczl_rq,"%Y.%m.%d") as sczl_rq,sczl_gdbh,sczl_yjno,sczl_gxh,
-            千件工价,Rate,sum(达标定额) as 达标定额,sum(个人计件工资) as 个人计件工资,sum(个人加班工资) as 个人加班工资,计时冲定额,sum(New_计件工资) as
-            New_计件工资,sum(New_加班工资) as New_加班工资,调整量_合计')
-            ->join('人事_基本资料','人事_基本资料.员工编号=绩效加班工资月度修正.bh','LEFT')
-            ->group('LEFT(sczl_rq, 10),sczl_gdbh')
-            ->where(['sys_ny'=>$req['date'],'bh'=>$req['code']])
-            ->select();
-        if(!$res){
-            $this->error('失败');
-        }
-        foreach($res as &$v){
-            if($v['sczl_yjno']>9){
-                $sczl_yjno=$v['sczl_yjno'];
-            }else{
-                $sczl_yjno='0'.$v['sczl_yjno'];
-            }
-            unset($v['sczl_yjno']);
-            if($v['sczl_gxh']>9){
-                $sczl_gxh=$v['sczl_gxh'];
-            }else{
-                $sczl_gxh='0'.$v['sczl_gxh'];
-            }
-            unset($v['sczl_gxh']);
-            $v['sczl_gdbh']=$v['sczl_gdbh'].'-'.$sczl_yjno.'-'.$sczl_gxh;
-            $v['bh']=$v['bh'].' '.$v['xm'];
-            unset($v['xm']); 
-        }
-        $this->success('成功',$res);
-    }
-
-    /**
-     * 员工工资明细查询
-     * @ApiMethod (GET)
-     * @param string $date 年月
-     * @param string $code 员工编号
-     */
-    public function getGzByYgbh()
-    {
-        //get请求
-        if(!$this->request->isGet()){
-            $this->error('请求方式错误');
-        }
-        $req = $this->request->param();
-        $res = db('绩效工资汇总')
-            ->field('LEFT(sczl_rq, 10) as sczl_rq, sczl_gdbh, rtrim(g.yj_yjmc) as Gd_cpmc, 
-            sczl_yjno, sczl_gxh, sczl_type, sczl_jtbh,班组车头产量, 
-            班组车头产量*工序难度系数 as 计件产量,
-            班组换算产量 as 补产产量,
-            (班组车头产量*工序难度系数+班组换算产量) as 核算产量,
-            工序难度系数, 个人计件工资,
-            个人加班工资, 装版工时, 
-            保养工时, 打样工时, 
-            异常停机工时, 车头产量占用机时, 日定额,
-            达标定额, 千件工价, 补产标准, bh, rtrim(xm) as xm, Rate')
-            ->join('工单_印件资料 g','g.Yj_Gdbh = 绩效工资汇总.sczl_gdbh AND g.yj_Yjno = 绩效工资汇总.sczl_yjno','LEFT')
-            ->where(['sys_ny'=>$req['date'],'bh'=>$req['code']])
-            ->select();
-        if($res===false){
-            $this->error('失败');
-        }
-        foreach($res as &$v){
-            $v['sczl_rq']=str_replace('-','.',$v['sczl_rq']);
-            if($v['sczl_yjno']>9){
-                $sczl_yjno=$v['sczl_yjno'];
-            }else{
-                $sczl_yjno='0'.$v['sczl_yjno'];
-            }
-            unset($v['sczl_yjno']);
-            if($v['sczl_gxh']>9){
-                $sczl_gxh=$v['sczl_gxh'];
-            }else{
-                $sczl_gxh='0'.$v['sczl_gxh'];
-            }
-            $v['计件产量'] = floatval(number_format($v['计件产量'], 2, '.', ''));
-            $v['核算产量'] = floatval(number_format($v['核算产量'], 2, '.', ''));
-            unset($v['sczl_gxh']);
-            $v['sczl_type']=$sczl_yjno.'-'.$sczl_gxh.'-->'.$v['sczl_type'];
-        }
-        $this->success('成功',$res);
-    }
-
-}

+ 38 - 33
application/api/controller/Manufacture.php

@@ -1186,7 +1186,7 @@ class Manufacture extends Api
         // 设置查询条件
         $where = [
             'Mod_rq' => null,
-            '订单编号|生产款号' => ['like', '%' . $param['search'] . '%'],
+            '订单编号|生产款号|客户编号|款式' => ['like', '%' . $param['search'] . '%'],
         ];
 
         $page = isset($param['page']) ? $param['page'] : 1;
@@ -1202,21 +1202,20 @@ class Manufacture extends Api
         // 获取总记录数
         $count = \db('工单_基本资料')
             ->where($where)
-            ->count();  // 使用 count() 方法优化
+            ->count();
+
         $orderIds = array_column($list, '订单编号');
 
-        // 合并查询相关附件
+        // ========== 1. 批量查询附件数据 ==========
         $relatedOrders = \db('工单_相关附件')
             ->whereIn('关联编号', $orderIds)
             ->whereIn('附件备注', ['技术附件', '订单资料附件'])
             ->column('关联编号,附件备注');
 
-        // 重新组织附件数据
         $groupedRelatedOrders = [
             'technical' => [],
-            'order' => []
+            'order'     => []
         ];
-
         foreach ($relatedOrders as $orderNumber => $attachmentRemark) {
             if ($attachmentRemark === '技术附件') {
                 $groupedRelatedOrders['technical'][] = $orderNumber;
@@ -1225,56 +1224,62 @@ class Manufacture extends Api
             }
         }
 
+        // ========== 2. 【优化】批量查询工艺资料,只查当前页所有工单 ==========
+        $gongyiList = \db('工单_基础工艺资料')
+            ->whereIn('work_order', $orderIds)
+            ->column('work_order'); // 只取出已上传工艺的订单编号
+
+        // 定义工序对应字段
+        $processIds = [
+            2 => '裁剪完工数量',
+            3 => '车缝完工数量',
+            4 => '手工完工数量',
+            5 => '大烫完工数量',
+            6 => '总检完工数量',
+            7 => '包装完工数量'
+        ];
+
         // 遍历工单列表并设置状态
         foreach ($list as &$value) {
-            // 设置订单状态
-            $value['status'] = in_array($value['订单编号'], $groupedRelatedOrders['technical']) ? '' : '*';
-            $value['orderstatus'] = in_array($value['订单编号'], $groupedRelatedOrders['order']) ? '' : '*';
-
-            // 定义工序编号数组
-            $processIds = [
-                2 => '裁剪完工数量',
-                3 => '车缝完工数量',
-                4 => '手工完工数量',
-                5 => '大烫完工数量',
-                6 => '总检完工数量',
-                7 => '工单完工数量'
-            ];
+            $orderNo = $value['订单编号'];
+
+            // 技术附件标记:有数据为空,无数据标 *
+            $value['status'] = in_array($orderNo, $groupedRelatedOrders['technical']) ? '' : '*';
+            // 订单资料附件标记
+            $value['orderstatus'] = in_array($orderNo, $groupedRelatedOrders['order']) ? '' : '*';
+            // 【新增】工艺资料标记:有数据为空,无数据标 *
+            $value['gongyistatus'] = in_array($orderNo, $gongyiList) ? '' : '*';
 
-            // 遍历工序编号,获取对应的完工数量
+            // 工序产量统计
             foreach ($processIds as $processId => $fieldName) {
                 if ($processId === 2 || $processId === 3) {
-                    // 查询所有记录
                     $records = \db('设备_产量计酬')
-                        ->where('订单编号', $value['订单编号'])
+                        ->where('订单编号', $orderNo)
                         ->where('工序编号', $processId)
-                        ->select();  // 获取所有匹配记录
-
-                    // 计算数量总和
+                        ->select();
                     $num_sum = 0;
                     foreach ($records as $record) {
-                        $num_sum += $record['数量'];  // 手动累加数量
+                        $num_sum += $record['数量'];
                     }
-
-                    $value[$fieldName] = $num_sum; // 裁剪和车缝存储数量
+                    $value[$fieldName] = $num_sum;
                 } else {
-                    // 其他工序是 s_num,总和计算
                     $s_num_sum = \db('设备_产量计酬')
-                        ->where('订单编号', $value['订单编号'])
+                        ->where('订单编号', $orderNo)
                         ->where('工序编号', $processId)
-                        ->sum('s_num'); // 继续使用 s_num 字段
-                    $value[$fieldName] = $s_num_sum; // 其他工序存储 s_num 总和
+                        ->sum('s_num');
+                    $value[$fieldName] = $s_num_sum;
                 }
             }
 
+            // 日期格式化
             if ($value['落货日期']) {
                 $value['落货日期'] = date('Y-m-d', strtotime($value['落货日期']));
             }
-            // 格式化接单日期,去掉时间部分
             if ($value['接单日期']) {
                 $value['接单日期'] = date('Y-m-d', strtotime($value['接单日期']));
             }
         }
+        unset($value);
 
         // 返回数据
         $data = [

+ 0 - 25
application/api/controller/RelatedSalaryAccounting.php

@@ -1,25 +0,0 @@
-<?php
-
-namespace app\api\controller;
-
-use app\common\controller\Api;
-use \think\Request;
-use \think\Db;
-/**
- * 关联工资核算接口
- */
-class RelatedSalaryAccounting extends Api
-{
-    protected $noNeedLogin = ['*'];
-    protected $noNeedRight = ['*'];
-
-    /**
-     * 首页
-     *
-     */
-    public function index()
-    {
-        $this->success('请求成功');
-    }
-
-}

+ 120 - 14
application/api/controller/ReportingWork.php

@@ -231,7 +231,7 @@ class ReportingWork extends Api
             $standardMinutes = floatval($item['standard_minutes']);
             $productionHour = $standardHour * $number;
             $productionScore = $standardScore * $number;
-            $productionMoney = $money * $number;
+            $salary = $this->calcReportSalary($number, $standardScore);
             $partCode = null;
             if (isset($item['part_code']) && $item['part_code'] !== '') {
                 $partCode = intval($item['part_code']);
@@ -254,7 +254,7 @@ class ReportingWork extends Api
                 'number' => $number,
                 'production_hour' => round($productionHour, 4),
                 'production_score' => round($productionScore, 4),
-                'salary' => round($productionMoney, 4),
+                'salary' => $salary,
                 'machine' => isset($item['machine']) ? $item['machine'] : '',
                 'sys_id' => isset($item['sys_id']) ? $item['sys_id'] : '',
                 'sys_rq' => $now,
@@ -418,14 +418,33 @@ class ReportingWork extends Api
         if (empty($params['mod_id'])) {
             $this->error('修改人不能为空');
         }
+        if (!isset($params['number']) || $params['number'] === '') {
+            $this->error('产量不能为空');
+        }
+
+        $number = floatval($params['number']);
+        $standardScore = (isset($params['standard_score']) && $params['standard_score'] !== '')
+            ? floatval($params['standard_score']) : null;
+        $productionScore = isset($params['production_score']) && $params['production_score'] !== ''
+            ? floatval($params['production_score']) : null;
+
+        if ($standardScore !== null) {
+            $productionScore = round($standardScore * $number, 4);
+            $salary = $this->calcReportSalary($number, $standardScore);
+        } elseif ($productionScore !== null) {
+            $salary = round($productionScore * 0.067, 4);
+        } else {
+            $this->error('标准工分不能为空');
+        }
+
         $data = [
             'mod_id' => $params['mod_id'],
             'mod_rq' => date('Y-m-d H:i:s'),
-            'number' => $params['number'],
+            'number' => $number,
             'production_hour' => $params['production_hour'],
-            'production_score' => $params['production_score'],
-            'money' => $params['money'],
-            'salary' => $params['money'] * $params['number'],
+            'production_score' => $productionScore,
+            'money' => isset($params['money']) ? $params['money'] : 0,
+            'salary' => $salary,
         ];
         $result = db('设备_工分计酬')
             ->where('id', $params['id'])
@@ -489,15 +508,102 @@ class ReportingWork extends Api
         if (empty($params['machine'])) {
             $this->error('机台编号不能为空');
         }
-        $rows = db('设备_工分计酬')
-            ->where('del_rq', null)
-            ->where('date', 'like', $params['date'] . '%')
-            ->where('machine', $params['machine'])
-            ->field('work_order,majorprocess,part_code,process_code,process_name,staff_no,staff_name,
-            standard_hour,standard_score,money,coefficient,number,production_hour,
-            production_score,salary,machine,sys_id,sys_rq,id')
-            ->order('process_code asc,staff_no asc,sys_rq desc')
+        $rows = db('设备_工分计酬')->alias('a')
+            ->join('工单_基本资料 b', 'a.work_order = b.订单编号', 'LEFT')
+            ->where('a.del_rq', null)
+            ->where('b.Mod_rq', null)
+            ->where('a.date', 'like', $params['date'] . '%')
+            ->where('a.machine', $params['machine'])
+            ->field('
+                    a.work_order,
+                    a.majorprocess,
+                    a.part_code,
+                    a.process_code,
+                    a.process_name,
+                    a.staff_no,
+                    a.staff_name,
+                    a.standard_hour,
+                    a.standard_score,
+                    a.money,
+                    a.coefficient,
+                    a.number,
+                    a.production_hour,
+                    a.production_score,
+                    a.salary,machine,
+                    a.sys_id,
+                    a.sys_rq,
+                    a.id,
+                    b.生产款号,
+                    b.款式
+                ')
+            ->order('a.process_code asc,a.staff_no asc,a.sys_rq desc')
             ->select();
         $this->success('成功', $rows);
     }
+
+    /**
+     * 按新公式批量重算历史报工工资(数量 × 工分 × 0.067)
+     * @ApiMethod (POST)
+     * @param string workorder 可选,限定工单编号
+     * @param string date_start 可选,报工日期起(Y-m-d)
+     * @param string date_end 可选,报工日期止(Y-m-d)
+     */
+    public function recalculateHistoricalSalary()
+    {
+        if (!$this->request->isPost()) {
+            $this->error('请求方法错误');
+        }
+        $params = $this->request->post();
+
+        $applyFilters = function ($query) use ($params) {
+            if (!empty($params['workorder'])) {
+                $query->where('work_order', $params['workorder']);
+            }
+            if (!empty($params['date_start'])) {
+                $query->where('date', '>=', $params['date_start']);
+            }
+            if (!empty($params['date_end'])) {
+                $query->where('date', '<=', $params['date_end']);
+            }
+            return $query;
+        };
+
+        $total = (int)$applyFilters(Db::table('设备_工分计酬')->whereNull('del_rq'))->count();
+        if ($total === 0) {
+            $this->error('没有需要重算的报工数据');
+        }
+
+        Db::startTrans();
+        try {
+            $affected = $applyFilters(Db::table('设备_工分计酬')->whereNull('del_rq'))->update([
+                'production_score' => Db::raw('ROUND(`number` * `standard_score`, 4)'),
+                'salary' => Db::raw('ROUND(`number` * `standard_score` * 0.067, 4)'),
+            ]);
+            if ($affected === false) {
+                throw new \Exception('批量更新失败');
+            }
+            Db::commit();
+        } catch (\think\exception\HttpResponseException $e) {
+            throw $e;
+        } catch (\Exception $e) {
+            Db::rollback();
+            $this->error('重算失败:' . $e->getMessage());
+        }
+
+        $this->success('重算成功', [
+            'matched' => $total,
+            'updated' => (int)$affected,
+        ]);
+    }
+
+    /**
+     * 报工工资:数量 × 工分 × 0.067
+     * @param mixed $number
+     * @param mixed $standardScore
+     * @return float
+     */
+    private function calcReportSalary($number, $standardScore)
+    {
+        return round(floatval($number) * floatval($standardScore) * 0.067, 4);
+    }
 }

+ 293 - 41
application/api/controller/StaffSalary.php

@@ -9,13 +9,38 @@ use think\Db;
 */
 class StaffSalary extends Api
 {
-   
+
     protected $noNeedLogin = ['*'];
     protected $noNeedRight = ['*'];
 
-
+//    public function GetReportingWorkMonth()
+//    {
+//        if (!$this->request->isGet()) {
+//            $this->error('请求方法错误');
+//        }
+//        $data = db('设备_工分计酬')
+//            ->where('del_rq', null)
+//            ->field('DISTINCT DATE_FORMAT(date, "%Y-%m") as month')
+//            ->order('date desc')
+//            ->select();
+//
+//        //获取员工部门
+//        $big_process = db('人员_基本资料')
+//            ->field('DISTINCT big_process')
+//            ->where('big_process','<>','')
+//            ->select();
+//        foreach ($big_process as $v) {
+//            $big_process_name[] = $v['big_process'];
+//        }
+//        $result = [];
+//        foreach ($data as $v) {
+//            $result[$v['month']] = $big_process_name;
+//        }
+//
+//        $this->success('成功', $result);
+//    }
     /**
-     * 查询报工数据月份
+     * 查询报工数据月份(年-年月-日期-工序-小组五级树)
      * @ApiMethod (GET)
      * @return array
      * @throws \think\db\exception\DataNotFoundException
@@ -27,28 +52,127 @@ class StaffSalary extends Api
         if (!$this->request->isGet()) {
             $this->error('请求方法错误');
         }
-        $data = db('设备_工分计酬')
+
+        $rows = db('设备_工分计酬')
             ->where('del_rq', null)
-            ->field('DISTINCT DATE_FORMAT(date, "%Y-%m") as month')
-            ->order('date desc')
-            ->select();
-    
-        //获取员工部门
-        $big_process = db('人员_基本资料')
-            ->field('DISTINCT big_process')
-            ->where('big_process','<>','')
+            ->where('sys_rq', 'not null')
+            ->field('LEFT(sys_rq, 10) as date, IF(majorprocess IS NULL OR majorprocess = "", "其他", majorprocess) as process, rtrim(sys_id) as sys_id')
+            ->group('LEFT(sys_rq, 10), process, sys_id')
+            ->order('sys_rq desc, process asc, sys_id asc')
             ->select();
-        foreach ($big_process as $v) {
-            $big_process_name[] = $v['big_process'];
+
+        if (empty($rows)) {
+            $this->success('成功', []);
+        }
+
+        $treeMap = [];
+        foreach ($rows as $row) {
+            $date = $row['date'];
+            if (empty($date)) {
+                continue;
+            }
+            // 拆分年、年月、日期
+            $year = substr($date, 0, 4);
+            $yearMonth = substr($date, 0, 7);
+            $process = $row['process'];
+            $sysId = $row['sys_id'] !== '' ? $row['sys_id'] : '未知';
+
+            // 构建五级结构
+            if (!isset($treeMap[$year])) {
+                $treeMap[$year] = [];
+            }
+            if (!isset($treeMap[$year][$yearMonth])) {
+                $treeMap[$year][$yearMonth] = [];
+            }
+            if (!isset($treeMap[$year][$yearMonth][$date])) {
+                $treeMap[$year][$yearMonth][$date] = [
+                    'processes' => [],
+                ];
+            }
+            if (!isset($treeMap[$year][$yearMonth][$date]['processes'][$process])) {
+                $treeMap[$year][$yearMonth][$date]['processes'][$process] = [];
+            }
+            if (!in_array($sysId, $treeMap[$year][$yearMonth][$date]['processes'][$process], true)) {
+                $treeMap[$year][$yearMonth][$date]['processes'][$process][] = $sysId;
+            }
         }
+
+        // 工序固定排序
+        $processOrder = ['裁剪', '车缝', '手工', '大烫', '总检', '包装', '其他'];
         $result = [];
-        foreach ($data as $v) {
-            $result[$v['month']] = $big_process_name;
+        krsort($treeMap);
+
+        foreach ($treeMap as $year => $yearMonths) {
+            $yearNode = [
+                'label' => (string)$year,
+                'value' => (string)$year,
+                'children' => [],
+            ];
+
+            krsort($yearMonths);
+            foreach ($yearMonths as $yearMonth => $dates) {
+                $yearMonthNode = [
+                    'label' => $yearMonth,
+                    'value' => $yearMonth,
+                    'children' => [],
+                ];
+
+                krsort($dates);
+                foreach ($dates as $dateKey => $dateData) {
+                    $processChildren = [];
+                    $sortedProcesses = $this->sortProcessList(array_keys($dateData['processes']), $processOrder);
+                    foreach ($sortedProcesses as $process) {
+                        $groups = $dateData['processes'][$process];
+                        sort($groups);
+                        $groupChildren = [];
+                        foreach ($groups as $group) {
+                            $groupChildren[] = [
+                                'label' => $group,
+                                'value' => $group,
+                            ];
+                        }
+                        $processChildren[] = [
+                            'label' => $process,
+                            'value' => $process,
+                            'children' => $groupChildren,
+                        ];
+                    }
+
+                    $dateNode = [
+                        'label' => $dateKey,
+                        'value' => $dateKey,
+                        'children' => $processChildren,
+                    ];
+                    $yearMonthNode['children'][] = $dateNode;
+                }
+
+                $yearNode['children'][] = $yearMonthNode;
+            }
+
+            $result[] = $yearNode;
         }
 
         $this->success('成功', $result);
     }
 
+    /**
+     * 按指定顺序排序工序
+     * @param array $processList
+     * @param array $order
+     * @return array
+     */
+    private function sortProcessList(array $processList, array $order): array
+    {
+        $sorted = [];
+        foreach ($order as $item) {
+            if (in_array($item, $processList)) {
+                $sorted[] = $item;
+                unset($processList[array_search($item, $processList)]);
+            }
+        }
+        return array_merge($sorted, $processList);
+    }
+
 
     /**
      * 查询员工工资列表
@@ -64,24 +188,52 @@ class StaffSalary extends Api
             $this->error('请求方法错误');
         }
         $param = $this->request->param();
-        if (empty($param['month'])) {
-            $this->error('请选择月份');
+
+        if (empty($param['sys_rq'])) {
+            $this->error('请选择日期(sys_rq)');
         }
-        if (empty($param['big_process'])) {
-            $this->error('请选择部门');
+
+        $sysRq = $param['sys_rq'];
+        $bigProcess = !empty($param['big_process']) ? $param['big_process'] : '';
+        $group = !empty($param['group']) ? $param['group'] : '';
+
+        // ========== 第一步:连表查询员工列表(无exp、无whereRaw) ==========
+        $staffWhere = [];
+        $staffWhere['a.status'] = 1;
+
+        // 日期条件:纯LIKE匹配,兼容带时分秒的sys_rq
+        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $sysRq)) {
+            $staffWhere['b.sys_rq'] = ['like', $sysRq . '%'];
+        } elseif (preg_match('/^\d{4}-\d{2}$/', $sysRq)) {
+            $staffWhere['b.sys_rq'] = ['like', $sysRq . '%'];
+        } elseif (preg_match('/^\d{4}$/', $sysRq)) {
+            $staffWhere['b.sys_rq'] = ['like', $sysRq . '%'];
+        } else {
+            $this->error('sys_rq 格式错误,请使用 2026 / 2026-06 / 2026-06-08 格式');
+        }
+
+        // 工序筛选(可选)
+        if (!empty($bigProcess)) {
+            $staffWhere['a.big_process'] = $bigProcess;
+        }
+
+        // 小组筛选(可选)
+        if (!empty($group)) {
+            $staffWhere['b.sys_id'] = $group;
         }
-        //获取大工序员工列表
+
+        // 关键:用whereNull处理del_rq IS NULL,彻底解决EXP报错
         $staff = db('人员_基本资料')
             ->alias('a')
             ->join('设备_工分计酬 b','a.staff_no = b.staff_no','left')
-            ->where('a.big_process',$param['big_process'])
-            ->where('a.status',1)
-            ->where('b.date', 'like', $param['month'] . '%')
+            ->where($staffWhere)
+            ->whereNull('b.del_rq')
             ->field('a.staff_no,a.staff_name,sum(b.salary) as salary')
             ->group('a.staff_no,a.staff_name')
             ->select();
+
         if(empty($staff)){
-            $this->error('该工序没有报工数据');
+            $this->error('当前条件下暂无工资数据');
         }
 
         $staffMap = [];
@@ -91,13 +243,37 @@ class StaffSalary extends Api
             $staffNos[] = $item['staff_no'];
         }
 
+        // ========== 第二步:查询明细数据(无exp、无whereRaw) ==========
+        $detailWhere = [];
+        $detailWhere['staff_no'] = ['in', $staffNos];
+
+        // 日期条件:和上面保持一致
+        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $sysRq)) {
+            $detailWhere['sys_rq'] = ['like', $sysRq . '%'];
+        } elseif (preg_match('/^\d{4}-\d{2}$/', $sysRq)) {
+            $detailWhere['sys_rq'] = ['like', $sysRq . '%'];
+        } elseif (preg_match('/^\d{4}$/', $sysRq)) {
+            $detailWhere['sys_rq'] = ['like', $sysRq . '%'];
+        }
+
+        // 工序筛选(可选)
+        if (!empty($bigProcess)) {
+            $detailWhere['majorprocess'] = $bigProcess;
+        }
+
+        // 小组筛选(可选)
+        if (!empty($group)) {
+            $detailWhere['sys_id'] = $group;
+        }
+
+        // 关键:用whereNull处理del_rq IS NULL
         $salaryRows = db('设备_工分计酬')
-            ->where('del_rq', null)
-            ->where('date', 'like', $param['month'] . '%')
-            ->where('staff_no', 'in', $staffNos)
-            ->field('staff_no,staff_name,DATE_FORMAT(date, "%Y-%m-%d") as date,sum(salary) as salary,sys_id')
-            ->group('staff_no,DATE_FORMAT(date, "%Y-%m-%d")')
-            ->order('staff_no asc,date asc')
+            ->where($detailWhere)
+            ->whereNull('del_rq')
+            // 新增sys_id字段,并在group里加上,确保不同小组的数据不被合并
+            ->field('staff_no,staff_name,DATE_FORMAT(sys_rq, "%Y-%m-%d") as date,sum(salary) as salary,sys_id')
+            ->group('staff_no,DATE_FORMAT(sys_rq, "%Y-%m-%d"),sys_id')
+            ->order('staff_no asc,sys_rq asc')
             ->select();
 
         $grouped = [];
@@ -116,18 +292,93 @@ class StaffSalary extends Api
                 '员工姓名' => !empty($row['staff_name']) ? $row['staff_name'] : (isset($staffMap[$staffNo]) ? $staffMap[$staffNo] : ''),
                 '日期' => $row['date'],
                 '工资' => $row['salary'],
+                // 新增小组字段
+                '小组' => $row['sys_id'],
             ];
             $grouped[$staffNo]['total_salary'] += $row['salary'];
         }
 
         $this->success('成功', array_values($grouped));
-            
     }
-   
+
+//    /**
+//     * 查询员工工资列表
+//     * @ApiMethod (GET)
+//     * @return array
+//     * @throws \think\db\exception\DataNotFoundException
+//     * @throws \think\db\exception\ModelNotFoundException
+//     * @throws \think\exception\DbException
+//     */
+//    public function GetStaffSalaryList()
+//    {
+//        if (!$this->request->isGet()) {
+//            $this->error('请求方法错误');
+//        }
+//        $param = $this->request->param();
+//        if (empty($param['month'])) {
+//            $this->error('请选择月份');
+//        }
+//        if (empty($param['big_process'])) {
+//            $this->error('请选择部门');
+//        }
+//        //获取大工序员工列表
+//        $staff = db('人员_基本资料')
+//            ->alias('a')
+//            ->join('设备_工分计酬 b','a.staff_no = b.staff_no','left')
+//            ->where('a.big_process',$param['big_process'])
+//            ->where('a.status',1)
+//            ->where('b.date', 'like', $param['month'] . '%')
+//            ->field('a.staff_no,a.staff_name,sum(b.salary) as salary')
+//            ->group('a.staff_no,a.staff_name')
+//            ->select();
+//        if(empty($staff)){
+//            $this->error('该工序没有报工数据');
+//        }
+//
+//        $staffMap = [];
+//        $staffNos = [];
+//        foreach ($staff as $item) {
+//            $staffMap[$item['staff_no']] = $item['staff_name'];
+//            $staffNos[] = $item['staff_no'];
+//        }
+//
+//        $salaryRows = db('设备_工分计酬')
+//            ->where('del_rq', null)
+//            ->where('date', 'like', $param['month'] . '%')
+//            ->where('staff_no', 'in', $staffNos)
+//            ->field('staff_no,staff_name,DATE_FORMAT(date, "%Y-%m-%d") as date,sum(salary) as salary,sys_id')
+//            ->group('staff_no,DATE_FORMAT(date, "%Y-%m-%d")')
+//            ->order('staff_no asc,date asc')
+//            ->select();
+//
+//        $grouped = [];
+//        foreach ($salaryRows as $row) {
+//            $staffNo = $row['staff_no'];
+//            if (!isset($grouped[$staffNo])) {
+//                $name = !empty($row['staff_name']) ? $row['staff_name'] : (isset($staffMap[$staffNo]) ? $staffMap[$staffNo] : '');
+//                $grouped[$staffNo] = [
+//                    'staff' => $staffNo . '-' . $name,
+//                    'total_salary' => 0,
+//                    'children' => [],
+//                ];
+//            }
+//            $grouped[$staffNo]['children'][] = [
+//                '员工编号' => $staffNo,
+//                '员工姓名' => !empty($row['staff_name']) ? $row['staff_name'] : (isset($staffMap[$staffNo]) ? $staffMap[$staffNo] : ''),
+//                '日期' => $row['date'],
+//                '工资' => $row['salary'],
+//            ];
+//            $grouped[$staffNo]['total_salary'] += $row['salary'];
+//        }
+//
+//        $this->success('成功', array_values($grouped));
+//
+//    }
+
 
     /**
      * 查询员工工资详情
-     * 
+     *
      */
     public function GetStaffSalaryDetail()
     {
@@ -143,18 +394,19 @@ class StaffSalary extends Api
         }
         $where = [
             'a.staff_no' => $param['staff_no'],
-            'a.date' => ['like', $param['date'] . '%'],
+            'a.sys_rq' => ['like', $param['date'] . '%'],
             'a.del_rq' => null,
         ];
         $list = db('设备_工分计酬')
             ->alias('a')
             ->join('工单_部件资料 b', 'a.work_order = b.work_order and a.part_code = b.part_code', 'left')
+            ->join('工单_基本资料 c', 'a.work_order = c.订单编号', 'left')
             ->field('a.work_order as 订单编号,DATE_FORMAT(a.date, "%Y-%m-%d") as 日期,b.part_name as 部件名称,
             a.part_code as 部件编号,a.salary as 工资,a.number as 数量,a.production_hour as 生产工时,a.production_score as 生产分数,
-            a.machine as 设备名称,a.process_name as 工序名称,a.standard_hour as 标准工时,a.standard_score as 标准分数,
-            a.coefficient as 系数,a.sys_id as 设备编号')
+            a.machine as 设备名称,a.process_code as 工序编号,a.process_name as 工序名称,a.standard_hour as 标准工时,a.standard_score as 标准分数,
+            a.coefficient as 系数,a.sys_id as 设备编号,c.生产款号,c.款式')
             ->where($where)
-            ->order('a.date asc,a.process_code asc')
+            ->order('a.sys_rq asc,a.process_code asc')
             ->select();
         if(empty($list)){
             $this->error('没有数据');
@@ -193,12 +445,12 @@ class StaffSalary extends Api
             ->group('staff_no,staff_name')
             ->field('staff_no,staff_name,DATE_FORMAT(date, "%Y-%m-%d") as date,sum(salary) as salary')
             ->group('staff_no,DATE_FORMAT(date, "%Y-%m-%d")')
-            ->order('staff_no asc,date asc')
+            ->order('staff_no asc,sys_rq asc')
             ->select();
         if(empty($list)){
             $this->error('没有数据');
-        }   
+        }
         $this->success('成功', $list);
     }
 
-}
+}

+ 831 - 1019
application/api/controller/Synchronization.php

@@ -4,1130 +4,942 @@ namespace app\api\controller;
 
 use app\common\controller\Api;
 use think\Db;
-use Overtrue\Pinyin;
+use think\exception\HttpResponseException;
 
 /**
- * 中间表数据同步
+ * MES-ERP 工单同步
  */
 class Synchronization extends Api
 {
     protected $noNeedLogin = ['*'];
     protected $noNeedRight = ['*'];
 
+    /** @var int 同步状态:待同步 */
+    const SYNC_STATUS_PENDING = 0;
+    /** @var int 同步状态:成功 */
+    const SYNC_STATUS_SUCCESS = 1;
+    /** @var int 同步状态:失败 */
+    const SYNC_STATUS_FAILED = 2;
+
+    /** @var int 操作状态:成功 */
+    const OPERATE_STATUS_SUCCESS = 1;
+    /** @var int 操作状态:失败 */
+    const OPERATE_STATUS_FAILED = 2;
+    /** @var int 操作状态:处理中 */
+    const OPERATE_STATUS_PROCESSING = 3;
+
     /**
-     * 工单资料数据同步
+     * ERP SQL Server 表映射(请按实际 ERP 表结构填写 table 与 fields)
+     * fields:MES 源字段名 => ERP 目标字段名;固定值以 = 开头,如 '=M' => 'is_mfg_wrk'
+     * 报工 sfb_id 规则:K+年月日(同步日期)+四位自增,如 K2606100201
      */
-    public function WorkOrderData()
+    protected $erpTableMap = [
+        // 1-工单数据:来源 工单_基本资料
+        'work_order' => [
+            'table' => 'mps_mfg_ord',
+            'fields' => [
+                '订单编号' => 'ordno',
+                '=M' => 'is_mfg_wrk',
+                '生产款号' => 'itemno',
+                '接单日期' => 'cr_date',
+                '落货日期' => 'rel_date',
+                '同步日期' => 'due_date',
+                '订单数量' => 'qty_ord',
+                'remark' => 'remark',
+                '计划制造工分' => 'curprc',
+                '=0001' => 'ocode',
+            ],
+        ],
+        // 2-工艺数据:来源 工单_基础工艺资料
+        'process' => [
+            'table' => 'mps_mfg_routing',
+            'fields' => [
+                'work_order' => 'ordno',
+                '=M' => 'is_mfg_wrk',
+                '生产款号' => 'itemno',
+                'process_code' => 'op',
+                'process_name' => 'routiname',
+                'standard_score' => 'preprc',
+                '=0001' => 'ocode',
+                '订单数量' => 'qty_ord',
+            ],
+        ],
+        // 3-报工数据:来源工序产量核查汇总(sfb_id 按同步日期自动生成)
+        'report' => [
+            'table' => 'wfc_shift_feedback',
+            'fields' => [
+                '员工编号' => 'emp_no',
+                '=1' => 'shift_id',
+                '订单编号' => 'ordno',
+                '生产款号' => 'itemno',
+                '工序号' => 'op',
+                '工序名称' => 'routiname',
+                '数量' => 'qty_comp',
+                '开工日期' => 'op_begdt',
+                '完工日期' => 'op_enddt',
+                '填报日期' => 'tran_date',
+                '=0202' => 'centerno',
+                '=0001.02.02' => 'detno',
+                '=0001' => 'ocode',
+                '工分' => 'preprc',
+            ],
+        ],
+    ];
+
+    /**
+     * 完工工单列表(含同步状态)
+     * @ApiMethod (GET)
+     * @param page 页码
+     * @param limit 每页条数
+     * @param search 搜索(订单编号/款号/款式/客户)
+     * @param sync_status 同步状态筛选:unsynced|pending|synced|failed|cancelled
+     */
+    public function getCompletedWorkOrderList()
     {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $db3 = Db::connect(config('database.db3'));
-        $workOrderList = $db3->name('U8_06工单资料')
-            ->where('MES接收时间',null)
-            ->where('MES接收状态','0')
-            ->where('U8插入类型','<>','关闭')
-            ->select();
-        if (empty($workOrderList)){
-            $this->success('未获取新工单');
+        if (!$this->request->isGet()) {
+            $this->error('请求方法错误');
         }
-        $j = $m = $n =0;
-        foreach ($workOrderList as $key=>$value){
-            $sort = 0;
-            if (substr($value['工单编号'],0,1) === 'Y'){
-                $sort = 1;
-            }else if (substr($value['工单编号'],-2) === 'JZ' || substr($value['工单编号'],-2) === 'JS'){
-                $sort = 2;
+        $param = $this->request->param();
+        $page = max(1, (int)(isset($param['page']) ? $param['page'] : 1));
+        $limit = max(15, min(100, (int)(isset($param['limit']) ? $param['limit'] : 15)));
+    
+        $baseWhere = function ($query) use ($param) {
+            $query->whereNull('Mod_rq')
+                ->whereNotNull('工单完工日期')
+                ->where('工单完工日期', '<>', '');
+            if (!empty($param['search'])) {
+                $query->where('订单编号|生产款号|客户编号|款式|工单完工日期', 'like', '%' . trim($param['search']) . '%');
             }
-            $code = substr($value['成品编号'],0,5);
-            $client = \db('物料_存货结构')->where('编号',$code)->value('名称');
-            //插入产品资料
-            $processData = \db('产品_基本资料')
-                ->where('产品编号',$value['成品编号'])
-                ->count();
-            $detail = \db('物料_存货编码')->where('物料代码',$value['成品编号'])->find();
-            if ($processData === 0){
-                $product = [
-                    '客户编号' => $code,
-                    '客户名称' => $client,
-                    '产品编号' => $value['成品编号'],
-                    '产品名称' => $value['成品名称'],
-                    '计量单位' => $detail['领用单位'],
-                    '状态' => '',
-                    'U8UID' => $detail['U8UID'],
-                    '产品类别' => $detail['规格'],
-                    'Sys_id' => '[272/超级用户]',
-                    'Sys_rq' => date('Y-m-d H:i:s',time()),
-                    'Mod_rq' => date('Y-m-d H:i:s',time()),
-                ];
-                $product['UniqID'] = \db('产品_基本资料')->order('UniqID desc')->value('UniqID')+1;
-                $productSql = \db('产品_基本资料')->fetchSql(true)->insert($product);
-                \db()->query($productSql);
+        };
+
+        $countQuery = \db('工单_基本资料');
+        $baseWhere($countQuery);
+        $total = (int)$countQuery->count();
+
+        $listQuery = \db('工单_基本资料');
+        $baseWhere($listQuery);
+        $list = $listQuery
+            ->field('Uniqid,订单编号,生产款号,款式,客户编号,工单完工日期,remark,gd_statu,Sys_id,Sys_rq')
+            ->order('工单完工日期 desc,订单编号 desc')
+            ->page($page, $limit)
+            ->select();
+        if (!empty($list)) {
+            $orderNos = array_column($list, '订单编号');
+            $statusMap = $this->batchResolveDisplaySyncStatus($orderNos);
+            foreach ($list as &$row) {
+                $orderNo = $row['订单编号'];
+                $statusInfo = isset($statusMap[$orderNo]) ? $statusMap[$orderNo] : $this->defaultDisplaySyncStatus();
+                $row['sync_status'] = $statusInfo['code'];
+                $row['sync_status_text'] = $statusInfo['text'];
+                $row['同步状态'] = $statusInfo['text'];
+                $row['last_sync_time'] = $statusInfo['sync_time'];
+                $row['last_sync_msg'] = $statusInfo['sync_msg'];
+                $row['last_sync_log_id'] = $statusInfo['sync_log_id'];
             }
-            //插入工单资料
-            if (substr($value['工单编号'],0,1) === 'Y' || substr($value['工单编号'],-2) === 'JZ' || substr($value['工单编号'],-2) === 'JS'){
-                $data = [
-                    'Gd_gdbh' => $value['工单编号'],
-                    '行号' => $value['行号'],
-                    'Gd_客户代号' => $code,
-                    'Gd_客户名称' => $client,
-                    'Gd_khdh' => $value['客户编号'],
-                    'Gd_khmc' => $value['客户名称'],
-                    '客户料号' => $value['客户料号'],
-                    '成品代号' => $value['成品编号'],
-                    '成品名称' => $value['成品名称'],
-                    'Gd_cpdh' => $value['产品编号'],
-                    'Gd_cpmc' => $value['产品名称'],
-                    '产品版本号' => $value['版本号'],
-                    '销售订单号' => $value['销售订单号'],
-                    '警语版面' => $value['警语版面'],
-                    '码源数量' => substr(str_replace('.','',$value['投料数量']),0,-2),
-                    'Gd_desc' => $value['备注'],
-                    '接单日期' => $value['接单日期'],
-                    '开单日期' => $value['开单日期'],
-                    '交货日期' => $value['交货日期'],
-                    '订单数量' => $value['订单数量'],
-                    '实际投料' => $value['投料数量'],
-                    '产品单价' => $value['产品单价'],
-                    '计量单位' => '万张',
-                    '成本考核_胶印' => 1,
-                    '成本考核_凹印' => 1,
-                    '成本考核_丝印' => 1,
-                    '成本考核_模切' => 1,
-                    '成本考核_检验' => 1,
-                    'gd_statu' => '3-计划中',
-                    'Sys_id' => '[1012/开单员]',
-                    'Sys_rq' => date('Y-m-d H:i:s',time()),
-                    'Mod_rq' => date('Y-m-d H:i:s',time()),
-                    'U8UID' => $value['U8_UID'],
-                    'Uniqid' => $value['UniqId'],
-                    '工单分类' => $sort
-                ];
-                $workOrderdata = \db('工单_基本资料')
-                    ->where('U8UID',$value['U8_UID'])
-                    ->count();
-                if ($workOrderdata === 0){
-                    $addSql = \db('工单_基本资料')->fetchSql(true)->insert($data);
-                    $result = \db()->query($addSql);
-                    if ($result === false){
-                        $m++;
-                    }else{
-                        $sqlString = $db3->name('U8_06工单资料')
-                            ->where('UniqId', $value['UniqId'])
-                            ->fetchSql(true)
-                            ->update([
-                                'MES接收时间' => date('Y-m-d H:i:s', time()),
-                                'MES接收状态' => '1'
-                            ]);
-                        $db3->execute($sqlString);
-                    }
-                }else{
-                    unset($data['Uniqid']);
-                    $updateSql = \db('工单_基本资料')->where('U8UID',$value['U8_UID'])->fetchSql(true)->update($data);
-                    $updateRes = \db()->query($updateSql);
-                    if ($updateRes === false){
-                        $j++;
-                    }else{
-                        $sqlString = $db3->name('U8_06工单资料')
-                            ->where('UniqId', $value['UniqId'])
-                            ->fetchSql(true)
-                            ->update([
-                                'MES接收时间' => date('Y-m-d H:i:s', time()),
-                                'MES接收状态' => '1'
-                            ]);
-                        $db3->execute($sqlString);
-                    }
-                }
+            unset($row);
+
+            if (!empty($param['sync_status'])) {
+                $filter = $param['sync_status'];
+                $list = array_values(array_filter($list, function ($row) use ($filter) {
+                    return $row['sync_status'] === $filter;
+                }));
             }
         }
-        if ($j !== 0 || $m !==0 || $n !== 0){
-            $this->error('工单资料同步失败');
-        }else{
-            $this->success('工单资料同步成功');
-        }
+
+        $this->success('成功', [
+            'total' => $total,
+            'page' => $page,
+            'limit' => $limit,
+            'list' => $list ?: [],
+        ]);
     }
 
     /**
-     * 工单bom资料同步
+     * 同步到 ERP
+     * @ApiMethod (POST)
+     * @param work_order_no 工单编号
+     * @param sync_module 1-工单 2-工艺 3-报工 4-全量
+     * @param operator 操作人
+     * @param operate_source backend|api|crontab,默认 backend
+     * @param operate_type sync|manual|auto,默认 manual
      */
+    public function syncWorkOrder()
+    {
+        $this->executeSync('sync');
+    }
 
-    public function WorkOrderBomData()
+    /**
+     * 重试同步(仅上次失败时可重试)
+     * @ApiMethod (POST)
+     */
+    public function retrySyncWorkOrder()
     {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
+        $params = $this->request->post();
+        $workOrderNo = isset($params['work_order_no']) ? trim($params['work_order_no']) : '';
+        if ($workOrderNo === '') {
+            $this->error('工单编号不能为空');
         }
-        $db3 = Db::connect(config('database.db3'));
-        $BomDataList = $db3->name('U8_09工单bom')
-            ->where('MES接收时间',null)
-            ->where('MES接收状态','0')
-            ->order('U8传递时间 desc')
-            ->select();
-        if (empty($BomDataList)){
-            $this->success('未找到新工单BOM');
-        }
-        $j = $m = 0;
-        foreach ($BomDataList as $key=>$value){
-            $res = \db('工单_bom资料')->where('U8UID',$value['U8_UID'])->count();
-            if (preg_match("/[A-Za-z]/",$value['BOM_工单编号'])){
-                $workcode = $value['BOM_工单编号'];
-            }else{
-                $workcode = 'Y'.$value['BOM_工单编号'];
-            }
-            $data = [
-                'BOM_方案' => '工单评审定案',
-                'BOM_工单编号' => $workcode,
-                'BOM_版本' => $value['BOM_版本'],
-                'BOM_工单行号' => $value['BOM_工单行号'],
-                'BOM_行号' => $value['BOM_行号'],
-                'BOM_产品编号' => $value['BOM_产品编号'],
-                'BOM_物料编码' => $value['BOM_物料编码'],
-                'BOM_物料名称' => $value['BOM_物料名称'],
-                'BOM_投料单位' => $value['BOM_投料单位'],
-                'BOM_投入数' => $value['BOM_投入数'],
-                'BOM_产出数' => $value['BOM_产出数'],
-                'BOM_产出单位' => $value['BOM_产出单位'],
-                'BOM_标准用量' => $value['BOM_标准用量'],
-                'BOM_实际用量' => $value['BOM_实际用量'],
-                'BOM_计划用量' => $value['BOM_计划用量'],
-                'BOM_核算价格' => 0,
-                'Bom_领用工序' => '01-01',
-                'BOM_备注' => $value['BOM_备注'],
-                'Mod_rq' => date('Y-m-d H:i:s',time()),
-                'U8UID' => $value['U8_UID'],
-                'UNIQID' => $value['UNIQID']
-            ];
-            if ($res === 0){
-                $addSql = \db('工单_bom资料')->fetchSql(true)->insert($data);
-                $addRes = \db()->query($addSql);
-                if ($addRes === false){
-                    $m++;
-                }else{
-                    $sqlString = $db3->name('U8_09工单bom')
-                        ->where('UNIQID', $value['UNIQID'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
-            }else{
-                unset($data['UNIQID']);
-                $updateSql = \db('工单_bom资料')
-                    ->where('U8UID',$value['U8_UID'])
-                    ->fetchSql(true)
-                    ->update($data);
-                $updateRes = \db()->query($updateSql);
-                if ($updateRes === false){
-                    $j++;
-                }else{
-                    $sqlString = $db3->name('U8_09工单bom')
-                        ->where('UNIQID', $value['UNIQID'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
-            }
-        }
-        if ($j !== 0 || $m !== 0){
-            $this->error('工单BOM资料同步失败');
-        }else{
-            $this->success('工单BOM资料同步成功');
+        $statusInfo = $this->resolveDisplaySyncStatus($workOrderNo);
+        if ($statusInfo['code'] !== 'failed') {
+            $this->error('仅同步失败的工单可重试');
         }
+        $this->executeSync('retry');
     }
 
     /**
-     * 存货结构数据同步
+     * 撤回同步
+     * @ApiMethod (POST)
+     * @param work_order_no 工单编号
+     * @param operator 操作人
+     * @param reason 撤回原因
      */
-
-    public function MaterialRequisitionData()
+    public function cancelSyncWorkOrder()
     {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
+        if (!$this->request->isPost()) {
+            $this->error('请求方法错误');
         }
-        $db3 = \db()->connect(config('database.db3'));
-        $MaterialDataList = $db3->name('U8_11存货结构')
-            ->where('MES接收时间',null)
-            ->where('MES接收状态','0')
-            ->select();
-        if (empty($MaterialDataList)){
-            $this->success('未找到新的物料存货结构');
+        $params = $this->request->post();
+        $workOrderNo = isset($params['work_order_no']) ? trim($params['work_order_no']) : '';
+        $operator = isset($params['operator']) ? trim($params['operator']) : '';
+        $reason = isset($params['reason']) ? trim($params['reason']) : '';
+
+        if ($workOrderNo === '') {
+            $this->error('工单编号不能为空');
+        }
+        if ($operator === '') {
+            $this->error('操作人不能为空');
         }
-        $i = 0;
-        foreach ($MaterialDataList as $key=>$value){
-            $data = [
-                '编号' => $value['编号'],
-                '名称' => $value['名称'],
-                'Sys_id' => '[272/超级用户]',
-                'Sys_rq' => date('Y-m-d H:i:s',time()),
-                'Mod_rq' => date('Y-m-d H:i:s',time()),
-                'U8UID' => $value['U8_UID'],
-                'UniqId' => $value['UniqId']
-            ];
-            if ($value['U8插入类型'] === '新增'){
-                $sql = \db('物料_存货结构')->fetchSql(true)->insert($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_11存货结构')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
-            }else{
-                $sql = \db('物料_存货结构')
-                    ->fetchSql(true)
-                    ->where('U8UID',$value['U8_UID'])
-                    ->update($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-
-                    $sqlString = $db3->name('U8_11存货结构')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
 
-                }
-            }
+        $workOrder = $this->fetchWorkOrderBasic($workOrderNo);
+        if (empty($workOrder)) {
+            $this->error('工单不存在');
         }
-        if ($i !== 0){
-            $this->error('存货结构同步失败');
-        }else{
-            $this->success('存货结构同步成功');
+
+        $statusInfo = $this->resolveDisplaySyncStatus($workOrderNo);
+        if ($statusInfo['code'] !== 'synced') {
+            $this->error('仅已同步的工单可撤回');
         }
+
+        $operTime = date('Y-m-d H:i:s');
+        $operateParam = json_encode([
+            'work_order_no' => $workOrderNo,
+            'reason' => $reason,
+        ], JSON_UNESCAPED_UNICODE);
+        $operateContent = '撤回同步工单' . $workOrderNo . ($reason !== '' ? ',原因:' . $reason : '');
+
+        $operationLogId = $this->insertOperationLog([
+            'operate_type' => 'cancel',
+            'operate_user' => $operator,
+            'operate_user_name' => isset($params['operate_user_name']) ? $params['operate_user_name'] : $operator,
+            'operate_time' => $operTime,
+            'sync_log_id' => $statusInfo['sync_log_id'],
+            'work_order_no' => $workOrderNo,
+            'style_no' => $workOrder['生产款号'],
+            'operate_content' => $operateContent,
+            'operate_param' => $operateParam,
+            'operate_status' => self::OPERATE_STATUS_PROCESSING,
+            'operate_source' => isset($params['operate_source']) ? $params['operate_source'] : 'backend',
+            'operate_ip' => $this->request->ip(),
+            'server_ip' => isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '',
+        ]);
+
+        Db::startTrans();
+        try {
+            $this->deleteErpDataByWorkOrder($workOrderNo);
+
+            Db::name('mes_erp_operation_log')
+                ->where('id', $operationLogId)
+                ->update([
+                    'operate_status' => self::OPERATE_STATUS_SUCCESS,
+                ]);
+
+            if (!empty($statusInfo['sync_log_id'])) {
+                Db::name('mes_erp_work_order_sync_log')
+                    ->where('id', $statusInfo['sync_log_id'])
+                    ->update([
+                        'sync_msg' => '已撤回' . ($reason !== '' ? ':' . $reason : ''),
+                        'update_time' => $operTime,
+                    ]);
+            }
+
+            Db::commit();
+        } catch (HttpResponseException $e) {
+            throw $e;
+        } catch (\Exception $e) {
+            Db::rollback();
+            Db::name('mes_erp_operation_log')
+                ->where('id', $operationLogId)
+                ->update([
+                    'operate_status' => self::OPERATE_STATUS_FAILED,
+                    'error_msg' => $e->getMessage(),
+                ]);
+            $this->error('撤回失败:' . $e->getMessage());
+        }
+
+        $this->success('撤回成功');
     }
 
     /**
-     * 人事基本资料同步
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\db\exception\BindParamException
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\exception\PDOException
+     * 同步日志列表
+     * @ApiMethod (GET)
+     * @param work_order_no 工单编号
      */
-    public function PersonnelData()
+    public function getSyncLogList()
     {
-        //拼音类
-        $pinyin = new Pinyin\Pinyin();
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
+        if (!$this->request->isGet()) {
+            $this->error('请求方法错误');
         }
-        $db3 = \db()->connect(config('database.db3'));
-        $PersonnelDataList = $db3->name('U8_02人事资料')
-            ->where('MES接收时间',null)
-            ->where('MES接收状态','0')
+        $workOrderNo = trim($this->request->param('work_order_no', ''));
+        if ($workOrderNo === '') {
+            $this->error('工单编号不能为空');
+        }
+
+        $list = Db::name('mes_erp_work_order_sync_log')
+            ->where('work_order_no', $workOrderNo)
+            ->order('id desc')
             ->select();
-        if (empty($PersonnelDataList)){
-            $this->success('未找到新的人事资料');
+
+        foreach ($list as &$row) {
+            $row['sync_status_text'] = $this->syncStatusText($row['sync_status']);
+            $row['sync_module_text'] = $this->syncModuleText($row['sync_module']);
         }
-        $i = 0;
-        foreach ($PersonnelDataList as $key=>$value){
-            //获取姓名首字母
-            $pycode = $pinyin->abbr($value['员工姓名']);
-            $nameCode = strtoupper($pycode);
-            $data = [
-                '工卡编号'=>'',
-                '卡钟设定'=>'',
-                '打卡设置'=>'',
-                '员工编号'=>$value['员工编号'],
-                '员工姓名'=>$value['员工姓名'],
-                '性别'=>$value['性别'],
-                '聘用日期'=>$value['聘用日期'],
-                '转正日期'=>$value['转正日期'],
-                'U8离职日期'=>$value['离职日期'],
-                'MES离职日期'=>$value['离职日期'],
-                '扣减司龄'=>0,
-                '部门编码'=>$value['部门编码'],
-                '所在部门'=>$value['所在部门'],
-                '人员类别'=>$value['人员类别'],
-                '人员性质'=>$value['人员性质'],
-                '班次类型'=>'',
-                '标准工时制'=>'',
-                '职称职务'=>$value['职称职务'],
-                '薪资级别'=>$value['级别'],
-                '工资表类别'=>'',
-                '基本工资'=>'',
-                '绩效工资1'=>'',
-                '绩效工资2'=>'',
-                '技能工资'=>'',
-                '岗位津贴'=>'',
-                '竞业补贴'=>'',
-                '专业技术津贴'=>'',
-                '技工技师津贴'=>'',
-                '特殊工种津贴'=>'',
-                '各类奖项津贴'=>'',
-                '职危津贴'=>'',
-                '夜班津贴'=>'',
-                '全勤津贴'=>'',
-                '住房津贴'=>'',
-                '高温津贴'=>'',
-                '用餐津贴'=>'',
-                '司龄津贴'=>'',
-                '联系电话'=>$value['联系电话'],
-                '合同类型'=>'',
-                '合同起始日期'=>'1900-01-01 00:00:00',
-                '合同终止日期'=>'1900-01-01 00:00:00',
-                '合同备注'=>'',
-                '出生日期'=>$value['出生日期'],
-                'pycode'=>$nameCode,
-                '籍贯'=>'',
-                '民族'=>'',
-                '身份证号'=>$value['身份证号'],
-                '证件有效日期'=>'1900-01-01 00:00:00',
-                '发证机关'=>'',
-                '家庭住址'=>'',
-                '学历'=>'',
-                '婚姻状况'=>'',
-                '社保开始日期'=>'1900-01-01 00:00:00',
-                '开户银行'=>$value['开户银行'],
-                '开户账号'=>$value['开户账号'],
-                '存折办理日期'=>'1900-01-01 00:00:00',
-                '紧急电话'=>'',
-                '照片ID'=>'',
-                '在职状态'=>$value['在职状态'],
-                'U8在职'=>$value['在职状态'],
-                '薪酬核算分组'=>'',
-                '考勤类型'=>'',
-                '班组代号'=>'',
-                'sys_id'=>'[272/超级用户]',
-                'sys_rq'=>date('Y-m-d H:i:s',time()),
-                'mod_rq'=>'1900-01-01 00:00:00',
-                'U8UID'=>$value['U8_UID'],
-                'UniqID'=>$value['UniqId']
-            ];
-            $number = \db('人事_基本资料')
-                ->where('U8UID',$value['U8_UID'])
-                ->count();
-            if ($number === 0){
-                $sql = \db('人事_基本资料')->fetchSql(true)->insert($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_02人事资料')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
-            }else{
-                $sql = \db('人事_基本资料')
-                    ->fetchSql(true)
-                    ->where('U8UID',$value['U8_UID'])
-                    ->update($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-
-                    $sqlString = $db3->name('U8_02人事资料')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
+        unset($row);
 
-                }
-            }
+        $this->success('成功', $list ?: []);
+    }
+
+    /**
+     * 操作过程记录列表
+     * @ApiMethod (GET)
+     * @param work_order_no 工单编号
+     * @param sync_log_id 同步日志ID(可选)
+     */
+    public function getOperationLogList()
+    {
+        if (!$this->request->isGet()) {
+            $this->error('请求方法错误');
+        }
+        $workOrderNo = trim($this->request->param('work_order_no', ''));
+        $syncLogId = $this->request->param('sync_log_id');
+
+        $query = Db::name('mes_erp_operation_log')->order('id desc');
+        if ($workOrderNo !== '') {
+            $query->where('work_order_no', $workOrderNo);
+        }
+        if ($syncLogId !== null && $syncLogId !== '') {
+            $query->where('sync_log_id', intval($syncLogId));
         }
-        if ($i !== 0){
-            $this->error('人事资料同步失败');
-        }else{
-            $this->success('人事资料同步成功');
+        if ($workOrderNo === '' && ($syncLogId === null || $syncLogId === '')) {
+            $this->error('请传入 work_order_no 或 sync_log_id');
+        }
+
+        $list = $query->select();
+        foreach ($list as &$row) {
+            $row['operate_status_text'] = $this->operateStatusText($row['operate_status']);
         }
+        unset($row);
+
+        $this->success('成功', $list ?: []);
     }
 
     /**
-     * 人事组织结构
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\db\exception\BindParamException
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\exception\PDOException
+     * 执行同步核心逻辑
+     * @param string $operateType sync|retry|manual|auto
      */
-    public function OrganizationalStructureData()
+    private function executeSync($operateType)
     {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
+        if (!$this->request->isPost()) {
+            $this->error('请求方法错误');
         }
-        $db3 = \db()->connect(config('database.db3'));
-        $OrganizationalDataList = $db3->name('U8_01组织结构')
-            ->where('MES接收时间',null)
-            ->where('MES接收状态','0')
-            ->select();
-        if (empty($OrganizationalDataList)){
-            $this->success('未找到新的组织结构');
+        $params = $this->request->post();
+        $workOrderNo = isset($params['work_order_no']) ? trim($params['work_order_no']) : '';
+        $syncModule = isset($params['sync_module']) ? (string)$params['sync_module'] : '4';
+        $operator = isset($params['operator']) ? trim($params['operator']) : '';
+
+        if ($workOrderNo === '') {
+            $this->error('工单编号不能为空');
+        }
+        if ($operator === '') {
+            $this->error('操作人不能为空');
+        }
+        if (!in_array($syncModule, ['1', '2', '3', '4'], true)) {
+            $this->error('同步模块参数错误');
         }
-        $i = 0;
-        foreach ($OrganizationalDataList as $key=>$value){
-            $data = [
-                '编号'=>$value['编号'],
-                '名称'=>$value['名称'],
-                '状态'=>$value['状态'],
-                'Sys_id'=>'[272/超级用户]',
-                'Sys_rq'=>date('Y-m-d H:i:s',time()),
-                'Mod_rq'=>'1900-01-01 00:00:00',
-                'U8UID'=>$value['U8_UID'],
-                'UNIQID'=>$value['UniqId'],
-            ];
-            $number = \db('人事_组织结构')
-                ->where('U8UID',$value['U8_UID'])
-                ->count();
-            if ($number === 0){
-                $sql = \db('人事_组织结构')->fetchSql(true)->insert($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_01组织结构')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
-            }else{
-                $sql = \db('人事_组织结构')
-                    ->fetchSql(true)
-                    ->where('U8UID',$value['U8_UID'])
-                    ->update($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-
-                    $sqlString = $db3->name('U8_01组织结构')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
 
-                }
-            }
+        $workOrder = $this->fetchWorkOrderBasic($workOrderNo);
+        if (empty($workOrder)) {
+            $this->error('工单不存在');
+        }
+        if (empty($workOrder['工单完工日期'])) {
+            $this->error('该工单尚未完工,不能同步');
         }
-        if ($i !== 0){
-            $this->error('人事组织结构同步失败');
-        }else{
-            $this->success('人事组织结构同步成功');
+
+        $operTime = date('Y-m-d H:i:s');
+        $operateSource = isset($params['operate_source']) ? $params['operate_source'] : 'backend';
+        $requestOperateType = isset($params['operate_type']) ? $params['operate_type'] : 'manual';
+        if ($operateType === 'retry') {
+            $requestOperateType = 'retry';
+        }
+
+        $operateParam = json_encode([
+            'work_order_no' => $workOrderNo,
+            'sync_module' => $syncModule,
+            'operator' => $operator,
+        ], JSON_UNESCAPED_UNICODE);
+
+        $operationLogId = $this->insertOperationLog([
+            'operate_type' => $requestOperateType,
+            'operate_user' => $operator,
+            'operate_user_name' => isset($params['operate_user_name']) ? $params['operate_user_name'] : $operator,
+            'operate_time' => $operTime,
+            'sync_log_id' => null,
+            'work_order_no' => $workOrderNo,
+            'style_no' => $workOrder['生产款号'],
+            'operate_content' => $this->buildSyncOperateContent($workOrderNo, $syncModule, $requestOperateType),
+            'operate_param' => $operateParam,
+            'operate_status' => self::OPERATE_STATUS_PROCESSING,
+            'operate_source' => $operateSource,
+            'operate_ip' => $this->request->ip(),
+            'server_ip' => isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '',
+        ]);
+
+        $seqRange = $this->fetchReportSeqRange($workOrderNo);
+        $syncLogId = $this->insertSyncLog([
+            'work_order_no' => $workOrderNo,
+            'style_no' => $workOrder['生产款号'],
+            'complete_date' => $this->formatDateValue($workOrder['工单完工日期']),
+            'operator' => $operator,
+            'sync_time' => $operTime,
+            'report_start_seq' => $seqRange['start'],
+            'report_end_seq' => $seqRange['end'],
+            'sync_status' => self::SYNC_STATUS_PENDING,
+            'sync_module' => $syncModule,
+            'sync_msg' => '同步处理中',
+            'erp_sync_id' => '',
+        ]);
+
+        Db::name('mes_erp_operation_log')
+            ->where('id', $operationLogId)
+            ->update(['sync_log_id' => $syncLogId]);
+
+        try {
+            $erpSyncId = $this->pushDataToErp($workOrderNo, $syncModule, $workOrder);
+            Db::name('mes_erp_work_order_sync_log')
+                ->where('id', $syncLogId)
+                ->update([
+                    'sync_status' => self::SYNC_STATUS_SUCCESS,
+                    'sync_msg' => '同步成功',
+                    'erp_sync_id' => $erpSyncId,
+                    'update_time' => date('Y-m-d H:i:s'),
+                ]);
+            Db::name('mes_erp_operation_log')
+                ->where('id', $operationLogId)
+                ->update(['operate_status' => self::OPERATE_STATUS_SUCCESS]);
+        } catch (HttpResponseException $e) {
+            throw $e;
+        } catch (\Exception $e) {
+            Db::name('mes_erp_work_order_sync_log')
+                ->where('id', $syncLogId)
+                ->update([
+                    'sync_status' => self::SYNC_STATUS_FAILED,
+                    'sync_msg' => $e->getMessage(),
+                    'update_time' => date('Y-m-d H:i:s'),
+                ]);
+            Db::name('mes_erp_operation_log')
+                ->where('id', $operationLogId)
+                ->update([
+                    'operate_status' => self::OPERATE_STATUS_FAILED,
+                    'error_msg' => $e->getMessage(),
+                ]);
+            $this->error('同步失败:' . $e->getMessage());
         }
+
+        $this->success('同步成功', [
+            'sync_log_id' => $syncLogId,
+            'operation_log_id' => $operationLogId,
+        ]);
     }
 
     /**
-     * 物料存货编码数据同步
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\db\exception\BindParamException
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\exception\PDOException
+     * 推送数据到 ERP(db2 / SQL Server)
+     * @param string $workOrderNo
+     * @param string $syncModule
+     * @param array $workOrder
+     * @return string ERP 同步标识
+     * @throws \Exception
      */
-    public function InventoryCodeData()
+    private function pushDataToErp($workOrderNo, $syncModule, $workOrder)
     {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $db3 = \db()->connect(config('database.db3'));
-        $OrganizationalDataList = $db3->name('U8_04物料编码')
-            ->where('MES接收时间',null)
-            ->where('MES接收状态','0')
-            ->select();
-        if (empty($OrganizationalDataList)){
-            $this->success('未找到新的物料编码');
-        }
-        $i = 0;
-        foreach ($OrganizationalDataList as $key=>$value){
-            $code = substr($value['物料代码'],0,3);
-            if ($code === 'Y10' || $code === 'Y14' || $code === 'Y12'){
-                //插入产品资料
-                $productData = \db('产品_基本资料')
-                    ->where('产品编号',$value['物料代码'])
-                    ->count();
-                $clientCode = substr($value['物料代码'],0,5);
-                $clientName = \db('物料_存货结构')->where('编号',$clientCode)->value('rtrim(名称)');
-                $product = [
-                    '客户编号' => $clientCode,
-                    '客户名称' => $clientName,
-                    '产品编号' => $value['物料代码'],
-                    '产品名称' => $value['物料名称'],
-                    '计量单位' => $value['领用单位'],
-                    '状态' => '',
-                    'U8UID' => $value['U8_UID'],
-                    '产品类别' => $value['规格'],
-                    'Sys_id' => '[272/超级用户]',
-                    'Sys_rq' => date('Y-m-d H:i:s',time()),
-                    'Mod_rq' => date('Y-m-d H:i:s',time()),
-                ];
-                if ($productData === 0){
-                    $product['UniqID'] = \db('产品_基本资料')->order('UniqID desc')->value('UniqID')+1;
-                    $productSql = \db('产品_基本资料')->fetchSql(true)->insert($product);
-                }else{
-                    $productSql = \db('产品_基本资料')->where('产品编号',$value['物料代码'])->fetchSql(true)->update($product);
-                }
-                $productRes = \db()->query($productSql);
-            }
-            $data = [
-                '物料代码'=>$value['物料代码'],
-                '物料名称'=>$value['物料名称'],
-                '规格'=>$value['规格'],
-                '采购单位'=>$value['采购单位'],
-                '领用单位'=>$value['领用单位'],
-                '单位换算率'=>$value['单位换算率'],
-                '单价'=>$value['单价'],
-                '币种'=>$value['币种'],
-                '物料备注'=>$value['物料备注'],
-                '状态'=>$value['状态'],
-                'Sys_id'=>'[272/超级用户]',
-                'Sys_rq'=>date('Y-m-d H:i:s',time()),
-                'Mod_rq'=>'1900-01-01 00:00:00',
-                'U8UID'=>$value['U8_UID'],
-                'UniqId'=>$value['UniqId'],
-            ];
-            $number = \db('物料_存货编码')
-                ->where('U8UID',$value['U8_UID'])
-                ->count();
-            if ($number === 0){
-                $sql = \db('物料_存货编码')->fetchSql(true)->insert($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_04物料编码')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
-            }else{
-                $sql = \db('物料_存货编码')
-                    ->fetchSql(true)
-                    ->where('U8UID',$value['U8_UID'])
-                    ->update($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_04物料编码')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
+        $erpDb = $this->getErpDb();
+        $modules = $syncModule === '4' ? ['1', '2', '3'] : [$syncModule];
+        $inserted = [];
+        $syncDate = date('Y-m-d');
+        $workOrder['同步日期'] = $syncDate;
+
+        $erpDb->startTrans();
+        try {
+            foreach ($modules as $module) {
+                if ($module === '1') {
+                    $rows = [$workOrder];
+                    $count = $this->insertErpRows($erpDb, 'work_order', $rows);
+                    $inserted['work_order'] = $count;
+                } elseif ($module === '2') {
+                    $rows = $this->fetchWorkOrderProcessList($workOrderNo);
+                    if (empty($rows)) {
+                        throw new \Exception('工单工艺数据为空');
+                    }
+                    foreach ($rows as &$processRow) {
+                        $processRow['生产款号'] = $workOrder['生产款号'];
+                        $processRow['订单数量'] = $workOrder['订单数量'];
+                    }
+                    unset($processRow);
+                    $count = $this->insertErpRows($erpDb, 'process', $rows);
+                    $inserted['process'] = $count;
+                } elseif ($module === '3') {
+                    $rows = $this->fetchProductionCheckRows($workOrderNo, $syncDate);
+                    if (empty($rows)) {
+                        throw new \Exception('报工数据为空,请先完成报工');
+                    }
+                    $count = $this->insertErpRows($erpDb, 'report', $rows, $syncDate);
+                    $inserted['report'] = $count;
                 }
             }
+            $erpDb->commit();
+        } catch (\Exception $e) {
+            $erpDb->rollback();
+            throw $e;
         }
-        if ($i !== 0){
-            $this->error('物料编码同步失败');
-        }else{
-            $this->success('物料编码同步成功');
-        }
+
+        return $workOrderNo . '_' . $syncModule . '_' . time();
     }
 
     /**
-     * 客户供应商数据同步
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\db\exception\BindParamException
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\exception\PDOException
+     * 写入 ERP 表
      */
-    public function CustomerSupplierData()
+    private function insertErpRows($erpDb, $tableKey, array $sourceRows, $syncDate = null)
     {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
+        $config = $this->erpTableMap[$tableKey];
+        if (empty($config['table'])) {
+            throw new \Exception('请先在 Synchronization.php 中配置 ERP [' . $tableKey . '] 表名');
         }
-        $db3 = \db()->connect(config('database.db3'));
-        $OrganizationalDataList = $db3->name('U8_03客户供应商')
-            ->where('MES接收时间',null)
-            ->where('MES接收状态','0')
-            ->select();
-        if (empty($OrganizationalDataList)){
-            $this->success('未找到新的客户供应商');
+
+        $sfbSeq = 0;
+        $sfbPrefix = '';
+        if ($tableKey === 'report') {
+            $syncDate = $syncDate ?: date('Y-m-d');
+            $sfbPrefix = 'K' . date('ymd', strtotime($syncDate));
+            $sfbSeq = $this->fetchMaxSfbSeq($erpDb, $sfbPrefix);
         }
-        $i = 0;
-        foreach ($OrganizationalDataList as $key=>$value){
-            $data = [
-                '类型'=>$value['类型'],
-                '编号'=>$value['编号'],
-                '名称'=>$value['名称'],
-                '简称'=>$value['简称'],
-                '地址'=>$value['地址'],
-                '对口部门'=>$value['对口部门'],
-                '联系人'=>$value['联系人'],
-                '电话'=>$value['电话'],
-                '业务员'=>$value['业务员'],
-                '币种'=>$value['币种'],
-                'Sys_id'=>'[272/超级用户]',
-                'Sys_rq'=>date('Y-m-d H:i:s',time()),
-                'Mod_rq'=>'1900-01-01 00:00:00',
-                'U8UID'=>$value['U8_UID'],
-                'UniqId'=>$value['UniqId'],
-            ];
-            $number = \db('erp_客户供应商')
-                ->where('U8UID',$value['U8_UID'])
-                ->count();
-            if ($number === 0){
-                $sql = \db('erp_客户供应商')->fetchSql(true)->insert($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_03客户供应商')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
-            }else{
-                $sql = \db('erp_客户供应商')
-                    ->fetchSql(true)
-                    ->where('U8UID',$value['U8_UID'])
-                    ->update($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_03客户供应商')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
+
+        $erpRows = [];
+        foreach ($sourceRows as $sourceRow) {
+            $mapped = $this->mapSourceRowToErp($sourceRow, $config['fields']);
+            if ($tableKey === 'report') {
+                $sfbSeq++;
+                $mapped['sfb_id'] = $sfbPrefix . str_pad((string)$sfbSeq, 4, '0', STR_PAD_LEFT);
+            }
+            if (!empty($mapped)) {
+                $erpRows[] = $mapped;
             }
         }
-        if ($i !== 0){
-            $this->error('客户供应商同步失败');
-        }else{
-            $this->success('客户供应商同步成功');
+        if (empty($erpRows)) {
+            throw new \Exception('ERP [' . $tableKey . '] 字段映射未配置或映射结果为空');
+        }
+
+        $result = $erpDb->name($config['table'])->insertAll($erpRows);
+        if ($result === false || $result === 0) {
+            throw new \Exception('写入 ERP [' . $tableKey . '] 失败');
         }
+        return (int)$result;
     }
 
     /**
-     * 物料领用记录数据同步
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\db\exception\BindParamException
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\exception\PDOException
+     * 查询 ERP 报工表当日 sfb_id 最大序号(K+年月日+四位自增)
+     * 须对末四位做数值 MAX,字符串 MAX 在序号≥10 时会算错导致主键冲突
      */
-    public function ReceiptRecordData()
+    private function fetchMaxSfbSeq($erpDb, $sfbPrefix)
     {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $db3 = \db()->connect(config('database.db3'));
-        $OrganizationalDataList = $db3->name('U8_07物料领用')
-            ->where('MES接收时间',null)
-            ->where('MES接收状态','0')
-            ->select();
-        if (empty($OrganizationalDataList)){
-            $this->success('未找到新的物料领用记录');
-        }
-        $i = 0;
-        foreach ($OrganizationalDataList as $key=>$value){
-            if (preg_match("/[A-Za-z]/",$value['工单编号'])){
-                $workcode = $value['工单编号'];
-            }else{
-                $workcode = 'Y'.$value['工单编号'];
+        $row = $erpDb->query(
+            'SELECT MAX(CAST(RIGHT(sfb_id, 4) AS INT)) AS max_seq FROM wfc_shift_feedback WHERE sfb_id LIKE ?',
+            [$sfbPrefix . '%']
+        );
+        if (empty($row) || !isset($row[0]['max_seq']) || $row[0]['max_seq'] === null) {
+            return 0;
+        }
+        return (int)$row[0]['max_seq'];
+    }
+
+    /**
+     * 撤回时删除 ERP 数据(需配置表名及工单编号字段)
+     */
+    private function deleteErpDataByWorkOrder($workOrderNo)
+    {
+        $erpDb = $this->getErpDb();
+        foreach (['work_order', 'process', 'report'] as $tableKey) {
+            $config = $this->erpTableMap[$tableKey];
+            if (empty($config['table'])) {
+                continue;
             }
-            $data = [
-                'st_rq'=>$value['日期'],
-                'st_jylb'=>$value['交易类别'],
-                'st_gdbh'=>$workcode,
-                '采购单号'=>$value['采购单号'],
-                '供方批次'=>$value['供方批次'],
-                'st_wlbh'=>$value['物料编号'],
-                'st_sl'=>$value['领用数量'],
-                'st_dw'=>$value['领用单位'],
-                '领用单价'=>$value['领用单价'],
-                'st_desc'=>$value['备注'],
-                '仓库编号'=>$value['仓库编号'],
-                'st_dpt'=>$value['采购单号'],
-                'st_jtbh'=>$value['机台编号'],
-                'sys_id'=>'[272/超级用户]',
-                'sys_rq'=>date('Y-m-d H:i:s',time()),
-                'mod_rq'=>'1900-01-01 00:00:00',
-                'U8UID'=>$value['U8_UID'],
-                'Uniqid'=>$value['UniqId'],
-                'cpdh' => $value['产品编码']
-            ];
-            $number = \db('物料_收发记录')
-                ->where('U8UID',$value['U8_UID'])
-                ->count();
-            if ($number === 0){
-                $sql = \db('物料_收发记录')->fetchSql(true)->insert($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_07物料领用')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
-            }else{
-                $sql = \db('物料_收发记录')
-                    ->fetchSql(true)
-                    ->where('U8UID',$value['U8_UID'])
-                    ->update($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_07物料领用')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
+            $workOrderField = $this->resolveErpWorkOrderField($tableKey, $config['fields']);
+            if ($workOrderField === '') {
+                continue;
             }
-        }
-        if ($i !== 0){
-            $this->error('物料领用记录同步失败');
-        }else{
-            $this->success('物料领用记录同步成功');
+            $erpDb->name($config['table'])->where($workOrderField, $workOrderNo)->delete();
         }
     }
 
     /**
-     * 仓库信息数据同步
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\db\exception\BindParamException
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\exception\PDOException
+     * MES 行映射为 ERP 行
      */
-    public function WarehouseInformationData()
+    private function mapSourceRowToErp(array $sourceRow, array $fieldMap)
     {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
+        $erpRow = [];
+        foreach ($fieldMap as $mesField => $erpField) {
+            if ($erpField === '' || $erpField === null) {
+                continue;
+            }
+            if ($mesField !== '' && $mesField[0] === '=') {
+                $erpRow[$erpField] = substr($mesField, 1);
+                continue;
+            }
+            if (array_key_exists($mesField, $sourceRow)) {
+                $erpRow[$erpField] = $sourceRow[$mesField];
+            }
         }
-        $db3 = \db()->connect(config('database.db3'));
-        $OrganizationalDataList = $db3->name('U8_12仓库信息')
-            ->where('MES接收时间',null)
-            ->where('MES接收状态','0')
-            ->select();
-        if (empty($OrganizationalDataList)){
-            $this->success('未找到新的仓库信息');
+        return $erpRow;
+    }
+
+    private function resolveErpWorkOrderField($tableKey, array $fieldMap)
+    {
+        $candidates = ['订单编号', 'work_order', 'work_order_no'];
+        if ($tableKey === 'work_order') {
+            $candidates = ['订单编号', 'work_order_no'];
         }
-        $i = 0;
-        foreach ($OrganizationalDataList as $key=>$value){
-            $data = [
-                '编号'=>$value['编号'],
-                '名称'=>$value['名称'],
-                'Sys_id'=>'[272/超级用户]',
-                'Sys_rq'=>date('Y-m-d H:i:s',time()),
-                'Mod_rq'=>'1900-01-01 00:00:00',
-                'U8UID'=>$value['U8_UID'],
-                'UniqId'=>$value['UniqId'],
-            ];
-            $number = \db('物料_仓库信息')
-                ->where('U8UID',$value['U8_UID'])
-                ->count();
-            if ($number === 0){
-                $sql = \db('物料_仓库信息')->fetchSql(true)->insert($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_12仓库信息')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
-            }else{
-                $sql = \db('物料_仓库信息')
-                    ->fetchSql(true)
-                    ->where('U8UID',$value['U8_UID'])
-                    ->update($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_12仓库信息')
-                        ->where('UniqId', $value['UniqId'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
+        foreach ($candidates as $mesField) {
+            if (isset($fieldMap[$mesField]) && $fieldMap[$mesField] !== '') {
+                return $fieldMap[$mesField];
             }
         }
-        if ($i !== 0){
-            $this->error('仓库信息同步失败');
-        }else{
-            $this->success('仓库信息同步成功');
-        }
+        return '';
     }
 
     /**
-     * 职位编码数据同步
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\db\exception\BindParamException
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\exception\PDOException
+     * 工序产量核查数据(与 WorkOrderProcess::checkProcessProduction 一致,扁平化为报工行)
      */
-    public function PositionData()
+    private function fetchProductionCheckRows($workOrderNo, $syncDate = null)
     {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $db3 = \db()->connect(config('database.db3'));
-        $OrganizationalDataList = $db3->name('U8_13职位编码')
-            ->where('MES接收时间',null)
-            ->where('MES接收状态','0')
+        $syncDate = $syncDate ?: date('Y-m-d');
+        $list = Db::name('设备_工分计酬')->alias('a')
+            ->join('工单_基本资料 b', 'a.work_order = b.订单编号 AND b.Mod_rq IS NULL', 'LEFT')
+            ->where('a.work_order', $workOrderNo)
+            ->whereNull('a.del_rq')
+            ->field('b.订单编号,b.生产款号,b.款式,a.process_code as 工序号,a.process_name as 工序名称,a.staff_no 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($OrganizationalDataList)){
-            $this->success('未找到新的职位编码');
+
+        if (empty($list)) {
+            return [];
         }
-        $i = 0;
-        foreach ($OrganizationalDataList as $key=>$value){
-            $data = [
-                '职位编码'=>$value['职位编码'],
-                '职位名称'=>$value['职位名称'],
-                '定编人数'=>0,
-                '备注说明'=>'',
-                'sys_id'=>'[272/超级用户]',
-                'sys_rq'=>date('Y-m-d H:i:s',time()),
-                'Mod_rq'=>'1900-01-01 00:00:00',
-                'U8UID'=>$value['U8_UID'],
-                'UniqID'=>$value['UniqID'],
+
+        $rows = [];
+        foreach ($list as $row) {
+            $rows[] = [
+                '订单编号' => $row['订单编号'],
+                '生产款号' => $row['生产款号'],
+                '款式' => $row['款式'],
+                '工序号' => $row['工序号'],
+                '工序名称' => $row['工序名称'],
+                '员工编号' => $row['员工编号'],
+                '员工姓名' => $row['员工姓名'],
+                '数量' => floatval($row['数量']),
+                '开工日期' => !empty($row['开工日期']) ? date('Y-m-d', strtotime($row['开工日期'])) : '',
+                '完工日期' => !empty($row['完工日期']) ? date('Y-m-d', strtotime($row['完工日期'])) : '',
+                '填报日期' => $syncDate,
+                '工分' => round(floatval($row['工分']), 4),
+                '工时' => round(floatval($row['工时']), 4),
+                '工资' => round(floatval($row['工资']), 4),
             ];
-            $number = \db('人事_职位编码')
-                ->where('U8UID',$value['U8_UID'])
-                ->count();
-            if ($number === 0){
-                $sql = \db('人事_职位编码')->fetchSql(true)->insert($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_13职位编码')
-                        ->where('UniqID', $value['UniqID'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
-            }else{
-                $sql = \db('人事_职位编码')
-                    ->fetchSql(true)
-                    ->where('U8UID',$value['U8_UID'])
-                    ->update($data);
-                $res = \db()->query($sql);
-                if ($res === false){
-                    $i++;
-                }else{
-                    $sqlString = $db3->name('U8_13职位编码')
-                        ->where('UniqID', $value['UniqID'])
-                        ->fetchSql(true)
-                        ->update([
-                            'MES接收时间' => date('Y-m-d H:i:s', time()),
-                            'MES接收状态' => '1'
-                        ]);
-                    $db3->execute($sqlString);
-                }
-            }
-        }
-        if ($i !== 0){
-            $this->error('职位编码同步失败');
-        }else{
-            $this->success('职位编码同步成功');
         }
+        return $rows;
     }
 
-    /**
-     * 设备产量计酬云中间表数据库同步
-     * @return void
-     * @throws \think\db\exception\BindParamException
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     * @throws \think\exception\PDOException
-     */
-//    public function ProductionData()
-//    {
-//        if ($this->request->isGet() === false){
-//            $this->error('请求错误');
-//        }
-//        if(is_dir(ROOT_PATH.'public/'.date('Y-m-d',time())) == null)
-//        {
-//            mkdir(ROOT_PATH.'public/'.date('Y-m-d',time()),0777,true);
-//        }
-//        $machineList = \db('设备_基本资料')
-//            ->where('mn_设备编号','<>','')
-//            ->where('sys_sbID','<>','')
-//            ->field('mn_设备编号')
-//            ->select();
-//        $machine = [];
-//        foreach ($machineList as $value){
-//            array_push($machine,$value['mn_设备编号']);
-//        }
-//        $db5 = \db()->connect(config('database.db5'));
-//        $where = [
-//            'sczl_rq' => ['>=','2024-05-01 00:00:00']
-//        ];
-//        $productData = $db5->name('设备_产量计酬')
-//            ->where($where)
-//            ->where('sczl_jtbh','in',$machine)
-//            ->select();
-//        //获取机台信息
-//        $machineData = \db('设备_基本资料')
-//            ->where('mn_设备编号','<>','')
-//            ->where('sys_sbID','<>','')
-//            ->field('rtrim(设备编号) as 设备编号,rtrim(mn_设备编号) as 美浓设备编号')
-//            ->select();
-//        //获取员工资料
-//        $employeeData = \db('人事_基本资料')
-//            ->where('mn_员工编号','<>','')
-//            ->field('rtrim(mn_员工编号) as 美浓员工编号')
-//            ->select();
-//        $employee = array_column($employeeData,'美浓员工编号');
-//        //循环判断机台、员工编号
-//        $j = 0;
-//        $data = [];
-//        foreach ($productData as $key=>$value){
-////            判断机台编号
-//            foreach ($machineData as $v){
-//                if ($value['sczl_jtbh'] === $v['美浓设备编号']){
-//                    $productData[$key]['sczl_jtbh'] = $v['美浓设备编号'];
-//                    array_push($data,$productData[$key]);
-//                }
-//            }
-//        }
-//        if (empty($data)){
-//            $this->error('未找到新的生产数据');
-//        }
-//        foreach ($data as $key=>$value){
-//            $name = [];
-//            //判断员工编号,如果不存在写入日志文件
-//            for($i=1;$i<=10;$i++){
-//                if (in_array($data[$key]['sczl_bh'.$i],$employee)){
-//                    $data[$key]['sczl_bh'.$i] = \db('人事_基本资料')
-//                        ->where('mn_员工编号',$data[$key]['sczl_bh'.$i])
-//                        ->value('员工编号');
-//                }else{
-//                    array_push($name,$value['sczl_bh'.$i]);
-//                    $data[$key]['sczl_bh'.$i] = '';
-//                }
-//
-//            }
-//            $name = array_unique($name);
-//            $filename = ROOT_PATH.'public/'.date('Y-m-d',time()).'/'.$value['sczl_jtbh'].'日志文件.txt';
-//            $handle = fopen($filename, 'w');
-//            foreach ($name as $v){
-//                fwrite($handle, $v);
-//            }
-//            fclose($handle);
-//            //修改工单编号
-////            if (preg_match("/[A-Za-z]/",$value['sczl_gdbh'])){
-////                $workcode = $value['sczl_gdbh'];
-////            }else{
-////                $workcode = 'Y'.$value['sczl_gdbh'];
-////            }
-////            $data[$key]['sczl_gdbh'] = $workcode;
-//        }
-//        //插入设备产量计酬数据
-//        \db('设备_产量计酬')->delete(true);
-//        $sql = \db('设备_产量计酬')->fetchSql(true)->insertAll($data);
-//        $res = \db()->query($sql);
-//        if ($res !== false){
-//            $this->success('同步成功');
-//        }else{
-//            $this->error('同步失败');
-//        }
-//    }
-
-
-
-    //工单核检单同步
-    public function copy()
+    private function fetchWorkOrderBasic($workOrderNo)
     {
-        $param = $this->request->param();
-        $db5 = \db()->connect(config('database.db5'));
-        $list = $db5->name('db_qczl')
-            ->where('qczl_gdbh',$param['order'])
-            ->where('qczl_yjno',$param['yjno'])
+        return Db::table('工单_基本资料')
+            ->where('订单编号', $workOrderNo)
+            ->whereNull('Mod_rq')
+            ->find();
+    }
+
+    private function fetchWorkOrderProcessList($workOrderNo)
+    {
+        return Db::table('工单_基础工艺资料')
+            ->where('work_order', $workOrderNo)
+            ->whereNull('del_rq')
+            ->field('work_order,part_code,part_name,process_code,process_name,big_process,
+                standard_hour,standard_minutes,standard_score,money,coefficient,remark')
+            ->order('process_code')
             ->select();
-        foreach ($list  as $key=>$value){
-            for ($i=1;$i<14;$i++){
-                if (!empty($value['fp_bh'.$i])){
-                    $name = \db('人事_基本资料')
-                        ->where('mn_员工编号',$value['fp_bh'.$i])
-                        ->order('Uniqid')
-                        ->value('员工编号');
-                    if (empty($name)){
-                        $name = '0000';
-                    }
-                    $list[$key]['fp_bh'.$i] = $name;
+    }
+
+    private function fetchReportSeqRange($workOrderNo)
+    {
+        $range = Db::table('设备_工分计酬')
+            ->where('work_order', $workOrderNo)
+            ->whereNull('del_rq')
+            ->field('MIN(id) as min_id,MAX(id) as max_id')
+            ->find();
+        return [
+            'start' => !empty($range['min_id']) ? (string)$range['min_id'] : '',
+            'end' => !empty($range['max_id']) ? (string)$range['max_id'] : '',
+        ];
+    }
+
+    private function insertSyncLog(array $data)
+    {
+        $data['create_time'] = date('Y-m-d H:i:s');
+        $data['update_time'] = $data['create_time'];
+        return (int)Db::name('mes_erp_work_order_sync_log')->insertGetId($data);
+    }
+
+    private function insertOperationLog(array $data)
+    {
+        $data['create_time'] = date('Y-m-d H:i:s');
+        return (int)Db::name('mes_erp_operation_log')->insertGetId($data);
+    }
+
+    private function getErpDb()
+    {
+        return Db::connect(config('database.db2'));
+    }
+
+    private function batchResolveDisplaySyncStatus(array $orderNos)
+    {
+        $orderNos = array_values(array_unique(array_filter($orderNos)));
+        if (empty($orderNos)) {
+            return [];
+        }
+
+        $defaultStatus = $this->defaultDisplaySyncStatus();
+        $result = [];
+        foreach ($orderNos as $orderNo) {
+            $result[$orderNo] = $defaultStatus;
+        }
+
+        $latestSyncRows = Db::name('mes_erp_work_order_sync_log')
+            ->whereIn('work_order_no', $orderNos)
+            ->order('id desc')
+            ->select();
+        $latestSyncMap = [];
+        foreach ($latestSyncRows as $row) {
+            if (!isset($latestSyncMap[$row['work_order_no']])) {
+                $latestSyncMap[$row['work_order_no']] = $row;
+            }
+        }
+
+        $successSyncRows = Db::name('mes_erp_work_order_sync_log')
+            ->whereIn('work_order_no', $orderNos)
+            ->where('sync_status', self::SYNC_STATUS_SUCCESS)
+            ->order('id desc')
+            ->select();
+        $latestSuccessSyncMap = [];
+        foreach ($successSyncRows as $row) {
+            if (!isset($latestSuccessSyncMap[$row['work_order_no']])) {
+                $latestSuccessSyncMap[$row['work_order_no']] = $row;
+            }
+        }
+
+        $cancelRows = Db::name('mes_erp_operation_log')
+            ->whereIn('work_order_no', $orderNos)
+            ->where('operate_type', 'cancel')
+            ->where('operate_status', self::OPERATE_STATUS_SUCCESS)
+            ->order('id desc')
+            ->select();
+        $latestCancelMap = [];
+        foreach ($cancelRows as $row) {
+            if (!isset($latestCancelMap[$row['work_order_no']])) {
+                $latestCancelMap[$row['work_order_no']] = $row;
+            }
+        }
+
+        foreach ($orderNos as $orderNo) {
+            $latestSync = isset($latestSyncMap[$orderNo]) ? $latestSyncMap[$orderNo] : null;
+            if (empty($latestSync)) {
+                continue;
+            }
+
+            $latestSuccessSync = isset($latestSuccessSyncMap[$orderNo]) ? $latestSuccessSyncMap[$orderNo] : null;
+            if (!empty($latestSuccessSync)) {
+                $cancelAfterSync = isset($latestCancelMap[$orderNo]) ? $latestCancelMap[$orderNo] : null;
+                if (!empty($cancelAfterSync) && $cancelAfterSync['operate_time'] >= $latestSuccessSync['sync_time']) {
+                    $result[$orderNo] = [
+                        'code' => 'cancelled',
+                        'text' => '已撤回',
+                        'sync_time' => $latestSuccessSync['sync_time'],
+                        'sync_msg' => $latestSync['sync_msg'],
+                        'sync_log_id' => $latestSuccessSync['id'],
+                    ];
+                    continue;
                 }
+                $result[$orderNo] = [
+                    'code' => 'synced',
+                    'text' => '已同步',
+                    'sync_time' => $latestSuccessSync['sync_time'],
+                    'sync_msg' => $latestSuccessSync['sync_msg'],
+                    'sync_log_id' => $latestSuccessSync['id'],
+                ];
+                continue;
+            }
+
+            if ((int)$latestSync['sync_status'] === self::SYNC_STATUS_FAILED) {
+                $result[$orderNo] = [
+                    'code' => 'failed',
+                    'text' => '同步失败',
+                    'sync_time' => $latestSync['sync_time'],
+                    'sync_msg' => $latestSync['sync_msg'],
+                    'sync_log_id' => $latestSync['id'],
+                ];
+                continue;
+            }
+
+            $result[$orderNo] = [
+                'code' => 'pending',
+                'text' => '待同步',
+                'sync_time' => $latestSync['sync_time'],
+                'sync_msg' => $latestSync['sync_msg'],
+                'sync_log_id' => $latestSync['id'],
+            ];
+        }
+
+        return $result;
+    }
+
+    private function resolveDisplaySyncStatus($workOrderNo)
+    {
+        $latestSync = Db::name('mes_erp_work_order_sync_log')
+            ->where('work_order_no', $workOrderNo)
+            ->order('id desc')
+            ->find();
+
+        if (empty($latestSync)) {
+            return $this->defaultDisplaySyncStatus();
+        }
+
+        $latestSuccessSync = Db::name('mes_erp_work_order_sync_log')
+            ->where('work_order_no', $workOrderNo)
+            ->where('sync_status', self::SYNC_STATUS_SUCCESS)
+            ->order('id desc')
+            ->find();
+
+        if (!empty($latestSuccessSync)) {
+            $cancelAfterSync = Db::name('mes_erp_operation_log')
+                ->where('work_order_no', $workOrderNo)
+                ->where('operate_type', 'cancel')
+                ->where('operate_status', self::OPERATE_STATUS_SUCCESS)
+                ->where('operate_time', '>=', $latestSuccessSync['sync_time'])
+                ->order('id desc')
+                ->find();
+            if (!empty($cancelAfterSync)) {
+                return [
+                    'code' => 'cancelled',
+                    'text' => '已撤回',
+                    'sync_time' => $latestSuccessSync['sync_time'],
+                    'sync_msg' => $latestSync['sync_msg'],
+                    'sync_log_id' => $latestSuccessSync['id'],
+                ];
             }
+            return [
+                'code' => 'synced',
+                'text' => '已同步',
+                'sync_time' => $latestSuccessSync['sync_time'],
+                'sync_msg' => $latestSuccessSync['sync_msg'],
+                'sync_log_id' => $latestSuccessSync['id'],
+            ];
+        }
+
+        if ((int)$latestSync['sync_status'] === self::SYNC_STATUS_FAILED) {
+            return [
+                'code' => 'failed',
+                'text' => '同步失败',
+                'sync_time' => $latestSync['sync_time'],
+                'sync_msg' => $latestSync['sync_msg'],
+                'sync_log_id' => $latestSync['id'],
+            ];
         }
-        $sql = \db('db_qczl')->fetchSql(true)->insertAll($list);
-        \db()->query($sql);
 
+        return [
+            'code' => 'pending',
+            'text' => '待同步',
+            'sync_time' => $latestSync['sync_time'],
+            'sync_msg' => $latestSync['sync_msg'],
+            'sync_log_id' => $latestSync['id'],
+        ];
+    }
+
+    private function defaultDisplaySyncStatus()
+    {
+        return [
+            'code' => 'unsynced',
+            'text' => '未同步',
+            'sync_time' => '',
+            'sync_msg' => '',
+            'sync_log_id' => null,
+        ];
+    }
+
+    private function buildSyncOperateContent($workOrderNo, $syncModule, $operateType)
+    {
+        $moduleText = $this->syncModuleText($syncModule);
+        $typeMap = [
+            'sync' => '同步',
+            'retry' => '重试同步',
+            'manual' => '手动同步',
+            'auto' => '自动同步',
+        ];
+        $typeText = isset($typeMap[$operateType]) ? $typeMap[$operateType] : '同步';
+        return $typeText . '工单' . $workOrderNo . ',模块:' . $moduleText;
+    }
+
+    private function syncStatusText($status)
+    {
+        $map = [
+            self::SYNC_STATUS_PENDING => '待同步',
+            self::SYNC_STATUS_SUCCESS => '同步成功',
+            self::SYNC_STATUS_FAILED => '同步失败',
+        ];
+        return isset($map[(int)$status]) ? $map[(int)$status] : '未知';
+    }
+
+    private function syncModuleText($module)
+    {
+        $map = [
+            '1' => '工单数据',
+            '2' => '工艺数据',
+            '3' => '报工数据',
+            '4' => '全量同步',
+        ];
+        return isset($map[(string)$module]) ? $map[(string)$module] : (string)$module;
+    }
+
+    private function operateStatusText($status)
+    {
+        $map = [
+            self::OPERATE_STATUS_SUCCESS => '成功',
+            self::OPERATE_STATUS_FAILED => '失败',
+            self::OPERATE_STATUS_PROCESSING => '处理中',
+        ];
+        return isset($map[(int)$status]) ? $map[(int)$status] : '未知';
+    }
+
+    private function formatDateValue($value)
+    {
+        if (empty($value)) {
+            return null;
+        }
+        $timestamp = strtotime($value);
+        return $timestamp ? date('Y-m-d', $timestamp) : null;
     }
-}
+}

+ 81 - 23
application/api/controller/WorkOrder.php

@@ -226,38 +226,96 @@ class WorkOrder extends Api
     }
 
     /**
-     * U8工单资料删除
-     * @param string $workOrder  工单编号
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
+     * U8工单资料批量删除(软删除)
+     * @param string Uniqid 工单Uniqid,多个用英文逗号拼接
      */
-
-
     public function orderDataDel()
     {
-        if($this->request->isGet() === false){
+        if (!$this->request->isGet()) {
             $this->error('请求错误');
         }
-        $workOrder = input('Uniqid');
-        if (empty($workOrder)){
+        $uniqidParam = $this->request->param('Uniqid');
+        if (empty($uniqidParam)) {
             $this->error('参数错误');
         }
-        $order = \db('工单_基本资料')->where('UniqId',$workOrder)->find();
-        \db()->startTrans();
+
+        $uniqids = array_values(array_unique(array_filter(array_map('trim', explode(',', $uniqidParam)))));
+        if (empty($uniqids)) {
+            $this->error('参数错误');
+        }
+
+        $orders = Db::table('工单_基本资料')
+            ->where(function ($query) use ($uniqids) {
+                $query->whereIn('Uniqid', $uniqids)->whereOr('UniqId', 'in', $uniqids);
+            })
+            ->whereNull('Mod_rq')
+            ->field('Uniqid,UniqId,订单编号')
+            ->select();
+        if (empty($orders)) {
+            $this->error('工单不存在或已删除');
+        }
+
+        $foundKeys = [];
+        foreach ($orders as $order) {
+            if (!empty($order['Uniqid'])) {
+                $foundKeys[$order['Uniqid']] = true;
+            }
+            if (!empty($order['UniqId'])) {
+                $foundKeys[$order['UniqId']] = true;
+            }
+        }
+        $notFound = array_diff($uniqids, array_keys($foundKeys));
+        if (!empty($notFound)) {
+            $this->error('部分工单不存在或已删除:' . implode(',', $notFound));
+        }
+
+        $orderNos = array_unique(array_column($orders, '订单编号'));
+        $now = date('Y-m-d H:i:s');
+        $softDelete = ['Mod_rq' => $now];
+
+        Db::startTrans();
         try {
-            \db('工单_印件资料')->where('订单编号',$order['订单编号'])->update(['Mod_rq'=>date('Y-m-d H:i:s')]);
-            \db('工单_工艺资料')->where('订单编号',$order['订单编号'])->update(['Mod_rq'=>date('Y-m-d H:i:s')]);
-            $res = \db('工单_基本资料')->where('UniqId',$workOrder)->update(['Mod_rq'=>date('Y-m-d H:i:s')]);
-            \db()->commit();
-        } catch (\Exception $e){
-            \db()->rollback();
-        }
-        if ($res !== false){
-            $this->success('成功');
-        }else{
-            $this->error('失败');
+            Db::table('工单_印件资料')
+                ->whereIn('订单编号', $orderNos)
+                ->whereNull('Mod_rq')
+                ->update($softDelete);
+            Db::table('工单_bom资料')
+                ->whereIn('BOM_工单编号', $orderNos)
+                ->whereNull('Mod_rq')
+                ->update($softDelete);
+            Db::table('工单关联表')
+                ->whereIn('订单编号', $orderNos)
+                ->whereNull('Mod_rq')
+                ->update($softDelete);
+            Db::table('工单_面料资料')
+                ->whereIn('BOM_工单编号', $orderNos)
+                ->whereNull('Mod_rq')
+                ->update($softDelete);
+            Db::table('工单_工艺资料')
+                ->whereIn('订单编号', $orderNos)
+                ->whereNull('Mod_rq')
+                ->update($softDelete);
+            $result = Db::table('工单_基本资料')
+                ->where(function ($query) use ($uniqids) {
+                    $query->whereIn('Uniqid', $uniqids)->whereOr('UniqId', 'in', $uniqids);
+                })
+                ->whereNull('Mod_rq')
+                ->update($softDelete);
+            if ($result === false) {
+                throw new \Exception('删除工单失败');
+            }
+            if ($result === 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($orders)]);
     }
 
 

+ 9 - 6
application/api/controller/WorkOrderProcess.php

@@ -280,7 +280,7 @@ class WorkOrderProcess extends Api
 
        /**
      * 工单工艺列表
-     *  @param workorder 工单编号 
+     *  @param workorder 工单编号
      */
     // public function GetProcessList()
     // {
@@ -404,6 +404,7 @@ class WorkOrderProcess extends Api
         $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'],
@@ -452,7 +453,7 @@ class WorkOrderProcess extends Api
         if (empty($params['big_process'])) {
             $this->error('大工艺不能为空');
         }
-  
+
         if (!isset($params['coefficient']) || $params['coefficient'] === '') {
             $params['coefficient'] = 'C';
         }
@@ -1113,7 +1114,7 @@ class WorkOrderProcess extends Api
         }
         $this->success('修改成功');
     }
-   
+
 
 
     /**
@@ -1819,14 +1820,15 @@ class WorkOrderProcess extends Api
             ->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 员工姓名,
+            a.sys_id as 小组,
                 SUM(a.number) as 数量,MIN(a.date) as 开工日期,MAX(a.date) as 完工日期,
-                SUM(a.salary) as 金额,SUM(a.production_hour) as 工时,SUM(a.salary) 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('未找到报工数据');
+            $this->error('暂无报工数据');
         }
 
         $data = [
@@ -1851,10 +1853,11 @@ class WorkOrderProcess extends Api
             $endDate = !empty($row['完工日期']) ? date('Y-m-d', strtotime($row['完工日期'])) : '';
             $processMap[$processKey]['staffs'][] = [
                 '员工姓名' => $row['员工姓名'],
+                '小组' => $row['小组'],
                 '数量' => floatval($row['数量']),
                 '开工日期' => $startDate,
                 '完工日期' => $endDate,
-                '金额' => round(floatval($row['金额']), 4),
+                '工分' => round(floatval($row['工分']), 4),
                 '工时' => round(floatval($row['工时']), 4),
                 '工资' => round(floatval($row['工资']), 4),
             ];