<?php
namespace app\adminVue\controller;

use think\facade\Db;
use think\exception\HttpResponseException;

/** 新版售后台账，只读；使用已有后台Token和菜单角色权限。 */
class CsRecords extends TokenCheck
{
    protected $recordAdmin;
    public function initialize() {
        // 当前账号和角色实时校验，避免沿用旧Token缓存中的已撤销权限。
        $token=$this->request->header('token','');
        $this->recordAdmin=is_string($token)&&$token!==''?Db::name('admin_user')->where(['token'=>$token,'status'=>1])->find():null;
        if (!$this->recordAdmin) $this->reject('登录已失效，请重新登录',470);
    }
    private function reject($message,$status=400) { throw new HttpResponseException(json(['code'=>1,'msg'=>$message,'data'=>null],$status)); }
    private function authorize($kind) {
        if ($this->request->method()!=='GET') $this->reject('仅支持查询',405);
        if (!in_array($kind,['dailyIssue','afterSalesRepair'],true)) $this->reject('记录类型不正确');
        $path=$kind==='dailyIssue'?'/cs/dailyIssue':'/cs/afterSalesRepair';
        $menu=Db::name('admin_menus_vue')->where('status',1)->whereIn('frontpath',[$path,ltrim($path,'/')])->find();
        if (!$menu) $this->reject('功能菜单未启用',403);
        if ((int)$this->recordAdmin['rightid']>=99) return;
        $roles=Db::name('admin_rights')->where('id',$this->recordAdmin['rightid'])->value('vue_right');
        if (!in_array((int)$menu['id'],array_map('intval',explode(',',(string)$roles)),true)) $this->reject('无权查看或下载此类记录',403);
    }
    private function text($key,$max=100) {
        $value=$this->request->get($key,'');
        if (!is_string($value)||mb_strlen($value)>$max) $this->reject('搜索参数不正确');
        return trim($value);
    }
    private function date($value) {
        if (!is_string($value)) $this->reject('日期格式不正确');
        $date=\DateTimeImmutable::createFromFormat('!Y-m-d',$value,new \DateTimeZone('Asia/Shanghai'));
        if (!$date||$date->format('Y-m-d')!==$value||$value<'2000-01-01'||$value>'2099-12-31') $this->reject('日期格式不正确');
        return $date;
    }
    private function integer($key,$default,$max) {
        $value=$this->request->get($key,$default);
        if ((!is_string($value)&&!is_int($value))||!preg_match('/^[1-9][0-9]{0,9}$/',(string)$value)||(float)$value>$max) $this->reject('数字参数不正确');
        return (int)$value;
    }
    private function query($kind,$export) {
        $daily=$kind==='dailyIssue';
        $query=Db::name($daily?'quality_wir_list':'after_sales_repair');
        if ($daily) $query->whereIn('status',[1,2])->where('wirDate','>',0); else $query->whereNull('deleted_at');
        $start=$this->request->get('startDate',''); $end=$this->request->get('endDate','');
        if ($export&&($start===''||$end==='')) $this->reject('请选择下载日期区间');
        $first=$start!==''?$this->date($start):null; $last=$end!==''?$this->date($end):null;
        if ($first&&$last&&$first>$last) $this->reject('开始日期不能晚于结束日期');
        if ($first) $query->where($daily?'wirDate':'repair_at','>=',$daily?$first->getTimestamp():$first->format('Y-m-d').' 00:00:00');
        if ($last) $query->where($daily?'wirDate':'repair_at','<=',$daily?$last->getTimestamp()+86399:$last->format('Y-m-d').' 23:59:59');
        // 下载以弹窗日期为准，覆盖区间内全部记录，不受列表分页或搜索条件限制。
        if (!$export) {
            $keyword=$this->text('keyword');
            if ($keyword!=='') $query->whereLike($daily?'project|dpn|desc|station':'record_no|trace_no|project|harness_name|problem_description','%'.addcslashes($keyword,'%_\\').'%');
            $project=$this->text('project',50); if ($project!=='') $query->where('project',$project);
            $person=$this->text('personName');
            if ($person!=='') {
                $ids=Db::name('admin_user')->whereLike('truename','%'.addcslashes($person,'%_\\').'%')->column('id');
                $query->whereIn($daily?'owner':'creator_id',$ids?:[0]);
            }
            if ($daily) {
                $status=$this->request->get('status','');
                if ($status!=='') { if (!in_array((string)$status,['1','2'],true)) $this->reject('状态不正确'); $query->where('status',(int)$status); }
            } else {
                $area=$this->text('repairArea',30); if ($area!=='') $query->where('repair_area',$area);
            }
        }
        return $query;
    }
    public function options() {
        $kind=$this->request->get('kind',''); $this->authorize($kind);
        return json(['code'=>0,'data'=>['projects'=>$this->app->config->get('daily_issue.projects',[]),
            'areas'=>['内饰区','底盘区','完成线/终线区','返修调试区','其他区域'],
            'today'=>(new \DateTimeImmutable('now',new \DateTimeZone('Asia/Shanghai')))->format('Y-m-d')]]);
    }
    private function formatted($time,$format='Y-m-d H:i') { return (int)$time>0?(new \DateTimeImmutable('@'.(int)$time))->setTimezone(new \DateTimeZone('Asia/Shanghai'))->format($format):''; }
    private function imageUrl($path) {
        $path=str_replace('\\','/',(string)$path);
        return strpos($path,'/storage/')===0&&strpos($path,'..')===false?rtrim($this->request->domain(),'/').$path:'';
    }
    private function present($kind,$rows,$export=false) {
        if (!$rows) return [];
        $daily=$kind==='dailyIssue'; $recordIds=array_column($rows,'id'); $personIds=array_column($rows,$daily?'owner':'creator_id');
        if ($daily) $personIds=array_merge($personIds,array_column($rows,'publisher_id'));
        $names=Db::name('admin_user')->whereIn('id',array_unique($personIds))->column('truename','id');
        $images=[]; $assist=[];
        if ($daily) {
            foreach (Db::name('img_list')->where(['mid'=>55,'status'=>1])->whereIn('mark',$recordIds)->order('id')->select() as $image) {
                $url=$this->imageUrl($image['img']); if ($url) $images[$image['mark']][]=$export?['id'=>(int)$image['id']]:$url;
            }
        } else {
            foreach (Db::name('after_sales_repair_image')->whereIn('repair_id',$recordIds)->order('id')->select() as $image) {
                $url=$this->imageUrl($image['file_path']); if ($url) $images[$image['repair_id']][(int)$image['image_type']][]=$export?['id'=>(int)$image['id']]:$url;
            }
            foreach (Db::name('after_sales_repair_person')->alias('p')->leftJoin('admin_user a','a.id=p.admin_id')->whereIn('p.repair_id',$recordIds)->field('p.repair_id,p.admin_id,a.truename')->select() as $person)
                $assist[$person['repair_id']][(int)$person['admin_id']]=$person['truename'] ?: '人员已变更';
        }
        $result=[];
        foreach ($rows as $row) {
            if ($daily) {
                $item=['id'=>(int)$row['id'],'wirDate'=>$this->formatted($row['wirDate'],'Y-m-d'),'issueDate'=>$this->formatted($row['issueDate'],'Y-m-d'),
                    'ownerName'=>$names[$row['owner']]??'人员已变更','dutyName'=>[1=>'TBD',3=>'Daily Issue',2=>'WIR'][(int)$row['duty']]??'',
                    'backName'=>[1=>'是',2=>'否'][(int)$row['back']]??'','statusName'=>(int)$row['status']===2?'已发布':'待发布',
                    'createdAt'=>$this->formatted($row['update']),'updatedAt'=>$this->formatted($row['updated_at']),
                    'publishedAt'=>$this->formatted($row['published_at']),'publisherName'=>$names[$row['publisher_id']]??'','images'=>$images[$row['id']]??[]];
                foreach (['project','dpn','station','desc','repair','reason','remark','checkQty','allNgQty','ngQty'] as $field) $item[$field]=(string)$row[$field];
            } else {
                $people=$assist[$row['id']]??[]; unset($people[(int)$row['creator_id']]);
                $item=['id'=>(int)$row['id'],'recordNo'=>$row['record_no'],'repairAt'=>substr($row['repair_at'],0,16),
                    'traceNo'=>$row['trace_no'],'project'=>$row['project'],'harnessName'=>$row['harness_name'],'problemDescription'=>$row['problem_description'],
                    'repairMethod'=>$row['repair_method'],'repairArea'=>$row['repair_area'],'remark'=>$row['remark'],
                    'repairerName'=>$names[$row['creator_id']]??'人员已变更','assistantNames'=>implode('、',array_values($people)),
                    'faultImages'=>$images[$row['id']][1]??[],'completedImages'=>$images[$row['id']][2]??[],
                    'createdAt'=>$row['created_at'],'updatedAt'=>$row['updated_at']];
            }
            $result[]=$item;
        }
        return $result;
    }
    private function read($kind,$export=false) {
        $this->authorize($kind); $query=$this->query($kind,$export);
        $order=$kind==='dailyIssue'?'wirDate desc,id desc':'repair_at desc,id desc';
        if ($export) {
            $rows=$this->present($kind,$query->order($order)->select()->toArray(),true);
            $columns=$kind==='dailyIssue'?[
                'id'=>'记录ID','wirDate'=>'反馈日期','ownerName'=>'反馈人员','project'=>'项目','dpn'=>'线束号','issueDate'=>'生产日期','station'=>'工段','desc'=>'问题描述',
                'repair'=>'现场维修方法','checkQty'=>'排查数量','allNgQty'=>'NG数量','reason'=>'现场初步原因','backName'=>'缺陷件是否返回','ngQty'=>'缺陷数量',
                'remark'=>'备注','dutyName'=>'职责类型','statusName'=>'状态','images'=>'不良图片','createdAt'=>'提交时间','updatedAt'=>'修改时间','publishedAt'=>'发布时间','publisherName'=>'发布人员'
            ]:[
                'recordNo'=>'流水号','repairAt'=>'返修时间','traceNo'=>'车架号/其他追溯号','project'=>'项目','harnessName'=>'线束名称','problemDescription'=>'返修问题描述',
                'repairMethod'=>'返修方法','repairArea'=>'返修区域','repairerName'=>'维修人员','assistantNames'=>'协助维修人员','remark'=>'备注',
                'faultImages'=>'故障图片','completedImages'=>'返修完成图片','createdAt'=>'创建时间','updatedAt'=>'修改时间'
            ];
            $data=[]; foreach ($rows as $row) { $item=[]; foreach ($columns as $key=>$label) $item[$label]=$row[$key]; $data[]=$item; }
            return json(['code'=>0,'data'=>$data,'count'=>count($data)]);
        }
        $page=$this->integer('page',1,1000000); $limit=$this->integer('limit',15,100); $count=(clone $query)->count();
        return json(['code'=>0,'data'=>$this->present($kind,$query->order($order)->page($page,$limit)->select()->toArray()),'count'=>$count]);
    }
    public function dailyIssueRecords() { return $this->read('dailyIssue'); }
    public function dailyIssueExport() { return $this->read('dailyIssue',true); }
    public function repairRecords() { return $this->read('afterSalesRepair'); }
    public function repairExport() { return $this->read('afterSalesRepair',true); }
    protected function imageRoot() { return $this->app->getRootPath().'public/storage/'; }
    public function exportImage() {
        $kind=$this->request->get('kind',''); $this->authorize($kind); $id=$this->integer('imageId',0,2147483647);
        if ($kind==='dailyIssue') {
            $image=Db::name('img_list')->where(['id'=>$id,'mid'=>55,'status'=>1])->find();
            $record=$image?Db::name('quality_wir_list')->where('id',$image['mark'])->whereIn('status',[1,2])->where('wirDate','>',0)->find():null;
            $path=$image['img']??'';
        } else {
            $image=Db::name('after_sales_repair_image')->where('id',$id)->find();
            $record=$image?Db::name('after_sales_repair')->where('id',$image['repair_id'])->whereNull('deleted_at')->find():null;
            $path=$image['file_path']??'';
        }
        if (!$record||strpos($path,'/storage/')!==0||strpos($path,'..')!==false) $this->reject('图片不存在或记录已删除',404);
        $root=realpath($this->imageRoot()); $file=$root?realpath($root.'/'.substr($path,9)):false;
        if (!$file||strpos($file,$root.DIRECTORY_SEPARATOR)!==0||!is_file($file)||!is_readable($file)||filesize($file)>5*1024*1024) $this->reject('图片文件不可读取，请检查记录图片',404);
        $info=@getimagesize($file);
        if (!$info||!in_array($info['mime'],['image/jpeg','image/png','image/webp'],true)) $this->reject('图片格式不正确');
        $bytes=file_get_contents($file); if ($bytes===false) $this->reject('图片读取失败',503);
        return json(['code'=>0,'data'=>['dataUrl'=>'data:'.$info['mime'].';base64,'.base64_encode($bytes)]]);
    }
}
