liuhairui 7 months ago
parent
commit
69bfdd9c48

+ 1 - 1
application/.htaccess

@@ -1 +1 @@
-deny from all
+deny from all

+ 183 - 711
application/api/controller/Facility.php

@@ -3,746 +3,218 @@ namespace app\api\controller;
 use app\common\controller\Api;
 use think\Db;
 use think\Request;
-/**
- * 质量继绩效管理
- */
-class Facility extends Api{
+
+class Facility extends Api
+{
     protected $noNeedLogin = ['*'];
     protected $noNeedRight = ['*'];
-    /**
-     * 1.0查询子订单编号
-     * 通过订单编号查询对应子订单编号
-     */
-    public function Apiorderids() {
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        $gdlist = \db('工单_印件资料')
-            ->field('子订单编号')
-            ->where('订单编号',$param['order'])
-            ->where('Mod_rq', null)
-            ->select();
-        $this->success('成功', [
-            'list' => $gdlist,
-        ]);
-    }
 
-    /**
-     * 1.1查询订单号或生产款号
-     * 查询对应订单编号或生产款号
-     */
-    public function Apiorder() {
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        $gdlist = \db('工单_基本资料')
-            ->field('订单编号,生产款号')
-            ->where('订单编号|生产款号','like','%'.$param['search'].'%')
-            ->where('Mod_rq', null)
+    public function getlsit()
+    {
+        // 获取前端传入的图片路径参数
+        $params = $this->request->param('path', '');
+        // 查询数据库
+        $res = Db::name('text_to_image')->alias('b')
+            ->field('b.chinese_description,b.english_description,b.new_image_url,b.custom_image_url,b.size,b.old_image_url')
+            ->where('old_image_url', $params)
+            ->where('custom_image_url', '<>', '')
+            ->where('status', 1)
+            ->order('b.id desc')
             ->select();
-        $this->success('成功', [
-            'list' => $gdlist,
-        ]);
+        return json(['code' => 0, 'msg' => '查询成功', 'data' => $res,'count'=>count($res)]);
     }
 
-    /**
-     * 1.2查询新增基本信息
-     * 新增查询信息
-     */
-    public function queryOrderSize() {
-        // 检查请求类型是否为GET
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-
-        //问题分类
-        $fetchCategory = \db('db_问题分类')->field('问题类型, classification as 分类名称,num')->order('num desc')->select();
-        $groupedCategories = [];
-        // 遍历数据,将相同分类名称的问题类型归类
-        foreach ($fetchCategory as $item) {
-            $categoryname = $item['分类名称'];
-            $category = $item['问题类型'];
-            // 如果分类名称不存在,则初始化为空数组
-            if (!isset($groupedCategories[$categoryname])) {
-                $groupedCategories[$categoryname] = [];
-            }
-            // 避免重复添加相同的问题类型
-            if (!in_array($category, $groupedCategories[$categoryname])) {
-                $groupedCategories[$categoryname][] = $category;
-            }
-        }
-
 
-        $gdlist = \db('工单_基本资料')
-            ->field('订单编号,生产款号,款式,订单数量')
-            ->where(['订单编号|生产款号' => $param['订单编号']])
-            ->where('Mod_rq', null)
-            ->find();
-
-        if (empty($gdlist)) {
-            $this->error('未找到相关数据');
-        }
-        // 查询订单尺码信息
-        $sizeData = \db('工单_印件资料')->where(['订单编号' => $gdlist['订单编号']])->where('Mod_rq', null)->select();
-        if (empty($sizeData)) {
-            $this->error('未找到相关数据');
-        }
-        // 计算所有尺码数据
-        $sizes = [];
-        foreach ($sizeData as $order) {
-            foreach ($order as $key => $value) {
-                if (strpos($key, 'cm') === 0 && strpos($key, 'cmsl') === false && $value !== null && $value !== '') {
-                    $sizes[] = $value;
-                }
-            }
-        }
-        // 去重后所有子订单重复的尺码数据
-        $sizes = array_values(array_unique($sizes));
-        // 获取颜色备注并统计每个颜色的sctotal和zdtotal
-        $colorData = []; // 用于存储每个颜色备注对应的sctotal和zdtotal
-        foreach ($sizeData as $item) {
-            if (!empty($item['颜色备注'])) {
-                $color = $item['颜色备注'];
-
-                $sctotal = (int)$item['sctotal'];
-                $zdtotal = (int)$item['zdtotal'];
-                if (isset($colorData[$color])) {
-                    $colorData[$color]['sctotal'] += $sctotal;
-                    $colorData[$color]['zdtotal'] += $zdtotal;
-                } else {
-                    $colorData[$color] = [
-                        'sctotal' => $sctotal,
-                        'zdtotal' => $zdtotal
-                    ];
-                }
-            }
-        }
-        // 获取颜色备注(去重)
-        $colorremark = array_values(array_unique(array_keys($colorData)));
-
-
-        //面料分类|面料名称
-        $getarr = \db('工单_bom资料')
-            ->field('物料分类,BOM_物料名称')
-            ->where('BOM_工单编号', $param['订单编号'])
-            ->where('Mod_rq', null)
+    //获取指定目录所有图片
+    public function getPreviewimg(){
+        $relativePath = $this->request->param('path', '');
+        $basePath = ROOT_PATH . 'public/';
+        $fullPath = $basePath . $relativePath;
+        if (!is_dir($fullPath)) {
+            return json(['code' => 1, 'msg' => '目录不存在']);
+        }
+        // 1. 获取该目录下所有图片
+        $images = glob($fullPath . '/*.{jpg,jpeg,png}', GLOB_BRACE);
+        // 2. 获取数据库中已处理的图片数据
+        $processedList = Db::name('text_to_image')
+            ->field('old_image_url,new_image_url,custom_image_url,chinese_description,english_description')
+            ->where('custom_image_url', '<>', '')
+            ->whereNotNull('custom_image_url')
             ->select();
-        $fabricArr = []; // 存储拼接后的数据
-        foreach ($getarr as $value) {
-            $materialName = $value['BOM_物料名称'];
-            // 如果物料分类为空,就用'-'代替
-            $bomDesc = !empty($value['物料分类']) ? $value['物料分类'] : '';
-            // 拼接字符串,并去除多余空格
-            $combinedData = trim($bomDesc . ' - ' . $materialName);
-            // 存入数组
-            $fabricArr[] = $combinedData;
-//            $bomDesc = !empty($value['物料分类']) ? $value['物料分类'] : ''; // 防止null
-//            // 拼接字符串,并去除可能的前后空格
-//            $combinedData = trim($bomDesc . ' - ' . $materialName, ' -');
-//            // 存入数组
-//            $fabricArr[] = $combinedData;
-        }
-
-
-        // 获取面料颜色
-        $getAllFabricData = \db('工单_面料资料')
-            ->field('BOM_物料名称,BOM_定额门幅,BOM_计划门幅,BOM_颜色')
-            ->where('BOM_工单编号', $param['订单编号'])
-            ->where('Mod_rq', null)
-            ->select();
-        // 用于统计每个物料的用料情况
-        $uniqueFabricData = []; // 去重后的面料数据
-        foreach ($getAllFabricData as $fabric) {
-            $key = $fabric['BOM_颜色'] . '-' . $fabric['BOM_物料名称']; // 以颜色和物料名称为唯一标识
-            $uniqueFabricData[$key] = $fabric; // 使用唯一标识作为数组的键,自动去重
-        }
-        // 重建数组索引,移除键名
-        $uniqueFabricData = array_values($uniqueFabricData);
-        $materialUsage = [];
-        // 遍历每种颜色的统计数据
-        foreach ($colorData as $color => $data) {
-            // 遍历去重后的面料数据
-            foreach ($uniqueFabricData as $fabric) {
-                // 判断颜色是否匹配
-                if ($fabric['BOM_颜色'] === $color) {
-                    // 直接统计每个物料的数量,而不进行用料的计算
-                    $materialUsage[$color][$fabric['BOM_物料名称']][] = $fabric; // 使用物料名称作为键,存储所有相关的面料数据
-                }
-            }
-        }
-        // 生成实际用料数据
-        $actualUsage = [];
-        foreach ($materialUsage as $color => $materials) {
-            foreach ($materials as $materialName => $fabricData) {
-                // 获取该颜色下的 sctotal 和 zdtotal
-                $sctotal = isset($colorData[$color]['sctotal']) ? $colorData[$color]['sctotal'] : 0;
-                $zdtotal = isset($colorData[$color]['zdtotal']) ? $colorData[$color]['zdtotal'] : 0;
-                // 获取定额门幅和计划门幅
-                $standardWidth = isset($fabricData[0]['BOM_定额门幅']) ? $fabricData[0]['BOM_定额门幅'] : 0;
-                $plannedWidth = isset($fabricData[0]['BOM_计划门幅']) ? $fabricData[0]['BOM_计划门幅'] : 0;
-                // 直接根据去重后的面料数据进行统计
-                $actualUsage[] = [
-                    '颜色' => $color,
-                    '物料名称' => $materialName,
-                    '定额门幅' => $standardWidth,
-                    '计划门幅' => $plannedWidth,
-                    'sctotal' => $sctotal,
-                    'zdtotal' => $zdtotal
-                ];
-            }
+        // 3. 构建以 old_image_url 为 key 的映射数组,方便快速查找
+        $processedMap = [];
+        foreach ($processedList as $item) {
+            $processedMap[$item['old_image_url']] = $item;
         }
-        foreach ($actualUsage as &$item) {
-            // 如果 'sctotal' 或 '定额门幅' 为空,则默认为 0
-            $sctotal = isset($item['sctotal']) && is_numeric($item['sctotal']) ? $item['sctotal'] : 0;
-            $demf = isset($item['定额门幅']) && is_numeric($item['定额门幅']) ? $item['定额门幅'] : 0;
-
-            $zdtotal = isset($item['zdtotal']) && is_numeric($item['zdtotal']) ? $item['zdtotal'] : 0;
-            $jhmf = isset($item['计划门幅']) && is_numeric($item['计划门幅']) ? $item['计划门幅'] : 0;
-
-            $item['实际用料'] = $sctotal * $demf;
-            $item['计划用料'] = $zdtotal * $jhmf;
-        }
-
-        // 选择显示的字段
-        $fieldsToShow = ['颜色', '物料名称', '实际用料', '计划用料'];
-        $finalResult = array();
-        foreach ($actualUsage as $item) {
-            $filteredItem = array();
-            foreach ($fieldsToShow as $field) {
-                if (isset($item[$field])) {
-                    $filteredItem[$field] = $item[$field];
-                }
-            }
-            $finalResult[] = $filteredItem;
-        }
-
-        //定义接口
-        $this->success('成功', [
-            'list' => $gdlist,
-            'colorremark' => $colorremark,
-            'fetchCategory' => $groupedCategories,
-            'FabricData' => $fabricArr,
-            'size' => $sizes,
-            '面料统计' => $finalResult
-        ]);
-    }
-
-    /**
-     * 1.3新增次品或返工
-     * 新增到设备_质量汇总表
-     */
-    public function ApiAddDefective(){
-        if (!$this->request->isPost()) {
-            $this->error('非法请求');
-        }
-        $params = $this->request->param();
-        if (empty($params)){
-            $this->error('参数错误');
-        }
-        $res = \db('设备_质量汇总')->where('mod_rq', null)->order('status_num desc')->find();
-        //记录每次新增次数排序,判断是否有返回值,没有则从1开始
-        $status_num = isset($res['status_num']) ? $res['status_num'] : 1;
-
-        // 构建单条记录的函数,传递 $list_gd 作为参数
-        function buildRecords($item,$status_num) {
-            // 拆分物料名称(假设格式为 面料分类-面料名称)
-            $materialParts = explode('-', $item['物料名称']);
-            // 面料分类
-            $materialCategory = isset($materialParts[0]) ? $materialParts[0] : '';
-            // 面料名称
-            $materialName = isset($materialParts[1]) ? $materialParts[1] : '';
-            // 获取最新的单据编号
-            $resd = \db('设备_质量汇总')
-                ->field('单据编号')
-                ->where('mod_rq', null)
-                ->order('单据编号 desc')
-                ->find();
-            // 获取当前日期
-            $currentDate = date('Ymd');
-            // 如果查询到最新的单据编号
-            if ($resd) {
-                // 提取最新单据编号的日期和流水号部分
-                preg_match('/ZL(\d{8})(\d{4})/', $resd['单据编号'], $matches);
-                // 如果匹配成功,进行累加
-                if ($matches) {
-                    $lastDate = $matches[1];
-                    $lastNumber = (int)$matches[2];  // 将流水号转为数字
-                    // 如果当前日期和最新单据的日期不同,则从0001开始
-                    $newNumber = ($currentDate !== $lastDate) ? '0001' : str_pad($lastNumber + 1, 4, '0', STR_PAD_LEFT);
-                } else {
-                    // 如果没有匹配到正确的格式,则从0001开始
-                    $newNumber = '0001';
-                }
-            } else {
-                // 如果没有查询到单据编号,默认从0001开始
-                $newNumber = '0001';
-            }
-
-            return [
-                '单据编号' => 'ZL' . $currentDate . $newNumber,
-                '订单编号' => $item['订单编号'],
-                '生产款号' => $item['生产款号'],
-                '款式' => $item['款式'],
-                '颜色' => $item['颜色'],
-                '尺码' => $item['尺码'],
-                '数量' => $item['数量'],
-                '组别' => $item['组别'],
-                '实际用料' => $item['实际用料'],
-                '计划用料' => $item['计划用料'],
-                '备注' => $item['备注'],
-                '问题分类' => $item['问题分类'],
-                'sczl_rq' => date('Y-m-d H:i:s'),
-                'Sys_rq' =>  $item['Sys_rq'],
-                'Sys_id' => $item['Sys_id'],
-                '状态' => $item['状态'],
-                'status_num' => $status_num + 1,
-                '面料分类' => $materialCategory,
-                '面料名称' => $materialName,
-
-            ];
-        }
-
-        // 检查是否是索引数组(多条记录)
-        if (isset($params[0]) && is_array($params[0])) {
-            foreach ($params as $item) {
-                $list[] = buildRecords($item,$status_num);
-            }
-        } else {
-            // 处理单条记录
-            $list[] = buildRecords($params,$status_num);
-        }
-        // 插入前统计问题分类的使用次数
-        foreach ($list as $item) {
-            $category = $item['问题分类'];
-            // 查询满足 问题类型 + classification 的记录
-            $record = \db('db_问题分类')
-                ->where('问题类型', $category)
-                // 可选,防止 null 报错
-                ->whereNotNull('classification')
-                ->find();
-            if ($record) {
-                $newNum = intval($record['num']) + 1;
-                // 使用 update 替代 setInc,手动加1
-                $updateSql = \db('db_问题分类')->fetchSql(true)
-                    ->where('id', $record['id']) // 建议用主键精确定位
-                    ->update(['num' => $newNum]);
-                \db()->query($updateSql);
-            }
-        }
-        $result = \db('设备_质量汇总')->insertAll($list);
-        if ($result) {
-            $this->success('数据插入成功 : ' . date('H:i:s'));
-        } else {
-            $this->error('数据插入失败');
-        }
-    }
-
-    /**
-     * 1.4质量管理左侧菜单栏查询
-     */
-    public function ApiMouthlist() {
-        // 检查请求类型是否为GET
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        // 查询符合条件的数据
-        $list = \db('设备_质量汇总')
-            ->where('状态', $param['code'])
-            ->where('mod_rq', null)
-            ->order('Sys_rq desc')
-            ->group('Sys_rq')
-            ->select();
-        if (empty($list)) {
-            $this->success('成功', '');
-            return;
-            //$this->error('未查询到数据');
-        }
-        // 用于存储按年和月分类的数据
+        // 4. 组装结果数据
         $data = [];
-        // 遍历查询结果,将日期按年、月分组
-        foreach ($list as $item) {
-            // 获取 Sys_rq 字段的值(日期)
-            $sys_rq = $item['Sys_rq'];
-
-            // 提取年、月、日
-            $year = date('Y', strtotime($sys_rq));
-            $month = date('Y-m', strtotime($sys_rq));
-            $day = date('Y-m-d', strtotime($sys_rq));
-
-            // 将数据按年、月、日分类
-            if (!isset($data[$year])) {
-                $data[$year] = [];
-            }
-
-            if (!isset($data[$year][$month])) {
-                $data[$year][$month] = [];
-            }
-
-            // 将日期加入到对应的年、月下
-            $data[$year][$month][] = $day;
-        }
-        $this->success('成功', $data);
-    }
-
-    /**
-     * 1.5查询单据汇总次片、返工列表数据
-     */
-    public function ApiSubPieceAnd() {
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-        $params = $this->request->param();
-        $where = ['mod_rq' => null];
-        if (!empty($params['code'])) {
-            $where['状态'] = $params['code'];
-        }
-        if (!empty($params['组别'])) {
-            $where['组别'] = $params['组别'];
-        }
-        if (!empty($params['search'])) {
-            $where['单据编号|订单编号|生产款号|面料名称|面料分类|颜色|问题分类|款式|组别'] = ['like', '%' . $params['search'] . '%'];
-        }
-        // 处理日期查询(支持按天和按月)
-        if (!empty($params['Sys_rq'])) {
-            if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $params['Sys_rq'])) {
-                // 按天查询
-                $where['Sys_rq'] = $params['Sys_rq'];
-            } elseif (preg_match('/^\d{4}-\d{2}$/', $params['Sys_rq'])) {
-                // 按月查询
-                $where['Sys_rq'] = ['like', $params['Sys_rq'] . '%'];
-            }elseif (preg_match('/^\d{4}$/', $params['Sys_rq'])) {
-                // 按年查询
-                //需要年份查询将代码屏蔽取消
-                // $where['Sys_rq'] = $params['Sys_rq'];
-                $this->success('成功', ['data' => '', 'total' => '']);
-            }
-        }
-        $data = \db('设备_质量汇总')
-            ->field('单据编号,订单编号,生产款号,面料名称,面料分类,问题分类,颜色,数量,款式,Sys_rq,尺码,组别')
-            ->where($where)
-            ->select();
-        $mergedData = [];
-        foreach ($data as $item) {
-            //一条数据
-            if (!isset($mergedData[$item['单据编号']])) {
-                $mergedData[$item['单据编号']] = [
-                    '单据编号' => $item['单据编号'],
-                    '订单编号' => $item['订单编号'],
-                    '款式' => $item['款式'],
-                    '生产款号' => $item['生产款号'],
-                    '问题分类' => $item['问题分类'],
-                    '颜色' => $item['颜色'],
-                    '面料名称' => $item['面料名称'],
-                    '面料分类' => $item['面料分类'],
-                    '数量' => $item['数量'],
-                    '组别' => $item['组别'],
-                    '尺码' => $item['尺码'],
-                    'Sys_rq' => $item['Sys_rq']
-                ];
-            } else {
-                // 多条合并数据、数量进行累加
-                $mergedData[$item['单据编号']]['问题分类'] = implode(',', array_unique(array_filter(array_merge(explode(',', $mergedData[$item['单据编号']]['问题分类']), [$item['问题分类']]))));
-                $mergedData[$item['单据编号']]['颜色'] = implode(',', array_unique(array_filter(array_merge(explode(',', $mergedData[$item['单据编号']]['颜色']), [$item['颜色']]))));
-                $mergedData[$item['单据编号']]['面料名称'] = implode(',', array_unique(array_filter(array_merge(explode(',', $mergedData[$item['单据编号']]['面料名称']), [$item['面料名称']]))));
-                $mergedData[$item['单据编号']]['面料分类'] = implode(',', array_unique(array_filter(array_merge(explode(',', $mergedData[$item['单据编号']]['面料分类']), [$item['面料分类']]))));
-                $mergedData[$item['单据编号']]['订单编号'] = implode(',', array_unique(array_filter(array_merge(explode(',', $mergedData[$item['单据编号']]['订单编号']), [$item['订单编号']]))));
-                $mergedData[$item['单据编号']]['生产款号'] = implode(',', array_unique(array_filter(array_merge(explode(',', $mergedData[$item['单据编号']]['生产款号']), [$item['生产款号']]))));
-                $mergedData[$item['单据编号']]['款式'] = implode(',', array_unique(array_filter(array_merge(explode(',', $mergedData[$item['单据编号']]['款式']), [$item['款式']]))));
-                $mergedData[$item['单据编号']]['尺码'] = implode(',', array_unique(array_filter(array_merge(explode(',', $mergedData[$item['单据编号']]['尺码']), [$item['尺码']]))));
-                $mergedData[$item['单据编号']]['组别'] = implode(',', array_unique(array_filter(array_merge(explode(',', $mergedData[$item['单据编号']]['组别']), [$item['组别']]))));
-                $mergedData[$item['单据编号']]['数量'] += $item['数量'];
-            }
-        }
-        $finalData = array_values($mergedData);
-        $this->success('成功', ['data' => $finalData, 'total' => count($finalData)]);
-    }
-
-    /**
-     * 1.6查询单据明细次片、返工列表数据
-     */
-    public function ApiSubPieceAndReworkList() {
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-
-        $params = $this->request->param();
-        $where = ['mod_rq' => null];
-
-        // 状态查询
-        if (!empty($params['code'])) {
-            $where['状态'] = $params['code'];
-        }
-
-        // 关键词模糊搜索
-        if (!empty($params['search'])) {
-            $where['单据编号|订单编号|生产款号|面料名称|面料分类|颜色|问题分类'] = ['like', '%' . $params['search'] . '%'];
+        $id = 1;
+        foreach ($images as $imgPath) {
+            $relative = str_replace($basePath, '', $imgPath);
+            $info = getimagesize($imgPath);
+            $sizeKB = round(filesize($imgPath) / 1024, 2);
+            $ctime = date('Y-m-d H:i:s', filectime($imgPath));
+
+            $processed = $processedMap[$relative] ?? '';
+
+            // 查询数据库中相同 old_image_url 的条数
+            $sameCount = Db::name('text_to_image')
+                ->where('old_image_url', $relative)
+                ->where('custom_image_url', '<>', '')
+                ->count();
+
+            $data[] = [
+                'id' => $id++,
+                'path' => $relative,
+                'width' => $info[0] ?? 0,
+                'height' => $info[1] ?? 0,
+                'size_kb' => $sizeKB,
+                'created_time' => $ctime,
+                'is_processed' => $processed ? 1 : 0,
+                'new_image_url' => $processed['new_image_url'] ?? '',
+                'custom_image_url' => $processed['custom_image_url'] ?? '',
+                'chinese_description' => ($processed['chinese_description'] ?? '') . ($processed['english_description'] ?? ''),
+                'same_count' => $sameCount  // ✅ 加入统计数量
+            ];
         }
 
-        // 处理日期查询(支持按天和按月)
-        if (!empty($params['Sys_rq'])) {
-            if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $params['Sys_rq'])) {
-                // 按天查询(2025-03-27)
-                $where['Sys_rq'] = $params['Sys_rq'];
-            } elseif (preg_match('/^\d{4}-\d{2}$/', $params['Sys_rq'])) {
-                // 按月查询(2025-03),匹配该月的所有数据
-                $where['Sys_rq'] = ['like', $params['Sys_rq'] . '%'];
-            }
-        }
-        $res = \db('设备_质量汇总')
-            ->where($where)
-            ->limit(($params['page'] - 1) * $params['limit'], $params['limit'])
-            ->order('sczl_rq','desc')
-            ->select();
-        $this->success('获取成功', ['data' => $res, 'total' => count($res)]);
+        return json(['code' => 0, 'msg' => '获取成功', 'data' => $data]);
     }
 
-
     /**
-     * 查询获取问题分类
+     * 获取原图目录及每个目录下的图片数量
      */
-    public function getProblemCategories() {
-        if (!$this->request->isGet()) {
-            $this->error('请求错误');
-        }
-        $params = $this->request->param();
-        // 仅查询未被删除的数据
-        $where = ['mod_rq' => null];
-        // 允许通过问题类型进行搜索
-        if (!empty($params['search'])) {
-            $where['问题类型'] = ['like', '%' . $params['search'] . '%'];
-        }
-        $data = \db('db_问题分类')->where($where)->order('update_time desc')->select();
-        if (!$data) {
-            $this->error('未查询到数据');
+    public function getPreviewSubDirs()
+    {
+//        $baseDir = ROOT_PATH . 'public/uploads/operate/ai/Preview/';
+        $baseDir = rtrim(str_replace('\\', '/', ROOT_PATH), '/') . '/public/uploads/operate/ai/Preview/';
+        $baseRelativePath = 'uploads/operate/ai/Preview/';
+
+        if (!is_dir($baseDir)) {
+            return json(['code' => 1, 'msg' => '目录不存在']);
+        }
+
+        $items = scandir($baseDir);
+        $dirs = [];
+        $index = 1;
+
+        foreach ($items as $item) {
+            if ($item === '.' || $item === '..') continue;
+
+            $fullPath = $baseDir . $item;
+
+            if (!is_dir($fullPath)) continue;
+
+            $relativeDir = $baseRelativePath . $item;
+
+            // 查询该目录在数据库中是否有有效数据
+            $hasData = Db::name('text_to_image')
+                ->where('custom_image_url', '<>', '')
+                ->whereLike('old_image_url', $relativeDir . '/%')
+                ->whereNotNull('custom_image_url')
+                ->count();
+//            if ($hasData === 0) {
+//                continue; // 如果没有有效数据,跳过此目录
+//            }
+
+            // 统计图片数量
+            $imageFiles = glob($fullPath . '/*.{jpg,jpeg,png}', GLOB_BRACE);
+            $imageCount = is_array($imageFiles) ? count($imageFiles) : 0;
+            // 创建时间
+            $ctime = filectime($fullPath);
+            $formattedDate = date('Y-m-d', $ctime);
+
+            $dirs[] = [
+                'id' => $index++,
+                'name' => $item,
+                'count' => $hasData,
+                'ctime' => $formattedDate,
+                'image_count' => $imageCount,
+                'new_image_url' => "/uploads/operate/ai/dall-e/",
+                'old_image_url' => $relativeDir
+            ];
         }
-        $this->success('获取成功', ['data' => $data, 'total' => count($data)]);
-    }
 
-    /**
-     * 添加问题分类接口
-     */
-    public function addProblemCategory() {
-        if (!$this->request->isPost()) {
-            $this->error('非法请求');
-        }
-        $params = $this->request->param();
-        if (empty($params['问题类型'])) {
-            $this->error('问题类型不能为空');
-        }
-        $insertData = [
-            '问题类型' => $params['问题类型'],
-            'sys_id' => $params['sys_id'],
-            'classification' => $params['classification'],
-            'Sys_rq' => date('Y-m-d H:i:s')
-        ];
-        $sql = \db('db_问题分类')
-            ->fetchSql(true)
-            ->insert($insertData);
-        $res = \db()->query($sql);
-        $this->success('添加成功');
-    }
+        // 排序:按时间倒序
+        usort($dirs, function ($a, $b) {
+            return strtotime($b['ctime']) - strtotime($a['ctime']);
+        });
 
-    /**
-     * 删除问题分类接口
-     */
-    public function deleteProblemCategory() {
-        if (!$this->request->isPost()) {
-            $this->error('非法请求');
-        }
-        $params = $this->request->param();
-        if (empty($params['id'])) {
-            $this->error('ID 不能为空');
-        }
-        $updateData = [
-            'mod_rq' => date('Y-m-d H:i:s')
-        ];
-        $res = \db('db_问题分类')->where('id', $params['id'])->update($updateData);
-        if ($res) {
-            $this->success('删除成功');
-        } else {
-            $this->error('删除失败');
-        }
+        return json(['code' => 0, 'msg' => '获取成功', 'data' => $dirs]);
     }
 
-    /**
-     * 机台设备查询
-     */
-    public function getMachineDeviceTypes(){
-        $res = \db('设备_基本资料')
-            ->where('mod_rq', null)
-            ->select();
-        $this->success('成功', [
-            'list' => $res,
-        ]);
-    }
 
     /**
-     * 设备_基本资料
-     * 更新机台设备
+     * 图片上传
+     * @return void
      */
-    public function updateMachineDeviceTypes() {
-        if (!$this->request->isPost()) {
-            $this->error('非法请求');
-        }
-        $params = $this->request->param();
-        if (empty($params['UniqId'])) {
-            $this->error('UniqId 参数不能为空');
-        }
-        $deviceData = [
-//            'sys_sbID' => $params['sys_sbID'],
-//            '工序' => $params['工序'],
-//            '设备编号' => $params['设备编号'],
-//            '生产工序' => $params['生产工序'],
-//            '设备编组' => $params['设备编组'],
-//            '组长' => $params['组长'],
-            'status' => $params['status'],
-        ];
-        $result = \db('设备_基本资料')
-            ->where('UniqId', $params['UniqId'])
-            ->where('mod_rq', null)
-            ->update($deviceData);
-        if ($result) {
-            $this->success('设备更新成功');
-        } else {
-            $this->error('设备更新失败');
-        }
-    }
+    public function ImgUpload()
+    {
+        // 处理 CORS OPTIONS 预检请求
+        if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
+            header('Access-Control-Allow-Origin: *');
+            header('Access-Control-Allow-Methods: POST, OPTIONS');
+            header('Access-Control-Allow-Headers: Content-Type, Authorization');
+            header('Access-Control-Max-Age: 86400');
+            exit(204);
+        }
+
+        // 实际请求必须返回 CORS 头
+        header('Access-Control-Allow-Origin: *');
+
+        $file = request()->file('image');
+
+        if ($file) {
+            $info = $file->validate([
+                'size' => 10 * 1024 * 1024, // 10MB
+                'ext' => 'jpg,png,jpeg'
+            ])->move(ROOT_PATH . 'public' . DS . 'uploads/operate/ai/Preview/');
+
+            if ($info) {
+                $saveName = $info->getSaveName();
+                $savePath = str_replace('\\', '/', $saveName);
+                $fullPath = ROOT_PATH . 'public/uploads/operate/ai/Preview/' . $savePath;
+                $relativePath = 'uploads/operate/ai/Preview/' . $savePath;
+
+                // 获取图片信息
+                $imgInfo = getimagesize($fullPath);
+                $width = $imgInfo[0] ?? 0;
+                $height = $imgInfo[1] ?? 0;
+                $size_kb = round(filesize($fullPath) / 1024, 2);
+                $created_time = date('Y-m-d H:i:s');
+
+                // 写入数据库 original_image 表
+                $insertData = [
+                    'path' => $relativePath,
+                    'width' => $width,
+                    'height' => $height,
+                    'size_kb' => $size_kb,
+                    'created_time' => $created_time
+                ];
 
-    /**
-     * 新增设备_基本资料
-     * 新增机台设备
-     */
-    public function addMachineDeviceTypes() {
-        if (!$this->request->isPost()) {
-            $this->error('非法请求');
-        }
-        $params = $this->request->param();
-        // 生产工序与工序号的映射
-        $processMapping = [
-            '裁剪' => 2,
-            '车缝' => 3,
-            '手工' => 4,
-            '总检' => 6,
-            '大烫' => 5,
-            '包装' => 7,
-        ];
-        $productionProcess = $params['生产工序'] ?? '';
-        $UniqId = \db('设备_基本资料')
-            ->field('UniqId')
-            ->order('UniqId desc')
-            ->find();
-        // 新的设备数据
-        $deviceData = [
-            'UniqId' => $UniqId['UniqId'] + 1,
-            'sys_sbID' => $params['sys_sbID'],
-            '工序' => $processMapping[$productionProcess],
-            '设备编号' => $params['设备编号'],
-            '生产工序' => $params['生产工序'],
-            '设备编组' => $params['设备编组'],
-            '组长' => $params['组长'],
-            'sys_id' => $params['sys_id'],
-            'sys_rq' => date('Y-m-d H:i:s'),
-            'status' => 1,
-        ];
-        $result = \db('设备_基本资料')->fetchSql(true)
-            ->insert($deviceData);
-        $list_gd = \db()->query($result);
-        if ($result) {
-            $this->success('设备新增成功');
-        } else {
-            $this->error('设备新增失败');
-        }
-    }
+                $result = Db::name('original_image')->insert($insertData);
 
-    /**
-     * 订单状态更新
-     */
-    public function Apigdstatus() {
-        if (!$this->request->isPost()) {
-            $this->error('非法请求');
-        }
-        $params = $this->request->param();
-        $uniqids = explode(',', $params['Uniqid']);
-        // 判断gd_statu是否为“3-已完工”,只判断一次
-        $isFinished = $params['gd_statu'] == '3-已完工';
-        foreach ($uniqids as $uniqid) {
-            $uniqid = trim($uniqid);
-            $updateData = [
-                'gd_statu' => $params['gd_statu']
-            ];
-            // 如果是“已完工”,加上完工日期
-            if ($isFinished) {
-                $updateData['工单完工日期'] = date('Y-m-d H:i:s');
+                return json([
+                    'code' => 0,
+                    'msg' => '上传成功',
+                    'data' => [
+                        'url' => $relativePath,
+                        'db_inserted' => $result ? true : false
+                    ]
+                ]);
             } else {
-                // 如果不是已完工,清空完工日期
-                $updateData['工单完工日期'] = null;
+                return json([
+                    'code' => 1,
+                    'msg' => '上传失败',
+                    'data' => $file->getError()
+                ]);
             }
-            $ReportSql = \db('工单_基本资料')->where('Uniqid', $uniqid)->fetchSql(true)->update($updateData);
-            \db()->query($ReportSql);
         }
-        $this->success('订单状态更新成功');
-    }
 
-    /**
-     * 产品BOM资料
-     */
-    public function Apibomlistarr(){
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        $page = isset($param['page']) ? (int)$param['page'] : 1;  // 默认第1页
-        $limit = isset($param['limit']) ? (int)$param['limit'] : 50; // 默认每页50条
-        $bomlist = Db::name('工单_bom资料')
-            ->alias('a')
-            ->field('
-                a.BOM_工单编号 as 订单编号,
-                a.BOM_desc as 备注,
-                a.BOM_库存总量 as 库存总量,
-                a.BOM_面料结余 as 面料结余,
-                a.BOM_实际门幅 as 实际门幅,
-                a.BOM_物料编码 as 物料编码,
-                a.BOM_物料名称 as 物料名称,
-                a.BOM_投料单位 as 投料单位,
-                a.BOM_标准用量 as 定额用料,
-                a.BOM_计划用量 as 计划用料,
-                a.BOM_实际用量 as 标准用料,
-                a.Bom_领用数量 as 领用数量,
-                a.BOM_退还数量 as 退还数量,
-                a.BOM_退还数量 as 退还数量,
-                a.Sys_ID,
-                a.Sys_rq,
-                a.UNIQID,
-                a.物料分类 as 物料分类,
-                a.BOM_计划门幅 as 计划门幅,
-                a.BOM_定额门幅 as 定额门幅,
-                b.生产款号,
-                b.客户编号,
-                b.款式
-            ')
-            ->join('工单_基本资料 b', 'a.BOM_工单编号 = b.订单编号', 'left')  // 多条件关联
-            ->where('a.BOM_工单编号|a.BOM_物料编码|a.BOM_物料名称|a.物料分类|b.生产款号|b.款式|b.客户编号', 'like', "{$param['search']}%")
-            ->order('a.BOM_工单编号 desc')
-            ->where('a.Mod_rq',null)
-            ->limit(($page - 1) * $limit, $limit)
-            ->select();
-        // 处理数据,去掉计划用料字段的小数点后多余的0
-        foreach ($bomlist as &$item) {
-            // 转换为浮点数,去掉无意义的 0
-            $item['计划用料'] = floatval($item['计划用料']);
-        }
-        // 解除引用,防止意外修改
-        unset($item);
-        $count = Db::name('工单_bom资料')
-            ->where('Mod_rq',null)
-            ->count();
-        $data['total'] = $count;
-        $data['list'] = $bomlist;
-        $this->success('成功',$data);
+        return json([
+            'code' => 1,
+            'msg' => '没有接收到上传文件',
+            'data' => null
+        ]);
     }
-
 }

+ 0 - 1
application/api/controller/Index.php

@@ -1700,7 +1700,6 @@ class Index extends Controller{
 
         // 初始化 cURL
         $ch = curl_init('https://niubi.zeabur.app/v1/chat/completions');
-
         // 设置 cURL 选项
         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
         curl_setopt($ch, CURLOPT_HTTPHEADER, [

+ 600 - 2867
application/api/controller/WorkOrder.php

@@ -2,2913 +2,646 @@
 
 namespace app\api\controller;
 
-
 use app\common\controller\Api;
-use PhpOffice\PhpSpreadsheet\Spreadsheet;
-use PhpOffice\PhpSpreadsheet\Writer\Pdf\Tcpdf;
-use think\Config;
+use app\job\ImageJob;
+use app\service\ImageService;
+use think\App;
 use think\Db;
-use think\Exception;
-use think\Request;
-use PhpOffice\PhpSpreadsheet\IOFactory;
-use function EasyWeChat\Kernel\Support\rsa_public_encrypt;
-use function fast\e;
+use think\Log;
+use think\Queue;
+use think\queue\job\Redis;
 
 
-/**
- * 工单资料管理
- */
 class WorkOrder extends Api
 {
     protected $noNeedLogin = ['*'];
     protected $noNeedRight = ['*'];
 
-
-    public function _initialize()
-    {
-
-        if (isset($_SERVER['HTTP_ORIGIN'])) {
-            header('Access-Control-Expose-Headers: __token__');//跨域让客户端获取到
-        }
-        //跨域检测
-        check_cors_request();
-
-        if (!isset($_COOKIE['PHPSESSID'])) {
-            Config::set('session.id', $this->request->server("HTTP_SID"));
-        }
-        parent::_initialize();
-    }
-
-    /**
-     * 工单资料菜单列表
-     *
-     * @ApiMethod (GET)
-     * @return false|string
-     * @throws \think\Exception
-     */
-    public function DataList()
-    {
-        $where['j.Mod_rq'] = null;
-        $allCustomers = \db('erp_客户供应商')->alias('e')
-            ->field('e.编号 as 客户编号')
-            ->select();
-        $customerData = [];
-        foreach ($allCustomers as $customer) {
-            $customerID = $customer['客户编号'];
-            $customerData[$customerID] = ['计划中' => 0, '生产中' => 0];
-        }
-        $data = \db('erp_客户供应商')->alias('e')
-            ->join('工单_基本资料 j', 'e.编号 = j.客户编号', 'LEFT')
-            ->field('e.编号 as 客户编号, j.订单编号, j.gd_statu')
-            ->where($where)
-            ->select();
-        foreach ($data as $row) {
-            $customerID = $row['客户编号'];
-            $status = $row['gd_statu'];
-
-            if ($status == '1-计划中') {
-                $customerData[$customerID]['计划中']++;
-            } elseif ($status == '2-生产中') {
-                $customerData[$customerID]['生产中']++;
-            }
-        }
-        ksort($customerData);
-        $output = [];
-        foreach ($customerData as $customerID => $statusCounts) {
-            $statusString = [];
-            if ($statusCounts['计划中'] > 0) {
-                $statusString[] = "计划中:{$statusCounts['计划中']}";
-            }
-            if ($statusCounts['生产中'] > 0) {
-                $statusString[] = "生产中:{$statusCounts['生产中']}";
-            }
-            $output[] = "{$customerID}【" . implode(' ', $statusString) . "】";
-        }
-        $this->success('成功', $output);
-    }
-
-    /**
-     * 工单基本资料列表
-     * @ApiMethod (GET)
-     * @param string $limit 查询长度
-     * @param string $Gd_khdh 客户代号
-     * @param string $startTime 接单日期开始时间
-     * @param string $endTime  接单日期结束时间
-     * @return \think\response\Json
-     * @throws \think\exception\DbException
-     */
-    public function WorkOrderList()
-    {
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-
-        $search = input('search');
-        $page = input('page');
-        $limit = input('limit');
-        $param = $this->request->param();
-
-        $where = [];
-        if (!empty($search)) {
-            $where['订单编号|生产款号|客户编号|款式|审核|Sys_id'] = ['like', '%' . $search . '%'];
-        }
-        $where['Mod_rq'] = null;
-
-        $list = \db('工单_基本资料')
-            ->where($where)
-            ->order('订单编号 desc, Gd_statu desc, Sys_rq desc')
-            ->limit(($page - 1) * $limit, $limit)
-            ->select();
-
-        $count = \db('工单_基本资料')
-            ->where($where)
-            ->order('订单编号 desc, Gd_statu desc, Sys_rq desc')
-            ->select();
-
-        // 提取所有订单编号
-        $orderIds = array_column($list, '订单编号');
-
-        // 查询所有在“工单_相关附件”表中存在的订单编号
-        $relatedOrders = \db('工单_相关附件')
-            ->whereIn('关联编号', $orderIds)
-            ->whereIn('附件备注', '技术附件')
-            ->whereNull('mod_rq')
-            ->column('关联编号');
-
-        // 遍历数据,判断每个订单编号是否在相关附件表中
-        foreach ($list as &$value) {
-            if (in_array($value['订单编号'], $relatedOrders)) {
-                $value['status'] = '';  // 有相关附件,status为空
-            } else {
-                $value['status'] = '*'; // 没有相关附件,标记为新订单
-            }
-            if ($value['落货日期']) {
-                $value['落货日期'] = date('Y-m-d', strtotime($value['落货日期']));
-            }
-            // 格式化接单日期,去掉时间部分
-            if ($value['接单日期']) {
-                $value['接单日期'] = date('Y-m-d', strtotime($value['接单日期']));
-            }
-        }
-
-
-        $this->success('成功', ['data' => $list, 'total' => count($count)]);
-    }
-
-    /**
-     * 月度客户订单汇总
-     */
-    public function ProductInformation()
-    {
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-
-        // 查询生产中和未生产的数据,使用 CASE WHEN 进行分类统计
-        $data = \db('工单_基本资料')->alias('j')
-            ->field('
-            j.客户编号,
-            REPLACE(DATE_FORMAT(j.Sys_rq, "%Y-%m"), "-", "") as 年月,
-            SUM(CASE WHEN j.gd_statu = "2-生产中" THEN 1 ELSE 0 END) as 生产中数量,
-            SUM(CASE WHEN j.gd_statu = "1-计划中" THEN 1 ELSE 0 END) as 未生产数量
-        ')
-            ->where('j.Mod_rq', null) // 统一的查询条件
-            ->group('j.客户编号, 年月')
-            ->order('j.客户编号 asc')
-            ->select();
-
-        // 格式化数据
-        $result = [];
-        foreach ($data as $item) {
-            $result[$item['年月']][] = $item['客户编号'] . '【生产中' . $item['生产中数量'] . ',计划中' . $item['未生产数量'] . '】';
-        }
-
-        $this->success('请求成功', ['data' => $result]);
-    }
-
     /**
-     * U8工单资料删除
-     * @param string $workOrder  工单编号
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-
-
-    public function orderDataDel()
+     * 出图接口
+    */
+    public function imageToText()
     {
-        if($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $workOrder = input('Uniqid');
-        if (empty($workOrder)){
-            $this->error('参数错误');
-        }
-        $order = \db('工单_基本资料')->where('UniqId',$workOrder)->find();
-        \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('失败');
-        }
+        $params = $this->request->param();
+        $service = new ImageService();
+        $service->handleImage($params);
+        $this->success('成功存入队列中');
     }
 
 
     /**
-     * 印件资料修改
-     * @ApiMethod (POST)
-     * @param  void
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
+     * 查看队列任务
      */
-
-    public function PrintedEdit()
+    public function queueStats()
     {
-        if (Request::instance()->isPost() === false){
-            $this->error('请求错误');
-        }
-        $param = Request::instance()->post();
-        if (empty($param) || isset($param['Uniqid']) === false){
-            $this->error('参数错误');
-        }
-        $param['Yj_Gdbh'] = \db('工单_印件资料')->where('Uniqid',$param['Uniqid'])->value('Yj_Gdbh');
-        $data = [
-            'Yj_Gdbh' =>$param['Yj_Gdbh'],
-            'yj_Yjno' =>$param['yjno'],
-            'yj_Yjdh' =>$param['yjdh'],
-            'yj_yjmc' =>$param['yjmc'],
-            'yj_zzdh' =>$param['zzdh'],
-            'yj_zzdh1' =>$param['zzdh1'],
-            'yj_zzdh2' =>$param['zzdh2'],
-            'yj_zzdh3' =>$param['zzdh3'],
-            'yj_zzdh4' =>$param['zzdh4'],
-            'yj_zzmc' =>$param['zzmc'],
-            'yj_zzmc1' =>$param['zzmc1'],
-            'yj_zzmc2' =>$param['zzmc2'],
-            'yj_zzmc3' =>$param['zzmc3'],
-            'yj_zzmc4' =>$param['zzmc4'],
-            'yj_tlgg' =>$param['tlgg'],
-            'yj_klgg' =>$param['klgg'],
-            'Yj_核算规格' =>$param['hsgg'],
-            'yj_成品数量' =>$param['cpsl'],
-            'yj_平张投料' =>$param['pztl'],
-            'yj_ks' =>$param['ks'],
-            'yj_ls' =>$param['ls'],
-            'yj_desc' =>$param['desc'],
-        ];
-
-        $UniqId = $param['Uniqid'];
-        $sql = \db('工单_印件资料')->where('Uniqid',$UniqId)->fetchSql(true)->update($data);
-        $res = Db::query($sql);
-        $process = \db('工单_工艺资料')
-            ->where('Gy0_gdbh',$data['Yj_Gdbh'])
-            ->where('Gy0_yjno',$data['yj_Yjno'])
+        $statusCounts = Db::name('queue_log')
+            ->field('status, COUNT(*) as total')
+            ->whereTime('created_at', 'today')  // 只取今天的记录
+            ->where('status','<>', 4)
+            ->group('status')
             ->select();
-        if ((int)$data['yj_平张投料'] > 0 && !empty($process)){
-            //重新分配工序计划产量
-            $result = $this->PlannedProcessYield($data['Yj_Gdbh'],$data['yj_Yjno'],0,$data['yj_平张投料']);
-            if ($result === false){
-                $this->success('修改工序产量失败');
-            }
-        }
-        if ($res !== false){
-            $this->success('成功');
-        }else{
-            $this->error('失败');
-        }
-    }
-
-    /**
-     * 工艺资料修改
-     * @ApiMethod (POST)
-     */
-    public function ProcessDetailEdit()
-    {
-        if (Request::instance()->isPost() === false){
-            $this->error('请求错误');
-        }
-        $param = Request::instance()->post();
-        if (empty($param) || isset($param['UniqId']) === false){
-            $this->error('参数错误');
-        }
-        if (empty($param['Gy0_shdh'])){
-            $rate['rate0'] = 0;
-            $rate['rate1'] = 0;
-        }else{
-            $rate = \db('dic_lzsh')->where('sys_bh',$param['Gy0_shdh'])->field('rtrim(sys_rate0) as rate0,rtrim(sys_rate1) as rate1')->find();
-        }
-        $param['Gy0_Rate0']= isset($rate['rate0'])?$rate['rate0']:0;
-        $param['Gy0_Rate1'] = isset($rate['rate1'])?$rate['rate1']:0;
-        $param['Mod_rq']  = date('Y-m-d H:i:s',time());
-        $UniqId = $param['UniqId'];
-        unset($param['UniqId']);
-        //修改工艺资料
-        $sql = \db('工单_工艺资料')->where('UniqId',$UniqId)->fetchSql(true)->update($param);
-        $res = Db::query($sql);
-        //获取工艺资料数据
-        $list = \db('工单_工艺资料')->where('UniqId',$UniqId)->field('Gy0_yjno,Gy0_gxh,rtrim(Gy0_计划接货数) as 计划接货数')->find();
-//        //修改工单状态
-//        $status = \db('工单_基本资料')->where('Gd_gdbh',$param['Gy0_gdbh'])->field('rtrim(gd_statu) as status')->find();
-//        if ($status['status'] !== '2-生产中'){
-//            $statusSql = \db('工单_基本资料')->where('Gd_gdbh',$param['Gy0_gdbh'])->fetchSql(true)->update(['gd_statu'=>'2-生产中']);
-//            Db::query($statusSql);
-//        }
-        //重新分配工序计划产量
-        if ((int)$list['计划接货数'] > 0){
-            $result = $this->PlannedProcessYield($param['Gy0_gdbh'],$list['Gy0_yjno'],$list['Gy0_gxh'],$list['计划接货数']);
-        }
-        if ($res !== false){
-            $this->success('成功');
-        }else{
-            $this->error('失败');
-        }
-    }
-
-
-    /**
-     * 新增工单->添加工单
-     * @ApiMethod (POST)
-     * @param
-     */
-
-    public function WorkOrderAdd()
-    {
-        if (Request::instance()->isPost() === false){
-            $this->error('请求错误');
-        }
-        $param = Request::instance()->post();
-        if (empty($param)){
-            $this->error('参数错误');
-        }
-        $param['Sys_rq'] = date('Y-m-d H:i:s');
-        $param['gd_statu'] = '1-计划中';
-
-        $prefix = substr($param['订单编号'], 0, 2);  // e.g., "DC"
-        $maxOrder = \db('工单_基本资料')
-            ->where('订单编号', 'like', "{$prefix}%")
-            ->order('订单编号', 'desc')
-            ->limit(1)
-            ->value('订单编号');
-        if ($maxOrder) {
-            $numericPart = substr($maxOrder, 2);
-            $newNumericPart = str_pad((int)$numericPart + 1, strlen($numericPart), '0', STR_PAD_LEFT);
-            $param['订单编号'] = $prefix . $newNumericPart;
-        } else {
-            $param['订单编号'] = $param['订单编号'];
-        }
-        if ($maxOrder) {
-            $numericPart = substr($maxOrder, 2);
-            $newNumericPart = str_pad((int)$numericPart + 1, strlen($numericPart), '0', STR_PAD_LEFT);
-            $param['订单编号'] = $prefix . $newNumericPart;
-        } else {
-            $param['订单编号'] = $param['订单编号'];
-        }
-        $data = $param;
-        unset($data['关联订单']);
-        unset($data['关联面料ID']);
-        //新增订单插入至工单基本资料
-        $sql = \db('工单_基本资料')->fetchSql(true)->insert($data);
-        \db()->query($sql);
-        if (!empty($param['关联订单']) && !empty($param['关联面料ID'])){
-            //关联订单编号
-            $OrderId = $param['关联订单'];
-            $OrderNumber = explode(',',$OrderId);
-            //关联面料ID
-            $RelevanceId = $param['关联面料ID'];
-            //查询订单BOM资料,面料资料
-            $RelevanceList = explode(',',$RelevanceId);
-            $FabricList = $BomList = $MaterielList = [];
-            foreach ($RelevanceList as $item){
-                //工单面料信息
-                $Fabric = \db('工单_面料资料')
-                    ->where('UNIQID',$item)
-                    ->where('Mod_rq',null)
-                    ->field('BOM_工单编号,BOM_颜色,BOM_物料编码,BOM_物料名称,BOM_投料单位,BOM_计划门幅,BOM_定额门幅')
-                    ->find();
-                $OrderData = $Fabric;
-                $OrderData['BOM_工单编号'] = $param['订单编号'];
-                $OrderData['Sys_ID'] = $param['Sys_id'];
-                $OrderData['Sys_rq'] = date('Y-m-d H:i:s',time());
-                $OrderData['BOM_desc'] = $param['要求'];
-                array_push($FabricList,$OrderData);
-                //关联订单
-                $AssociatedNumber = \db('工单关联表')
-                    ->where('订单编号',$Fabric['BOM_工单编号'])
-                    ->where('颜色',$Fabric['BOM_颜色'])
-                    ->where('物料编号',$Fabric['BOM_物料编码'])
-                    ->value('关联编号');
-                $materiel = [
-                    '关联编号' => $AssociatedNumber,
-                    '订单编号' => $Fabric['BOM_工单编号'],
-                    '生产款号' => $param['生产款号'],
-                    '颜色' => $Fabric['BOM_颜色'],
-                    '物料编号' => $Fabric['BOM_物料编码'],
-                    '物料名称' => $Fabric['BOM_物料名称'],
-                    '备注' => $param['要求'],
-                    'Sys_id' => $param['Sys_id'],
-                    'Sys_rq' => date('Y-m-d H:i:s',time()),
-                ];
-                array_push($MaterielList,$materiel);
-            }
-            foreach ($MaterielList as $index => $item){
-                $MaterielList[$index]['订单编号'] = $param['订单编号'];
-                //工单BOM信息
-                $Bom = \db('工单_bom资料')
-                    ->where('BOM_工单编号',$item['订单编号'])
-                    ->where('BOM_物料名称',$item['物料名称'])
-                    ->where('Mod_rq',null)
-                    ->find();
-                unset($Bom['UNIQID']);
-                unset($Bom['Mod_rq']);
-                $Bom['Sys_ID'] = $param['Sys_id'];
-                $Bom['Sys_rq'] = date('Y-m-d H:i:s',time());
-                if (empty($BomList)){
-                    array_push($BomList,$Bom);
-                }else{
-                    foreach ($BomList as $value){
-                        if ($value['BOM_工单编号'] !== $Bom['BOM_工单编号'] && $value['BOM_物料名称'] !== $Bom['BOM_物料名称']){
-                            array_push($BomList,$Bom);
-                        }
-                    }
-                }
-            }
-            foreach ($BomList as $key => $value){
-                $BomList[$key]['BOM_工单编号'] = $param['订单编号'];
-            }
-
-            //插入数据
-            Db::startTrans();
-            try {
-                //BOM表数据插入
-                $BomSql = \db('工单_bom资料')->fetchSql(true)->insertAll($BomList);
-                $BomRes = \db()->query($BomSql);
-                //面料表数据插入
-                $FabricSql = \db('工单_面料资料')->fetchSql(true)->insertAll($FabricList);
-                $FabricRes = \db()->query($FabricSql);
-                //工单关联表数据插入
-                $materielSql = \db('工单关联表')->fetchSql(true)->insertAll($MaterielList);
-                $materielRes = \db()->query($materielSql);
-
-                //提交数据
-                Db::commit();
-            }catch (\Exception $e){
-                //回滚事务
-                Db::rollback();
-            }
-        }else{
-            //判断新增时面料是否存在,如果有调用gtp自动生成BOM资料
-            if (!empty($param['面料'])) {
-                // 只有面料不为空时,才调用 GdGtpAiOrder 方法
-                $this->GdGtpAiOrder($param['订单编号']);
-            }
-        }
-        $this->success('成功');
-    }
 
-    /**
-     * 新增印件资料->印件资料添加
-     * @return void
-     * @throws \think\db\exception\BindParamException
-     * @throws \think\exception\PDOException
-     */
-    public function PrintDetailAdd()
-    {
-        if (Request::instance()->isPost() === false){
-            $this->error('请求错误');
-        }
-        $param = Request::instance()->post();
-        if (empty($param)){
-            $this->error('参数错误');
-        }
-        $param['Sys_rq'] = date('Y-m-d H:i:s',time());
-        $process = [
-            ['1','仓库出库'],['2','裁剪'],['3','车缝'],['4','后道收样'],['5','大烫'],['6','总检'],['7','包装']
+        $result = [
+            '待处理' => 0,
+            '处理中' => 0,
+            '成功' => 0,
+            '失败' => 0
         ];
-        $processDetail = [];
-        foreach ($process as $key=>$value){
-            $total = null;
-            if ($key !== 0){
-                $total = $param['zdtotal'];
-            }
-            $processDetail[$key] = [
-                '订单编号' => $param['订单编号'],
-                '子订单编号' => $param['子订单编号'],
-                '款号' => $param['款号'],
-                '颜色' => $param['颜色'],
-                '颜色备注' => $param['颜色备注'],
-                '工序编号' => $value[0],
-                '工序名称' => $value[1],
-                '计划产量' => $total,
-                'Sys_id' => $param['Sys_id'],
-                'Sys_rq' => $param['Sys_rq']
-            ];
-        }
-        $color = \db('工单_面料资料')
-            ->where('Bom_工单编号',$param['订单编号'])
-            ->where('BOM_颜色',$param['颜色备注'])
-            ->where('Mod_rq',null)
-            ->select();
-        $colorList = [];
-        if (empty($color)){
-            $BomList = \db('工单_bom资料')
-                ->where('BOM_工单编号',$param['订单编号'])
-                ->where('Mod_rq',null)
-                ->select();
-            foreach ($BomList as $key=>$value){
-                $colorList[$key] = [
-                    'BOM_工单编号' => $param['订单编号'],
-                    'BOM_颜色' => $param['颜色备注'],
-                    'BOM_物料编码' => $param['款号'].'-'.$param['颜色备注'].($key+1),
-                    'BOM_物料名称' => $value['BOM_物料名称'],
-                    'U8UID' => $value['UNIQID'],
-                    'BOM_投料单位' => '',
-                    'Sys_ID' => $param['Sys_id'],
-                    'Sys_rq' => date('Y-m-d H:i:s',time()),
-                    'BOM_desc' => $value['BOM_desc']
-                ];
-            }
-        }
-        //获取最新的关联编号
-        $AssociatedNumber = \db('工单关联表')->order('关联编号 desc')->column('关联编号');
-        if (empty($AssociatedNumber)){
-            $number = 0;
-        }else{
-            $number = (int)substr($AssociatedNumber[0],3);
-        }
-        $MaterielList = [];
-        //插入工单关联数据表
-        foreach ($colorList as $key=>$value){
-            $MaterielList[$key] = [
-                '关联编号' => 'GDGL'.($number + $key + 1),
-                '订单编号' => $value['BOM_工单编号'],
-                '生产款号' => $param['款号'],
-                '颜色' => $param['颜色备注'],
-                '物料编号' => $value['BOM_物料编码'],
-                '物料名称' => $value['BOM_物料名称'],
-                '备注' => $value['BOM_desc'],
-                'Sys_id' => $param['Sys_id'],
-                'Sys_rq' => date('Y-m-d H:i:s',time())
-            ];
-        }
-        //开启事务
-        db()->startTrans();
-        try{
-            //工单颜色录入
-            $priSql = \db('工单_印件资料')->fetchSql(true)->insert($param);
-            $priRes = \db()->query($priSql);
-            //工单工艺录入
-            $proSql = \db('工单_工艺资料')->fetchSql(true)->insertAll($processDetail);
-            $proRes = \db()->query($proSql);
-            if (!empty($colorList)){
-                //工单面料录入
-                $fabricSql = \db('工单_面料资料')->fetchSql(true)->insertAll($colorList);
-                $fabricRes = \db()->query($fabricSql);
-            }
-            if (!empty($MaterielList)){
-                //工单关联表录入
-                $meterieSql = \db('工单关联表')->fetchSql(true)->insertAll($MaterielList);
-                $meterieRes = \db()->query($meterieSql);
-            }
-
-            // 提交事务
-            db()->commit();
-        } catch (\Exception $e) {
-            // 回滚事务
-            db()->rollback();
-            $this->error($e->getMessage());
-        }
-
-        if ($priRes !== false && $proRes !== false){
-            $this->success('成功');
-        }else{
-            $this->error('失败');
-        }
+        $total = 0;
+
+        foreach ($statusCounts as $row) {
+            $count = $row['total'];
+            $total += $count;
+            switch ($row['status']) {
+                case 0:
+                    $result['待处理'] = $count;
+                    break;
+                case 1:
+                    $result['处理中'] = $count;
+                    break;
+                case 2:
+                    $result['成功'] = $count;
+                    break;
+                case 3:
+                    $result['失败'] = $count;
+                    break;
+            }
+        }
+
+        return json([
+            'code' => 0,
+            'msg' => '获取成功',
+            'data' => ['总任务数' => $total] + $result
+        ]);
     }
 
-
     /**
-     * 子订单列表
-     * @return null
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
+     * 清空队列
      */
-    public function PrintListData()
+    public function stopQueueProcesses()
     {
-        // 检查请求方式
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-
-        $param = $this->request->param();
-
-        // 检查参数是否存在
-        if (isset($param) === false) {
-            $this->error('参数错误');
-        }
+        $redis = new \Redis();
+        $redis->connect('127.0.0.1', 6379);
+        $redis->select(15);
 
-        // 查询型号
-        $where['Mod_rq'] = null;
-        $xhdata = \db('工单_印件资料')
-            ->where('订单编号', $param['order'])
-            ->where($where)
-            ->field('cm1,cm2,cm3,cm4,cm5,cm6,cm7,cm8,cm9,cm10')
-            ->select();
-
-        $arr = [];
-        // 收集cm1到cm10的非空非null值
-        foreach ($xhdata as $key => $value) {
-            for ($i = 1; $i <= 10; $i++) {
-                if ($value['cm' . $i] !== '' && $value['cm' . $i] !== null) {
-                    array_push($arr, $value['cm' . $i]);
-                }
-            }
-        }
+        $key = 'queues:default';
+        $count = $redis->lLen($key);
 
-        $arr = array_unique($arr);
-        sort($arr);
-
-        // 查询详细列表
-        $list = \db('工单_印件资料')
-            ->where('订单编号', $param['order'])
-            ->where($where)
-            ->field('订单编号,子订单编号,款号,颜色,船样,zdtotal,Sys_id,Sys_rq,ck_rq,sc_rq,cm1,cm2,cm3,cm4,cm5,cm6,updatatime as 更新时间,颜色备注,color_id,cm7,cm8,cm9,cm10,cmsl1,cmsl2,cmsl3,cmsl4,cmsl5,cmsl6,cmsl7,cmsl8,cmsl9,cmsl10,Uniqid')
-            ->select();
-
-        // 遍历列表并处理cm和cmsl字段
-        foreach ($list as $key => $value) {
-            for ($i = 1; $i <= 10; $i++) {
-                if ($value['cm' . $i] !== '') {
-                    // 如果 cmsl 的值为 0,则设置为空字符串
-                    $list[$key][$value['cm' . $i]] = ($value['cmsl' . $i] === 0) ? '' : $value['cmsl' . $i];
-                }
-                // 删除原有的 cm 和 cmsl 字段
-//                unset($list[$key]['cm' . $i], $list[$key]['cmsl' . $i]);
-            }
+        if ($count === 0) {
+            return json([
+                'code' => 1,
+                'msg'  => '暂无队列需要停止'
+            ]);
         }
 
-        // 自定义型号排序
-        $customOrder = array('XXS','XS','S', 'M', 'L', 'XL','XXL', 'XXXL', 'XXXXL', '2XL', '3XL', '4XL');
-        usort($arr, function ($a, $b) use ($customOrder) {
-            $posA = array_search($a, $customOrder);
-            $posB = array_search($b, $customOrder);
-            return $posA - $posB;
-        });
-        // 返回结果
-        $data['型号'] = $arr;
-        $data['列表'] = $list;
-        $this->success('成功', $data);
-    }
+        $redis->del($key);
 
-    /**
-     * 工单资料管理->印件资料删除
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\exception\PDOException
-     */
-    public function PrintDetailDel()
-    {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        if (isset($param['UniqId']) === false){
-            $this->error('参数错误');
-        }
-        $printId = explode(',',$param['UniqId']);
-        $i = 0;
-        foreach ($printId as $value){
-            $res = \db('工单_印件资料')
-                ->where('Uniqid',$value)
-                ->update(['Mod_rq'=>date('Y-m-d H:i:s',time())]);
-            if ($res === false){
-                $i++;
-            }
-        }
-        if ($i === 0){
-            $this->success('删除成功');
-        }else{
-            $this->error('删除失败');
-        }
+        Db::name('queue_log')
+            ->where('status', 0)
+            ->whereTime('created_at', 'today')
+            ->update([
+                'status'     => 4,
+                'updated_at' => date('Y-m-d H:i:s')
+            ]);
 
+        return json([
+            'code' => 0,
+            'msg'  => '已成功停止队列任务,共清除 ' . $count . ' 条'
+        ]);
     }
 
     /**
-     * 月度车间报工汇总->报工删除记录
+     * 显示当前运行中的队列监听进程
      */
-    public function ProcessDetailDel()
+    public function viewQueueStatus()
     {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        if (empty($param)) {
-            $this->error('参数错误');
-        }
-
-        $where['a.mod_rq'] = ['neq', ''];
-        $list = \db('设备_产量计酬')->alias('a')
-            ->join('工单_印件资料 b', 'b.订单编号 = a.订单编号 AND a.子订单编号 = a.子订单编号')
-            ->join('工单_基本资料 j', 'b.订单编号 = j.订单编号', 'LEFT')
-            ->field('
-                b.订单编号, b.子订单编号, b.款号, b.颜色, b.船样, a.尺码, b.zdtotal as 制单数,b.颜色备注,
-                a.数量, a.sys_rq as 上报时间,a.UniqId,a.mod_rq,a.delsys_id,a.sczl_bh,
-                j.客户编号,j.生产款号,j.款式
-                ')
-            ->where($where)
-            ->order('a.mod_rq desc')
-            ->limit($param['page'],$param['limit'])
-            ->group('a.UniqId')
-            ->select();
-
-        $count = \db('设备_产量计酬')->alias('a')
-            ->join('工单_印件资料 b', 'b.订单编号 = a.订单编号 AND a.子订单编号 = a.子订单编号')
-            ->join('工单_基本资料 j', 'b.订单编号 = j.订单编号', 'LEFT')
-            ->field('
-                b.订单编号, b.子订单编号, b.款号, b.颜色, b.船样, a.尺码, b.zdtotal as 制单数,b.颜色备注,
-                a.数量, a.sys_rq as 上报时间,a.UniqId,a.mod_rq,a.delsys_id,a.sczl_bh,
-                j.客户编号,j.生产款号,j.款式
-                ')
-            ->where($where)
-            ->order('a.mod_rq desc')
-            ->group('a.UniqId')
-            ->select();
-
-        // 提取所有的尺码,并去重
-        $sizeList = array_values(array_unique(array_column($list, '尺码')));
-        // 动态将尺码的数量添加到每个订单中,并替换已完成字段
-        foreach ($list as &$item) {
-            $size = $item['尺码'];
-            $item[$size] = $item['数量']; // 动态添加尺码字段,值为数量
-//            unset($item['数量']); // 移除原来的已完成字段
-        }
-        $data['total'] = count($count);
-        $data['table'] = $list;
-        $this->success('成功',$data);
+//        // 构建 10 条模拟任务
+//        $mockTasks = [];
+//        for ($i = 1; $i <= 10; $i++) {
+//            $mockTasks[] = [
+//                'job' => 'app\\job\\ImageJob',
+//                'data' => [
+//                    'dir_name'     => '/uploads/operate/ai/Preview/20250511/',
+//                    'file_name'    => "46c086fa3214f7548a0dc4f7595be140.png",
+//                    'prompt'       => '请按以下要求分析图案,详细描述图案信息提示词,描述信息仅限图案本体,生成的描述信息',
+//                    'outputDirRaw' => '/uploads/operate/ai/dall-e/',
+//                    'width'        => '679',
+//                    'height'       => '862'
+//                ],
+//                'id' => 'mockID' . $i,
+//                'attempts' => rand(1, 10)
+//            ];
+//        }
+//
+//        return json([
+//            'code' => 0,
+//            'msg'  => '查询成功(模拟10条)',
+//            'count' => count($mockTasks),
+//            'tasks_preview' => $mockTasks
+//        ]);
+//        die;
+
+        $redis = new \Redis();
+        $redis->connect('127.0.0.1', 6379);
+        $redis->select(15);
+
+        $key = 'queues:default';
+
+        $count = $redis->lLen($key);
+        $list = $redis->lRange($key, 0, 9);
+
+        $parsed = array_map(function ($item) {
+            return json_decode($item, true);
+        }, $list);
+
+        return json([
+            'code' => 0,
+            'msg'  => '查询成功',
+            'count' => $count,
+            'tasks_preview' => $parsed
+        ]);
     }
 
-    /**
-     * 产品附件新增
-     * 1.前端进行上传xlsx文件表格
-     * 2.接口接受数据文件进行保存xlsx文件以及pdf转换
-     * 3.前端进行预览pdf图片显示文件中的内容再页面上
-     */
-    public function gdAnnexAdd() {
-        ini_set('display_errors', 'On');
-        ini_set('error_reporting', E_ALL);
-
-        if (!$this->request->isPost()) {
-            $this->error('请求方式错误');
-        }
 
-        // 获取请求参数
-        $req = $this->request->param();
-        $relateId = $req['关联编号'];
-        $attachmentContent = $req['附件内容'];
-        $attachmentType = $req['附件类型'];
-        $prefixDir = ROOT_PATH . '/public/';
-        $uploadDir = ''.'uploads/' . date('Ymd') . '/' . $relateId;
+    //单个调用
+//    protected $config = [
+//        'gpt' => [
+//            'api_key' => 'sk-Bhos1lXTRpZiAAmN06624a219a874eCd91Dc068b902a3e73',
+//            'api_url' => 'https://one.opengptgod.com/v1/chat/completions'
+//        ],
+//        'dalle' => [
+//            'api_key' => 'sk-e0JuPjMntkbgi1BoMjrqyyzMKzAxILkQzyGMSy3xiMupuoWY',
+//            'api_url' => 'https://niubi.zeabur.app/v1/images/generations'
+//        ]
+//    ];
+//    public function imageToTexts()
+//    {
+//        $params = $this->request->param();
+//
+//        // 统一路径格式
+//        $sourceDirRaw = str_replace('\\', '/', trim($params['sourceDir'] ?? '', '/'));
+//        $fileName = trim($params['file_name'] ?? '');
+//
+//        // 自动拆分文件名
+//        if (!$fileName && preg_match('/([^\/]+\.(jpg|jpeg|png))$/i', $sourceDirRaw, $matches)) {
+//            $fileName = $matches[1];
+//            $sourceDirRaw = preg_replace('/\/' . preg_quote($fileName, '/') . '$/', '', $sourceDirRaw);
+//        }
+//
+//        // 参数校验
+//        if ($sourceDirRaw === '' || $fileName === '') {
+//            return $this->error('参数错误:sourceDir 或 file_name 不能为空');
+//        }
+//
+//        // 构建路径
+//        $rootPath = str_replace('\\', '/', ROOT_PATH);
+//        $sourceDir = rtrim($rootPath . 'public/' . $sourceDirRaw, '/') . '/';
+//        $filePath = $sourceDir . $fileName;
+//        $relativePath = $sourceDirRaw . '/' . $fileName;
+//
+//        // 文件检查
+//        if (!is_dir($sourceDir)) {
+//            return $this->error('源目录不存在:' . $sourceDir);
+//        }
+//        if (!is_file($filePath)) {
+//            return $this->error('文件不存在:' . $filePath);
+//        }
+//
+//        // 避免重复处理
+////        $exists = Db::name('text_to_image')
+////            ->where('old_image_url', $relativePath)
+////            ->where('chinese_description', '<>', '')
+////            ->find();
+////        if ($exists) {
+////            return $this->success('该图片已生成描述,无需重复处理');
+////        }
+//
+////        try {
+//            // 获取图片信息
+//            $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
+//            $mime = ($ext === 'jpg' || $ext === 'jpeg') ? 'jpeg' : $ext;
+//
+//            list($width, $height) = getimagesize($filePath);
+//            $imageData = base64_encode(file_get_contents($filePath));
+//            if (!$imageData || strlen($imageData) < 1000) {
+//                throw new \Exception('图片内容读取失败');
+//            }
+//            $imageUrl = "data:image/{$mime};base64,{$imageData}";
+//
+//            // 构建严格格式的提示词
+//            $userPrompt = preg_replace('/\s+/u', '', $params['prompt']); // 移除所有空白字符
+//            $strictPrompt = "严格遵守以下规则:
+//1. 只返回三段内容:
+//   第一段:纯中文图案描述
+//   第二段:---json json---
+//   第三段:纯英文图案描述
+//2. 描述中必须体现图案的类型、颜色、风格等关键信息
+//3. 不允许添加任何解释、引导、说明、示例等文字,必须只包含图案描述内容本身
+//3. 示例:
+//这张图中的图案是代表达拉斯足球队的标志,包括一个头盔图形和围绕它的文字。头盔以灰色和白色为主,有蓝色和黑色的细节。
+//---json json---
+//The pattern in this picture is the logo representing the Dallas football team, including a helmet figure and the text around it. The helmet is mainly gray and white, with blue and black details.
+//请直接描述这个图案:
+//" . $userPrompt;
+//
+//            // 调用 GPT 接口
+//            $gptRes = $this->callGptApi($imageUrl, $strictPrompt);
+//            $gptText = trim($gptRes['choices'][0]['message']['content'] ?? '');
+//
+//            // 验证 GPT 返回格式
+//            if (strpos($gptText, '---json json---') === false) {
+//                throw new \Exception('GPT 返回格式不正确,缺少分隔符');
+//            }
+//
+//            list($chineseDesc, $englishDesc) = array_map('trim', explode('---json json---', $gptText));
+//
+//            if ($chineseDesc === '' || $englishDesc === '') {
+//                throw new \Exception('描述内容为空,请检查 GPT 返回');
+//            }
+//
+//            // 插入数据库(成功时才插入)
+//            $this->logToDatabase([
+//                'old_image_url'       => $relativePath,
+//                'chinese_description' => $chineseDesc,
+//                'english_description' => $englishDesc,
+//                'size'                => "",
+//                'status'              => 1
+//            ]);
+//
+//            return $this->success('图生文成功', [
+//                'chinese' => $chineseDesc,
+//                'english' => $englishDesc
+//            ]);
+//
+////        } catch (\Exception $e) {
+////            // 只写日志,不重复插入数据库
+//////            Log::error('图生文失败 [' . $relativePath . ']:' . $e->getMessage());
+////            Db::name('text_to_image')->insert([
+////                'old_image_url' => $relativePath,
+////                'error_msg'     => $e->getMessage(),
+////                'status'        => 0,
+////                'create_time'   => date('Y-m-d H:i:s') // 可选:记录时间戳
+////            ]);
+////            return json([
+////                'code' => 1,
+////                'msg'  => '图生文失败:' . $e->getMessage()
+////            ]);
+////        }
+//    }
+//
+//    /**
+//     * 调用GPT API生成文字描述(改进版)
+//     */
+//    public function callGptApi($imageUrl, $prompt)
+//    {
+//        $data = [
+//            "model" => "gpt-4-vision-preview",
+//            "messages" => [[
+//                "role" => "user",
+//                "content" => [
+//                    ["type" => "text", "text" => $prompt],
+//                    ["type" => "image_url", "image_url" => [
+//                        "url" => $imageUrl,
+//                        "detail" => "auto" // ✅ 显式添加 detail 字段,兼容 vision API
+//                    ]]
+//                ]
+//            ]],
+//            "max_tokens" => 1000
+//        ];
+//
+//        return $this->callApi($this->config['gpt']['api_url'], $this->config['gpt']['api_key'], $data);
+//    }
+//
+//
+//    /**
+//     * 文字生成图片(第二步) - 等比缩放生成指定尺寸图
+//     */
+//    public function textToImage()
+//    {
+//        $params = $this->request->param();
+//        $fileName = trim($params['file_name'] ?? '');
+//        $outputDirRaw = trim($params['outputDir'] ?? '', '/');
+//        $width = intval($params['width'] ?? 512);
+//        $height = intval($params['height'] ?? 512);
+//        $prompt = trim($params['prompt'] ?? '');
+//
+//        // 统一路径格式
+//        $rootPath = str_replace('\\', '/', ROOT_PATH);
+//        $outputDir = rtrim($rootPath . 'public/' . $outputDirRaw, '/') . '/';
+//        $dateDir = date('Y-m-d') . '/';
+//        $fullBaseDir = $outputDir . $dateDir;
+//
+//        foreach ([$fullBaseDir, $fullBaseDir . '1024x1024/', $fullBaseDir . "{$width}x{$height}/"] as $dir) {
+//            if (!is_dir($dir)) {
+//                mkdir($dir, 0755, true);
+//            }
+//        }
+//
+//        // 提示词合法性校验
+//        $prompt = preg_replace('/[\r\n\t]+/', ' ', $prompt);
+////        if (empty($prompt) || mb_strlen($prompt) < 10) {
+////            return json(['code' => 1, 'msg' => '提示词过短或为空,请填写有效的英文图像描述']);
+////        }
+////        if (preg_match('/[\x{4e00}-\x{9fa5}]/u', $prompt)) {
+////            return json(['code' => 1, 'msg' => '请使用英文提示词,当前提示内容包含中文']);
+////        }
+//
+//        // 查询图像记录
+//        $record = Db::name('text_to_image')
+//            ->where('old_image_url', 'like', "%{$fileName}")
+//            ->order('id desc')
+//            ->find();
+////        echo "<pre>";
+////        print_r($record);
+////        echo "<pre>";
+//
+//        if (!$record) {
+//            return json(['code' => 1, 'msg' => '没有找到匹配的图像记录']);
+//        }
+//
+////        try {
+//            // 日志记录
+//            $logDir = ROOT_PATH . 'runtime/logs/';
+//            if (!is_dir($logDir)) mkdir($logDir, 0755, true);
+//            file_put_contents($logDir . 'prompt_log.txt', date('Y-m-d H:i:s') . " prompt: {$prompt}\n", FILE_APPEND);
+//
+//            // 调用 DALL·E API
+//            $dalle1024 = $this->callDalleApi($prompt);
+//
+//            file_put_contents($logDir . 'dalle_response.log', date('Y-m-d H:i:s') . "\n" . print_r($dalle1024, true) . "\n", FILE_APPEND);
+//
+//            if (!isset($dalle1024['data'][0]['url']) || empty($dalle1024['data'][0]['url'])) {
+//                $errorText = $dalle1024['error']['message'] ?? '未知错误';
+//                throw new \Exception('DALL·E 生成失败:' . $errorText);
+//            }
+//
+//            $imgUrl1024 = $dalle1024['data'][0]['url'];
+//            $imgData1024 = @file_get_contents($imgUrl1024);
+//            if (!$imgData1024 || strlen($imgData1024) < 1000) {
+//                throw new \Exception("下载图像失败或内容异常");
+//            }
+//
+//            // 保存原图
+//            $filename1024 = 'dalle_' . md5($record['old_image_url'] . microtime()) . '_1024.png';
+//            $savePath1024 = $fullBaseDir . '1024x1024/' . $filename1024;
+//            file_put_contents($savePath1024, $imgData1024);
+//
+//            // 创建图像资源
+//            $im = @imagecreatefromstring($imgData1024);
+//            if (!$im) {
+//                throw new \Exception("图像格式不受支持或已损坏");
+//            }
+//
+//// 获取原图尺寸
+//            $srcWidth = imagesx($im);
+//            $srcHeight = imagesy($im);
+//
+//// 目标尺寸
+//            $targetWidth = $width;
+//            $targetHeight = $height;
+//
+//// 计算缩放比例(以覆盖为目标,可能会超出一边)
+//            $ratio = max($targetWidth / $srcWidth, $targetHeight / $srcHeight);
+//            $newWidth = intval($srcWidth * $ratio);
+//            $newHeight = intval($srcHeight * $ratio);
+//
+//// 创建目标图像(目标尺寸)
+//            $dstImg = imagecreatetruecolor($targetWidth, $targetHeight);
+//
+//// 缩放后居中裁剪偏移
+//            $offsetX = intval(($newWidth - $targetWidth) / 2);
+//            $offsetY = intval(($newHeight - $targetHeight) / 2);
+//
+//// 临时缩放图像
+//            $tempImg = imagecreatetruecolor($newWidth, $newHeight);
+//            imagecopyresampled($tempImg, $im, 0, 0, 0, 0, $newWidth, $newHeight, $srcWidth, $srcHeight);
+//
+//// 裁剪中间部分到最终尺寸
+//            imagecopy($dstImg, $tempImg, 0, 0, $offsetX, $offsetY, $targetWidth, $targetHeight);
+//
+//// 保存结果
+//            $filenameCustom = 'dalle_' . md5($record['old_image_url'] . microtime()) . "_custom.png";
+//            $savePathCustom = $fullBaseDir . "{$width}x{$height}/" . $filenameCustom;
+//            imagepng($dstImg, $savePathCustom);
+//
+//// 释放内存
+//            imagedestroy($im);
+//            imagedestroy($tempImg);
+//            imagedestroy($dstImg);
+//
+//            // 更新数据库
+//            Db::name('text_to_image')->where('id', $record['id'])->update([
+//                'new_image_url'     => str_replace($rootPath . 'public/', '', $savePath1024),
+//                'custom_image_url'  => str_replace($rootPath . 'public/', '', $savePathCustom),
+//                'error_msg'         => '',
+//                'size'              => "{$width}x{$height}",
+//                'updated_time'      => date('Y-m-d H:i:s')
+//            ]);
+//
+//            return json([
+//                'code' => 0,
+//                'msg'  => '文生图生成完成',
+//                'data' => [
+//                    'new_image_url'    => str_replace($rootPath . 'public/', '', $savePath1024)?? '',
+//                    'custom_image_url' => str_replace($rootPath . 'public/', '', $savePathCustom)?? '',
+//                    'size'             => "{$width}x{$height}"
+//                ]
+//            ]);
+//
+////        } catch (\Exception $e) {
+////            Db::name('text_to_image')->where('id', $record['id'])->update([
+////                'status'    => 0,
+////                'error_msg' => $e->getMessage()
+////            ]);
+////
+////            return json(['code' => 1, 'msg' => '文生图失败:' . $e->getMessage()]);
+////        }
+//    }
+//
+//    /**
+//     * 调用 DALL·E 接口
+//     * 文生图
+//     */
+//    public function callDalleApi($prompt)
+//    {
+//        $data = [
+//            'prompt' => $prompt,
+//            'model'  => 'dall-e-2',
+//            'n'      => 1,
+//            'size'   => '1024x1024'
+//        ];
+//        return $this->callApi($this->config['dalle']['api_url'], $this->config['dalle']['api_key'], $data);
+////        $data = [
+////            'prompt'  => "A stylized representation of a Dallas football team logo, featuring a helmet in shades of gray and white with blue and black accents. The word 'Dallas' in bold, italicized, gray-white capital letters on a dark blue curved banner, with the year '1960' in smaller font at the bottom, matching the helmet's color scheme. The design reflects the visual elements and style typical of American football culture, presented on a plain black background.",
+////            'model'   => 'dall-e-2',
+////            'n'       => 1,
+////            'size'    => '1024x1024',
+////            'quality' => 'standard',
+////            'style'   => 'vivid'
+////        ];
+////
+////        return $this->callApi($this->config['dalle']['api_url'], $this->config['dalle']['api_key'], $data);
+//    }
+//
+//    /**
+//     * 翻译为英文
+//     */
+//    public function translateToEnglish($text)
+//    {
+//        $data = [
+//            'model' => 'gpt-3.5-turbo',
+//            'messages' => [[
+//                'role' => 'user',
+//                'content' => "请将以下内容翻译为英文,仅输出英文翻译内容,不需要解释:\n\n{$text}"
+//            ]],
+//            'max_tokens' => 300,
+//            'temperature' => 0.3
+//        ];
+//
+//        $response = $this->callApi($this->config['gpt']['api_url'], $this->config['gpt']['api_key'], $data);
+//        return trim($response['choices'][0]['message']['content'] ?? '');
+//    }
+//
+//
+//    /**
+//     * 通用API调用方法
+//     */
+//    public function callApi($url, $apiKey, $data)
+//    {
+//        $maxRetries = 2;
+//        $attempt = 0;
+//        $lastError = '';
+//
+//        while ($attempt <= $maxRetries) {
+//            $ch = curl_init();
+//            curl_setopt_array($ch, [
+//                CURLOPT_URL => $url,
+//                CURLOPT_RETURNTRANSFER => true,
+//                CURLOPT_POST => true,
+//                CURLOPT_POSTFIELDS => json_encode($data),
+//                CURLOPT_HTTPHEADER => [
+//                    'Content-Type: application/json',
+//                    'Authorization: Bearer ' . $apiKey
+//                ],
+//                CURLOPT_TIMEOUT => 120,
+//                CURLOPT_SSL_VERIFYPEER => false,
+//                CURLOPT_SSL_VERIFYHOST => 0,
+//                CURLOPT_TCP_KEEPALIVE => 1,
+//                CURLOPT_FORBID_REUSE => false
+//            ]);
+//
+//            $response = curl_exec($ch);
+//            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+//            $curlError = curl_error($ch);
+//            curl_close($ch);
+//
+//            if ($response !== false && $httpCode === 200) {
+//                $result = json_decode($response, true);
+//                return $result;
+//            }
+//
+//            $lastError = $curlError ?: "HTTP错误:{$httpCode}";
+//            $attempt++;
+//            sleep(1);
+//        }
+//
+//        throw new \Exception("请求失败(重试{$maxRetries}次):{$lastError}");
+//    }
+//
+//    /**
+//     * 记录到数据库
+//     */
+//    public function logToDatabase($data)
+//    {
+//        $record = [
+//            'old_image_url' => $data['old_image_url'] ?? '',
+//            'new_image_url' => $data['new_image_url'] ?? '',
+//            'custom_image_url' => $data['custom_image_url'] ?? '',
+//            'size' => isset($data['image_width'], $data['image_height']) ?
+//                $data['image_width'] . 'x' . $data['image_height'] : '',
+//            'chinese_description' => $data['chinese_description'] ?? '',
+//            'english_description' => $data['english_description'] ?? '',
+//            'model' => 'dall-e-2',
+//            'quality' => 'standard',
+//            'style' => 'vivid',
+//            'status' => $data['status'] ?? 0,
+//            'error_msg' => $data['error_msg'] ?? '',
+//            'created_time' => date('Y-m-d H:i:s'),
+//            'updated_time' => date('Y-m-d H:i:s')
+//        ];
+//
+//        if (isset($data['id'])) {
+//            Db::name('text_to_image')->where('id', $data['id'])->update($record);
+//        } else {
+//            Db::name('text_to_image')->insert($record);
+//        }
+//    }
+//
+//    /**
+//     * 获取待处理的源图片列表
+//     */
+//    public function getSourceImages()
+//    {
+//        $params = $this->request->param();
+//        $sourceDir = rtrim(ROOT_PATH . 'public/' . $params['sourceDir'], '/') . '/';
+//
+//        if (!is_dir($sourceDir)) return $this->error('源目录不存在');
+//
+//        $files = glob($sourceDir . '*.{jpg,jpeg,png}', GLOB_BRACE);
+//        $result = [];
+//
+//        foreach ($files as $file) {
+//            $relativePath = trim($params['sourceDir'], '/') . '/' . basename($file);
+//
+//            $exists = Db::name('text_to_image')
+//                ->where('old_image_url', $relativePath)
+//                ->where('status', 1)
+//                ->find();
+//
+//            if (!$exists) {
+//                $result[] = basename($file);
+//            }
+//        }
+//
+//        return $this->success('获取成功', $result);
+//    }
+//
+//    /**
+//     * 获取处理成功的列表
+//     */
+//    public function getlist()
+//    {
+//        $today = date('Y-m-d');
+//        $tomorrow = date('Y-m-d', strtotime('+1 day'));
+//
+//        $res = Db::name('text_to_image')
+//            ->where('status', 1)
+//            ->where('created_time', '>=', $today . ' 00:00:00')
+//            ->where('created_time', '<', $tomorrow . ' 00:00:00')
+//            ->order('id desc')
+//            ->select();
+//
+//        foreach ($res as &$item) {
+//            $item['status_text'] = '成功';
+//        }
+//
+//        return json(['code' => 0, 'msg' => '获取成功', 'data' => $res]);
+//    }
+//
+//    /**
+//     * 获取错误日志
+//     */
+//    public function getErrorLogs()
+//    {
+//        $res = Db::name('text_to_image')
+//            ->where('status', 0)
+//            ->order('id desc')
+//            ->limit(20)
+//            ->select();
+//
+//        return json(['code' => 0, 'msg' => '获取失败记录成功', 'data' => $res]);
+//    }
 
-        DB::name('工单_基本资料')
-            ->where('订单编号', $relateId)
-            ->update(['gd_statu' => '2-生产中']);
 
-        // 检查并创建目录
-        if (!is_dir($prefixDir . $uploadDir)) {
-            mkdir($prefixDir . $uploadDir, 0777, true);
-        }
-
-        // 处理 Base64 附件内容
-        if (strpos($attachmentContent, 'base64,') !== false) {
-            $attachmentContent = explode('base64,', $attachmentContent)[1];
-        }
-        $fileContent = base64_decode($attachmentContent);
-        $filename = time();
-
-        // 初始化文件路径变量
-        $xlsxFilePath = '';
-        $pdfFilePath = '';
-
-        if ($attachmentType === 'pdf') {
-            // 保存 PDF 文件
-            $pdfFilePath = $uploadDir . '/' . $filename . '.pdf';
-            file_put_contents($prefixDir . $pdfFilePath, $fileContent);
-        } elseif ($attachmentType === 'xlsx') {
-            // 保存 Excel 文件
-            $xlsxFilePath = $uploadDir . '/' . $filename . '.xlsx';
-            file_put_contents($prefixDir . $xlsxFilePath, $fileContent);
-
-            // 转换为 PDF 文件
-            $pdfFilePath = $uploadDir . '/' . $filename . '.pdf';
-            $cmd = sprintf(
-                'libreoffice --headless --convert-to pdf --outdir %s %s',
-                escapeshellarg($prefixDir . $uploadDir),
-                escapeshellarg($prefixDir . $xlsxFilePath)
-            );
-            exec($cmd, $out, $retval);
-
-            if ($retval !== 0) {
-                $this->error('Excel 转 PDF 失败');
-            }
-        } else {
-            $this->error('不支持的附件类型');
-        }
-
-        // 获取最新的记录,按 sys_rq 降序排列
-        $latestItems = \db('工单_相关附件')
-            ->where('关联编号', $relateId)  // 根据关联编号筛选
-            ->where('附件备注', $req['附件备注'])  // 根据附件备注筛选
-            ->whereNull('mod_rq')
-            ->order('sys_rq desc')  // 按照 sys_rq 降序排列
-            ->group('关联编号')  // 按关联编号分组,获取每个订单的最新记录
-            ->find();
-
-        // 如果查询为空,设置默认的版本号为 'v1.0'
-        if (!$latestItems) {
-            $currentVersion = 'v1.0';
-        } else {
-            $currentVersion = $latestItems['version'];  // 当前记录的 version
-        }
-
-        // 解析当前版本号
-        if (preg_match('/v(\d+)\.(\d+)/', $currentVersion, $matches)) {
-            $majorVersion = (int)$matches[1];  // 主版本号
-            $minorVersion = (int)$matches[2];  // 次版本号
-
-            // 递增次版本号,若次版本号为 9,则主版本号加 1,次版本号置为 0
-            if ($minorVersion < 9) {
-                $minorVersion++;
-            } else {
-                $majorVersion++;
-                $minorVersion = 0;
-            }
-
-            // 生成新的版本号
-            $newVersion = 'v' . $majorVersion . '.' . $minorVersion;
-        } else {
-            // 如果没有匹配到版本号(例如没有 `v`),可以默认从 `v1.0` 开始
-            $newVersion = 'v1.0';
-        }
-
-        // 组织数据
-        $data = [
-            'version' => $newVersion,
-            '关联编号' => $relateId,
-            'sys_id' => $req['sys_id'],
-            '附件备注' => $req['附件备注'],
-            '附件类型' => $attachmentType,
-            'sys_rq' => date('Y-m-d H:i:s'),
-            'url' => $xlsxFilePath,  // 保存 xlsx 文件路径(如果存在)
-            'pdf' => $pdfFilePath  // 保存 pdf 文件路径
-        ];
-
-        // 数据库事务处理
-        db()->startTrans();
-        try {
-            // 插入数据
-            $sql = db('工单_相关附件')->fetchSql(true)->insert($data);
-            $result = db()->query($sql);
-            db()->commit();
-        } catch (\Exception $e) {
-            // 回滚事务
-            db()->rollback();
-            $this->error($e->getMessage());
-        }
-
-        if ($result === false) {
-            $this->error('失败');
-        }
-
-        $this->success('成功');
-    }
-
-
-    /**
-     * 订单打印接口
-     * order:订单编号
-     * 通过订单编号获取订单表数据以及子订单数据
-     */
-    public function orderPrint(){
-        if ($this->request->isGet() === false){$this->error('请求错误');}
-        $param = $this->request->param();
-        if (empty($param['order'])){$this->error('参数错误');}
-
-        $where['Mod_rq'] = null;
-        //订单信息
-        $list = \db('工单_基本资料')
-            ->where('订单编号',$param['order'])
-            ->where($where)
-            ->field('订单编号,img,生产款号,客户编号,款式,落货日期,箱唛要求,面料,船样描述,船样合计,粘衬,订单数量,审核,审核日期,要求,water')
-            ->find();
-
-        //尺码表格表头
-        $xhdata = \db('工单_印件资料')->where('订单编号', $param['order'])->where($where)->select();
-        $arr = [];
-        foreach ($xhdata as $key => $value) {
-            for ($i = 1; $i <= 10; $i++) {
-                if ($value['cm' . $i] !== '' && $value['cm' . $i] !== null) {
-                    array_push($arr, $value['cm' . $i]);
-                }
-            }
-        }
-
-        // 去重并重新索引
-        $arr = array_unique($arr);
-        $arr = array_values($arr);
-
-        // 自定义排序函数
-        usort($arr, function($a, $b) {
-            // 判断是否为数字
-            $isNumericA = is_numeric($a);
-            $isNumericB = is_numeric($b);
-
-            if ($isNumericA && $isNumericB) {
-                // 如果都是数字,按从小到大排序
-                return $a - $b;
-            } elseif (!$isNumericA && !$isNumericB) {
-                // 如果都是字母,按字母顺序排序(可以自定义顺序)
-                $sizeOrder = ['XXS', 'XS', 'S', 'M', 'L', 'XL', 'XXL', 'XXXL','XXXXL'];
-                $posA = array_search($a, $sizeOrder);
-                $posB = array_search($b, $sizeOrder);
-                return $posA - $posB;
-            } else {
-                // 如果一个是数字一个是字母,数字排在前
-                return $isNumericA ? -1 : 1;
-            }
-        });
-
-
-        //打印table数据表格
-        $porlis = \db('工单_印件资料')
-            ->where('订单编号',$param['order'])
-            ->where('船样',0)
-            ->where($where)
-            ->field('子订单编号')
-            ->select();
-        //合并后的子订单条码数据
-        $subOrder = $porlis[0]['子订单编号'];
-        // 找到子订单编号中的 '-' 位置
-        $dashPos = strpos($subOrder, '-');
-
-        if ($dashPos !== false) {
-            // 提取 '-' 后面的部分
-            $afterDash = substr($subOrder, $dashPos + 1);
-
-            // 判断长度是否等于2或等于4
-            if (strlen($afterDash) == 2) {
-                // 查询船样为0的数据
-                $processlist = \db('工单_印件资料')
-                    ->where('订单编号', $param['order'])
-                    ->where($where)
-                    ->where('船样', 0)
-                    ->field('子订单编号,颜色,款号,zdtotal,颜色备注,color_id,
-                            cm1,cm2,cm3,cm4,cm5,cm6,cm7,cm8,cm9,cm10,
-                            cmsl1,cmsl2,cmsl3,cmsl4,cmsl5,cmsl6,cmsl7,cmsl8,cmsl9,cmsl10,Uniqid')
-                    ->select();
-
-                // 初始化汇总数组
-                $scslTotals = [
-                    "cmsl1" => 0,
-                    "cmsl2" => 0,
-                    "cmsl3" => 0,
-                    "cmsl4" => 0,
-                    "cmsl5" => 0,
-                    "cmsl6" => 0,
-                    "cmsl7" => 0,
-                    "cmsl8" => 0,
-                    "cmsl9" => 0,
-                    "cmsl10" => 0,
-                    "zdtotal" => 0, // 总计数量
-                ];
-                // 遍历数据集进行汇总
-                foreach ($processlist as $item) {
-                    // 遍历每个尺码字段(cmsl1 到 cmsl10)
-                    for ($i = 1; $i <= 10; $i++) {
-                        // 获取当前字段的数量
-                        $sizeQty = $item['cmsl' . $i];
-                        // 判断数量是否有效(非空且大于0)
-                        if (!empty($sizeQty)) {
-                            // 累加当前字段的数量
-                            $scslTotals['cmsl' . $i] += $sizeQty;
-                            // 累加到总计字段
-                            $scslTotals['zdtotal'] += $sizeQty;
-                        }
-                    }
-                }
-
-                $data['scslTotals'] = $scslTotals;
-
-                foreach ($processlist as $key => $value) {
-                    // 将尺码和对应的数量从 cm1-cm10 和 cmsl1-cmsl10 转换为动态键值对
-                    for ($i = 1; $i <= 10; $i++) {
-                        if ($value['cm' . $i] !== '' && $value['cm' . $i] !== null) {
-                            $processlist[$key][$value['cm' . $i]] = $value['cmsl' . $i];
-                        }
-                        // 移除原始的 cm 和 cmsl 字段
-                        unset($processlist[$key]['cm' . $i], $processlist[$key]['cmsl' . $i]);
-                    }
-                }
-                // 用于存储合并后的数据
-                $mergedData = [];
-                // 按颜色备注进行合并
-                foreach ($processlist as $item) {
-                    $key = $item['颜色备注'];
-
-                    if (!isset($mergedData[$key])) {
-                        $mergedData[$key] = $item;
-                        // 添加条码字段,值为子订单编号
-                        $mergedData[$key]['条码'] = $item['子订单编号'];
-                    } else {
-                        // 合并尺码对应的数量
-                        foreach ($item as $size => $quantity) {
-                            if (is_numeric($size)) {
-                                if (!isset($mergedData[$key][$size])) {
-                                    $mergedData[$key][$size] = 0;
-                                }
-                                $mergedData[$key][$size] += $quantity;
-                            }
-                        }
-                        // 合并 zdtotal
-                        $mergedData[$key]['zdtotal'] += $item['zdtotal'];
-                    }
-                }
-                // 查询船样为1的数据
-                $chuanyang = \db('工单_印件资料')
-                    ->where('订单编号', $param['order'])
-                    ->where($where)
-                    ->where('船样', 1)
-                    ->field('子订单编号,颜色,款号,zdtotal,颜色备注,color_id,
-                        cm1,cm2,cm3,cm4,cm5,cm6,cm7,cm8,cm9,cm10,
-                        cmsl1,cmsl2,cmsl3,cmsl4,cmsl5,cmsl6,cmsl7,cmsl8,cmsl9,cmsl10,Uniqid')
-                    ->select();
-                foreach ($chuanyang as $key => $value) {
-                    // 将尺码和对应的数量从 cm1-cm10 和 cmsl1-cmsl10 转换为动态键值对
-                    for ($i = 1; $i <= 10; $i++) {
-                        if ($value['cm' . $i] !== '' && $value['cm' . $i] !== null) {
-                            $chuanyang[$key][$value['cm' . $i]] = $value['cmsl' . $i];
-                        }
-                        // 移除原始的 cm 和 cmsl 字段
-                        unset($chuanyang[$key]['cm' . $i], $chuanyang[$key]['cmsl' . $i]);
-                    }
-                    // 添加条码字段,值为子订单编号
-                    $chuanyang[$key]['条码'] = $value['子订单编号'];
-                }
-
-                // 将合并后的数据插入到相应颜色备注的原始数据尾部
-                $finalList = [];
-                $groupedData = [];
-
-                // 将原始数据按颜色备注分组
-                foreach ($processlist as $item) {
-                    $key = $item['颜色备注'];
-                    if (!isset($groupedData[$key])) {
-                        $groupedData[$key] = [];
-                    }
-                    $groupedData[$key][] = $item;
-                }
-
-                // 将合并后的数据插入到对应的颜色备注组的尾部
-                foreach ($groupedData as $key => $items) {
-                    $finalList = array_merge($finalList, $items); // 先添加原始数据
-                    if (isset($mergedData[$key])) {
-                        $finalList[] = $mergedData[$key]; // 在组的尾部添加合并数据
-                    }
-                }
-                // 将船样为1的数据添加到最终列表中
-                $finalList = array_merge($finalList, $chuanyang);
-                $data['process'] = $finalList;
-                $data['order'] = $list;
-                $data['xhdata'] = $arr;
-                $this->success('成功',$data);
-            } elseif (strlen($afterDash) == 4) {
-                //一条子订单编号一个条码,统计颜色
-//                $processlist = \db('工单_印件资料')
-//                    ->where('订单编号', $param['order'])
-//                    ->whereNull('Mod_rq') // 查询未删除数据
-//                    ->select();
-//
-//                $table = [];
-//                foreach ($processlist as $item) {
-//                    // 当前子订单编号的数据
-//                    $subOrder = [
-//                        '颜色备注' => $item['颜色备注'],
-//                        '色系名称' => $item['颜色'],
-//                        '订单编号' => $item['订单编号'],
-//                        '子订单编号' => $item['子订单编号'],
-//                        '条码' => $item['子订单编号'],
-//                        '款号' => $item['款号'],
-//                    ];
-//                    // 当前子订单编号的合计
-//                    $subOrderTotal = 0;
-//                    for ($i = 1; $i <= 10; $i++) {
-//                        if (!empty($item['cm' . $i])) {
-//                            $subOrder[$item['cm' . $i]] = $item['cmsl' . $i];
-//                            // 累加每个尺码的数量
-//                            $subOrderTotal += $item['cmsl' . $i];
-//                        }
-//                        unset($item['cm' . $i], $item['cmsl' . $i]);
-//                    }
-//                    $subOrder['合计'] = $subOrderTotal; // 添加合计
-//                    $table[] = $subOrder; // 将当前子订单的数据添加到 $table 中
-//                }
-                $processlist = \db('工单_印件资料')
-                    ->where('订单编号', $param['order'])
-                    ->whereNull('Mod_rq') // 查询未删除数据
-                    ->select();
-
-                $table = [];
-                foreach ($processlist as $item) {
-                    // 当前子订单编号的数据
-                    $subOrder = [
-                        '颜色备注' => $item['颜色备注'],
-                        '色系名称' => $item['颜色'],
-                        '订单编号' => $item['订单编号'],
-                        '子订单编号' => $item['子订单编号'],
-                        '条码' => $item['子订单编号'],
-                        '款号' => $item['款号'],
-                    ];
-                    // 当前子订单编号的合计
-                    $subOrderTotal = 0;
-                    for ($i = 1; $i <= 10; $i++) {
-                        // 判断 cm 和 cmsl 是否有值,空值不显示,0 则显示
-                        if (isset($item['cm' . $i]) && $item['cm' . $i] !== '') {
-                            $subOrder[$item['cm' . $i]] = $item['cmsl' . $i] ?? 0; // 默认数量为 0
-                            // 累加每个尺码的数量
-                            $subOrderTotal += (int)$item['cmsl' . $i]; // 确保是数值类型
-                        }
-                        // 清理字段
-                        unset($item['cm' . $i], $item['cmsl' . $i]);
-                    }
-                    $subOrder['合计'] = $subOrderTotal; // 添加合计
-                    $table[] = $subOrder; // 将当前子订单的数据添加到 $table 中
-                }
-
-
-                // 初始化汇总数组
-                $scslTotals = [
-                    "cmsl1" => 0,
-                    "cmsl2" => 0,
-                    "cmsl3" => 0,
-                    "cmsl4" => 0,
-                    "cmsl5" => 0,
-                    "cmsl6" => 0,
-                    "cmsl7" => 0,
-                    "cmsl8" => 0,
-                    "cmsl9" => 0,
-                    "cmsl10" => 0,
-                    "zdtotal" => 0, // 总计数量
-                ];
-
-                // 遍历数据集进行汇总
-                foreach ($processlist as $item) {
-                    // 遍历每个尺码字段(cmsl1 到 cmsl10)
-                    for ($i = 1; $i <= 10; $i++) {
-                        // 获取当前字段的数量
-                        $sizeQty = $item['cmsl' . $i];
-                        // 判断数量是否有效(非空且大于0)
-                        if (!empty($sizeQty)) {
-                            // 累加当前字段的数量
-                            $scslTotals['cmsl' . $i] += $sizeQty;
-                            // 累加到总计字段
-                            $scslTotals['zdtotal'] += $sizeQty;
-                        }
-                    }
-                }
-                $data['scslTotals'] = $scslTotals;
-                $data['process'] = $table;//汇总数据集
-                $data['order'] = $list;//表格数据
-                $data['xhdata'] = $arr;//尺码表头
-                $this->success('成功', $data);
-//                }
-            } else {
-                echo "子订单编号 - 后不是2位也不是4位:$afterDash";
-            }
-        } else {
-            echo "子订单编号中没有找到'-'";
-        }
-    }
-
-    /**
-     * 订单编号自动获取
-     * @return void
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     */
-    public function getWorkOrder()
-    {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $time =substr( date('Ym',time()),2);
-        $lastOrder = \db('工单_基本资料')
-            ->where('订单编号','like','%'.$time.'%')
-            ->order('Uniqid desc')
-            ->find();
-        if (empty($lastOrder)){
-            $newNumber = 1;
-        }else{
-            $lastNumber = substr($lastOrder['订单编号'],6);
-            $newNumber = (int)$lastNumber + 1;
-        }
-        if ($newNumber<10){
-            $newOrder = 'DC'.$time.'00'.$newNumber;
-        }elseif ($newNumber>=10 && $newNumber<100){
-            $newOrder = 'DC'.$time.'0'.$newNumber;
-        }else{
-            $newOrder = 'DC'.$time.$newNumber;
-        }
-        $this->success('成功',$newOrder);
-    }
-
-    /**
-     * 获取子订单编号
-     * @return void
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     */
-    public function getSuborder(){
-        // 确保是GET请求
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        if (empty($param) || !isset($param['cy']) || !isset($param['order'])) {
-            $this->error('参数错误');
-        }
-        // 判断是否“船样”获取对应的子订单编号
-        if ($param['cy'] == '否') {
-
-            //1.通过色系名称查询对应的编号
-            $colorlist = \db('工单_颜色编号')
-                ->field('colorcode, colorname')
-                ->where('colorname', $param['colorname'] ?? '')
-                ->find();
-
-            if (empty($colorlist)) {
-                $this->error('未找到对应的颜色编号');
-            }
-            $num = $param['order'] . '-' . $colorlist['colorcode'];
-
-            // 查询子订单编号
-            $data = \db('工单_印件资料')
-                ->field('子订单编号,cm1,cm2,cm3,cm4,cm5,cm6,cm7,cm8,cm9,cm10')
-                ->where('子订单编号', 'like', '%' . $num . '%')
-                ->where('船样', '=', 0)
-                ->whereNull('Mod_rq')
-                ->order('子订单编号', 'desc')
-                ->find();
-
-            if (empty($data)) {
-                // 如果没有找到数据,生成默认的订单编号,后两位从00开始
-                $order = $param['order'] . '-' . $colorlist['colorcode'] . '00';
-            } else {
-
-                if (strlen($data['子订单编号']) == 12) {
-                    $data = \db('工单_印件资料')
-                        ->where('订单编号',$param['order'])
-                        ->where('船样',0)
-                        ->whereNull('Mod_rq')
-                        ->order('子订单编号 desc')
-                        ->find();
-                    if(empty($data)){
-                        $order = $param['order'].'-01';
-                    }else{
-                        $num = (int)substr($data['子订单编号'],10) + 1;
-                        if ($num<10){
-                            $order = $param['order'].'-0'.$num;
-                        }else{
-                            $order = $param['order'].'-'.$num;
-                        }
-                    }
-                }else{
-                    // 如果找到数据,提取子订单编号并递增
-                    $order = $data['子订单编号'];
-                    if (preg_match('/(.*-' . $colorlist['colorcode'] . ')(\d{2})$/', $order, $matches)) {
-                        $prefix = $matches[1]; // 前缀部分(包括订单编号和颜色代码)
-                        $number = $matches[2]; // 数字部分(后两位)
-
-                        // 循环生成子订单编号并检查数据库中是否存在相同编号
-                        do {
-                            $incrementedNumber = (int)$number + 1;
-                            // 将数字部分补充为两位数,例如 1 -> 01,2 -> 02
-                            $order = $prefix . str_pad($incrementedNumber, 2, '0', STR_PAD_LEFT);
-                            $exists = \db('工单_印件资料')->whereNull('Mod_rq')->where('子订单编号', '=', $order)->find();
-                            $number = $incrementedNumber; // 更新 number 用于下一次循环
-                        } while ($exists); // 如果存在相同编号则继续循环递增
-                    } else {
-                        $this->error('订单编号格式错误');
-                    }
-                }
-
-            }
-
-            //2.获取色系名称信息
-            $colorlist = \db('工单_颜色编号')->select();
-
-            //3.获取历史尺码数据
-            $cm_list = \db('工单_印件资料')
-                ->where('订单编号', $param['order'])
-                ->group('订单编号')
-                ->find();
-
-            $cm_data = [];
-            if ($cm_list) {
-                // 精准筛选字段名以 "cm" 开头并跟1到2位数字的字段
-                foreach ($cm_list as $key => $value) {
-                    if (preg_match('/^cm\d{1,2}$/', $key)) {
-                        $cm_data[$key] = $value ?? ''; // 如果值为 null,设为空字符串
-                    }
-                }
-            } else {
-                // 如果查询结果为空,将 cm1 到 cm10 都设置为空
-                for ($i = 1; $i <= 10; $i++) {
-                    $cm_data["cm$i"] = '';
-                }
-            }
-
-
-
-            $result = ['order' => $order,'colorlist' => $colorlist,'cm' => $cm_data];
-            $this->success('成功', $result);
-
-        } else if ($param['cy'] == '是') {
-
-            //1.获取船样子订单编号
-            $data = \db('工单_印件资料')
-                ->where('订单编号', $param['order'])
-                ->where('船样', '=', 1)
-                ->order('子订单编号 asc')
-                ->find();
-
-            if (empty($data)) {
-                // 如果没有数据,初始子订单编号为 '99'
-                $order = $param['order'] . '-99';
-            } else {
-                // 提取子订单编号中的数字部分
-                $subOrder = $data['子订单编号'];  // 例如 "DC2410006-99"
-                if (preg_match('/-(\d+)$/', $subOrder, $matches)) {
-                    $numberPart = (int)$matches[1];  // 提取到的数字部分
-                    $newNumber = $numberPart - 1;    // 减 1
-                    // 将新的数字拼接回订单编号
-                    $order = preg_replace('/-\d+$/', '-' . $newNumber, $subOrder);
-                } else {
-                    $this->error('订单编号格式错误');
-                }
-            }
-
-            $this->success('成功', $order);
-        }
-    }
-
-    /**
-     * 获取PO号 【代码展示未用到】
-     */
-    public function getPonumber() {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        if (empty($param)){
-            $this->error('参数错误');
-        }
-        // $num = substr($param['child_order'], 0, 12);  // 如果需要,可以用这个方式截取子订单编号
-//        $sql = "SELECT * FROM `工单_印件资料` WHERE `子订单编号` LIKE '{$num}%' ORDER BY `子订单编号` DESC LIMIT 1";
-//        $data = \db()->query($sql);
-        $colorlist = \db('工单_颜色编号')
-            ->field('colorcode,colorname')
-            ->where('colorname',$param['child_order'])
-            ->find();
-        $num = $param['order'] . '-' . $colorlist['colorcode'];  // 生成 num,用于模糊查询
-        $data = \db('工单_印件资料')
-            ->where('子订单编号', 'like', '%' . $num . '%')
-            ->order('子订单编号', 'desc')
-            ->find();
-        if(count($data) === 1){
-            $order = $num.'01';
-        }else{
-            $number = (int)substr($data['子订单编号'],12,14) + 1;
-            if ($num<10){
-                $order = $num.'0'.$number;
-            }else{
-                $order = $num.$number;
-            }
-        }
-        $this->success('成功',$order);
-    }
-
-    /**
-     * 订单资料修改
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\db\exception\BindParamException
-     * @throws \think\exception\PDOException
-     */
-    public function WorkOrderEdit()
-    {
-        if (Request::instance()->isPost() === false){
-            $this->error('请求错误');
-        }
-        $param = Request::instance()->post();
-        if (empty($param)){
-            $this->error('参数错误');
-        }
-        $id = $param['id'];
-        unset($param['id']);
-        $sql = \db('工单_基本资料')
-            ->where('Uniqid',$id)
-            ->fetchSql(true)
-            ->update($param);
-        $res = \db()->query($sql);
-        if ($res === false){
-            $this->error('失败');
-        }else{
-            $this->success('成功');
-        }
-    }
-
-
-    /**
-     * 颜色资料修改
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\db\exception\BindParamException
-     * @throws \think\exception\PDOException
-     */
-    public function PrintDataEdit()
-    {
-        if(Request::instance()->post() === false){
-            $this->error('请求错误');
-        }
-        $param = Request::instance()->post();
-        if (empty($param)){
-            $this->error('参数错误');
-        }
-
-        $updata = [
-            '订单编号' => $param['订单编号'],
-            '子订单编号' => $param['子订单编号'],
-            '款号' => $param['款号'],
-            '船样' => $param['船样'],
-            '颜色' => $param['颜色'],
-            'color_id' => $param['color_id'],
-            '颜色备注' => $param['颜色备注'],
-            'zdtotal' => $param['zdtotal']
-        ];
-        for ($i = 1; $i <= 10; $i++) {
-            $updata["cmsl{$i}"] = isset($param["cmsl{$i}"]) ? $param["cmsl{$i}"] : '';
-        }
-        $sql = \db('工单_印件资料')
-            ->where('Uniqid', $param['id'])
-            ->fetchSql(true)
-            ->update($updata);
-        $res = \db()->query($sql);
-        if ($res !== false) {
-            $this->success('修改成功');
-        } else {
-            $this->error('修改失败');
-        }
-    }
-
-    /**
-     * 图片上传
-     * @return void
-     */
-    public function ImgUpload(){
-        $file = request()->file('image');
-        if($file){
-            $info = $file->validate(['size'=>10485760,'ext'=>'jpg,png'])->move(ROOT_PATH . 'public' . DS . 'uploads');
-            if($info){
-                $fileName = $info->getSaveName();
-//                $ymd = date('Ymd');
-//                $imageUrl = '/uploads/' . $ymd.'/'.$fileName;
-                $imageUrl = '/uploads/' . str_replace('\\', '/', $fileName);
-                return json(['code' => 0, 'msg' => '成功', 'data' => ['url' => $imageUrl]]);
-            }else{
-                $res = $file->getError();
-                return json(['code' => 1, 'msg' => '失败', 'data' => $res]);
-            }
-        }
-        return json(['code' => 1, 'msg' => '没有文件上传', 'data' => null]);
-    }
-
-    /**
-     * 工单技术附件
-     * @return void
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     */
-    public function OrderAttachments()
-    {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        $page = input('page');
-        $limit = input('limit');
-        if($param['order'] == ''){
-            //查询全部附件
-            $list = \db('工单_相关附件')
-                ->field('UniqId, mod_rq, pdf, sys_id, sys_rq, updatetime, url, version,
-                    关联编号, 
-                    关联编号 as 订单编号,  
-                    附件内容, 附件备注, 附件类型')
-                ->where('附件备注', '技术附件')
-                ->where('version', '<>', '')
-                ->whereNull('mod_rq')
-                ->limit(($page - 1) * $limit, $limit)
-                ->order('sys_rq desc')
-                ->select();
-            $count = \db('工单_相关附件')
-                ->field('UniqId, mod_rq, pdf, sys_id, sys_rq, updatetime, url, version,
-                    关联编号, 
-                    关联编号 as 订单编号,  
-                    附件内容, 附件备注, 附件类型')
-                ->where('附件备注', '技术附件')
-                ->where('version', '<>', '')
-                ->whereNull('mod_rq')
-                ->order('sys_rq desc')
-                ->count();
-            $data['total'] = $count;
-            $data['list'] = $list;
-            $this->success('成功',$data);
-        }else{
-            //查询订单对应附件
-            $list = \db('工单_相关附件')
-                ->field('UniqId, mod_rq, pdf, sys_id, sys_rq, updatetime, url, version,
-                    关联编号, 
-                    关联编号 as 订单编号,  
-                    附件内容, 附件备注, 附件类型')
-                ->where('关联编号', $param['order'])
-                ->where('附件备注', $param['desc'])
-                ->where('version', '<>', '')
-                ->whereNull('mod_rq')
-                ->order('sys_rq desc')
-                ->select();
-            $this->success('成功', $list);
-        }
-    }
-
-    /**
-     * 工单附件删除
-     */
-    public function delfujian(){
-        if (!$this->request->isPost()) {
-            $this->error('非法请求');
-        }
-        $params = $this->request->param();
-        $updateData = [
-            'mod_rq' => date('Y-m-d H:i:s'),
-            'mod_id' => $params['登录用户'],
-        ];
-        $res = \db('工单_相关附件')->where('UniqId', $params['UniqId'])->update($updateData);
-        if ($res) {
-            $this->success('删除成功');
-        } else {
-            $this->error('删除失败');
-        }
-    }
-
-
-    /**
-     * 订单BOM资料显示
-     */
-    public function OrderBomList()
-    {
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        if (empty($param) || !isset($param['order'])) {
-            $this->error('参数错误');
-        }
-        $where = ['a.BOM_工单编号' => $param['order']];
-
-        $list = \db('工单_bom资料')
-            ->alias('a')
-            ->join('工单_基本资料 b', 'b.订单编号 = a.BOM_工单编号')
-            ->field('a.BOM_工单编号 as 订单编号,b.生产款号 as 生产款号,b.客户编号 as 客户编号,b.款式 as 款式,
-            a.BOM_物料名称 as 物料名称,a.BOM_投料单位 as 投料单位,a.BOM_计划用量 as 计划用料,a.BOM_标准用量 as 定额用料,
-            a.BOM_实际用量 as 裁床实际用料,a.BOM_desc as 备注,a.UNIQID,a.物料分类,
-            a.BOM_计划门幅 as 计划门幅, a.BOM_定额门幅 as 定额门幅,a.Sys_ID as ID,a.Sys_rq as 日期')
-            ->where($where)
-            ->whereNull('a.Mod_rq')
-            ->order('a.UNIQID desc')
-            ->select();
-
-        if (!empty($list)) {
-            // 获取去重后的物料名称
-            $materialNames = array_column($list, '物料名称');
-            $materialNames = array_unique($materialNames);
-
-            // 根据去重后的物料名称查询工单_面料资料表,并获取BOM_desc
-            $materialDetails = \db('工单_面料资料')
-                ->field('BOM_物料名称 as 物料名称,BOM_desc')
-                ->whereIn('BOM_物料名称', $materialNames)
-                ->select();
-
-            // 将物料名称与BOM_desc对应起来
-            $materialDescMap = [];
-            foreach ($materialDetails as $detail) {
-                $materialDescMap[$detail['物料名称']] = $detail['BOM_desc'];
-            }
-            // 在list中添加对应的BOM_desc
-            foreach ($list as &$item) {
-                if (isset($materialDescMap[$item['物料名称']])) {
-                    $item['BOM_desc'] = $materialDescMap[$item['物料名称']];
-                } else {
-                    $item['BOM_desc'] = '';
-                }
-            }
-            $this->success('成功', $list);
-        } else {
-            $this->GdGtpAiOrder($param['order']);
-            $this->success('没有找到相关数据',[]);
-//            return $this->success('没有找到相关数据', []);
-        }
-    }
-
-    /**
-     * Bom资料删除
-     * */
-    public function Bomdel(){
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        if (empty($param) || !isset($param['UNIQID'])) {
-            $this->error('参数错误');
-        }
-        $uniqids = strpos($param['UNIQID'], ',') !== false ? explode(',', $param['UNIQID']) : [$param['UNIQID']];
-        $where = [];
-        $where['Mod_rq'] = date('Y-m-d H:i:s', time());
-
-        $allUpdated = true;
-        $failedUniqids = [];
-        // 遍历所有UNIQID并更新数据库
-        foreach ($uniqids as $uniqid) {
-            $result = \db('工单_bom资料')
-                ->where('UNIQID', $uniqid)
-                ->update($where);
-            $arr = \db('工单_面料资料')
-                ->where('UNIQID', $uniqid)
-                ->update($where);
-            if (!$result) {
-                // 如果某个UNIQID更新失败,记录失败的ID
-                $allUpdated = false;
-                $failedUniqids[] = $uniqid;
-            }
-        }
-        if ($allUpdated) {
-            $list = \db('工单_bom资料')
-                ->whereIn('UNIQID', $uniqids)
-                ->select();
-            if (!empty($list)) {
-                $this->success('删除成功');
-            } else {
-                $this->GdGtpAiOrder($param['order']);
-                return $this->success('没有找到相关数据', []);
-            }
-        } else {
-            $this->error('部分更新失败,无法更新以下UNIQID: ' . implode(', ', $failedUniqids));
-        }
-
-//        $this->error('删除权限为开放');
-    }
-
-
-
-
-    /**
-     * 前端选择订单时如果BOM资料数据为空则单独调用,重新生成最新
-     */
-    public function GdGtpAiOrder($order){
-        // 判断是否有指定的订单号
-        if (!empty($order)) {
-            // 查询单个订单的最大编号
-            $maxOrder = \db('工单_基本资料')
-                ->where('订单编号', 'like', "{$order}%")
-                ->order('订单编号', 'desc')
-                ->limit(1)
-                ->value('订单编号');
-
-            // 查询该订单的基本资料
-            $list = \db('工单_基本资料')
-                ->where('订单编号', 'like', "{$order}%")
-                ->order('订单编号', 'desc')
-                ->limit(1)
-                ->find();
-
-            // 如果面料数据为空,提示错误
-            if (empty($list['面料'])) {
-                $this->error('面料数据为空无法定义BOM');
-            }
-
-            // 处理订单编号
-            $numericPart = substr($maxOrder, 2);
-            $newNumericPart = str_pad((int)$numericPart + 1, strlen($numericPart), '0', STR_PAD_LEFT);
-            $param['订单编号'] = $order . $newNumericPart;
-
-            // 处理物料信息
-            $massage = empty($list['粘衬']) || $list['粘衬'] == '无' ? $list['面料'] : $list['面料'] . ',粘衬:' . $list['粘衬'];
-            $materialCategories = [];
-            $pattern = '/(\S+?):([^,]+)/'; // 匹配 类别:物料 格式
-
-            preg_match_all($pattern, $massage, $matches, PREG_SET_ORDER);
-
-            foreach ($matches as $match) {
-                $category = $match[1]; // 分类名称
-                $materials = explode('+', $match[2]); // 如果物料名称中有‘+’,则分开处理多个物料
-
-                // 将分类和对应的物料添加到数组中
-                foreach ($materials as $material) {
-                    $materialCategories[$category][] = trim($material); // 去除物料两边的空格
-                }
-            }
-
-            $mianliao = $this->Gpt($massage);
-
-//            // 插入物料数据
-//            $data = [];
-//            foreach ($mianliao as $key => $value) {
-//                if (!empty($value) && $value !== '粘衬') { // 排除空值和粘衬
-//                    $data[] = [
-//                        'BOM_工单编号' => $list['订单编号'],
-//                        'BOM_物料名称' => $value,
-//                        'BOM_desc' => '',
-//                        '物料分类' => '',
-//                        'Sys_rq' => date('Y-m-d H:i:s'),
-//                        'Sys_ID' => $list['Sys_id']
-//                    ];
-//                }
-//            }
-            $data = [];
-            foreach ($mianliao as $value) {
-                if (!empty($value) && $value !== '粘衬') { // 排除空值和粘衬
-                    $category = '';
-
-                    // 查找物料对应的分类
-                    foreach ($materialCategories as $cat => $materials) {
-                        if (in_array($value, $materials)) {
-                            $category = $cat;
-                            break;
-                        }
-                    }
-
-                    // 如果找到分类,将数据存入BOM
-                    $data[] = [
-                        'BOM_工单编号' => $list['订单编号'],
-                        'BOM_物料名称' => $value,
-                        'BOM_desc' => '',
-                        '物料分类' => $category ? $category : '',
-                        'Sys_rq' => date('Y-m-d H:i:s'),
-                        'Sys_ID' => $list['Sys_id']
-                    ];
-                }
-            }
-            foreach ($data as &$item) {
-                if (empty($item['物料分类'])) {
-                    $item['物料分类'] = '';
-                }
-                // 去除所有非汉字字符
-                $item['物料分类'] = preg_replace('/[^\p{Han}]/u', '', $item['物料分类']);
-            }
-            // 批量插入BOM资料
-            if (!empty($data)) {
-                \db('工单_bom资料')->insertAll($data);
-            }
-
-            $this->success('成功',$order);
-        } else {
-            // 如果没有指定订单号,批量查询订单号并处理
-            $has_bom = \db('工单_bom资料')->alias('a')->field('a.BOM_工单编号')->group('a.BOM_工单编号')->select();
-            $all_orders = \db('工单_基本资料')->alias('a')->field('a.订单编号')->where('a.面料', '<>', '')->group('a.订单编号')->select();
-
-            // 提取有BOM资料的订单号
-            $has_bom_orders = array_column($has_bom, 'BOM_工单编号');
-
-            // 筛选出没有对应BOM资料的订单号
-            $no_bom_orders = array_filter($all_orders, function ($order) use ($has_bom_orders) {
-                return !in_array($order['订单编号'], $has_bom_orders);
-            });
-
-            // 遍历没有BOM资料的订单
-            foreach ($no_bom_orders as $orderData) {
-                // 获取该订单号的最大订单编号
-                $maxOrder = \db('工单_基本资料')
-                    ->where('订单编号', 'like', "{$orderData['订单编号']}%")
-                    ->order('订单编号', 'desc')
-                    ->limit(1)
-                    ->value('订单编号');
-
-                // 获取该订单号的具体数据
-                $list = \db('工单_基本资料')
-                    ->where('订单编号', 'like', "{$orderData['订单编号']}%")
-                    ->order('订单编号', 'desc')
-                    ->limit(1)
-                    ->find();
-
-                if (empty($list['面料'])) {
-                    $this->error("订单 {$orderData['订单编号']} 面料数据为空,无法定义BOM");
-                }
-
-                // 处理订单编号
-                $numericPart = substr($maxOrder, 2);
-                $newNumericPart = str_pad((int)$numericPart + 1, strlen($numericPart), '0', STR_PAD_LEFT);
-                $param['订单编号'] = $order . $newNumericPart;
-
-//                // 处理物料信息
-//                $massage = empty($list['粘衬']) || $list['粘衬'] == '无' ? $list['面料'] : $list['面料'] . ',粘衬:' . $list['粘衬'];
-//                $mianliao = $this->Gpt($massage);
-//                // 插入物料数据
-//                $data = [];
-//                foreach ($mianliao as $key => $value) {
-//                    if (!empty($value) && $value !== '粘衬') { // 排除空值和粘衬
-//                        $data[] = [
-//                            'BOM_工单编号' => $list['订单编号'],
-//                            'BOM_物料名称' => $value,
-//                            'BOM_desc' => '',
-//                            '物料分类' => '',
-//                            'Sys_rq' => date('Y-m-d H:i:s'),
-//                            'Sys_ID' => '超级管理员'
-//                        ];
-//                    }
-//                }
-                // 假设massage是从数据库获取的数据
-                $massage = empty($list['粘衬']) || $list['粘衬'] == '无' ? $list['面料'] : $list['面料'] . ',粘衬:' . $list['粘衬'];
-
-                $materialCategories = [];
-                $pattern = '/(\S+?):([^,]+)/'; // 匹配 类别:物料 格式
-
-                preg_match_all($pattern, $massage, $matches, PREG_SET_ORDER);
-
-                foreach ($matches as $match) {
-                    $category = $match[1]; // 分类名称
-                    $materials = explode('+', $match[2]); // 如果物料名称中有‘+’,则分开处理多个物料
-
-                    // 将分类和对应的物料添加到数组中
-                    foreach ($materials as $material) {
-                        $materialCategories[$category][] = trim($material); // 去除物料两边的空格
-                    }
-                }
-
-                $mianliao = $this->Gpt($massage);
-
-                $data = [];
-                foreach ($mianliao as $value) {
-                    if (!empty($value) && $value !== '粘衬') { // 排除空值和粘衬
-                        $category = '';
-
-                        // 查找物料对应的分类
-                        foreach ($materialCategories as $cat => $materials) {
-                            if (in_array($value, $materials)) {
-                                $category = $cat;
-                                break;
-                            }
-                        }
-
-                        // 如果找到分类,将数据存入BOM
-                        $data[] = [
-                            'BOM_工单编号' => $list['订单编号'],
-                            'BOM_物料名称' => $value,
-                            'BOM_desc' => '',
-                            '物料分类' => $category ? $category : '',
-                            'Sys_rq' => date('Y-m-d H:i:s'),
-                            'Sys_ID' => '超级管理员'
-                        ];
-                    }
-                }
-                foreach ($data as &$item) {
-                    if (empty($item['物料分类'])) {
-                        $item['物料分类'] = '';
-                    }
-                    // 去除所有非汉字字符
-                    $item['物料分类'] = preg_replace('/[^\p{Han}]/u', '', $item['物料分类']);
-                }
-
-                // 批量插入BOM资料
-                if (!empty($data)) {
-                    \db('工单_bom资料')->insertAll($data);
-                }
-            }
-            $this->success('成功');
-        }
-    }
-
-
-    /**
-     * 订单面料修改接口
-     * @return void
-     * @throws \think\Exception
-     * @throws \think\db\exception\BindParamException
-     * @throws \think\exception\PDOException
-     */
-    public function FabricEdit()
-    {
-        if ($this->request->isPost() === false){
-            $this->error('请求错误');
-        }
-
-        $param = Request::instance()->post();
-        if (empty($param)){
-            $this->error('请求错误');
-        }
-
-        // 判断前端传来的参数是否为空,避免空订单编号造成问题
-        if(empty($param[0]['BOM_工单编号'])){
-            $this->error('请求错误,请重新打开此页面');
-        }
-        foreach ($param as $key=>$value){
-            $data = $value;
-            unset($data['UNIQID']);
-            if ($value['UNIQID'] !== '' || !empty($value['UNIQID'])){
-                $sql = \db('工单_bom资料')
-                    ->where('UNIQID',$value['UNIQID'])
-                    ->fetchSql(true)
-                    ->update($data);
-                $res = \db()->query($sql);
-            }else{
-                $sql = \db('工单_bom资料')
-                    ->fetchSql(true)
-                    ->insert($value);
-                $res = \db()->query($sql);
-            }
-            if ($res === false){
-                $this->error('修改失败');
-            }
-        }
-        // 查询工单基本资料
-        $orderList = \db('工单_基本资料')
-            ->field('订单编号, 生产款号, Sys_id')
-            ->where('订单编号', $param[0]['BOM_工单编号'])
-            ->find();
-
-        if (!$orderList) {
-            $this->error('工单基本资料未找到');
-        }
-
-        // 查询所有颜色备注
-        $colorList = \db('工单_印件资料')
-            ->field('颜色备注')
-            ->where('订单编号', $orderList['订单编号'])
-            ->group('颜色备注')
-            ->select();
-
-        // 获取 BOM 面料数据
-        $BomList = \db('工单_bom资料')
-            ->where('BOM_工单编号', $orderList['订单编号'])
-            ->whereNull('Mod_rq')
-            ->select();
-
-        if (!$BomList) {
-            $this->error('BOM 面料数据未找到');
-        }
-
-        // 获取当前最大关联编号
-        $AssociatedNumber = \db('工单关联表')->order('关联编号 desc')->value('关联编号');
-        $number = empty($AssociatedNumber) ? 0 : (int)substr($AssociatedNumber, 4);
-
-        $MaterielList = [];
-        $MaterielLists = [];
-        $colorCounter = []; // 记录每种颜色的序号
-
-        foreach ($colorList as $color) {
-            $colorName = $color['颜色备注'];
-            $colorCounter[$colorName] = 1;
-
-            foreach ($BomList as $bom) {
-                $wulbm = $orderList['生产款号'] . '-' . $colorName . $colorCounter[$colorName]++;
-
-                // 检查工单面料资料是否存在
-                $existsMateriel = \db('工单_面料资料')
-                    ->where([
-                        'BOM_工单编号' => $orderList['订单编号'],
-                        'BOM_颜色' => $colorName,
-                        'BOM_物料名称' => $bom['BOM_物料名称']
-                    ])
-                    ->find();
-
-                if (!$existsMateriel) {
-                    $MaterielList[] = [
-                        'BOM_工单编号' => $orderList['订单编号'],
-                        'BOM_颜色' => $colorName,
-                        'BOM_物料名称' => $bom['BOM_物料名称'],
-                        'BOM_标准用量' => $bom['BOM_标准用量'],
-                        'BOM_计划用量' => $bom['BOM_计划用量'],
-                        'BOM_计划门幅' => $bom['BOM_计划门幅'],
-                        'BOM_定额门幅' => $bom['BOM_定额门幅'],
-                        'BOM_投料单位' => $bom['BOM_投料单位'],
-                        'BOM_desc' => $bom['BOM_desc'],
-                        'BOM_物料编码' => $wulbm,
-                        'Sys_ID' => $bom['Sys_ID'],
-                        'Sys_rq' => date('Y-m-d H:i:s')
-                    ];
-                }
-
-                // 检查工单关联表是否存在
-                $existsRelation = \db('工单关联表')
-                    ->where([
-                        '订单编号' => $orderList['订单编号'],
-                        '颜色' => $colorName,
-                        '物料名称' => $bom['BOM_物料名称']
-                    ])
-                    ->find();
-
-                if (!$existsRelation) {
-                    $MaterielLists[] = [
-                        '关联编号' => 'GDGL' . ($number + 1),
-                        '订单编号' => $orderList['订单编号'],
-                        '生产款号' => $orderList['生产款号'],
-                        '颜色' => $colorName,
-                        '物料编号' => $wulbm,
-                        '物料名称' => $bom['BOM_物料名称'],
-                        '备注' => $bom['BOM_desc'],
-                        'Sys_id' => $bom['Sys_ID'],
-                        'Sys_rq' => date('Y-m-d H:i:s')
-                    ];
-                    $number++;
-                }
-            }
-        }
-
-        // 批量插入数据
-        if (!empty($MaterielList)) {
-            \db('工单_面料资料')->insertAll($MaterielList);
-        }
-
-        if (!empty($MaterielLists)) {
-            \db('工单关联表')->insertAll($MaterielLists);
-        }
-
-        $this->success('修改成功');
-    }
-
-    /**
-     * 入库、出库、退还详情数据
-     */
-    public function FabricDetaillist()
-    {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        $where = [];
-        if (isset($param['order']) && !empty($param['order'])){
-            $where['a.order_id'] = $param['order'];
-        }
-        if (isset($param['lotNumber']) && !empty($param['lotNumber'])){
-            $where['a.批次号'] = $param['lotNumber'];
-        }
-        // 定义查询字段
-        $fields = '
-            a.id,
-            a.批次号,
-            a.order_id as 订单编号,
-            a.客户编号,
-            a.款号 as 生产款号,
-            a.款式,
-            a.物料名称,
-            c.BOM_计划用量 as 计划用料,
-            c.BOM_标准用量 as 定额用料,
-            c.BOM_计划门幅 as 计划门幅,
-            c.BOM_定额门幅 as 定额门幅,
-            b.入仓总量 as 入库总量,
-            b.库存数量 as 面料结余,
-            a.number as 入库数量,
-            a.number as 出库数量,
-            a.库存数量 as 库存数量,
-            b.单位 as 投料单位,
-            a.rq as 入库时间,
-            a.rq as 出库时间,
-            a.sys_id as 入库人员,
-            a.sys_id as 出库人员,
-            a.recipient as 领用人员,
-            a.receipt_number as 单号,
-            c.BOM_desc as 备注,
-            a.type as 退还类型
-        ';
-        $list['入库记录'] = \db('设备_报工日志')
-            ->alias('a')
-            ->join('物料_库存 b', 'a.批次号 = b.批次号 AND a.物料编码 = b.物料编号', 'left')  // 多条件关联
-            ->join('工单_面料资料 c','a.order_id = c.BOM_工单编号 AND a.物料编码 = c.BOM_物料编码','left')
-            ->where($where)
-            ->where('a.name', '入库')
-            ->field($fields)
-            ->order('a.rq desc')
-            ->whereNull('a.Mod_rq')
-            ->select();
-
-        //出库记录查询
-        $list['出库记录'] = \db('设备_报工日志')->alias('a')
-            ->join('物料_库存 b', 'a.批次号 = b.批次号 AND a.物料编码 = b.物料编号', 'left')  // 多条件关联
-            ->join('工单_面料资料 c','a.order_id = c.BOM_工单编号 AND a.物料编码 = c.BOM_物料编码','left')
-            ->where($where)
-            ->where('a.name', '出库')
-            ->field($fields)
-            ->order('a.rq desc')
-            ->whereNull('a.Mod_rq')
-            ->select();
-        //退还记录查询
-        $list['退还记录'] = \db('设备_报工日志')->alias('a')
-            ->join('物料_库存 b', 'a.批次号 = b.批次号 AND a.物料编码 = b.物料编号', 'left')  // 多条件关联
-            ->join('工单_面料资料 c','a.order_id = c.BOM_工单编号 AND a.物料编码 = c.BOM_物料编码','left')
-            ->where($where)
-            ->where('a.name', '退还')
-            ->field($fields)
-            ->order('a.rq desc')
-            ->whereNull('a.Mod_rq')
-            ->select();
-        $this->success('成功',$list);
-    }
-
-    /**
-     * 入库、出库、退还删除
-     */
-    public function FabricDetaildel()
-    {
-        if ($this->request->isPost() === false){
-            $this->error('请求错误');
-        }
-        $param = Request::instance()->post();
-        if (empty($param)){
-            $this->error('请求错误');
-        }
-        // 判断UNIQID是否是逗号分隔的多个ID,如果是则拆分成数组,否则直接处理为单个ID
-        $ids = strpos($param['id'], ',') !== false ? explode(',', $param['id']) : [$param['id']];
-
-        $where = [];
-        $where['Mod_id'] = $param['Mod_id'];
-        $where['Mod_rq'] = date('Y-m-d H:i:s', time());
-
-        // 定义一个标志变量来追踪是否所有更新都成功
-        $allUpdated = true;
-        $failedUniqids = [];
-        // 遍历所有UNIQID并更新数据库
-        foreach ($ids as $id) {
-            // 更新指定UNIQID的记录
-            $result = \db('设备_报工日志')
-                ->where('id', $id)
-                ->update($where);
-
-            // 检查更新结果
-            if (!$result) {
-                // 如果某个UNIQID更新失败,记录失败的ID
-                $allUpdated = false;
-                $failedUniqids[] = $id;
-            }
-        }
-
-        // 如果所有更新都成功,返回成功信息
-        if ($allUpdated) {
-            $list = \db('设备_报工日志')
-                ->whereIn('id', $id)  // 查询所有传入的UNIQID
-                ->select();
-            if (!empty($list)) {
-                $this->success('删除成功');
-            } else {
-                $this->GdGtpAiOrder($param['order']);
-                return $this->success('没有找到相关数据', []);
-            }
-        } else {
-            // 如果有更新失败的记录,返回失败的UNIQID
-            $this->error('部分更新失败,无法更新以下UNIQID: ' . implode(', ', $failedUniqids));
-        }
-    }
-
-    //GPT
-    public function Gpt($massage)
-    {
-
-
-        // 设置 API 密钥
-        $apiKey = 'sk-e0JuPjMntkbgi1BoMjrqyyzMKzAxILkQzyGMSy3xiMupuoWY'; // 替换为您的 API 密钥
-
-        // 要发送给 GPT 的消息
-//        $messages = [
-//            [
-//                'role' => 'user',
-//                'content' => '你好,帮我按照:面料1、面料2、面料3……来整理归纳下面的面料信息,我只需要面料信息,不需要其他:'.$massage
-//            ]
-//        ];
-        $messages = [
-            [
-                'role' => 'user',
-                'content' => '你好,帮我按照:面料1、面料2、面料3……来整理归纳下面的面料信息,我只需要面料信息,不需要其他:'.$massage
-            ]
-        ];
-
-        // 创建请求数据
-        $data = [
-            'model' => 'gpt-3.5-turbo', // 使用的模型
-            'messages' => $messages,
-            'max_tokens' => 100, // 设置最大 token 数
-        ];
-
-        // 初始化 cURL
-        $ch = curl_init('https://niubi.zeabur.app/v1/chat/completions');
-
-        // 设置 cURL 选项
-        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-        curl_setopt($ch, CURLOPT_HTTPHEADER, [
-            'Content-Type: application/json',
-            'Authorization: Bearer ' . $apiKey,
-        ]);
-        curl_setopt($ch, CURLOPT_POST, true);
-        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
-        curl_setopt($ch, CURLOPT_CAINFO, ROOT_PATH . '/public/uploads/cacert.pem');
-
-        // 执行请求
-        $response = curl_exec($ch);
-
-        // 检查错误
-        if (curl_errno($ch)) {
-            echo 'Error:' . curl_error($ch);
-        }
-
-        // 关闭 cURL
-        curl_close($ch);
-
-        // 解析和输出响应
-        $responseData = json_decode($response, true);
-
-        // 获取 GPT 的回复
-        if (isset($responseData['choices'][0]['message']['content'])) {
-            //获取返回内容
-            $gptReply = $responseData['choices'][0]['message']['content'];
-//            halt($gptReply);
-            //返回面料信息
-            $gptArray = explode('面料',$gptReply);
-            array_shift($gptArray);
-            foreach ($gptArray as $key=>$value){
-                $gptArray[$key] = preg_replace('/\s+/', '', substr($value,4));
-            }
-            return $gptArray;
-        } else {
-            echo "未能获取 GPT 的回复。";
-        }
-    }
-
-
-    /**
-     * 面料库存月份查询
-     */
-    public function fabricListmonth()
-    {
-//        $list = \db('物料_库存')
-//            ->group("DATE_FORMAT(sys_rq, '%Y-%m')")
-//            ->orderRaw("DATE_FORMAT(sys_rq, '%Y-%m') desc")
-//            ->column("DATE_FORMAT(sys_rq, '%Y-%m') as date");
-//
-//        $result = [];
-//        foreach ($list as $item) {
-//            $result[$item] = \db('物料_库存')
-//                ->whereRaw("DATE_FORMAT(sys_rq, '%Y-%m') = ?", [$item])
-//                ->order('sys_rq desc')
-//                ->distinct('sys_rq')
-//                ->column("DATE_FORMAT(sys_rq, '%Y-%m-%d') as date");
-//        }
-//        if (!empty($result)) {
-//            $this->success('成功', $result);
-//        } else {
-//            $this->success('没有找到相关数据', []);
-//        }
-
-        $data = \db('设备_报工日志')
-            ->whereNull('Mod_rq')
-            ->field('DISTINCT DATE_FORMAT(rq, "%Y-%m") as month, DATE_FORMAT(rq, "%Y-%m-%d") as date')
-            ->whereNull('Mod_rq')
-            ->order('rq desc')
-            ->select();
-
-        // 按月份分组数据
-        $groupedData = [];
-        foreach ($data as $entry) {
-            $groupedData[$entry['month']][] = $entry['date'];
-        }
-
-        // 去重处理,防止重复
-        foreach ($groupedData as $month => $dates) {
-            $groupedData[$month] = array_values(array_unique($dates));
-        }
-
-        $this->success('成功', $groupedData);
-    }
-
-    /**
-     * 获取每月的面料记录\设备_报工日志
-     * 入库出库退还日期
-     */
-    public function fetchMonthlyFabricRecords() {
-        $types = ['入库', '出库', '退还'];
-        $list = [];
-
-        foreach ($types as $type) {
-            $data = \db('设备_报工日志')
-                ->where('name', $type)
-                ->whereNull('Mod_rq')
-                ->field('DISTINCT DATE_FORMAT(rq, "%Y-%m") as month, DATE_FORMAT(rq, "%Y-%m-%d") as date')
-                ->order('rq desc')
-                ->select();
-
-            // 按照月份分组数据
-            $groupedData = [];
-            foreach ($data as $entry) {
-                $groupedData[$entry['month']][] = $entry['date'];
-            }
-
-            // 进一步去重,避免意外重复
-            foreach ($groupedData as $month => $dates) {
-                $groupedData[$month] = array_values(array_unique($dates));
-            }
-
-            // 添加到返回列表
-            $list[$type] = $groupedData;
-        }
-
-        $this->success('成功', $list);
-    }
-
-
-    /**
-     * 面料库存列表
-     */
-    public function fabricList()
-    {
-        if ($this->request->isGet() === false) {
-            $this->error('请求错误');
-        }
-
-        $param = $this->request->param();
-        $where = [];
-
-        // 根据传入的参数构造查询条件
-        if (isset($param['order'])) {
-            $where['a.BOM_工单编号|b.生产款号|a.BOM_物料名称'] = ['like', $param['order'] . '%'];
-        }
-
-        if (isset($param['mouth'])) {
-            $where['a.Sys_rq'] = ['like', $param['mouth'] . '%'];
-        }
-
-        // 分页参数,防止未传递时出错
-        $page = isset($param['page']) ? (int)$param['page'] : 1;  // 默认第1页
-        $limit = isset($param['limit']) ? (int)$param['limit'] : 50; // 默认每页50条
-
-        // 获取数据
-        $data = \db('工单_面料资料')
-            ->alias('a')
-            ->join('工单_基本资料 b', 'b.订单编号 = a.BOM_工单编号')
-            ->field('a.BOM_工单编号 as 订单编号,a.BOM_颜色 as 颜色, b.生产款号 as 生产款号, b.客户编号 as 客户编号, b.款式 as 款式,
-            a.BOM_物料编码,a.BOM_物料名称 as 物料名称, a.BOM_投料单位 as 投料单位,
-            a.BOM_标准用量 as 定额用料,a.Mod_rq,
-            a.BOM_实际用量 as 裁床实际用料, a.BOM_领用数量 as 裁床领用面料, a.BOM_退还数量 as 裁床退回仓库面料,a.BOM_desc,
-            a.BOM_desc as 备注, a.UNIQID, a.BOM_库存总量 as 入库总量, a.BOM_计划门幅 as 计划门幅, a.BOM_定额门幅 as 定额门幅, 
-            a.BOM_面料结余 as 面料结余, a.Sys_ID as ID, a.Sys_rq as 日期')
-            ->where($where)
-            ->group('a.BOM_物料编码')
-            ->order("a.Sys_rq desc")
-            ->where('a.Mod_rq',null)
-            ->limit(($page - 1) * $limit, $limit)
-            ->select();
-
-
-        // 统计条数进行分页
-        $count = \db('工单_面料资料')->where('BOM_工单编号',$param['order'])->count();
-        // 确保返回的格式固定
-        $list = [
-            'total' => $count,
-            'table' => $data ?: [] // 如果 $data 为空,返回空数组,而不是 ''
-        ];
-
-        $this->success('成功', $list);
-    }
-
-
-    /**
-     * 单条面料详情
-     */
-    public function oneFabricDetail()
-    {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        if (empty($param)){
-            $this->error('参数错误');
-        }
-        //面料入库记录
-        $list['入库'] = \db('设备_报工日志')
-            ->where('',$param['order'])
-            ->where('物料名称',$param['fabricName'])
-            ->where('name','入库')
-            ->where('Mod_rq',null)
-            ->field('order_id as 订单编号,款号,物料编码,物料名称,number as 数量,rq as 日期,sys_id as 操作机台,recipient as 入仓人员')
-            ->select();
-        //面料出库记录
-        $list['出库'] = \db('设备_报工日志')
-            ->where('order_id',$param['order'])
-            ->where('物料名称',$param['fabricName'])
-            ->where('name','出库')
-            ->where('Mod_rq',null)
-            ->field('order_id as 订单编号,款号,物料名称,number as 数量,rq as 日期,sys_id as 操作机台,receipt_number as 出库单据编号,recipient as 领用人员')
-            ->select();
-        //面料退还记录
-        $list['退还'] = \db('设备_报工日志')
-            ->where('order_id',$param['order'])
-            ->where('物料名称',$param['fabricName'])
-            ->where('name','退还')
-            ->where('Mod_rq',null)
-            ->field('order_id as 订单编号,款号,物料名称,number as 数量,rq as 日期,sys_id as 操作机台,recipient as 退还人员')
-            ->select();
-        $this->success('成功',$list);
-    }
-
-    /**
-     * 单据号查询数据
-     * @return void
-     * @throws \think\db\exception\DataNotFoundException
-     * @throws \think\db\exception\ModelNotFoundException
-     * @throws \think\exception\DbException
-     */
-    public function ReceiptDetail()
-    {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        if (empty($param)){
-            $this->error('单据编号参数错误');
-        }
-        $list = \db('设备_报工日志')
-            ->alias('a')
-            ->join('工单_面料资料 b','a.order_id = b.BOM_工单编号 AND b.BOM_物料编码 = a.物料编码')
-            ->join('物料_库存 c','a.物料编码 = c.物料编号 AND a.批次号 = c.批次号')
-            ->where('a.receipt_number',$param['receipt'])
-            ->field('a.id,a.order_id as 订单编号,a.款号,a.物料名称,a.number as 数量,a.rq as 日期,a.sys_rq as 创建日期,a.sys_id as 操作机台,
-                a.departname,a.remark,a.type as 退还类型,
-                a.receipt_number as 出库单据编号,a.recipient as 领用人员,b.BOM_颜色,c.单位,
-                b.BOM_计划用量 as 计划用料,
-                b.BOM_计划门幅 as 计划门幅,
-                b.BOM_标准用量 as 定额用料,
-                b.BOM_定额门幅 as 定额门幅,
-                c.实际门幅,c.状态,c.库存数量,c.入仓总量
-            ')
-            ->whereNull('a.Mod_rq')
-            ->select();
-        if (empty($list)){
-            $this->error('未找到该出库单');
-        }else{
-            $this->success('成功',$list);
-        }
-    }
-
-    /**
-     * 入库、出库、退还单号列表
-     */
-    public function ReceiptList(){
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        if (empty($param)){
-            $this->error('参数错误');
-        }
-        $where= [];
-        if (isset($param['search'])) {
-            $where['物料名称|款号|order_id|receipt_number|款式|物料编码'] = ['like', $param['search'] . '%'];
-        }
-        if (isset($param['mouth'])) {
-            $where['rq'] = ['like', $param['mouth'] . '%'];
-        }
-        $page = isset($param['page']) ? (int)$param['page'] : 1;  // 默认第1页
-        $limit = isset($param['limit']) ? (int)$param['limit'] : 50; // 默认每页50条
-
-        $list = \db('设备_报工日志')
-            ->where('Mod_rq', null)
-            ->where($where)
-            ->where('name',$param['code'])
-            ->order('sys_rq desc')
-            ->limit(($page-1)*$limit,$limit)
-            ->select();
-        // 初始化一个合并后的数组
-        $merged = [];
-        foreach ($list as $item) {
-            $key = $item['receipt_number'];
-            if (!isset($merged[$key])) {
-                // 首次出现,初始化
-                $merged[$key] = [
-                    '单号类型' => $item['name'],
-                    '出库单' => $item['receipt_number'],
-                    '订单编号' => $item['order_id'],
-                    '款号' => $item['款号'],
-                    '款式' => $item['款式'],
-                    '物料编码' => $item['物料编码'],
-                    '物料名称' => $item['物料名称'],
-                    '总数' => floatval($item['number']),
-                    '日期' => $item['rq'],
-                    '创建日期' => $item['sys_rq'],
-                    '操作机台' => $item['sys_id'],
-                    '领料人员' => $item['recipient'],
-                ];
-            } else {
-                // 合并相同 receipt_number 的记录
-                $merged[$key]['订单编号'] .= ',' . $item['order_id'];
-                $merged[$key]['款号'] .= ',' . $item['款号'];
-                $merged[$key]['款式'] .= ',' . $item['款式'];
-                $merged[$key]['物料编码'] .= ',' . $item['物料编码'];
-                $merged[$key]['物料名称'] .= ',' . $item['物料名称'];
-                $merged[$key]['总数'] += floatval($item['number']);
-            }
-        }
-
-        // 对需要的字段进行逗号分隔后的去重
-        foreach ($merged as &$item) {
-            $item['订单编号'] = implode(',', array_unique(explode(',', $item['订单编号'])));
-            $item['款号'] = implode(',', array_unique(explode(',', $item['款号'])));
-            $item['款式'] = implode(',', array_unique(explode(',', $item['款式'])));
-            $item['物料编码'] = implode(',', array_unique(explode(',', $item['物料编码'])));
-            $item['物料名称'] = implode(',', array_unique(explode(',', $item['物料名称'])));
-            // 格式化总数
-            $item['总数'] = round($item['总数'], 2); // 保留2位小数,防止长尾
-        }
-        unset($item); // 避免引用问题
-
-        //统计数量
-        $count = \db('设备_报工日志')
-            ->where($where)
-            ->where('name',$param['code'])
-            ->field('receipt_number as 出库单')
-            ->group('出库单')
-            ->where('Mod_rq',null)
-            ->order('rq desc')
-            ->select();
-
-        if (empty($merged)){
-            $this->success('未找到数据', '');
-        } else {
-            $data['total'] = count($count);
-            $data['table'] = array_values($merged);
-            $this->success('成功', $data);
-        }
-
-    }
-
-    /**
-     * 出库单左侧菜单
-     */
-    public function getReceiptTab()
-    {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $list = \db('设备_报工日志')
-            ->field([
-                "DATE_FORMAT(rq, '%Y-%m') AS month",
-            ])
-            ->group('month')
-            ->order('month DESC')
-            ->select();
-        if (empty($list)){
-            $this->error('未查询到入库、出库、退还数据');
-        }else{
-            $this->success('成功',$list);
-        }
-    }
-
-    /**
-     * 获取入库单号、出库单号
-     * @return void
-     */
-    public function gitReceiptNumber()
-    {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        if (empty($param)){
-            $this->error('参数错误');
-        }
-        $lastNumber = \db('设备_报工日志')
-            ->where('receipt_number','like',$param['number'].'%')
-            ->order('receipt_number desc')
-            ->whereNull('Mod_rq')
-            ->limit(1)
-            ->column('receipt_number as 单号');
-        if (empty($lastNumber)){
-            $num = 1;
-        }else{
-            $num = (int)(substr($lastNumber[0],12,3))+1;
-        }
-        if ($num < 10){
-            $num = '00'.$num;
-        }elseif ($num>=10 && $num<100){
-            $num = '0'.$num;
-        }else{
-            $num;
-        }
-        $number = $param['number'].date('Ymd',time()).'-'.$num;
-
-        $lastNumber = \db('设备_报工日志')
-            ->where('name','出库')
-            ->order('recipient desc')
-            ->group('recipient')
-            ->whereNull('Mod_rq')
-            ->limit(1)
-            ->value('recipient as 人员');
-        $data = [
-            'number' => $number,
-            'username' => $lastNumber
-        ];
-        $this->success('成功', $data);
-    }
-
-
-    /**
-     * 面料批次列表
-     */
-    public function FabricLotList()
-    {
-        if ($this->request->isGet() === false){
-            $this->error('请求错误');
-        }
-        $param = $this->request->param();
-        if (empty($param)){
-            $this->error('参数错误');
-        }
-        $where= [];
-        if (isset($param['search'])) {
-            $where['a.物料名称|d.款号|c.订单编号|b.BOM_颜色'] = ['like', $param['search'] . '%'];
-        }
-        if (isset($param['date'])) {
-            $where['d.rq'] = ['like', $param['date'] . '%'];
-        }
-        $field = '
-            a.批次号,
-            a.关联号,
-            a.物料编号,
-            a.物料名称,
-            a.入仓总量,
-            a.库存数量,
-            a.领用数量,
-            a.退还数量 as 裁切退还,
-            a.单位,
-            a.实际门幅,
-            a.状态,
-            a.sys_id as 入仓人员,
-            a.sys_rq as 入仓日期,
-            b.BOM_颜色 as 颜色,
-            d.款号,
-            b.BOM_计划用量 as 计划用料,
-            b.BOM_标准用量 as 定额用料,
-            b.BOM_计划门幅 as 计划门幅,
-            b.BOM_定额门幅 as 定额门幅,
-            GROUP_CONCAT(DISTINCT c.订单编号 SEPARATOR ",") AS 关联订单
-        ';
-        $list = \db('物料_库存')
-            ->alias('a')
-           ->join('设备_报工日志 d','a.批次号 = d.批次号')
-            ->join('工单_面料资料 b','a.物料编号 = b.BOM_物料编码')
-            ->join('工单关联表 c','a.关联号 = c.关联编号')
-            ->field($field)
-            ->whereNull('d.Mod_rq')
-            ->where($where)
-//            ->where('a.sys_rq','like',$param['date'].'%')
-            ->group('a.批次号')
-            ->select();
-        if (empty($list)){
-            $this->error('未找到面料数据');
-        }else{
-            $this->success('成功',$list);
-        }
-    }
-
-
-    /**
-     * 仓库管理
-     * 入库、出库、退还更新
-     */
-    public function rApictedit()
-    {
-        if (!$this->request->isPost()) {
-            $this->error('请求错误');
-        }
-
-        $param = Request::instance()->post();
-        if (empty($param)) {
-            $this->error('参数错误');
-        }
-
-        $logData = []; // 日志记录数组
-        $now = date('Y-m-d H:i:s');
-
-        foreach ($param as $item) {
-            $id = $item['id'] ?? null;
-            $newQty = floatval($item['数量'] ?? 0);
-            $name = $item['name'] ?? '';
-            $returnType = $item['退还类型'] ?? '';
-            $sysId = $item['sys_id'] ?? '未知用户';
-
-            if (!$id || !$name) {
-                $this->error('缺少必要参数');
-            }
-
-            // 获取设备_报工日志 原记录
-            $record = \db('设备_报工日志')
-                ->field('id, 批次号, number, type')
-                ->where('name', $name)
-                ->whereNull('Mod_rq')
-                ->where('id', $id)
-                ->find();
-
-            if (!$record) {
-                $this->error("未找到 ID 为 {$id} 的记录");
-            }
-
-            $batchNo = $record['批次号'];
-            $oldQty = floatval($record['number']);
-            $diff = $newQty - $oldQty;
-
-            // === 修改设备_报工日志.number(如果有变化) ===
-            if ($diff != 0) {
-                $updateSql = \db('设备_报工日志')
-                    ->where('id', $id)
-                    ->where('name', $name)
-                    ->whereNull('Mod_rq')
-                    ->fetchSql(true)
-                    ->update(['number' => $newQty]);
-
-                \db()->query($updateSql); // 执行 SQL
-
-                // 写入日志,增加 ids 字段
-                $logData[] = [
-                    '批次号' => $batchNo,
-                    '操作字段' => 'number',
-                    '原值' => $oldQty,
-                    '新值' => $newQty,
-                    '操作人' => $sysId,
-                    '操作类型' => $name,
-                    '操作时间' => $now,
-                    '修改表' => '设备_报工日志',
-                    'ids' => $id
-                ];
-            }
-
-            // === 获取同批次的记录以统计新合计 ===
-            $sameBatchList = \db('设备_报工日志')
-                ->field('number')
-                ->where('name', $name)
-                ->whereNull('Mod_rq')
-                ->where('批次号', $batchNo)
-                ->select();
-
-            $newTotal = array_sum(array_column($sameBatchList, 'number'));
-
-            // === 获取物料_库存信息(加上 id 字段) ===
-            $inventory = \db('物料_库存')
-                ->field('id, 入仓总量, 领用数量, 库存数量, 退还数量')
-                ->where('批次号', $batchNo)
-                ->find();
-
-            if ($inventory) {
-                $stockId = $inventory['id']; // 记录当前库存表的 id
-                $inQty = floatval($inventory['入仓总量']);
-                $stockQty = floatval($inventory['库存数量']);
-                $useQty = floatval($inventory['领用数量']);
-                $returnQty = floatval($inventory['退还数量']);
-
-                if ($name == '入库') {
-                    $newIn = $inQty + $diff;
-                    $newStock = $stockQty + $diff;
-
-                    $updateFields = [];
-
-                    if ($newIn != $inQty) {
-                        $updateFields['入仓总量'] = $newIn;
-
-                        $logData[] = [
-                            '批次号' => $batchNo,
-                            '操作字段' => '入仓总量',
-                            '原值' => $inQty,
-                            '新值' => $newIn,
-                            '操作人' => $sysId,
-                            '操作类型' => '入库',
-                            '操作时间' => $now,
-                            '修改表' => '物料_库存',
-                            'ids' => $stockId
-                        ];
-                    }
-
-                    if ($newStock != $stockQty) {
-                        $updateFields['库存数量'] = $newStock;
-
-                        $logData[] = [
-                            '批次号' => $batchNo,
-                            '操作字段' => '库存数量',
-                            '原值' => $stockQty,
-                            '新值' => $newStock,
-                            '操作人' => $sysId,
-                            '操作类型' => '入库',
-                            '操作时间' => $now,
-                            '修改表' => '物料_库存',
-                            'ids' => $stockId
-                        ];
-                    }
-
-                    if (!empty($updateFields)) {
-                        $updateStockSql = \db('物料_库存')
-                            ->where('id', $stockId)
-                            ->fetchSql(true)
-                            ->update($updateFields);
-
-                        \db()->query($updateStockSql);
-                    }
-                }
-
-                elseif ($name == '出库') {
-                    if ($newTotal != $useQty) {
-                        // 计算新的库存数量
-                        $newStock = $inQty - $newTotal + $returnQty; // 入仓 - 领用 + 退还(可选)
-
-                        $updateFields = [
-                            '领用数量' => $newTotal,
-                            '库存数量' => $newStock
-                        ];
-
-                        $updateStockSql = \db('物料_库存')
-                            ->where('id', $stockId)
-                            ->fetchSql(true)
-                            ->update($updateFields);
-
-                        \db()->query($updateStockSql);
-
-                        $logData[] = [
-                            '批次号' => $batchNo,
-                            '操作字段' => '领用数量',
-                            '原值' => $useQty,
-                            '新值' => $newTotal,
-                            '操作人' => $sysId,
-                            '操作类型' => '出库',
-                            '操作时间' => $now,
-                            '修改表' => '物料_库存',
-                            'ids' => $stockId
-                        ];
-
-                        $logData[] = [
-                            '批次号' => $batchNo,
-                            '操作字段' => '库存数量',
-                            '原值' => $stockQty,
-                            '新值' => $newStock,
-                            '操作人' => $sysId,
-                            '操作类型' => '出库',
-                            '操作时间' => $now,
-                            '修改表' => '物料_库存',
-                            'ids' => $stockId
-                        ];
-                    }
-                }
-
-                elseif ($name == '退还') {
-                    if ($returnType == '退面料' && $newTotal != $returnQty) {
-                        $updateStockSql = \db('物料_库存')
-                            ->where('id', $stockId)
-                            ->fetchSql(true)
-                            ->update(['退还数量' => $newTotal]);
-
-                        \db()->query($updateStockSql);
-
-                        $logData[] = [
-                            '批次号' => $batchNo,
-                            '操作字段' => '退还数量',
-                            '原值' => $returnQty,
-                            '新值' => $newTotal,
-                            '操作人' => $sysId,
-                            '操作类型' => '退还',
-                            '操作时间' => $now,
-                            '修改表' => '物料_库存',
-                            'ids' => $stockId
-                        ];
-                    }
-                }
-            }
-        }
-
-        // 批量写入日志
-        if (!empty($logData)) {
-            \db('物料_库存日志')->insertAll($logData);
-        }
-
-        $this->success('更新成功');
-    }
 
 }

+ 138 - 308
application/api/controller/WorkOrderVerification.php

@@ -3,333 +3,163 @@
 namespace app\api\controller;
 
 use app\common\controller\Api;
-use \think\Request;
-use \think\Db;
-use \think\cache;
-/**
- * 工单核验单维护接口
- */
+use app\job\ImageJob;
+use app\job\InsertDataJob;
+use think\Db;
+use think\Log;
+use think\Queue;
+
 class WorkOrderVerification extends Api
 {
     protected $noNeedLogin = ['*'];
     protected $noNeedRight = ['*'];
 
-    /**
-     * 首页
-     *
-     */
-    public function index()
+    protected $config = [
+        'gpt' => [
+            'api_key' => 'sk-Bhos1lXTRpZiAAmN06624a219a874eCd91Dc068b902a3e73',
+            'api_url' => 'https://one.opengptgod.com/v1/chat/completions'
+        ],
+        'dalle' => [
+            'api_key' => 'sk-e0JuPjMntkbgi1BoMjrqyyzMKzAxILkQzyGMSy3xiMupuoWY',
+            'api_url' => 'https://niubi.zeabur.app/v1/images/generations'
+        ]
+    ];
+
+    public function startGenerateImage()
     {
-        $this->success('请求成功');
-    }
-
-    /**
-     * 获取报工后历史记录
-     *
-     */
-//    public function getTab(){
-//        //get请求
-//        if(!$this->request->isGet()){
-//            $this->error('请求方式错误');
-//        }
-//        $param = $this->request->param();
-//        $where = [
-//            '子订单编号' => $param['order_id'],
-//            'sczl_jtbh' => $param['sczl_jtbh']
-//        ];
-//        //通过当前子订单编号和机台查看历史记录数据
-//        $table_list = \db('设备_产量计酬')->alias('c')
-//            ->field('c.订单编号, c.子订单编号, c.款号, c.工序编号, c.工序名称, c.尺码, c.数量, c.sczl_jtbh, c.尾包,c.UniqId,c.ci_num,c.s_num,
-//                         c.sys_rq, c.serial, y.zdtotal, y.sctotal, j.款式, y.颜色')
-//            ->join('工单_印件资料 y', 'c.子订单编号 = y.子订单编号', 'left')
-//            ->join('工单_基本资料 j', 'c.订单编号 = j.订单编号', 'left')
-//            ->where('c.子订单编号', $param['order_id'])
-//            ->where('c.工序名称', '手工')
-//            ->where('c.sczl_jtbh', $param['sczl_jtbh'])
-//            ->whereNull('c.mod_rq') // 查询未删除数据
-//            ->where(function($query) {
-//                $query->whereNotNull('y.ck_rq')->where('y.ck_rq', '<>', '');
-//            }) // 查询出库数据
-//            ->order('c.UniqId', 'desc')
-//            ->distinct('c.子订单编号')
-//            ->select();
-//        $output = [];
-//        foreach ($table_list as $record) {
-//            $output[] = [
-//                'serial' => '第('.$record['serial'].')包',
-//                'sys_rq' => $record['sys_rq'],
-//                '订单编号' => $record['订单编号'],
-//                '子订单编号' => $record['子订单编号'],
-//                '颜色' => $record['颜色'],
-//                '尺码' => $record['尺码'],
-//                '数量' => $record['数量'],
-//                '上报数量' => $record['s_num'],
-//                '尾包' => $record['尾包'],
-//                '组别' => $record['sczl_jtbh'],
-//            ];
-//        }
-//
-//        $this->success('请求成功', [
-//            'records' => $output
-//        ]);
-//    }
-
-    /**
-     * 生产产量进度月报表(Excel)
-     */
-    public function getOneWorkOrder() {
-        if (!$this->request->isGet()) {
-            $this->error('请求方式错误');
-        }
-
-        $param = $this->request->param();
-
-        // 查询当前订单的生产总数和整单总数
-        $totals = db()->table('工单_印件资料')->alias('y')
-            ->field('y.订单编号, SUM(y.sctotal) as sctotal, SUM(y.zdtotal) as zdtotal')
-            ->group('y.订单编号')
-            ->whereNull('y.Mod_rq')
-            ->order('y.订单编号')
-            ->select();
-
-        // 保存当前订单的生产总数和整单总数到一个数组,以便后续关联
-        $totalsMap = [];
-        foreach ($totals as $total) {
-            $totalsMap[$total['订单编号']] = [
-                'sctotal' => $total['sctotal'],
-                'zdtotal' => $total['zdtotal'],
+        //插入队列
+        $job = new ImageJob(); // 创建任务实例
+        // 推送任务到队列
+        //批量图片插入
+        $imgs = [
+            "202506763-jz1229_A_painting_of_sunflowers_with_each_flower_having_six_pet_c65bd1f7-8a30-4774-ad12-05ff34fa1b21.png",
+            "202506763-jz1229_A_painting_of_sunflowers_with_each_flower_having_six_pet_c65bd1f7-8a30-4774-ad12-05ff34fa1b21.png",
+            "202511157-zwu7493_Vintage_Sunflower_Bunch_on_Vintage_Background_sunflower_8f02bc13-354c-474c-acca-65d45585f885.png",
+            "202511157-zwu7493_Vintage_Sunflower_Bunch_on_Vintage_Background_sunflower_8f02bc13-354c-474c-acca-65d45585f885.png",
+            "202511199-jz1229_watercolor_jungle_leaves_white_background_light_blue_and_053c2fbb-beca-45e7-a812-ed76f311cc12.png",
+            "202511199-jz1229_watercolor_jungle_leaves_white_background_light_blue_and_053c2fbb-beca-45e7-a812-ed76f311cc12.png",
+            "202514598-zwu7493_Watercolor_Succulents_Beautiful_Colors_and_Light_Dreamy_85cbc0d4-c729-429f-a9d8-b2042993be3f.png",
+            "202514598-zwu7493_Watercolor_Succulents_Beautiful_Colors_and_Light_Dreamy_85cbc0d4-c729-429f-a9d8-b2042993be3f.png"
+        ];
+        $arr = [];
+        foreach ($imgs as $k=>$v){
+            $arr[$k] = [
+                "dir_name"=>"/uploads/operate/ai/Preview/20250508",
+                "file_name"=>$v,
+                "prompt"=>"请按以下要求分析图案,详细描述的图案信息提示词,描述的信息只保留图案内容原版风格仅限图案本体,生成的描述信息",
+                "outputDirRaw"=>"/uploads/operate/ai/dall-e/",
+                "width"=>"679",
+                "height"=>"862"
             ];
         }
-
-        // 获取上个月的日期,格式为 Y-m
-        $lastMonth = date('Y-m', strtotime($param['riqi'] . ' -1 month'));
-
-        // 构造查询条件
-        $wheres['sczl_rq'] = ['like', '%' . $lastMonth . '%'];  // 查询上个月的数据
-        $wheres['sczl_bh'] = ['neq', '']; // 根据需要加上你想要的工序条件(假设 sczl_bh 是工序字段)
-
-        $sql = db()->table('设备_产量计酬')
-            ->field('订单编号, sczl_jtbh, sczl_bh,
-                 CASE 
-                WHEN 工序名称 IN ("裁剪", "车缝") THEN SUM(数量)
-                ELSE SUM(s_num) 
-                END as 上月累计')  // 加上工序字段
-            ->where($wheres)
-            ->whereNull('mod_rq')  // 确保 mod_rq 字段为空
-            ->group('订单编号, sczl_jtbh, sczl_bh')  // 按 订单编号, sczl_jtbh, sczl_bh 分组
-            ->select();
-
-        // 将上个月的累计数据保存到一个数组,确保按订单编号和机台号保存
-        $lastMonthMap = [];
-        foreach ($sql as $lastRow) {
-            $lastMonthMap[$lastRow['订单编号']][$lastRow['sczl_jtbh']] = (int)$lastRow['上月累计'];
-        }
-
-        $currentMonth = date('Y-m', strtotime($param['riqi']));  // 获取前端传来的日期所在月份,格式为 Y-m
-        $lastMonth = date('Y-m', strtotime($param['riqi'] . ' -1 month'));  // 获取前端日期的上个月,格式为 Y-m
-
-        // 当前月份的查询条件
-        $where['c.sczl_rq'] = ['like', '%' . $currentMonth . '%'];
-
-        // 查询每天的上报数量,并关联生产总数和整单总数
-        $rows = db()->table('设备_产量计酬')->alias('c')
-            ->join('工单_基本资料 j', 'c.订单编号 = j.订单编号', 'left')
-            ->field('
-                    c.订单编号, j.款式, j.生产款号, j.客户编号, 
-                    c.sczl_jtbh, c.工序名称 as 工序, c.sczl_bh,
-                    CASE 
-                    WHEN c.工序名称 IN ("裁剪", "车缝") THEN c.数量
-                    ELSE c.s_num 
-                    END as 上报数量,
-                    c.sczl_rq as 上报时间  
-                ')
-            ->where($where)
-            ->whereNull('c.mod_rq')
-            ->order('c.sczl_rq desc')
-            ->select();
-
-        // 初始化
-        $result = [];
-        // 处理当前月份的数据
-        foreach ($rows as $row) {
-            $key = $row['款式'] . '_' . $row['生产款号'] . '_' . $row['订单编号'] . '_' . $row['sczl_jtbh'];
-
-            // 获取当前订单编号的生产总数和整单总数
-            $sctotal = isset($totalsMap[$row['订单编号']]) ? $totalsMap[$row['订单编号']]['sctotal'] : 0;
-            $zdtotal = isset($totalsMap[$row['订单编号']]) ? $totalsMap[$row['订单编号']]['zdtotal'] : 0;
-
-            // 获取上个月的累计数量,按机台号获取
-            $lastMonthTotal = isset($lastMonthMap[$row['订单编号']][$row['sczl_jtbh']]) ? $lastMonthMap[$row['订单编号']][$row['sczl_jtbh']] : 0;
-
-            // 初始化当前订单编号和组别的数据
-            if (!isset($result[$key])) {
-                $result[$key] = [
-                    '订单编号' => $row['订单编号'],
-                    '客户编号' => $row['客户编号'],
-                    '机台号' => $row['sczl_jtbh'],
-                    '款式' => $row['款式'],
-                    '款号' => $row['生产款号'],
-                    '工序' => $row['工序'],
-                    '组别' => $row['sczl_bh'],
-                    '制单数' => $zdtotal,
-                    '裁剪数' => $sctotal,
-                    '上月累计' => $lastMonthTotal,
-                    '上报数量' => 0,
-                ];
-
-                // 初始化每一天的数据
-                for ($day = 1; $day <= 31; $day++) {
-                    $result[$key][$day] = 0;
-                }
-            }
-
-            // 获取上报的具体日期
-            $day = (int)date('d', strtotime($row['上报时间']));
-
-            // 按天累加上报数量
-            $result[$key][$day] += (int)$row['上报数量'];
-
-            // 累计上报数量
-            $result[$key]['上报数量'] += (int)$row['上报数量'];
-        }
-
-        // 计算本月累计数据
-        foreach ($result as &$item) {
-            $item['本月累计'] = 0;
-            // 累计本月每天的数据
-            for ($day = 1; $day <= 31; $day++) {
-                $item['本月累计'] += $item[$day];
-                if ($item[$day] === 0) {
-                    $item[$day] = '';
-                }
-            }
+//        $arr = [
+//            [
+//                "dir_name"=>"/uploads/operate/ai/Preview/20250508",
+//                "file_name"=>"202506763-jz1229_A_painting_of_sunflowers_with_each_flower_having_six_pet_c65bd1f7-8a30-4774-ad12-05ff34fa1b21.png",
+//                "prompt"=>"请按以下要求分析图案,详细描述的图案信息提示词,描述的信息只保留图案内容原版风格仅限图案本体,生成的描述信息",
+//                "outputDirRaw"=>"/uploads/operate/ai/dall-e/",
+//                "width"=>"679",
+//                "height"=>"862"
+//            ],
+//        ];
+        foreach ($arr as $key => $value){
+            Queue::push('app\job\ImageJob',$value); // 推送任务到队列
         }
-
-        // 排序
-        usort($result, function ($a, $b) {
-            // 先按客户编号排序
-            $clientComparison = strcmp($a['客户编号'], $b['客户编号']);
-            if ($clientComparison !== 0) {
-                return $clientComparison;
-            }
-
-            // 再按组别排序
-            $groupComparison = strcmp($a['组别'], $b['组别']);
-            if ($groupComparison !== 0) {
-                return $groupComparison;
-            }
-
-            // 最后按订单编号排序
-            return strcmp($a['订单编号'], $b['订单编号']);
-        });
-        $result = array_values($result);
-
-        $this->success('成功', $result);
     }
 
-
-    /**
-     *
-     */
-    public function getInfo()
+    public function callGptApi($imageUrl, $prompt)
     {
-
-    }
-
-
-    /**
-     *
-     */
-    public function getOrderInfo(){
-
-    }
-    /**
-     *
-     */
-    public function getYjInfo(){
-
-
-    }
-    /**
-     *
-     */
-    public function getWastInfo(){
-
-    }
-    /**
-     *
-     */
-    public function getGxAndLeader(){
-
-    }
-    /**
-     *
-     */
-    public function edit(){
-
-    }
-    /**
-     *
-     */
-    public function add(){
-
-    }
-    /**
-     *
-     */
-    public function wasteDistribution(){
-
-    }
-    /**
-     *
-     */
-    public function getOrderDate(){
-
-    }
-    /**
-     *
-     */
-    public function editOrderFinishDate(){
-
-    }
-    /**
-     *
-     */
-    public function getOrderProcessLeft(){
-
-    }
-    /**
-     *
-     */
-    public function getOrderProcessRight(){
-
-    }
-    /**
-     *
-     */
-    public function getDaysWast()
+        $data = [
+            "model" => "gpt-4-vision-preview",
+            "messages" => [[
+                "role" => "user",
+                "content" => [
+                    ["type" => "text", "text" => $prompt],
+                    ["type" => "image_url", "image_url" => [
+                        "url" => $imageUrl,
+                        "detail" => "auto"
+                    ]]
+                ]
+            ]],
+            "max_tokens" => 1000
+        ];
+        return $this->callApi($this->config['gpt']['api_url'], $this->config['gpt']['api_key'], $data);
+    }
+
+    public function callDalleApi($prompt)
     {
-
+        $data = [
+            'prompt' => $prompt,
+            'model'  => 'dall-e-2',
+            'n'      => 1,
+            'size'   => '1024x1024'
+        ];
+        return $this->callApi($this->config['dalle']['api_url'], $this->config['dalle']['api_key'], $data);
     }
-    /**
-     *
-     */
-    public function getMonthPeopleTotal(){
 
+    public function callApi($url, $apiKey, $data)
+    {
+        $maxRetries = 2;
+        $attempt = 0;
+        $lastError = '';
+
+        while ($attempt <= $maxRetries) {
+            $ch = curl_init();
+            curl_setopt_array($ch, [
+                CURLOPT_URL => $url,
+                CURLOPT_RETURNTRANSFER => true,
+                CURLOPT_POST => true,
+                CURLOPT_POSTFIELDS => json_encode($data),
+                CURLOPT_HTTPHEADER => [
+                    'Content-Type: application/json',
+                    'Authorization: Bearer ' . $apiKey
+                ],
+                CURLOPT_TIMEOUT => 180,
+                CURLOPT_SSL_VERIFYPEER => false,
+                CURLOPT_SSL_VERIFYHOST => 0
+            ]);
+
+            $response = curl_exec($ch);
+            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+            $curlError = curl_error($ch);
+            curl_close($ch);
+
+            if ($response !== false && $httpCode === 200) {
+                $result = json_decode($response, true);
+                if (json_last_error() === JSON_ERROR_NONE) return $result;
+            }
 
-    }
-    /**
-     *
-     */
-    public function getOrderWasteTotal(){
+            $lastError = $curlError ?: "HTTP错误:{$httpCode}";
+            $attempt++;
+            sleep(1);
+        }
 
+        return ['error' => true, 'msg' => $lastError];
     }
 
-    /**
-     *
-     */
-    public function del()
+    public function logToDatabase($data)
     {
-
+        $record = [
+            'old_image_url' => $data['old_image_url'] ?? '',
+            'new_image_url' => $data['new_image_url'] ?? '',
+            'custom_image_url' => $data['custom_image_url'] ?? '',
+            'size' => isset($data['image_width'], $data['image_height']) ?
+                $data['image_width'] . 'x' . $data['image_height'] : '',
+            'chinese_description' => $data['chinese_description'] ?? '',
+            'english_description' => $data['english_description'] ?? '',
+            'model' => 'dall-e-2',
+            'quality' => 'standard',
+            'style' => 'vivid',
+            'status' => $data['status'] ?? 0,
+            'error_msg' => $data['error_msg'] ?? '',
+            'created_time' => date('Y-m-d H:i:s'),
+            'updated_time' => date('Y-m-d H:i:s')
+        ];
+
+        if (isset($data['id'])) {
+            Db::name('text_to_image')->where('id', $data['id'])->update($record);
+        } else {
+            Db::name('text_to_image')->insert($record);
+        }
     }
 }

+ 5 - 79
application/database.php

@@ -16,44 +16,15 @@ return [
 
     // 数据库类型
     'type'            => Env::get('database.type', 'mysql'),
-//    // 服务器地址
-//    'hostname'        => Env::get('database.hostname', '127.0.0.1'),
-//    // 数据库名
-//    'database'        => Env::get('database.database', 'fastadmin'),
-//    // 用户名
-//    'username'        => Env::get('database.username', 'root'),
-//    // 密码
-//    'password'        => Env::get('database.password', ''),
-//    // 端口
-//    'hostport'        => Env::get('database.hostport', ''),
-//// 服务器地址
-//    'hostname'        => Env::get('database.hostname', 'rm-bp1y64151f8x1b37n0o.mysql.rds.aliyuncs.com'),
-//// 数据库名
-//    'database'        => Env::get('database.database', 'zjmn_mes'),
-//// 用户名
-//    'username'        => Env::get('database.username', 'zjminong'),
-//// 密码
-//    'password'        => Env::get('database.password', '83h2)$3^kd(up^w'),
-//    // 端口
-//    'hostport'        => Env::get('database.hostport', ''),
     // 服务器地址
-    //    'hostname'        => Env::get('database.hostname', '20.0.16.172'),
-    //    // 数据库名
-    //    'database'        => Env::get('database.database', 'mesdb'),
-    //    // 用户名
-    //    'username'        => Env::get('database.username', 'root'),
-    //    // 密码
-    //    'password'        => Env::get('database.password', 'ZJYX_Mes8052'),
-    //    // 端口
-    //    'hostport'        => Env::get('database.hostport', '3306'),
-    // 服务器地址
-    'hostname'        => Env::get('database.hostname', '20.0.51.77'),
+    'hostname'        => Env::get('database.hostname', '20.0.16.128'),
     // 数据库名
-    'database'        => Env::get('database.database', 'mesdb'),
+    'database'        => Env::get('database.database', 'ai_mesdb'),
     // 用户名
-    'username'        => Env::get('database.username', 'mesdb'),
+    'username'        => Env::get('database.username', 'ai_mesdb'),
     // 密码
-    'password'        => Env::get('database.password', 'nY72kLdaXtpKdLNf'),
+    'password'        => Env::get('database.password', 'a6BLYaEB54a5d22W'),
+
     // 端口
     'hostport'        => Env::get('database.hostport', '3306'),
     // 连接dsn
@@ -128,50 +99,5 @@ return [
         'datetime_format' => false,
         // 是否需要进行SQL性能分析
         'sql_explain'     => false,
-    ],
-    /**
-     * mes云同步数据库
-     */
-    'db4'             => [
-        // 数据库类型
-        'type'            => Env::get('database.type', 'mysql'),
-        // 服务器地址
-        'hostname'        => Env::get('database3.hostname', 'rm-bp1y64151f8x1b37n0o.mysql.rds.aliyuncs.com'),
-        // 数据库名
-        'database'        => Env::get('database3.database', 'zjmn_mes'),
-        // 用户名
-        'username'        => Env::get('database3.username', 'zjminong'),
-        // 密码
-        'password'        => Env::get('database3.password', '83h2)$3^kd(up^w'),
-        // 端口
-        'hostport'        => Env::get('database3.hostport', ''),
-        // 连接dsn
-        'dsn'             => '',
-        // 数据库连接参数
-        'params'          => [],
-        // 数据库编码默认采用 utf8mb4
-        'charset'         => Env::get('database3.charset', 'utf8mb4'),
-        // 数据库表前缀
-        'prefix'          => Env::get('database3.prefix', ''),
-        // 数据库调试模式
-        'debug'           => Env::get('database3.debug', false),
-        // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
-        'deploy'          => 0,
-        // 数据库读写是否分离 主从式有效
-        'rw_separate'     => false,
-        // 读写分离后 主服务器数量
-        'master_num'      => 1,
-        // 指定从服务器序号
-        'slave_no'        => '',
-        // 是否严格检查字段是否存在
-        'fields_strict'   => true,
-        // 数据集返回类型
-        'resultset_type'  => 'array',
-        // 自动写入时间戳字段
-        'auto_timestamp'  => false,
-        // 时间字段取出后的默认时间格式,默认为Y-m-d H:i:s
-        'datetime_format' => false,
-        // 是否需要进行SQL性能分析
-        'sql_explain'     => false,
     ]
 ];

+ 388 - 0
application/job/ImageJob.php

@@ -0,0 +1,388 @@
+<?php
+// 1. 正确的队列任务类 application/job/ImageJob.php
+namespace app\job;
+
+use think\Db;
+use think\queue\Job;
+
+class ImageJob
+{
+    protected $config = [
+        'gpt' => [
+            'api_key' => 'sk-Bhos1lXTRpZiAAmN06624a219a874eCd91Dc068b902a3e73',
+            'api_url' => 'https://one.opengptgod.com/v1/chat/completions'
+        ],
+        'dalle' => [
+            'api_key' => 'sk-e0JuPjMntkbgi1BoMjrqyyzMKzAxILkQzyGMSy3xiMupuoWY',
+            'api_url' => 'https://niubi.zeabur.app/v1/images/generations'
+        ]
+    ];
+    /**
+     * fire方法是队列默认调用的方法
+     * @param Job $job 当前的任务对象
+     * @param array|mixed $data 发布任务时自定义的数据
+     */
+    public function fire(Job $job, $data)
+    {
+        echo "队列任务开始执行\n";
+        echo "接收的数据: " . json_encode($data) . "\n";
+
+        $logId = $data['log_id'] ?? null;
+        try {
+            if ($logId) {
+                Db::name('queue_log')->where('id', $logId)->update([
+                    'status' => 1, // 正在处理
+                    'updated_at' => date('Y-m-d H:i:s')
+                ]);
+            }
+
+            // 执行业务逻辑
+            $this->processImage($data);
+
+            if ($logId) {
+                Db::name('queue_log')->where('id', $logId)->update([
+                    'status' => 2,
+                    'log' => '执行成功',
+                    'updated_at' => date('Y-m-d H:i:s')
+                ]);
+            }
+
+            $job->delete();
+        } catch (\Exception $e) {
+            if ($logId) {
+                Db::name('queue_log')->where('id', $logId)->update([
+                    'status' => 3,
+                    'log' => $e->getMessage(),
+                    'updated_at' => date('Y-m-d H:i:s')
+                ]);
+            }
+
+            // 重试
+            if ($job->attempts() < 3) {
+                $job->release(30);
+            } else {
+                $job->failed();
+            }
+        }
+    }
+
+//    public function fire(Job $job, $data)
+//    {
+//        echo "队列任务开始执行\n";
+//        echo "接收的数据: " . json_encode($data) . "\n";
+//
+//        try {
+//            // 执行实际的业务逻辑
+//            $this->processImage($data);
+//
+//            // 任务执行成功后删除
+//            $job->delete();
+//            echo "任务执行成wwww功\n";
+//
+//        } catch (\Exception $e) {
+//            echo "任务执行失败: " . $e->getMessage() . "\n";
+//
+//            // 重试机制
+//            if ($job->attempts() < 3) {
+//                $job->release(30); // 30秒后重试
+//                echo "任务重新入队,重试次数: " . $job->attempts() . "\n";
+//            } else {
+//                $job->failed();
+//                echo "任务最终失败\n";
+//            }
+//        }
+//    }
+
+    /**
+     * 任务失败时的处理
+     */
+    public function failed($data)
+    {
+        // 记录失败日志或发送通知
+        \think\Log::error("ImageJob failed: " . json_encode($data));
+    }
+
+    /**
+     * 处理图片的具体逻辑
+     */
+    public function processImage($data)
+    {
+        // 根据传入的数据处理图片
+        $res = $this->imageToText($data["sourceDir"],$data["file_name"],$data["prompt"],$data);
+        echo $res;
+    }
+
+    public function imageToText($sourceDirRaw,$fileName,$prompt,$call_data)
+    {
+        // 自动拆分文件名
+        if (!$fileName && preg_match('/([^\/]+\.(jpg|jpeg|png))$/i', $sourceDirRaw, $matches)) {
+            $fileName = $matches[1];
+            $sourceDirRaw = preg_replace('/\/' . preg_quote($fileName, '/') . '$/', '', $sourceDirRaw);
+        }
+
+        // 参数校验
+        if ($sourceDirRaw === '' || $fileName === '') {
+            return '参数错误:原图路径 或 图片名称 不能为空';
+        }
+        // 构建路径
+        $rootPath = str_replace('\\', '/', ROOT_PATH);
+        $sourceDir = rtrim($rootPath . 'public/' . $sourceDirRaw, '/') . '/';
+        $filePath = $sourceDir . $fileName;
+        $relativePath = $sourceDirRaw . '/' . $fileName;
+
+        // 文件检查
+        if (!is_dir($sourceDir)) {
+            return '源目录不存在:' . $sourceDir;
+        }
+        if (!is_file($filePath)) {
+            return '文件不存在:' . $filePath;
+        }
+
+
+        // 获取图片信息
+        $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
+        $mime = ($ext === 'jpg' || $ext === 'jpeg') ? 'jpeg' : $ext;
+
+        list($width, $height) = getimagesize($filePath);
+        $imageData = base64_encode(file_get_contents($filePath));
+        if (!$imageData || strlen($imageData) < 1000) {
+            throw new \Exception('图片内容读取失败');
+        }
+        $imageUrl = "data:image/{$mime};base64,{$imageData}";
+
+        // 构建严格格式的提示词
+        //请严格按以下要求分析图案:只提取图案本身的视觉元素(图形、字母、文字、符号),忽略所有背景和载体信息(如壁画载体、衣服等), 描述必须包含: 主体图形特征(形状/颜色/材质感),文字内容(字母/单词/数字及其样式),空间排列关系,整体艺术风格---json json--- 格式:{纯图案的客观中文描述,不包含任何背景说明}---json json---{ "prompt": "English description focusing only on graphic elements with style details, on pure black background","size": "1024x1024","color_palette": ["主色1", "主色2"],"style": "图案风格"}---json json---
+        $userPrompt = preg_replace('/\s+/u', '', $prompt); // 移除所有空白字符
+        $strictPrompt = "严格遵守以下规则:
+                        1. 只返回三段内容:
+                           第一段:纯中文图案描述
+                           第二段:---json json---
+                           第三段:纯英文图案描述
+                        2. 描述中必须体现图案的类型、颜色、风格等关键信息
+                        3. 不允许添加任何解释、引导、说明、示例等文字,必须只包含图案描述内容本身
+                        4. 示例:
+                        这张图中的图案是代表达拉斯足球队的标志,包括一个头盔图形和围绕它的文字。头盔以灰色和白色为主,有蓝色和黑色的细节。
+                        ---json json---
+                        The pattern in this picture is the logo representing the Dallas football team, including a helmet figure and the text around it. The helmet is mainly gray and white, with blue and black details.
+                        请直接描述这个图案:
+                        " . $userPrompt;
+
+        // 调用图生文
+        $gptRes = $this->callGptApi($imageUrl, $strictPrompt);
+        $gptText = trim($gptRes['choices'][0]['message']['content'] ?? '');
+
+        // 验证 GPT 返回格式
+        if (strpos($gptText, '---json json---') === false) {
+            return  'GPT 返回格式不正确,缺少分隔符';
+        }
+
+        list($chineseDesc, $englishDesc) = array_map('trim', explode('---json json---', $gptText));
+
+        if ($chineseDesc === '' || $englishDesc === '') {
+            return  '描述内容为空,请检查 GPT 返回';
+        }
+
+        // 插入数据库(成功时才插入)
+        $this->logToDatabase([
+            'old_image_url'       => $relativePath,
+            'chinese_description' => $chineseDesc,
+            'english_description' => $englishDesc,
+            'size'                => "",
+            'status'              => 1
+        ]);
+        //进行文字转图片
+        $res = $this->textToImage($fileName,$call_data["outputDir"],$call_data["width"],$call_data["height"],$chineseDesc.$englishDesc);
+        return $res;
+
+    }
+
+    public function textToImage($fileName, $outputDirRaw, $width, $height, $prompt)
+    {
+        // 统一路径分隔符为 /
+        $rootPath = str_replace('\\', '/', ROOT_PATH);
+        $outputDir = rtrim($rootPath . 'public/' . $outputDirRaw, '/') . '/';
+        $dateDir = date('Y-m-d') . '/';
+        $fullBaseDir = $outputDir . $dateDir;
+
+        // 创建所需目录
+        foreach ([$fullBaseDir, $fullBaseDir . '1024x1024/', $fullBaseDir . "{$width}x{$height}/"] as $dir) {
+            if (!is_dir($dir)) {
+                mkdir($dir, 0755, true);
+            }
+        }
+
+        // 规范化提示词
+        $prompt = preg_replace('/[\r\n\t]+/', ' ', $prompt);
+
+        // 查询数据库记录
+        $record = Db::name('text_to_image')
+            ->where('old_image_url', 'like', "%{$fileName}")
+            ->order('id desc')
+            ->find();
+
+        if (!$record) {
+            return '没有找到匹配的图像记录';
+        }
+
+        // 记录提示词日志
+        $logDir = $rootPath . 'runtime/logs/';
+        if (!is_dir($logDir)) mkdir($logDir, 0755, true);
+        file_put_contents($logDir . 'prompt_log.txt', date('Y-m-d H:i:s') . " prompt: {$prompt}\n", FILE_APPEND);
+
+        // 调用 DALL·E 接口
+        $dalle1024 = $this->callDalleApi($prompt);
+        file_put_contents($logDir . 'dalle_response.log', date('Y-m-d H:i:s') . "\n" . print_r($dalle1024, true) . "\n", FILE_APPEND);
+
+        // 校验返回链接
+        if (!isset($dalle1024['data'][0]['url']) || empty($dalle1024['data'][0]['url'])) {
+            $errorText = $dalle1024['error']['message'] ?? '未知错误';
+            throw new \Exception('DALL·E 生成失败:' . $errorText);
+        }
+
+        $imgUrl1024 = $dalle1024['data'][0]['url'];
+        $imgData1024 = @file_get_contents($imgUrl1024);
+        if (!$imgData1024 || strlen($imgData1024) < 1000) {
+            return "下载图像失败或内容异常";
+        }
+
+        // 保存原图
+        $filename1024 = 'dalle_' . md5($record['old_image_url'] . microtime()) . '_1024.png';
+        $savePath1024 = $fullBaseDir . '1024x1024/' . $filename1024;
+        file_put_contents($savePath1024, $imgData1024);
+
+        // 创建图像资源
+        $im = @imagecreatefromstring($imgData1024);
+        if (!$im) {
+            return "图像格式不受支持或已损坏";
+        }
+
+        // 获取原图尺寸
+        $srcWidth = imagesx($im);
+        $srcHeight = imagesy($im);
+
+        // 创建目标图像(缩放到目标尺寸,无裁剪)
+        $dstImg = imagecreatetruecolor($width, $height);
+        imagecopyresampled($dstImg, $im, 0, 0, 0, 0, $width, $height, $srcWidth, $srcHeight);
+
+        // 保存缩放图
+        $filenameCustom = 'dalle_' . md5($record['old_image_url'] . microtime()) . "_custom.png";
+        $savePathCustom = $fullBaseDir . "{$width}x{$height}/" . $filenameCustom;
+        imagepng($dstImg, $savePathCustom);
+
+        // 释放资源
+        imagedestroy($im);
+        imagedestroy($dstImg);
+
+        // 更新数据库
+        Db::name('text_to_image')->where('id', $record['id'])->update([
+            'new_image_url'     => str_replace($rootPath . 'public/', '', $savePath1024),
+            'custom_image_url'  => str_replace($rootPath . 'public/', '', $savePathCustom),
+            'error_msg'         => '',
+            'size'              => "{$width}x{$height}",
+            'updated_time'      => date('Y-m-d H:i:s')
+        ]);
+
+        return 0;
+    }
+
+    public function callDalleApi($prompt)
+    {
+        $data = [
+            'prompt' => $prompt,
+            'model' => 'dall-e-2',
+            'n' => 1,
+            'size' => '1024x1024'
+        ];
+        return $this->callApi($this->config['dalle']['api_url'], $this->config['dalle']['api_key'], $data);
+    }
+
+    public function logToDatabase($data)
+    {
+        $record = [
+            'old_image_url' => $data['old_image_url'] ?? '',
+            'new_image_url' => $data['new_image_url'] ?? '',
+            'custom_image_url' => $data['custom_image_url'] ?? '',
+            'size' => isset($data['image_width'], $data['image_height']) ?
+                $data['image_width'] . 'x' . $data['image_height'] : '',
+            'chinese_description' => $data['chinese_description'] ?? '',
+            'english_description' => $data['english_description'] ?? '',
+            'model' => 'dall-e-2',
+            'quality' => 'standard',
+            'style' => 'vivid',
+            'status' => $data['status'] ?? 0,
+            'error_msg' => $data['error_msg'] ?? '',
+            'created_time' => date('Y-m-d H:i:s'),
+            'updated_time' => date('Y-m-d H:i:s')
+        ];
+
+        if (isset($data['id'])) {
+            Db::name('text_to_image')->where('id', $data['id'])->update($record);
+        } else {
+            Db::name('text_to_image')->insert($record);
+        }
+    }
+    public function callGptApi($imageUrl, $prompt)
+    {
+        $data = [
+            "model" => "gpt-4-vision-preview",
+            "messages" => [[
+                "role" => "user",
+                "content" => [
+                    ["type" => "text", "text" => $prompt],
+                    ["type" => "image_url", "image_url" => [
+                        "url" => $imageUrl,
+                        "detail" => "auto" // ✅ 显式添加 detail 字段,兼容 vision API
+                    ]]
+                ]
+            ]],
+            "max_tokens" => 1000
+        ];
+
+        return $this->callApi($this->config['gpt']['api_url'], $this->config['gpt']['api_key'], $data);
+    }
+
+    /**
+     * 通用API调用方法
+     */
+    public function callApi($url, $apiKey, $data)
+    {
+        $maxRetries = 2;
+        $attempt = 0;
+        $lastError = '';
+
+        while ($attempt <= $maxRetries) {
+            $ch = curl_init();
+            curl_setopt_array($ch, [
+                CURLOPT_URL => $url,
+                CURLOPT_RETURNTRANSFER => true,
+                CURLOPT_POST => true,
+                CURLOPT_POSTFIELDS => json_encode($data),
+                CURLOPT_HTTPHEADER => [
+                    'Content-Type: application/json',
+                    'Authorization: Bearer ' . $apiKey
+                ],
+                CURLOPT_TIMEOUT => 120,
+                CURLOPT_SSL_VERIFYPEER => false,
+                CURLOPT_SSL_VERIFYHOST => 0,
+                CURLOPT_TCP_KEEPALIVE => 1,
+                CURLOPT_FORBID_REUSE => false
+            ]);
+
+            $response = curl_exec($ch);
+            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+            $curlError = curl_error($ch);
+            curl_close($ch);
+
+            if ($response !== false && $httpCode === 200) {
+                $result = json_decode($response, true);
+                return $result;
+            }
+
+            $lastError = $curlError ?: "HTTP错误:{$httpCode}";
+            $attempt++;
+            sleep(1);
+        }
+
+        throw new \Exception("请求失败(重试{$maxRetries}次):{$lastError}");
+    }
+}

+ 56 - 56
application/job/InsertDataJob.php

@@ -17,61 +17,61 @@ class InsertDataJob
 
     public function handle()
     {
-        $options = [
-            'host'       => '127.0.0.1',
-            'port'       => 6379,
-            'password'   => '',
-            'select'     => 15,
-            'timeout'    => 0,
-            'expire'     => 0,
-            'persistent' => false,
-            'prefix'     => '',
-        ];
-        $redis = new Redis($options);
-        $taskIdentifier = md5(json_encode('date'));
-        $handData = [];
-        foreach ($this->data as $key=>$value){
-            $handData[$key]['sczl_gdbh'] = $value['sczl_gdbh'];
-            $handData[$key]['sczl_yjno'] = $value['sczl_yjno'];
-            $handData[$key]['sczl_gxh'] = $value['sczl_gxh'];
-            $handData[$key]['sczl_type'] = $value['sczl_type'];
-            $handData[$key]['sczl_rq'] = $value['sczl_rq'];
-            $handData[$key]['sczl_jtbh'] = $value['sczl_jtbh'];
-            $handData[$key]['班组车头产量'] = $value['班组车头产量'];
-            $handData[$key]['工价系数'] = $value['工价系数'];
-            $handData[$key]['工序难度系数'] = $value['工序难度系数'];
-            $handData[$key]['装版工时'] = $value['装版工时'];
-            $handData[$key]['保养工时'] = $value['保养工时'];
-            $handData[$key]['打样工时'] = $value['打样工时'];
-            $handData[$key]['异常停机工时'] = $value['异常停机工时'];
-            $handData[$key]['车头产量占用机时'] = $value['车头产量占用机时'];
-            $handData[$key]['日定额'] = $value['日定额'];
-            $handData[$key]['千件工价'] = $value['千件工价'];
-            $handData[$key]['补产标准'] = $value['补产标准'];
-            $handData[$key]['班组换算产量'] = $value['班组换算产量'];
-            $handData[$key]['计时补差额工资'] = $value['计时补差额工资'];
-            $handData[$key]['bh'] = $value['bh'];
-            $handData[$key]['xm'] = $value['xm'];
-            $handData[$key]['Rate'] = $value['Rate'];
-            $handData[$key]['sczl_ms'] = $value['sczl_ms'];
-            $handData[$key]['工时占比'] = $value['工时占比'];
-            $handData[$key]['达标定额'] = $value['达标定额'];
-            $handData[$key]['个人计件工资'] = $value['个人计件工资'];
-            $handData[$key]['个人加班工资'] = $value['个人加班工资'];
-            $handData[$key]['UniqID'] = $value['UniqID'];
-            $handData[$key]['sys_ny'] = $value['sys_ny'];
-            $handData[$key]['sys_rq'] = $value['sys_rq'];
-            $handData[$key]['sys_id'] = $value['sys_id'];
-            $handData[$key]['法定天数'] = $value['法定天数'];
-        }
-        $sql =Db::name('绩效工资汇总')->fetchSql(true)->insertAll($handData);
-        $res = Db::query($sql);
-        if ($res !== false){
-            // 获取队列的键名
-            $queueKey = 'default';
-            // 删除队列
-            Cache::store('redis')->handler()->del($queueKey);
-            $redis->rm($taskIdentifier);
-        }
+        // $options = [
+        //     'host'       => '127.0.0.1',
+        //     'port'       => 6379,
+        //     'password'   => '',
+        //     'select'     => 15,
+        //     'timeout'    => 0,
+        //     'expire'     => 0,
+        //     'persistent' => false,
+        //     'prefix'     => '',
+        // ];
+        // $redis = new Redis($options);
+        // $taskIdentifier = md5(json_encode('date'));
+        // $handData = [];
+        // foreach ($this->data as $key=>$value){
+        //     $handData[$key]['sczl_gdbh'] = $value['sczl_gdbh'];
+        //     $handData[$key]['sczl_yjno'] = $value['sczl_yjno'];
+        //     $handData[$key]['sczl_gxh'] = $value['sczl_gxh'];
+        //     $handData[$key]['sczl_type'] = $value['sczl_type'];
+        //     $handData[$key]['sczl_rq'] = $value['sczl_rq'];
+        //     $handData[$key]['sczl_jtbh'] = $value['sczl_jtbh'];
+        //     $handData[$key]['班组车头产量'] = $value['班组车头产量'];
+        //     $handData[$key]['工价系数'] = $value['工价系数'];
+        //     $handData[$key]['工序难度系数'] = $value['工序难度系数'];
+        //     $handData[$key]['装版工时'] = $value['装版工时'];
+        //     $handData[$key]['保养工时'] = $value['保养工时'];
+        //     $handData[$key]['打样工时'] = $value['打样工时'];
+        //     $handData[$key]['异常停机工时'] = $value['异常停机工时'];
+        //     $handData[$key]['车头产量占用机时'] = $value['车头产量占用机时'];
+        //     $handData[$key]['日定额'] = $value['日定额'];
+        //     $handData[$key]['千件工价'] = $value['千件工价'];
+        //     $handData[$key]['补产标准'] = $value['补产标准'];
+        //     $handData[$key]['班组换算产量'] = $value['班组换算产量'];
+        //     $handData[$key]['计时补差额工资'] = $value['计时补差额工资'];
+        //     $handData[$key]['bh'] = $value['bh'];
+        //     $handData[$key]['xm'] = $value['xm'];
+        //     $handData[$key]['Rate'] = $value['Rate'];
+        //     $handData[$key]['sczl_ms'] = $value['sczl_ms'];
+        //     $handData[$key]['工时占比'] = $value['工时占比'];
+        //     $handData[$key]['达标定额'] = $value['达标定额'];
+        //     $handData[$key]['个人计件工资'] = $value['个人计件工资'];
+        //     $handData[$key]['个人加班工资'] = $value['个人加班工资'];
+        //     $handData[$key]['UniqID'] = $value['UniqID'];
+        //     $handData[$key]['sys_ny'] = $value['sys_ny'];
+        //     $handData[$key]['sys_rq'] = $value['sys_rq'];
+        //     $handData[$key]['sys_id'] = $value['sys_id'];
+        //     $handData[$key]['法定天数'] = $value['法定天数'];
+        // }
+        // $sql =Db::name('绩效工资汇总')->fetchSql(true)->insertAll($handData);
+        // $res = Db::query($sql);
+        // if ($res !== false){
+        //     // 获取队列的键名
+        //     $queueKey = 'default';
+        //     // 删除队列
+        //     Cache::store('redis')->handler()->del($queueKey);
+        //     $redis->rm($taskIdentifier);
+        // }
     }
 }

+ 47 - 0
application/service/ImageService.php

@@ -0,0 +1,47 @@
+<?php
+// 1. 正确的队列任务类 application/job/ImageJob.php
+namespace app\service;
+
+use think\Db;
+use think\Queue;
+
+class ImageService
+{
+    public function handleImage($params) {
+        // 如果是单条,转为数组
+        if (isset($params['sourceDir'])) {
+            $params = [$params];
+        }
+        $arr = [];
+        foreach ($params as $k => $v) {
+            // 确保每项是数组,防止异常
+            if (!is_array($v)) continue;
+            $arr[$k] = [
+                "sourceDir" => $v['sourceDir'] ?? '',
+                "outputDir" => $v['outputDir'] ?? '',
+                "file_name" => $v['file_name'] ?? '',
+                "prompt" => $v['prompt'] ?? '',
+                "width" => $v['width'] ?? 512,
+                "height" => $v['height'] ?? 512
+            ];
+        }
+//         推送队列(启用时请去掉 die)
+         foreach ($arr as $value) {
+             // 推送队列前,记录日志
+             $id = Db::name('queue_log')->insertGetId([
+                 'job_name' => 'app\job\ImageJob',
+                 'status' => 0,
+                 'data' => json_encode($value, JSON_UNESCAPED_UNICODE),
+                 'created_at' => date('Y-m-d H:i:s'),
+             ]);
+
+             // 将日志ID传入队列中
+             $value['log_id'] = $id;
+
+             // 推送到队列
+             Queue::push('app\job\ImageJob', $value);
+         }
+
+
+    }
+}