Browse Source

fix:最新版验货端逻辑

super-yimizi 2 months ago
parent
commit
9c767cd0c1
27 changed files with 2624 additions and 200 deletions
  1. 181 0
      ORDER_STATISTICS_README.md
  2. 5 1
      application/admin/controller/inspection/Item.php
  3. 4 4
      application/admin/lang/zh-cn/inspection/item.php
  4. 12 6
      application/admin/view/inspection/item/add.html
  5. 15 6
      application/admin/view/inspection/item/edit.html
  6. 2 1
      application/api/controller/Order.php
  7. 59 0
      application/api/controller/inspection/Base.php
  8. 117 0
      application/api/controller/inspection/Index.php
  9. 330 0
      application/api/controller/inspection/Order.php
  10. 110 0
      application/api/controller/inspection/Sms.php
  11. 195 0
      application/api/controller/inspection/Supplier.php
  12. 270 0
      application/api/controller/inspection/User.php
  13. 17 0
      application/api/validate/Order.php
  14. 316 0
      application/api/validate/inspection/Order.php
  15. 99 0
      application/api/validate/inspection/User.php
  16. 33 17
      application/common/Enum/OrderEnum.php
  17. 392 0
      application/common/Service/InspectService.php
  18. 21 0
      application/common/Service/InspectionService.php
  19. 8 3
      application/common/Service/OrderService.php
  20. 252 0
      application/common/Service/SupplierService.php
  21. 7 157
      application/common/model/Order.php
  22. 5 0
      application/common/model/User.php
  23. 7 0
      application/common/model/inspection/InspectionApplication.php
  24. 50 0
      application/common/model/supplier/Category.php
  25. 92 0
      application/common/model/supplier/Index.php
  26. 8 3
      application/common/service/OrderService.php
  27. 17 2
      public/assets/js/backend/inspection/item.js

+ 181 - 0
ORDER_STATISTICS_README.md

@@ -0,0 +1,181 @@
+# 订单统计功能使用说明
+
+## 功能概述
+
+该功能为验货端用户提供订单统计服务,支持按日、月、年维度统计订单数据,包括验收订单、退回订单和售后订单的统计。
+
+## 接口列表
+
+### 1. 订单统计接口
+
+**接口地址:** `/api/inspection/order/statistics`
+
+**请求方式:** GET
+
+**参数说明:**
+- `type`: 统计类型,可选值:`day`(按日)、`month`(按月)、`year`(按年)
+- `date`: 统计日期,格式:`YYYY-MM-DD`
+
+**响应示例:**
+```json
+{
+    "code": 1,
+    "msg": "统计数据获取成功",
+    "data": {
+        "date": "07-14",
+        "type": "day",
+        "current_period": {
+            "inspection_count": 158,
+            "return_count": 12,
+            "aftersale_count": 2
+        },
+        "previous_period": {
+            "inspection_count": 145,
+            "return_count": 10,
+            "aftersale_count": 3
+        },
+        "growth_rate": {
+            "inspection_rate": 8.97,
+            "return_rate": 20.00,
+            "aftersale_rate": -33.33
+        },
+        "statistics": {
+            "inspection_count": 158,
+            "return_count": 12,
+            "aftersale_count": 2
+        }
+    }
+}
+```
+
+### 2. 日期范围接口
+
+**接口地址:** `/api/inspection/order/getStatisticsDateRange`
+
+**请求方式:** GET
+
+**响应示例:**
+```json
+{
+    "code": 1,
+    "msg": "日期范围获取成功",
+    "data": {
+        "earliest_date": "2024-01-01",
+        "latest_date": "2025-01-14",
+        "current_date": "2025-01-14",
+        "current_month": "2025-01",
+        "current_year": "2025"
+    }
+}
+```
+
+### 3. 趋势数据接口
+
+**接口地址:** `/api/inspection/order/getTrendData`
+
+**请求方式:** GET
+
+**参数说明:**
+- `type`: 统计类型(目前支持`day`)
+- `days`: 统计天数,默认7天,范围1-365
+
+**响应示例:**
+```json
+{
+    "code": 1,
+    "msg": "趋势数据获取成功",
+    "data": [
+        {
+            "date": "2025-01-08",
+            "display_date": "01-08",
+            "inspection_count": 120,
+            "return_count": 8,
+            "aftersale_count": 1
+        },
+        {
+            "date": "2025-01-09",
+            "display_date": "01-09",
+            "inspection_count": 135,
+            "return_count": 10,
+            "aftersale_count": 2
+        }
+    ]
+}
+```
+
+## 统计类型说明
+
+### 订单状态映射
+
+- **验收订单**:`ORDER_STATUS = 211`(验货通过)
+- **退回订单**:`ORDER_STATUS = 212`(验货不通过)
+- **售后订单**:`ORDER_STATUS IN (202, 203)`(退款、退款确认)
+
+### 时间维度
+
+- **day**:按日统计,显示格式:`MM-DD`
+- **month**:按月统计,显示格式:`YYYY-MM`
+- **year**:按年统计,显示格式:`YYYY年`
+
+## 使用示例
+
+### 获取今日订单统计
+```javascript
+// 获取今日统计数据
+fetch('/api/inspection/order/statistics?type=day&date=2025-01-14')
+    .then(response => response.json())
+    .then(data => {
+        console.log('今日验收订单:', data.data.statistics.inspection_count);
+        console.log('今日退回订单:', data.data.statistics.return_count);
+        console.log('今日售后订单:', data.data.statistics.aftersale_count);
+    });
+```
+
+### 获取本月统计数据
+```javascript
+// 获取本月统计数据
+fetch('/api/inspection/order/statistics?type=month&date=2025-01-14')
+    .then(response => response.json())
+    .then(data => {
+        console.log('本月统计:', data.data.statistics);
+        console.log('环比增长:', data.data.growth_rate);
+    });
+```
+
+### 获取最近7天趋势
+```javascript
+// 获取最近7天趋势数据
+fetch('/api/inspection/order/getTrendData?type=day&days=7')
+    .then(response => response.json())
+    .then(data => {
+        data.data.forEach(item => {
+            console.log(`${item.display_date}: 验收${item.inspection_count},退回${item.return_count},售后${item.aftersale_count}`);
+        });
+    });
+```
+
+## 注意事项
+
+1. 所有接口都需要用户登录认证
+2. 统计数据基于当前登录用户的订单数据
+3. 日期参数格式必须为 `YYYY-MM-DD`
+4. 趋势数据最多支持查询365天
+5. 增长率计算:当上期数据为0时,增长率为100%或0%
+6. 所有时间均基于服务器时区
+
+## 错误处理
+
+常见错误码:
+- `400`: 参数验证失败
+- `401`: 未登录或登录已过期
+- `403`: 权限不足
+- `500`: 服务器内部错误
+
+错误响应示例:
+```json
+{
+    "code": 0,
+    "msg": "统计类型只能是day、month、year",
+    "data": null
+}
+``` 

+ 5 - 1
application/admin/controller/inspection/Item.php

@@ -22,7 +22,11 @@ class Item extends Backend
     {
         parent::_initialize();
         $this->model = new \app\common\model\inspection\Item;
-        $this->view->assign("statusList", StatusEnum::getMap());
+
+        $this->view->assign("statusList",StatusEnum::getMap());
+        $this->view->assign("isRequiredList",StatusEnum::getYesNoMap());
+        $this->assignconfig('isRequiredList',json_encode(StatusEnum::getYesNoMap()));
+        $this->assignconfig('isRequiredSearchList',json_encode(StatusEnum::getYesNoMap()));
     }
 
 

+ 4 - 4
application/admin/lang/zh-cn/inspection/item.php

@@ -1,11 +1,11 @@
 <?php
 
 return [
-    'Id'            => '验货任务主键ID',
-    'Parent_id'     => '父项ID(支持层级结构)',
-    'Name'          => '验货选项(如“衣领”“口袋”)',
+    'Id'            => '序列号',
+    'Parent_id'     => '父项',
+    'Name'          => '验货选项名称',
     'Standard_desc' => '检查标准描述',
-    'Is_required'   => '是否必检项 0:否;1:是',
+    'Is_required'   => '是否必检项',
     'Createtime'    => '创建时间',
     'Updatetime'    => '更新时间',
     'Deletetime'    => '删除时间',

+ 12 - 6
application/admin/view/inspection/item/add.html

@@ -1,11 +1,11 @@
 <form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
 
-    <div class="form-group">
+    <!-- <div class="form-group">
         <label class="control-label col-xs-12 col-sm-2">{:__('Parent_id')}:</label>
         <div class="col-xs-12 col-sm-8">
             <input id="c-parent_id" data-rule="required" data-source="parent/index" class="form-control selectpage" name="row[parent_id]" type="text" value="">
         </div>
-    </div>
+    </div> -->
     <div class="form-group">
         <label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
         <div class="col-xs-12 col-sm-8">
@@ -21,18 +21,24 @@
     <div class="form-group">
         <label class="control-label col-xs-12 col-sm-2">{:__('Is_required')}:</label>
         <div class="col-xs-12 col-sm-8">
-            <input id="c-is_required" data-rule="required" class="form-control" name="row[is_required]" type="number" value="1">
+            
+            <div class="radio">
+                {foreach name="isRequiredList" item="vo"}
+                <label for="row[is_required]-{$key|htmlentities}"><input id="row[is_required]-{$key|htmlentities}" name="row[is_required]" type="radio" value="{$key|htmlentities}" {in name="key" value="1"}checked{/in} /> {$vo|htmlentities}</label>
+                {/foreach}
+            </div>
+
         </div>
     </div>
     <div class="form-group">
         <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
         <div class="col-xs-12 col-sm-8">
                         
-            <select  id="c-status" class="form-control selectpicker" name="row[status]">
+            <div class="radio">
                 {foreach name="statusList" item="vo"}
-                    <option value="{$key}" {in name="key" value=""}selected{/in}>{$vo}</option>
+                <label for="row[status]-{$key|htmlentities}"><input id="row[status]-{$key|htmlentities}" name="row[status]" type="radio" value="{$key|htmlentities}" {in name="key" value="1"}checked{/in} /> {$vo|htmlentities}</label>
                 {/foreach}
-            </select>
+            </div>
 
         </div>
     </div>

+ 15 - 6
application/admin/view/inspection/item/edit.html

@@ -1,11 +1,11 @@
 <form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
 
-    <div class="form-group">
+    <!-- <div class="form-group">
         <label class="control-label col-xs-12 col-sm-2">{:__('Parent_id')}:</label>
         <div class="col-xs-12 col-sm-8">
             <input id="c-parent_id" data-rule="required" data-source="parent/index" class="form-control selectpage" name="row[parent_id]" type="text" value="{$row.parent_id|htmlentities}">
         </div>
-    </div>
+    </div> -->
     <div class="form-group">
         <label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
         <div class="col-xs-12 col-sm-8">
@@ -21,18 +21,27 @@
     <div class="form-group">
         <label class="control-label col-xs-12 col-sm-2">{:__('Is_required')}:</label>
         <div class="col-xs-12 col-sm-8">
-            <input id="c-is_required" data-rule="required" class="form-control" name="row[is_required]" type="number" value="{$row.is_required|htmlentities}">
+            <div class="radio">
+                {foreach name="isRequiredList" item="vo"}
+                <label for="row[is_required]-{$key|htmlentities}"><input id="row[is_required]-{$key|htmlentities}" name="row[is_required]"
+                        type="radio" value="{$key|htmlentities}" {in name="key" value="$row.is_required" }checked{/in} />
+                    {$vo|htmlentities}</label>
+                {/foreach}
+            </div>
         </div>
     </div>
     <div class="form-group">
         <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
         <div class="col-xs-12 col-sm-8">
                         
-            <select  id="c-status" class="form-control selectpicker" name="row[status]">
+          
+            <div class="radio">
                 {foreach name="statusList" item="vo"}
-                    <option value="{$key}" {in name="key" value="$row.status"}selected{/in}>{$vo}</option>
+                <label for="row[status]-{$key|htmlentities}"><input id="row[status]-{$key|htmlentities}" name="row[status]"
+                        type="radio" value="{$key|htmlentities}" {in name="key" value="$row.status" }checked{/in} />
+                    {$vo|htmlentities}</label>
                 {/foreach}
-            </select>
+            </div>
 
         </div>
     </div>

+ 2 - 1
application/api/controller/Order.php

@@ -14,7 +14,6 @@ use think\Db;
 use app\common\Service\OrderService;
 use app\common\Enum\OrderEnum;
 use app\common\Service\CartService;
-use app\common\Service\Pay\PayOperService;
 /**
  * 订单接口
  */
@@ -157,6 +156,7 @@ class Order extends Base
         // $order->append(['status_text']);
         // $order->hidden(explode(',', 'method,transactionid,updatetime,deletetime'));
         // $order->expiretime = $order->expiretime - time();
+        $order->order_status_text = OrderEnum::SHOW_TYPE_STATUS_MAP[$order->order_status];
         $this->success('', $order);
     }
 
@@ -183,6 +183,7 @@ class Order extends Base
            // $item->append(['order_status_text']);
             $field = 'id,order_sn,amount,goods_price,order_amount,express_name,express_no,order_goods,order_status_text,order_status';
             $item->visible(explode(',', $field));
+            $item->order_status_text = OrderEnum::SHOW_TYPE_STATUS_MAP[$item->order_status];
         }
         $this->success('获取成功', $list);
     }

+ 59 - 0
application/api/controller/inspection/Base.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace app\api\controller\inspection;
+
+use app\common\controller\Api;
+use app\common\library\Auth;
+use think\Config;
+use think\Lang;
+use app\common\Service\InspectionService;
+use app\common\model\inspection\InspectionApplication;
+class Base extends Api
+{
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+    protected $application = null;
+    //设置返回的会员字段
+    protected $allowFields = ['id', 'username', 'nickname', 'mobile', 'avatar', 'score', 'level', 'bio', 'balance', 'money', 'gender'];
+
+    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();
+        Auth::instance()->setAllowFields($this->allowFields);
+       // 查询是否是审核员
+       $user = Auth::instance()->getUser();
+       $isInspection = null;
+       if ($user) {
+            $isInspection = InspectionService::getUserApplication($user->id);
+            if (!$isInspection) {
+            $this->error('您不是审核员');
+            }       
+            //  验证是否 通过
+            if ($isInspection->audit_status !== InspectionApplication::AUDIT_STATUS_PASSED) {
+              $this->error('您的验货员申请未通过');
+            }
+       }    
+       
+       $this->application = $isInspection;
+        //这里手动载入语言包
+        Lang::load(ROOT_PATH . '/addons/shop/lang/zh-cn.php');
+        Lang::load(APP_PATH . '/index/lang/zh-cn/user.php');
+        //加载当前控制器的语言包
+        $controllername = strtolower($this->request->controller());
+        $lang = $this->request->langset();
+        $lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
+        Lang::load(ADDON_PATH . 'shop/lang/' . $lang . '/' . str_replace('.', '/', $controllername) . '.php');
+    }
+
+}

+ 117 - 0
application/api/controller/inspection/Index.php

@@ -0,0 +1,117 @@
+<?php
+
+namespace app\api\controller\inspection;
+
+use app\api\controller\inspection\Base;
+use app\common\Service\InspectService;
+use app\common\Enum\StatusEnum;
+/**
+ * 示例接口
+ */
+class Index extends Base
+{
+
+     /**
+      * 获取验货选项列表
+      */
+     public function getOptions()
+     {
+        $params = [
+            'status' => StatusEnum::ENABLED,
+        ];
+        $options = InspectService::getInspectionItems($params);
+        $this->success('获取成功', $options);
+     }
+
+     /**
+      * 提交验货任务
+      *
+      * @ApiTitle    (提交验货任务)
+      * @ApiSummary  (提交验货任务,包含验货结果和照片信息)
+      * @ApiMethod   (POST)
+      * @ApiRoute    (/api/inspection/index/submitTask)
+      * @ApiParams   (name="order_id", type="integer", required=true, description="订单ID")
+      * @ApiParams   (name="inspector_id", type="integer", required=true, description="验货员ID")
+      * @ApiParams   (name="remark", type="string", required=false, description="备注信息")
+      * @ApiParams   (name="images", type="string", required=false, description="任务图片,多张用逗号分隔")
+      * @ApiParams   (name="start_time", type="integer", required=false, description="任务开始时间戳")
+      * @ApiParams   (name="end_time", type="integer", required=false, description="任务结束时间戳")
+      * @ApiParams   (name="task_id", type="integer", required=false, description="任务ID,更新时传入")
+      * @ApiParams   (name="results", type="array", required=true, description="验货结果数组")
+      * @ApiParams   (name="results.item_id", type="integer", required=true, description="检查项ID")
+      * @ApiParams   (name="results.name", type="string", required=false, description="检查项名称")
+      * @ApiParams   (name="results.is_qualified", type="integer", required=true, description="是否合格 0:否 1:是")
+      * @ApiParams   (name="results.remark", type="string", required=false, description="不合格原因")
+      * @ApiParams   (name="results.photos", type="array", required=false, description="照片数组")
+      * @ApiParams   (name="results.photos.photo_url", type="string", required=true, description="照片URL")
+      * @ApiReturnParams   (name="code", type="integer", required=true, sample="1")
+      * @ApiReturnParams   (name="msg", type="string", required=true, sample="验货任务提交成功")
+      * @ApiReturnParams   (name="data", type="object", description="返回数据")
+      * @ApiReturn   ({
+          'code':'1',
+          'msg':'验货任务提交成功',
+          'data': {
+              'task_id': 123
+          }
+         })
+      */
+     public function submitTask()
+     {
+         $params = $this->request->post();
+         
+         // 验证必要参数
+         if (empty($params['order_id'])) {
+             $this->error('订单ID不能为空');
+         }
+         
+         $params['inspector_id'] = $this->auth->id;
+         if (empty($params['results']) || !is_array($params['results'])) {
+             $this->error('验货结果不能为空');
+         }
+         
+         // 组装任务数据
+         $taskData = [
+             'order_id' => $params['order_id'],
+             'inspector_id' => $params['inspector_id'],
+             'remark' => $params['remark'] ?? '',
+             'images' => $params['images'] ?? '',
+             'start_time' => $params['start_time'] ?? time(),
+             'end_time' => $params['end_time'] ?? time(),
+             'task_status' => 1, // 进行中
+             'status' => 1 // 开启
+         ];
+         
+         // 如果是更新任务,传入task_id
+         if (!empty($params['task_id'])) {
+             $taskData['task_id'] = $params['task_id'];
+         }
+         
+         // 组装结果数据
+         $resultData = [];
+         foreach ($params['results'] as $result) {
+             if (empty($result['item_id'])) {
+                 $this->error('检查项ID不能为空');
+             }
+             
+             $resultItem = [
+                 'item_id' => $result['item_id'],
+                 'name' => $result['name'] ?? '',
+                 'is_qualified' => $result['is_qualified'] ?? 1,
+                 'remark' => $result['remark'] ?? '',
+                 'photos' => $result['photos'] ?? []
+             ];
+             
+             $resultData[] = $resultItem;
+         }
+         
+         // 调用服务提交验货任务
+         $result = InspectService::submitInspectionTask($taskData, $resultData);
+         
+         if ($result['code'] == 1) {
+             $this->success($result['msg'], $result['data']);
+         } else {
+             $this->error($result['msg']);
+         }
+     }
+
+}

+ 330 - 0
application/api/controller/inspection/Order.php

@@ -0,0 +1,330 @@
+<?php
+
+namespace app\api\controller\inspection;
+
+use app\api\controller\inspection\Base;
+use app\common\Service\OrderService;
+use app\common\Enum\OrderEnum;
+use app\common\Service\OrderActionService;
+use app\common\Enum\OrderActionEnum;
+/**
+ * 验货端订单接口
+ * 
+ * 包含功能:
+ * - 订单详情查询
+ * - 订单列表查询
+ * - 订单发货确认
+ * - 订单统计功能(按日/月/年统计)
+ * - 订单趋势数据
+ * 
+ * 统计功能说明:
+ * - 验收订单:已验货通过的订单
+ * - 退回订单:验货不通过的订单
+ * - 售后订单:退款相关的订单
+ */
+class Order extends Base
+{
+
+    protected $noNeedLogin = [];
+
+      //订单详情
+      public function detail()
+      {
+          // 验证请求参数
+          $validate = new \app\api\validate\Order();
+          $orderId = $this->request->get('orderId');
+          $params = ['orderId' => $orderId];
+          if (!$validate->scene('detail')->check($params)) {
+              $this->error($validate->getError());
+          }
+          $order = OrderService::getDetail($orderId, $this->auth->id);
+          if (empty($order)) {
+              $this->error('未找到订单');
+          }
+          //$order->append(['order_status_text']);
+          $address = OrderService::getAddressInfo($orderId);
+          $order->address = $address;
+          // $order->append(['status_text']);
+          // $order->hidden(explode(',', 'method,transactionid,updatetime,deletetime'));
+          // $order->expiretime = $order->expiretime - time();
+          $order->order_status_text = OrderEnum::SHOW_INSPECTION_STATUS_TEXT_MAP[$order->order_status];
+          $this->success('', $order);
+      }
+  
+      //订单列表
+      public function index()
+      {
+          // 验证请求参数
+          $validate = new \app\api\validate\inspection\Order();
+          $param = $this->request->param();
+          $param['time_range'] = '1'; // 添加触发时间范围验证的字段
+          
+          if (!$validate->scene('lists')->check($param)) {
+              $this->error($validate->getError());
+          }        
+          // 设置默认值
+          $userId = $this->auth->id;
+          $param['page']     = $param['page'] ?? 1;
+          $param['page_size'] = $param['page_size'] ?? 10;
+          $status   = $param['status'] ?? 0; // 默认为0(全部订单)
+          $param['keywords'] = $param['keywords'] ?? '';
+          $status   = OrderEnum::SHOW_TYPE_STATUS_MAP[$status];
+         
+
+          // 查询对应的工厂 信息
+          $supplierId = $this->application->supplier_id;
+          $list = OrderService::getOrderList($userId ,$param, $status,$supplierId);
+          foreach ($list as $item) {
+             // $item->append(['order_status_text']);
+              $field = 'id,order_sn,amount,goods_price,order_amount,express_name,express_no,order_goods,order_status_text,order_status';
+              $item->visible(explode(',', $field));
+              $item->order_status_text = OrderEnum::SHOW_INSPECTION_STATUS_TEXT_MAP[$item->order_status];
+          }
+          $this->success('获取成功', $list);
+      }
+
+      //确认发货
+      public function send()
+      {
+          // 验证请求参数
+        $validate = new \app\api\validate\Order();
+        $orderId = $this->request->post('orderId');
+        $params = ['orderId' => $orderId];
+        if (!$validate->scene('detail')->check($params)) {
+            $this->error($validate->getError());
+        }        
+        $order = OrderService::getByOrderId($orderId);
+        if (empty($order)) {
+            $this->error('订单不存在');
+        }
+        if ($order->user_id != $this->auth->id) {
+            $this->error('该订单不属于当前用户');
+        }
+        $expressname = $this->request->post('expressname');
+        $expressno = $this->request->post('expressno');
+        $order = OrderService::getDetail($orderId, $this->auth->id);
+        if (empty($order)) {
+            $this->error('未找到订单');
+        }
+        //发货 / 修改快递信息
+        if ($order->order_status == OrderEnum::STATUS_INSPECTION_PASS) {
+            $oldStatus = $order->order_status;
+            $order->express_name = $expressname;
+            $order->express_no = $expressno;
+            $order->order_status = OrderEnum::STATUS_SHIP;
+            $order->shipping_time = time();
+            $order->save();
+            
+            // 记录管理员操作
+            OrderActionService::recordAdminAction(
+                $order->order_sn,
+                OrderActionEnum::ACTION_SHIP,
+                '验货端',
+                '验货通过,发货,快递公司:' . $expressname . ',快递单号:' . $expressno,
+                $this->auth->id ?? 0,
+                [
+                    'express_name' => $expressname,
+                    'express_no' => $expressno,
+                ]
+            );            
+            $this->success('发货成功');
+          }else{
+            $this->error('订单不允许确认收货');
+          }
+      }
+
+      // 统计订单 
+      public function statistics()
+      {
+          // 验证请求参数
+          $validate = new \app\api\validate\Order();
+          $params = [
+              'type' => $this->request->param('type', 'day'),
+              'date' => $this->request->param('date', date('Y-m-d'))
+          ];
+          
+          if (!$validate->scene('statistics')->check($params)) {
+              $this->error($validate->getError());
+          }
+          
+          // 获取验证后的参数
+          $type = $params['type'];
+          $date = $params['date'];
+          
+          // 根据类型处理日期和时间范围
+          switch ($type) {
+              case 'day':
+                  $startTime = strtotime($date . ' 00:00:00');
+                  $endTime = strtotime($date . ' 23:59:59');
+                  $displayDate = date('m-d', $startTime);
+                  // 前一天
+                  $prevStartTime = strtotime($date . ' 00:00:00') - 86400;
+                  $prevEndTime = strtotime($date . ' 23:59:59') - 86400;
+                  break;
+              case 'month':
+                  $startTime = strtotime(date('Y-m-01 00:00:00', strtotime($date)));
+                  $endTime = strtotime(date('Y-m-t 23:59:59', strtotime($date)));
+                  $displayDate = date('Y-m', $startTime);
+                  // 前一个月
+                  $prevStartTime = strtotime(date('Y-m-01 00:00:00', strtotime($date . ' -1 month')));
+                  $prevEndTime = strtotime(date('Y-m-t 23:59:59', strtotime($date . ' -1 month')));
+                  break;
+              case 'year':
+                  $startTime = strtotime(date('Y-01-01 00:00:00', strtotime($date)));
+                  $endTime = strtotime(date('Y-12-31 23:59:59', strtotime($date)));
+                  $displayDate = date('Y', $startTime) . '年';
+                  // 前一年
+                  $prevStartTime = strtotime(date('Y-01-01 00:00:00', strtotime($date . ' -1 year')));
+                  $prevEndTime = strtotime(date('Y-12-31 23:59:59', strtotime($date . ' -1 year')));
+                  break;
+          }
+          
+          // 获取当前用户ID
+          $userId = $this->auth->id;
+          
+          // 如果需要根据工厂统计,可以在这里添加工厂相关逻辑
+          // 目前先按用户统计,后续可以根据实际的工厂关联字段进行调整
+          
+          // 当前期间统计
+          $currentStats = $this->getOrderStatistics($userId, $startTime, $endTime);
+          
+          // 上期统计(用于对比)
+          $prevStats = $this->getOrderStatistics($userId, $prevStartTime, $prevEndTime);
+          
+          // 计算增长率
+          $growthRate = [
+              'inspection_rate' => $this->calculateGrowthRate($prevStats['inspection_count'], $currentStats['inspection_count']),
+              'return_rate' => $this->calculateGrowthRate($prevStats['return_count'], $currentStats['return_count']),
+              'aftersale_rate' => $this->calculateGrowthRate($prevStats['aftersale_count'], $currentStats['aftersale_count'])
+          ];
+          
+          // 返回统计数据
+          $data = [
+              'date' => $displayDate,
+              'type' => $type,
+              'current_period' => $currentStats,
+              'previous_period' => $prevStats,
+              'growth_rate' => $growthRate,
+              'statistics' => [
+                  'inspection_count' => $currentStats['inspection_count'],
+                  'return_count' => $currentStats['return_count'],
+                  'aftersale_count' => $currentStats['aftersale_count']
+              ]
+          ];
+          
+          $this->success('统计数据获取成功', $data);
+      }
+      
+      /**
+       * 获取订单统计数据
+       */
+      private function getOrderStatistics($userId, $startTime, $endTime)
+      {
+          // 统计验收订单(验货通过)
+          $inspectionCount = \app\common\model\Order::where('user_id', $userId)
+              ->where('order_status', OrderEnum::STATUS_INSPECTION_PASS)
+              ->where('createtime', '>=', $startTime)
+              ->where('createtime', '<=', $endTime)
+              ->count();
+          
+          // 统计退回订单(验货不通过)
+          $returnCount = \app\common\model\Order::where('user_id', $userId)
+              ->where('order_status', OrderEnum::STATUS_INSPECTION_FAIL)
+              ->where('createtime', '>=', $startTime)
+              ->where('createtime', '<=', $endTime)
+              ->count();
+          
+          // 统计售后订单(退款相关)
+          $aftersaleCount = \app\common\model\Order::where('user_id', $userId)
+              ->whereIn('order_status', [OrderEnum::STATUS_REFUND, OrderEnum::STATUS_REFUND_CONFIRM])
+              ->where('createtime', '>=', $startTime)
+              ->where('createtime', '<=', $endTime)
+              ->count();
+          
+          return [
+              'inspection_count' => $inspectionCount,
+              'return_count' => $returnCount,
+              'aftersale_count' => $aftersaleCount
+          ];
+      }
+      
+      /**
+       * 计算增长率
+       */
+      private function calculateGrowthRate($prevValue, $currentValue)
+      {
+          if ($prevValue == 0) {
+              return $currentValue > 0 ? 100 : 0;
+          }
+          return round((($currentValue - $prevValue) / $prevValue) * 100, 2);
+      }
+      
+      /**
+       * 获取统计数据的时间范围选择
+       */
+      public function getStatisticsDateRange()
+      {
+          // 获取最早和最晚的订单时间
+          $userId = $this->auth->id;
+          
+          $earliest = \app\common\model\Order::where('user_id', $userId)
+              ->order('createtime', 'asc')
+              ->value('createtime');
+          
+          $latest = \app\common\model\Order::where('user_id', $userId)
+              ->order('createtime', 'desc')
+              ->value('createtime');
+          
+          $data = [
+              'earliest_date' => $earliest ? date('Y-m-d', $earliest) : date('Y-m-d'),
+              'latest_date' => $latest ? date('Y-m-d', $latest) : date('Y-m-d'),
+              'current_date' => date('Y-m-d'),
+              'current_month' => date('Y-m'),
+              'current_year' => date('Y')
+          ];
+          
+          $this->success('日期范围获取成功', $data);
+      }
+      
+             /**
+        * 获取历史趋势数据
+        */
+       public function getTrendData()
+       {
+           // 验证请求参数
+           $validate = new \app\api\validate\Order();
+           $params = [
+               'type' => $this->request->param('type', 'day'),
+               'days' => $this->request->param('days', 7)
+           ];
+           
+           if (!$validate->scene('trend')->check($params)) {
+               $this->error($validate->getError());
+           }
+           
+           // 获取验证后的参数
+           $type = $params['type'];
+           $days = $params['days'];
+          
+          $userId = $this->auth->id;
+          $trendData = [];
+          
+          for ($i = $days - 1; $i >= 0; $i--) {
+              $date = date('Y-m-d', strtotime("-{$i} days"));
+              $startTime = strtotime($date . ' 00:00:00');
+              $endTime = strtotime($date . ' 23:59:59');
+              
+              $stats = $this->getOrderStatistics($userId, $startTime, $endTime);
+              $trendData[] = [
+                  'date' => $date,
+                  'display_date' => date('m-d', $startTime),
+                  'inspection_count' => $stats['inspection_count'],
+                  'return_count' => $stats['return_count'],
+                  'aftersale_count' => $stats['aftersale_count']
+              ];
+          }
+          
+          $this->success('趋势数据获取成功', $trendData);
+      }
+
+}

+ 110 - 0
application/api/controller/inspection/Sms.php

@@ -0,0 +1,110 @@
+<?php
+
+namespace app\api\controller\inspection;
+
+
+use app\common\library\Sms as Smslib;
+use app\common\model\User;
+use think\Hook;
+use app\api\controller\inspection\Base;
+/**
+ * 手机短信接口
+ */
+class Sms extends Base
+{
+    protected $noNeedLogin = ['*'];
+
+    public function _initialize()
+    {
+        parent::_initialize();
+
+        if (!$this->request->isPost()) {
+            $this->error("请求错误");
+        }
+    }
+
+    /**
+     * 发送验证码
+     *
+     * @param string $mobile 手机号
+     * @param string $event  事件名称
+     */
+    public function send()
+    {
+        $mobile = $this->request->param("mobile");
+        $event = $this->request->param("event");
+        $event = $event ? $event : 'register';
+
+        if (!$mobile || !\think\Validate::regex($mobile, "^1\d{10}$")) {
+            $this->error(__('手机号不正确'));
+        }
+        $last = Smslib::get($mobile, $event);
+        if ($last && time() - $last['createtime'] < 60) {
+            $this->error(__('发送频繁'));
+        }
+        $ipSendTotal = \app\common\model\Sms::where(['ip' => $this->request->ip()])->whereTime('createtime', '-1 hours')->count();
+        if ($ipSendTotal >= 5) {
+            $this->error(__('发送频繁'));
+        }
+        if ($event) {
+            $userinfo = User::getByMobile($mobile);
+            if ($event == 'register' && $userinfo) {
+                //已被注册
+                $this->error(__('已被注册'));
+            } elseif (in_array($event, ['changemobile']) && $userinfo) {
+                //被占用
+                $this->error(__('已被占用'));
+            } elseif (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo) {
+                //未注册
+                $this->error(__('未注册'));
+            }
+        }
+        if (!Hook::get('sms_send')) {
+            $this->error(__('请在后台插件管理安装短信验证插件'));
+        }
+        $ret = Smslib::send($mobile, null, $event);
+        if ($ret) {
+            $this->success(__('发送成功'));
+        } else {
+            $this->error(__('发送失败,请检查短信配置是否正确'));
+        }
+    }
+
+    /**
+     * 检测验证码
+     *
+     * @param string $mobile  手机号
+     * @param string $event   事件名称
+     * @param string $captcha 验证码
+     */
+    public function check()
+    {
+        $mobile = $this->request->param("mobile");
+        $event = $this->request->param("event");
+        $event = $event ? $event : 'register';
+        $captcha = $this->request->param("captcha");
+
+        if (!$mobile || !\think\Validate::regex($mobile, "^1\d{10}$")) {
+            $this->error(__('手机号不正确'));
+        }
+        if ($event) {
+            $userinfo = User::getByMobile($mobile);
+            if ($event == 'register' && $userinfo) {
+                //已被注册
+                $this->error(__('已被注册'));
+            } elseif (in_array($event, ['changemobile']) && $userinfo) {
+                //被占用
+                $this->error(__('已被占用'));
+            } elseif (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo) {
+                //未注册
+                $this->error(__('未注册'));
+            }
+        }
+        $ret = Smslib::check($mobile, $captcha, $event);
+        if ($ret) {
+            $this->success(__('成功'));
+        } else {
+            $this->error(__('验证码不正确'));
+        }
+    }
+}

+ 195 - 0
application/api/controller/inspection/Supplier.php

@@ -0,0 +1,195 @@
+<?php
+
+namespace app\api\controller\inspection;
+
+use app\api\controller\inspection\Base;
+use app\common\Service\SupplierService;
+
+/**
+ * 供应商/工厂接口
+ */
+class Supplier extends Base
+{
+    // 无需登录的接口
+    protected $noNeedLogin = ['getFactoryList', 'getFactoryOptions', 'searchFactory', 'getActiveFactoryList'];
+    // 无需鉴权的接口
+    protected $noNeedRight = ['getFactoryList', 'getFactoryOptions', 'searchFactory', 'getActiveFactoryList'];
+
+    /**
+     * 获取工厂/供应商列表
+     *
+     * @ApiTitle    (获取工厂/供应商列表)
+     * @ApiSummary  (获取工厂/供应商列表信息,支持分页和搜索)
+     * @ApiMethod   (POST)
+     * @ApiRoute    (/api/inspection/supplier/getFactoryList)
+     * @ApiParams   (name="page", type="integer", required=false, description="页码,默认1")
+     * @ApiParams   (name="limit", type="integer", required=false, description="每页数量,默认10")
+     * @ApiParams   (name="name", type="string", required=false, description="供应商名称")
+     * @ApiParams   (name="category_id", type="integer", required=false, description="分类ID")
+     * @ApiParams   (name="status", type="string", required=false, description="状态:normal正常,hidden隐藏")
+     * @ApiReturnParams   (name="code", type="integer", required=true, sample="1")
+     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
+     * @ApiReturnParams   (name="data", type="object", description="返回数据")
+     * @ApiReturn   ({
+         'code':'1',
+         'msg':'返回成功',
+         'data': {
+             'list': [],
+             'total': 0,
+             'page': 1,
+             'limit': 10
+         }
+        })
+     */
+    public function getFactoryList()
+    {
+        $params = $this->request->param();
+        $page = $params['page'] ?? 1;
+        $limit = $params['limit'] ?? 10;
+        $name = $params['name'] ?? '';
+        $categoryId = $params['category_id'] ?? '';
+        $status = $params['status'] ?? '';
+        
+        $searchParams = [
+            'page' => $page,
+            'limit' => $limit
+        ];
+        
+        if ($name) {
+            $searchParams['name'] = $name;
+        }
+        
+        if ($categoryId) {
+            $searchParams['category_id'] = $categoryId;
+        }
+        
+        if ($status) {
+            $searchParams['status'] = $status;
+        }
+        
+        $supplierService = new SupplierService();
+        $result = $supplierService->getFactoryList($searchParams);
+        
+        $this->success('获取成功', $result);
+    }
+
+    /**
+     * 获取工厂/供应商选项列表
+     *
+     * @ApiTitle    (获取工厂/供应商选项列表)
+     * @ApiSummary  (获取工厂/供应商选项列表,用于下拉选择)
+     * @ApiMethod   (POST)
+     * @ApiRoute    (/api/inspection/supplier/getFactoryOptions)
+     * @ApiReturnParams   (name="code", type="integer", required=true, sample="1")
+     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
+     * @ApiReturnParams   (name="data", type="object", description="返回数据")
+     * @ApiReturn   ({
+         'code':'1',
+         'msg':'返回成功',
+         'data': {
+             '1': '供应商名称1',
+             '2': '供应商名称2'
+         }
+        })
+     */
+    public function getFactoryOptions()
+    {
+        $supplierService = new SupplierService();
+        $options = $supplierService->getFactoryOptions();
+        $this->success('获取成功', $options);
+    }
+
+    /**
+     * 搜索工厂/供应商
+     *
+     * @ApiTitle    (搜索工厂/供应商)
+     * @ApiSummary  (根据关键词搜索工厂/供应商)
+     * @ApiMethod   (POST)
+     * @ApiRoute    (/api/inspection/supplier/searchFactory)
+     * @ApiParams   (name="keyword", type="string", required=true, description="搜索关键词")
+     * @ApiParams   (name="limit", type="integer", required=false, description="限制数量,默认10")
+     * @ApiReturnParams   (name="code", type="integer", required=true, sample="1")
+     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
+     * @ApiReturnParams   (name="data", type="array", description="返回数据")
+     * @ApiReturn   ({
+         'code':'1',
+         'msg':'返回成功',
+         'data': []
+        })
+     */
+    public function searchFactory()
+    {
+        $params = $this->request->param();
+        $keyword = $params['keyword'] ?? '';
+        $limit = $params['limit'] ?? 10;
+        
+        if (empty($keyword)) {
+            $this->error('请输入搜索关键词');
+        }
+        
+        $supplierService = new SupplierService();
+        $result = $supplierService->searchFactory($keyword, $limit);
+        
+        $this->success('搜索成功', $result);
+    }
+
+    /**
+     * 获取工厂/供应商详情
+     *
+     * @ApiTitle    (获取工厂/供应商详情)
+     * @ApiSummary  (根据ID获取工厂/供应商详情)
+     * @ApiMethod   (POST)
+     * @ApiRoute    (/api/inspection/supplier/getFactoryDetail)
+     * @ApiParams   (name="id", type="integer", required=true, description="供应商ID")
+     * @ApiReturnParams   (name="code", type="integer", required=true, sample="1")
+     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
+     * @ApiReturnParams   (name="data", type="object", description="返回数据")
+     * @ApiReturn   ({
+         'code':'1',
+         'msg':'返回成功',
+         'data': {}
+        })
+     */
+    public function getFactoryDetail()
+    {
+        $params = $this->request->param();
+        $id = $params['id'] ?? 0;
+        
+        if (empty($id)) {
+            $this->error('请提供供应商ID');
+        }
+        
+        $supplierService = new SupplierService();
+        $result = $supplierService->getFactoryById($id);
+        
+        if (!$result) {
+            $this->error('供应商不存在');
+        }
+        
+        $this->success('获取成功', $result);
+    }
+
+    /**
+     * 获取启用状态的工厂/供应商列表
+     *
+     * @ApiTitle    (获取启用状态的工厂/供应商列表)
+     * @ApiSummary  (获取启用状态的工厂/供应商列表,带缓存)
+     * @ApiMethod   (POST)
+     * @ApiRoute    (/api/inspection/supplier/getActiveFactoryList)
+     * @ApiReturnParams   (name="code", type="integer", required=true, sample="1")
+     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
+     * @ApiReturnParams   (name="data", type="array", description="返回数据")
+     * @ApiReturn   ({
+         'code':'1',
+         'msg':'返回成功',
+         'data': []
+        })
+     */
+    public function getActiveFactoryList()
+    {
+        $supplierService = new SupplierService();
+        $result = $supplierService->getActiveFactoryListWithCache();
+        
+        $this->success('获取成功', $result);
+    }
+}

+ 270 - 0
application/api/controller/inspection/User.php

@@ -0,0 +1,270 @@
+<?php
+
+namespace app\api\controller\inspection;
+
+use app\common\Enum\UserEnum;
+use app\common\library\Sms;
+use think\Env;
+use app\api\controller\inspection\Base;
+use app\common\Enum\StatusEnum;
+use app\common\Service\InspectionService;
+use app\common\model\inspection\InspectionApplication;
+use app\common\Service\SupplierService;
+/**
+ * 会员
+ */
+class User extends Base
+{
+    protected $noNeedLogin = ['mobilelogin'];
+
+    public function _initialize()
+    {
+        parent::_initialize();
+
+    }
+
+
+       /**
+     * 手机验证码登录
+     *
+     * @param string $mobile 手机号
+     * @param string $captcha 验证码
+     */
+    public function mobilelogin()
+    {
+        $params = $this->request->param();
+        $mobile = $params['mobile'] ?? '';
+        $captcha = $params['captcha'] ?? '';
+        // 验证器
+        $validate = new \app\api\validate\User();
+        if (!$validate->check($params, [], 'mobilelogin')) {
+            $this->error($validate->getError());
+        }
+        // 这里需要处理 测试环境 env('app_debug') 为 true 时,不进行验证码验证 校验 验证码固定为env的配置 DEFAULT_SMSCODE: 123456
+        if (!Env::get('app.app_debug') && $captcha != Env::get('app.DEFAULT_SMSCODE')) {
+            if (!Sms::check($mobile, $captcha, 'mobilelogin')) {
+                $this->error(__('Captcha is incorrect'));
+            }
+        }
+        $user = \app\common\model\User::getByMobile($mobile);
+        if(!$user){
+            $this->error(__('Account does not exist'));
+        }
+        if ($user) {
+            if ($user->status != StatusEnum::ENABLED) {
+                $this->error(__('Account is locked'));
+            }
+            $isInspection = InspectionService::getUserApplication($user->id);
+            if (!$isInspection) {
+            $this->error('您不是审核员');
+            }
+            //  验证是否 通过
+            if ($isInspection->audit_status !== InspectionApplication::AUDIT_STATUS_PASSED) {
+            $this->error('您的验货员申请未通过');
+            }           
+            //如果已经有账号则直接登录
+            $ret = $this->auth->direct($user->id);
+        }   
+        if ($ret) {
+            Sms::flush($mobile, 'mobilelogin');
+            $user = $this->auth->getUserinfo();
+            $user['avatar'] = cdnurl($user['avatar'], true);
+            $data = ['token' => $this->auth->getToken(), 'user' => $user];
+            $this->success(__('Logged in successful'), $data);
+        } else {
+            $this->error($this->auth->getError());
+        }
+    }
+
+
+    /**
+     * 个人中心
+     */
+    public function index()
+    {
+        $info = $this->auth->getUserInfo();
+        $info['avatar'] = cdnurl($info['avatar'], true);
+        $info['gender_text'] = UserEnum::getGenderText($this->auth->getUser()->gender ?? 0);
+        $info['age'] = $this->auth->getUser()->age ?? 0;
+
+        //查询验货员申请信息
+        $inspectionApplication = InspectionService::getUserApplication($this->auth->id);
+        $info['inspection_application'] = $inspectionApplication;
+        $info['supplier'] = null;
+        // 查询供应商信息
+        $supplierId = $this->application->supplier_id;
+        if($supplierId){
+            // 查询供应商信息
+            $supplier = SupplierService::getFactoryById($supplierId);
+            $info['supplier'] = $supplier;
+        }
+        $this->success('', $info);
+    }
+
+
+    /**
+     * 个人资料
+     */
+    public function profile()
+    {
+        $user = $this->auth->getUser();
+        $params = $this->request->param();
+        
+        // 只处理实际传递的参数
+        $updateData = [];
+        
+        // 处理用户名
+        if (isset($params['username']) && $params['username'] !== '') {
+            $username = $params['username'];
+            // 检查用户名是否已存在
+            $exists = \app\common\model\User::where('username', $username)->where('id', '<>', $this->auth->id)->find();
+            if ($exists) {
+                $this->error(__('Username already exists'));
+            }
+            $updateData['username'] = $username;
+        }
+        
+        // 处理头像
+        if (isset($params['avatar'])) {
+            $avatar = $params['avatar'];
+            // 替换有域名的头像
+            $avatar = str_replace(cdnurl('', true), '', $avatar);
+            $updateData['avatar'] = $avatar;
+        }
+        
+        // 处理昵称
+        if (isset($params['nickname'])) {
+            $updateData['nickname'] = $params['nickname'];
+        }
+        
+        // 处理个人简介
+        if (isset($params['bio'])) {
+            $updateData['bio'] = $params['bio'];
+        }
+        
+        // 处理年龄
+        if (isset($params['age'])) {
+            $updateData['age'] = $params['age'];
+        }
+        
+        // 处理性别
+        if (isset($params['gender'])) {
+            $updateData['gender'] = $params['gender'];
+        }
+        
+        // 如果没有任何要更新的数据
+        if (empty($updateData)) {
+            $this->error('没有要更新的数据');
+        }
+        
+        // 验证器 - 只验证传递的参数
+        $validate = new \app\api\validate\inspection\User();
+        $validateParams = array_merge($params, isset($updateData['avatar']) ? ['avatar' => $updateData['avatar']] : []);
+        if (!$validate->check($validateParams, [], 'profile')) {
+            $this->error($validate->getError());
+        }
+        
+        // 批量更新用户信息
+        foreach ($updateData as $field => $value) {
+            $user->$field = $value;
+        }
+        $user->save();
+
+        $this->success('修改成功!');
+    }
+
+    /**
+     * 保存头像
+     */
+    public function avatar()
+    {
+        $user = $this->auth->getUser();
+        $avatar = $this->request->post('avatar');
+        if (!$avatar) {
+            $this->error("头像不能为空");
+        }
+
+        $avatar = str_replace(cdnurl('', true), '', $avatar);
+        $user->avatar = $avatar;
+        $user->save();
+        $this->success('修改成功!');
+    }
+
+    /**
+     * 注销登录
+     */
+    public function logout()
+    {
+        $this->auth->logout();
+        $this->success(__('Logout successful'), ['__token__' => $this->request->token()]);
+    }
+    /**
+     * 换绑手机号
+     */
+    public function changeMobile()
+    {
+        $params = $this->request->param();
+        $mobile = $params['mobile'] ?? '';
+        $captcha = $params['captcha'] ?? '';
+        // 验证器
+        $validate = new \app\api\validate\inspection\User();
+        if (!$validate->check($params, [], 'changeMobile')) {
+            $this->error($validate->getError());
+        }
+        $user = $this->auth->getUser();
+        if ($user->mobile == $mobile) {
+            $this->error(__('手机号不能与当前手机号相同'));
+        }
+        // 换绑手机号
+        $user = \app\common\model\User::getByMobile($mobile);
+        if ($user) {
+            $this->error(__('手机号已存在'));
+        }
+        if (!Env::get('app.app_debug') && $captcha != Env::get('app.DEFAULT_SMSCODE')) {
+            $ret = Sms::check($mobile, $captcha, 'resetpwd');
+            if (!$ret) {
+                $this->error(__('Captcha is incorrect'));
+            }
+        }
+        Sms::flush($mobile, 'resetpwd');
+        $this->auth->getUser()->save(['mobile' => $mobile]);
+        $this->success(__('换绑手机号成功'));
+    }
+
+    /**
+     * 修改密码
+     */
+    public function changePassword()
+    {
+        $params = $this->request->param();
+        $oldpassword = $params['oldpassword'] ?? '';
+        $newpassword = $params['newpassword'] ?? '';
+        $confirmpassword = $params['confirmpassword'] ?? '';
+        
+        // 验证器
+        $validate = new \app\api\validate\inspection\User();
+        if (!$validate->check($params, [], 'changePassword')) {
+            $this->error($validate->getError());
+        }
+        
+        $user = $this->auth->getUser();
+        
+        // 验证原密码是否正确
+        if ($user->password != $this->auth->getEncryptPassword($oldpassword, $user->salt)) {
+            $this->error(__('原密码错误'));
+        }
+        
+        // 检查新密码是否与原密码相同
+        if ($oldpassword === $newpassword) {
+            $this->error(__('新密码不能与原密码相同'));
+        }
+        
+        // 使用 Auth 类的 changepwd 方法修改密码
+        $ret = $this->auth->changepwd($newpassword, $oldpassword);
+        if ($ret) {
+            $this->success(__('密码修改成功'));
+        } else {
+            $this->error($this->auth->getError());
+        }
+    }
+}

+ 17 - 0
application/api/validate/Order.php

@@ -45,6 +45,11 @@ class Order extends Validate
         'start_time'      => 'date',
         'end_time'        => 'date',
         'time_range'      => 'checkTimeRange',
+        
+        // 统计相关
+        'type'            => 'require|in:day,month,year',
+        'date'            => 'require|date',
+        'days'            => 'integer|between:1,365',
     ];
 
     /**
@@ -97,6 +102,14 @@ class Order extends Validate
         'keywords.max'          => '搜索关键词长度不能超过50个字符',
         'start_time.date'       => '开始时间格式错误',
         'end_time.date'         => '结束时间格式错误',
+        
+        // 统计相关提示
+        'type.require'              => '统计类型不能为空',
+        'type.in'                   => '统计类型只能是day、month、year',
+        'date.require'              => '统计日期不能为空',
+        'date.date'                 => '统计日期格式错误',
+        'days.integer'              => '天数必须是整数',
+        'days.between'              => '天数必须在1-365之间',
     ];
 
     /**
@@ -115,6 +128,10 @@ class Order extends Validate
         'pay'               => ['order_sn', 'pay_type', 'method'],
         // 订单列表
         'lists'             => ['page', 'pageSize', 'status', 'keywords', 'start_time', 'end_time', 'time_range'],
+        
+        // 统计相关场景
+        'statistics'  => ['type', 'date'],
+        'trend'       => ['type', 'days'],
     ];
 
 

+ 316 - 0
application/api/validate/inspection/Order.php

@@ -0,0 +1,316 @@
+<?php
+
+namespace app\api\validate\inspection;
+
+use think\Validate;
+
+class Order extends Validate
+{
+    /**
+     * 验证规则
+     */
+    protected $rule = [
+        // 基础参数
+        'address_id'       => 'require|integer|gt:0',
+        'user_coupon_id'   => 'integer|gt:0',
+        'memo'            => 'max:500',
+        
+        // 购物车相关
+        'ids'             => 'require|array',
+        'cart_ids'        => 'require|array',
+        
+        // 商品列表相关
+        'goods_list'      => 'require|array|checkGoodsList',
+        'goods_list.*.goods_id'     => 'require|integer|gt:0',
+        'goods_list.*.goods_sku_id' => 'integer|egt:0',
+        'goods_list.*.nums'         => 'require|integer|gt:0',
+        
+        // 计算订单数据验证
+        'calculate_data'  => 'checkCalculateData',
+        
+        // 创建订单数据验证
+        'create_data'     => 'checkCreateData',
+        
+        // 订单操作相关
+        'order_sn'        => 'require|alphaNum',
+        'orderId'        => 'require|integer|gt:0',
+        'pay_type'         => 'require|in:alipay,wechat,unionpay,balance',
+        'method'          => 'require|in:web,wap,app,miniapp,mp,mini',
+        
+        // 订单列表查询相关
+        'page'            => 'integer|egt:1',
+        'page_size'        => 'integer|between:1,100',
+        'status'          => 'checkOrderStatus',
+        'keywords'        => 'max:50',
+        'start_time'      => 'date',
+        'end_time'        => 'date',
+        'time_range'      => 'checkTimeRange',
+        
+        // 统计相关
+        'type'            => 'require|in:day,month,year',
+        'date'            => 'require|date',
+        'days'            => 'integer|between:1,365',
+    ];
+
+    /**
+     * 提示消息
+     */
+    protected $message = [
+        // 基础参数
+        'address_id.require'    => '收货地址不能为空',
+        'address_id.integer'    => '收货地址ID必须是整数',
+        'address_id.gt'         => '收货地址ID必须大于0',
+        'address_id.egt'        => '收货地址ID格式错误',
+        'user_coupon_id.integer' => '优惠券ID必须是整数',
+        'user_coupon_id.gt'     => '优惠券ID必须大于0',
+        'memo.max'              => '备注长度不能超过500个字符',
+        
+        // 购物车相关
+        'ids.require'           => '请选择商品',
+        'ids.array'             => '商品选择参数格式错误',
+        'cart_ids.require'      => '购物车ID不能为空',
+        'cart_ids.array'        => '购物车ID必须是数组',
+        
+        // 商品列表相关
+        'goods_list.require'    => '商品列表不能为空',
+        'goods_list.array'      => '商品列表必须是数组',
+        'goods_list.*.goods_id.require' => '商品ID不能为空',
+        'goods_list.*.goods_id.integer' => '商品ID必须是整数',
+        'goods_list.*.goods_id.gt'      => '商品ID必须大于0',
+        'goods_list.*.goods_sku_id.integer' => '商品规格ID必须是整数',
+        'goods_list.*.goods_sku_id.egt'     => '商品规格ID必须大于或等于0',
+        'goods_list.*.nums.require'     => '商品数量不能为空',
+        'goods_list.*.nums.integer'     => '商品数量必须是整数',
+        'goods_list.*.nums.gt'          => '商品数量必须大于0',
+        
+        // 订单操作相关
+        'order_sn.require'      => '订单号不能为空',
+        'order_sn.alphaNum'     => '订单号格式错误',
+        'orderId.require'       => '订单ID不能为空',
+        'orderId.integer'       => '订单ID必须是整数',
+        'orderId.gt'            => '订单ID必须大于0',
+        'pay_type.require'       => '支付方式不能为空',
+        'pay_type.in'            => '支付方式不支持',
+        'method.require'        => '支付方法不能为空',
+        'method.in'             => '支付方法不支持',
+
+        // 订单列表查询相关
+        'page.integer'          => '页码必须是整数',
+        'page.egt'              => '页码必须大于等于1',
+        'pageSize.integer'      => '每页数量必须是整数',
+        'pageSize.between'      => '每页数量必须在1-100之间',
+        'keywords.max'          => '搜索关键词长度不能超过50个字符',
+        'start_time.date'       => '开始时间格式错误',
+        'end_time.date'         => '结束时间格式错误',
+        
+        // 统计相关提示
+        'type.require'              => '统计类型不能为空',
+        'type.in'                   => '统计类型只能是day、month、year',
+        'date.require'              => '统计日期不能为空',
+        'date.date'                 => '统计日期格式错误',
+        'days.integer'              => '天数必须是整数',
+        'days.between'              => '天数必须在1-365之间',
+    ];
+
+    /**
+     * 验证场景
+     */
+    protected $scene = [
+        // 统一创建订单接口(支持购物车和商品规格两种模式)
+        'create'            => ['address_id', 'user_coupon_id', 'memo', 'create_data'],
+        // 计算订单(支持购物车和商品规格两种模式) 地址不是必填
+        'calculate'         => ['address_id' => 'integer|egt:0', 'user_coupon_id', 'calculate_data'],
+        // 订单详情、确认收货、查询物流
+        'detail'            => ['orderId'],
+        // 取消订单
+        'cancel'            => ['orderId'],
+        // 订单支付
+        'pay'               => ['order_sn', 'pay_type', 'method'],
+        // 订单列表
+        'lists'             => ['page', 'page_size', 'status', 'keywords', 'start_time', 'end_time', 'time_range'],
+        
+        // 统计相关场景
+        'statistics'  => ['type', 'date'],
+        'trend'       => ['type', 'days'],
+    ];
+
+
+
+    /**
+     * 自定义验证规则:验证商品列表格式
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     */
+    protected function checkGoodsList($value, $rule, $data)
+    {
+        if (!is_array($value)) {
+            return '商品列表必须是数组';
+        }
+        
+        if (empty($value)) {
+            return '商品列表不能为空';
+        }
+        
+        foreach ($value as $index => $item) {
+            if (!is_array($item)) {
+                return "商品列表第" . ($index + 1) . "项格式错误";
+            }
+            
+            // 验证必要字段
+            if (!isset($item['goods_id']) || !is_numeric($item['goods_id']) || $item['goods_id'] <= 0) {
+                return "商品列表第" . ($index + 1) . "项的商品ID无效";
+            }
+            
+            if (!isset($item['nums']) || !is_numeric($item['nums']) || $item['nums'] <= 0) {
+                return "商品列表第" . ($index + 1) . "项的数量无效";
+            }
+            
+            // 验证可选字段
+            if (isset($item['goods_sku_id']) && (!is_numeric($item['goods_sku_id']) || $item['goods_sku_id'] < 0)) {
+                return "商品列表第" . ($index + 1) . "项的规格ID无效";
+            }
+        }
+        
+        return true;
+    }
+
+    /**
+     * 自定义验证规则:验证计算订单参数
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     */
+    protected function checkCalculateData($value, $rule, $data)
+    {
+        // 必须提供购物车ID或商品列表其中之一
+        $hasCartIds = isset($data['cart_ids']) && is_array($data['cart_ids']) && !empty($data['cart_ids']);
+        $hasGoodsList = isset($data['goods_list']) && is_array($data['goods_list']) && !empty($data['goods_list']);
+        
+        if (!$hasCartIds && !$hasGoodsList) {
+            return '请提供购物车ID或商品列表';
+        }
+        
+        // if ($hasCartIds && $hasGoodsList) {
+        //     return '不能同时提供购物车ID和商品列表';
+        // }
+        
+        // 验证购物车ID格式
+        if ($hasCartIds) {
+            foreach ($data['cart_ids'] as $index => $cart_id) {
+                if (!is_numeric($cart_id) || $cart_id <= 0) {
+                    return "购物车ID第" . ($index + 1) . "项格式错误";
+                }
+            }
+        }
+        
+        // 验证商品列表格式
+        if ($hasGoodsList) {
+            $result = $this->checkGoodsList($data['goods_list'], '', $data);
+            if ($result !== true) {
+                return $result;
+            }
+        }
+        
+        return true;
+    }
+
+    /**
+     * 自定义验证规则:验证创建订单参数
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     */
+    protected function checkCreateData($value, $rule, $data)
+    {
+        // 必须提供购物车ID或商品列表其中之一
+        $hasCartIds = isset($data['cart_ids']) && is_array($data['cart_ids']) && !empty($data['cart_ids']);
+        $hasGoodsList = isset($data['goods_list']) && is_array($data['goods_list']) && !empty($data['goods_list']);
+        
+        if (!$hasCartIds && !$hasGoodsList) {
+            return '请提供购物车ID或商品列表';
+        }
+        
+        if ($hasCartIds && $hasGoodsList) {
+            return '不能同时提供购物车ID和商品列表';
+        }
+        
+        // 验证购物车ID格式
+        if ($hasCartIds) {
+            foreach ($data['cart_ids'] as $index => $cart_id) {
+                if (!is_numeric($cart_id) || $cart_id <= 0) {
+                    return "购物车ID第" . ($index + 1) . "项格式错误";
+                }
+            }
+        }
+        
+        // 验证商品列表格式
+        if ($hasGoodsList) {
+            $result = $this->checkGoodsList($data['goods_list'], '', $data);
+            if ($result !== true) {
+                return $result;
+            }
+        }
+        
+        return true;
+    }
+
+    /**
+     * 自定义验证规则:验证时间范围
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     */
+    protected function checkTimeRange($value, $rule, $data)
+    {
+        // 如果提供了开始时间和结束时间,验证时间范围
+        if (isset($data['start_time']) && isset($data['end_time'])) {
+            $startTime = strtotime($data['start_time']);
+            $endTime = strtotime($data['end_time']);
+            
+            if ($startTime === false) {
+                return '开始时间格式错误';
+            }
+            
+            if ($endTime === false) {
+                return '结束时间格式错误';
+            }
+            
+            if ($startTime > $endTime) {
+                return '开始时间不能大于结束时间';
+            }
+            
+            // 限制查询时间范围不超过1年
+            $maxRange = 365 * 24 * 3600; // 1年的秒数
+            if (($endTime - $startTime) > $maxRange) {
+                return '查询时间范围不能超过1年';
+            }
+        }
+        
+        return true;
+    }
+
+    /**
+     * 自定义验证规则:验证订单状态
+     * @param $value
+     * @param $rule
+     * @param $data
+     * @return bool|string
+     */
+    protected function checkOrderStatus($value, $rule, $data)
+    {
+        // 引入OrderEnum
+        $allowedStatuses = array_keys(\app\common\Enum\OrderEnum::SHOW_TYPE_STATUS_MAP);
+        
+        if (!in_array($value, $allowedStatuses)) {
+            $allowedValues = implode(', ', $allowedStatuses);
+            return "订单状态值不正确,允许的值为:{$allowedValues}";
+        }
+        
+        return true;
+    }
+} 

+ 99 - 0
application/api/validate/inspection/User.php

@@ -0,0 +1,99 @@
+<?php
+
+namespace app\api\validate\inspection;
+
+use think\Validate;
+use app\common\Enum\UserEnum;
+
+class User extends Validate
+{
+
+    public function __construct(array $rules = [], $message = [], $field = [])
+    {
+        // 动态设置枚举值
+        $this->rule['gender'] = 'in:' .implode(',', UserEnum::getGenderList());
+        parent::__construct($rules, $message, $field);
+    }
+    
+    /**
+     * 验证规则
+     */
+    protected $rule = [
+        'account'   => 'length:3,30',
+        'username'  => 'length:3,30',
+        'nickname'  => 'length:3,30',
+        'password'  => 'length:6,30',
+        'oldpassword' => 'require|length:6,30',
+        'newpassword' => 'require|length:6,30',
+        'confirmpassword' => 'require|length:6,30|confirm:newpassword',
+        'mobile'    => 'require|regex:/^1\d{10}$/',
+        'email'     => 'email',
+        'avatar'    => [
+            'require',
+            'regex'=>'/\\.(jpg|jpeg|png|gif|bmp|webp)$/i'
+        ],
+        'bio'       => 'max:255',
+        'money'     => 'float|egt:0',
+        'balance'   => 'float|egt:0',
+        'score'     => 'integer|egt:0',
+        'level'     => 'integer|egt:0',
+        'age'       => 'integer|egt:0|elt:200', 
+        'captcha'   => 'require|length:4,6'
+    ];
+
+    /**
+     * 提示消息
+     */
+    protected $message = [
+        'account.require'   => '账号不能为空',
+        'account.length'    => '账号长度必须在3-30个字符之间',
+        'username.length'   => '用户名长度必须在3-30个字符之间',
+        'nickname.require'  => '昵称不能为空',
+        'nickname.length'   => '昵称长度必须在3-30个字符之间',
+        'password.require'  => '密码不能为空',
+        'password.length'   => '密码长度必须在6-30个字符之间',
+        'oldpassword.require' => '原密码不能为空',
+        'oldpassword.length' => '原密码长度必须在6-30个字符之间',
+        'newpassword.require' => '新密码不能为空',
+        'newpassword.length' => '新密码长度必须在6-30个字符之间',
+        'confirmpassword.require' => '确认密码不能为空',
+        'confirmpassword.length' => '确认密码长度必须在6-30个字符之间',
+        'confirmpassword.confirm' => '确认密码与新密码不一致',
+        'mobile.regex'      => '手机号格式不正确',
+        'mobile.require'    => '手机号不能为空',
+        'email'             => '邮箱格式不正确',
+        'avatar.require'    => '头像不能为空',
+        'avatar.regex'      => '头像格式不正确',
+        'gender.in'         => '性别只能是未知、男、女',
+        'gender.require'    => '性别不能为空',
+        'age.require'       => '年龄不能为空',
+        'age.integer'       => '年龄必须是整数',
+        'age.egt'           => '年龄不能为负数',
+        'age.elt'           => '年龄不能大于200',
+        'bio.max'           => '个人简介最多255个字符',
+        'money.float'       => '余额必须是数字',
+        'money.egt'         => '余额不能为负数',
+        'balance.float'     => '余额必须是数字',
+        'balance.egt'       => '余额不能为负数',
+        'score.integer'     => '积分必须是整数',
+        'score.egt'         => '积分不能为负数',
+        'level.integer'     => '等级必须是整数',
+        'level.egt'         => '等级不能为负数',
+        'captcha.require'   => '验证码不能为空',
+        'captcha.length'    => '验证码长度不正确'
+    ];
+
+    /**
+     * 验证场景
+     */
+    protected $scene = [
+        'register'  => ['username', 'password', 'mobile', 'captcha'],
+        'login'     => ['account', 'password'],
+        'mobilelogin' => ['mobile', 'captcha'],
+        'mobilePasswordLogin' => ['mobile', 'password'],
+        'unifiedLogin' => ['mobile'], // 统一登录,只验证手机号必须,其他根据登录类型动态验证
+        'profile'   => ['username', 'nickname', 'bio', 'avatar','age','gender'],
+        'changeMobile' => ['mobile', 'captcha'],
+        'changePassword' => ['oldpassword', 'newpassword', 'confirmpassword'],
+    ];
+} 

+ 33 - 17
application/common/Enum/OrderEnum.php

@@ -9,6 +9,14 @@ class OrderEnum
      */
     const STATUS_CREATE = 101;
     const STATUS_PAY = 201;
+
+    // 验货后 在发货
+    const STATUS_INSPECTION = 210;
+    // 验货通过
+    const STATUS_INSPECTION_PASS = 211;
+    // 验货不通过   
+    const STATUS_INSPECTION_FAIL = 212;
+    // 发货
     const STATUS_SHIP = 301;
     const STATUS_CONFIRM = 401;
     const STATUS_COMMENT = 501;
@@ -20,9 +28,7 @@ class OrderEnum
     const STATUS_GROUPON_TIMEOUT = 204;
     const STATUS_AUTO_CONFIRM = 402;
 
-    // pay_mode 支付模式:online=线上支付,offline=线下支付
-    const PAY_MODE_ONLINE = 'online';
-    const PAY_MODE_OFFLINE = 'offline';
+    
 
     // 订单类型
     const TYPE_NORMAL = 1;      // 普通订单
@@ -50,20 +56,6 @@ class OrderEnum
     const ACTIVITY_TYPE_DISCOUNT = 'discount';   // 折扣活动
 
 
-
-    public static function getPayModeList()
-    {
-        return [
-            self::PAY_MODE_ONLINE => '线上支付',
-            self::PAY_MODE_OFFLINE => '线下支付',
-        ];
-    }
-
-    public static function getPayModeText($pay_mode)
-    {
-        return self::getPayModeList()[$pay_mode] ?? '未知';
-    }
-
     public static function getOrderTypeList()
     {
         return [
@@ -133,6 +125,9 @@ class OrderEnum
         self::STATUS_CANCEL => "已取消",
         self::STATUS_AUTO_CANCEL => "已取消(系统)",
         self::STATUS_ADMIN_CANCEL => "已取消(管理员)",
+        self::STATUS_INSPECTION => "待验货",
+        self::STATUS_INSPECTION_PASS => "验货通过",
+        self::STATUS_INSPECTION_FAIL => "验货不通过",
         self::STATUS_PAY => "待发货",
         // self::STATUS_REFUND => "订单取消,退款中",
         // self::STATUS_REFUND_CONFIRM => "已退款",
@@ -188,5 +183,26 @@ class OrderEnum
         self::SHOW_TYPE_WAIT_COMMENT => [self::STATUS_CONFIRM],
     ];
 
+    const SHOW_INSPECTION_TYPE_STATUS_MAP = [
+        self::SHOW_TYPE_WAIT_PAY => [self::STATUS_CREATE],
+        self::SHOW_TYPE_WAIT_DELIVERY => [self::STATUS_INSPECTION_PASS],
+        self::SHOW_TYPE_WAIT_RECEIPT => [self::STATUS_SHIP],
+        self::SHOW_TYPE_WAIT_COMMENT => [self::STATUS_CONFIRM],
+    ];
+
+    const SHOW_INSPECTION_STATUS_TEXT_MAP = [
+        self::STATUS_CREATE => '未付款',
+        self::STATUS_CANCEL => "已取消",
+        self::STATUS_AUTO_CANCEL => "已取消(系统)",
+        self::STATUS_ADMIN_CANCEL => "已取消(管理员)",
+        self::STATUS_PAY => "待验货",
+        self::STATUS_INSPECTION_PASS => "验货通过",
+        self::STATUS_INSPECTION_FAIL => "验货不通过",      
+        self::STATUS_SHIP => "待收货",
+        self::STATUS_CONFIRM => "已完成",
+        self::STATUS_AUTO_CONFIRM => "已收货(系统)",
+        self::STATUS_COMMENT => "已评价",
+    ];
+
 
 }

+ 392 - 0
application/common/Service/InspectService.php

@@ -0,0 +1,392 @@
+<?php
+
+namespace app\common\Service;
+
+
+use think\Db;
+
+class InspectService
+{
+    /**
+     * 获取验货选项列表
+     * @param array $params 查询参数
+     * @return array
+     */
+    public static function getInspectionItems($params = [])
+    {
+        $where = [];
+        
+        // 父级ID筛选
+        if (isset($params['parent_id'])) {
+            $where['parent_id'] = $params['parent_id'];
+        }
+        
+        // 状态筛选
+        if (isset($params['status']) && $params['status'] !== '') {
+            $where['status'] = $params['status'];
+        }
+        
+        // 是否必检项筛选
+        if (isset($params['is_required']) && $params['is_required'] !== '') {
+            $where['is_required'] = $params['is_required'];
+        }
+        
+        // 名称搜索
+        if (isset($params['name']) && $params['name'] !== '') {
+            $where['name'] = ['like', '%' . $params['name'] . '%'];
+        }
+        
+        $query = (new \app\common\model\inspection\Item())->where($where)
+          ->field('id,name,parent_id,is_required,status,standard_desc');
+        
+        // 排序
+        $order = isset($params['order']) ? $params['order'] : 'id ASC';
+        $query->order($order);
+        
+        // 分页处理
+        if (isset($params['page']) && isset($params['page_size'])) {
+            $result = $query->paginate([
+                'page' => $params['page'],
+                'list_rows' => $params['page_size']
+            ]);
+            return $result;
+        }
+        
+        return $query->select();
+    }
+    
+    /**
+     * 获取树形结构的验货选项
+     * @param array $params 查询参数
+     * @return array
+     */
+    public function getInspectionItemTree($params = [])
+    {
+        // 获取所有选项
+        $allItems = $this->getInspectionItems($params);
+        
+        if (is_object($allItems)) {
+            // 分页对象转数组
+            $allItems = $allItems->toArray()['data'];
+        }
+        
+        return $this->buildTree($allItems);
+    }
+    
+    /**
+     * 构建树形结构
+     * @param array $items 选项数组
+     * @param int $parentId 父级ID
+     * @return array
+     */
+    private function buildTree($items, $parentId = 0)
+    {
+        $tree = [];
+        
+        foreach ($items as $item) {
+            if ($item['parent_id'] == $parentId) {
+                $children = $this->buildTree($items, $item['id']);
+                if (!empty($children)) {
+                    $item['children'] = $children;
+                }
+                $tree[] = $item;
+            }
+        }
+        
+        return $tree;
+    }
+    
+    /**
+     * 根据ID获取验货选项详情
+     * @param int $id 选项ID
+     * @return array|null
+     */
+    public function getInspectionItemById($id)
+    {
+        return Db::name('inspection_item')
+            ->where('id', $id)
+            ->where('deletetime', 'exp', 'IS NULL')
+            ->find();
+    }
+    
+    /**
+     * 获取必检项列表
+     * @param array $params 查询参数
+     * @return array
+     */
+    public function getRequiredItems($params = [])
+    {
+        $params['is_required'] = 1;
+        return $this->getInspectionItems($params);
+    }
+    
+    /**
+     * 获取顶级选项(parent_id = 0)
+     * @param array $params 查询参数
+     * @return array
+     */
+    public function getTopLevelItems($params = [])
+    {
+        $params['parent_id'] = 0;
+        return $this->getInspectionItems($params);
+    }
+    
+    /**
+     * 获取指定父级下的子选项
+     * @param int $parentId 父级ID
+     * @param array $params 其他查询参数
+     * @return array
+     */
+    public function getChildItems($parentId, $params = [])
+    {
+        $params['parent_id'] = $parentId;
+        return $this->getInspectionItems($params);
+    }
+    
+    /**
+     * 搜索验货选项
+     * @param string $keyword 搜索关键词
+     * @param array $params 其他查询参数
+     * @return array
+     */
+    public function searchItems($keyword, $params = [])
+    {
+        $params['name'] = $keyword;
+        return $this->getInspectionItems($params);
+    }
+
+
+    //  提交验货 记录
+    
+    /**
+     * 提交验货任务
+     * @param array $taskData 任务数据
+     * @param array $resultData 验货结果数据
+     * @return array
+     */
+    public static function submitInspectionTask($taskData, $resultData)
+    {
+        Db::startTrans();
+        
+        try {
+            // 1. 创建或更新验货任务
+            $taskId = self::saveInspectionTask($taskData);
+            
+            if (!$taskId) {
+                throw new \Exception('验货任务创建失败');
+            }
+            
+            // 2. 保存验货结果
+            if (!empty($resultData)) {
+                foreach ($resultData as $result) {
+                    $result['task_id'] = $taskId;
+                    $resultId = self::saveInspectionResult($result);
+                    
+                    // 3. 保存验货照片
+                    if (!empty($result['photos'])) {
+                        self::saveInspectionPhotos($resultId, $result['photos']);
+                    }
+                }
+            }
+            
+            // 4. 更新任务状态为已完成
+            self::updateTaskStatus($taskId, 2); // 2:已完成
+            
+            Db::commit();
+            
+            return [
+                'code' => 1,
+                'msg' => '验货任务提交成功',
+                'data' => ['task_id' => $taskId]
+            ];
+            
+        } catch (\Exception $e) {
+            Db::rollback();
+            return [
+                'code' => 0,
+                'msg' => '验货任务提交失败:' . $e->getMessage(),
+                'data' => []
+            ];
+        }
+    }
+    
+    /**
+     * 保存验货任务
+     * @param array $taskData 任务数据
+     * @return int 任务ID
+     */
+    private static function saveInspectionTask($taskData)
+    {
+        $data = [
+            'order_id' => $taskData['order_id'] ?? 0,
+            'inspector_id' => $taskData['inspector_id'] ?? 0,
+            'remark' => $taskData['remark'] ?? '',
+            'images' => $taskData['images'] ?? '',
+            'start_time' => $taskData['start_time'] ?? time(),
+            'end_time' => $taskData['end_time'] ?? time(),
+            'task_status' => $taskData['task_status'] ?? 1,
+            'status' => $taskData['status'] ?? 1,
+            'updatetime' => time()
+        ];
+        
+        // 如果提供了task_id,则更新,否则创建
+        if (isset($taskData['task_id']) && $taskData['task_id'] > 0) {
+            $result = Db::table('inspection_task')
+                ->where('id', $taskData['task_id'])
+                ->update($data);
+            return $result ? $taskData['task_id'] : false;
+        } else {
+            $data['createtime'] = time();
+            return Db::table('inspection_task')->insertGetId($data);
+        }
+    }
+    
+    /**
+     * 保存验货结果
+     * @param array $resultData 结果数据
+     * @return int 结果ID
+     */
+    private static function saveInspectionResult($resultData)
+    {
+        $data = [
+            'task_id' => $resultData['task_id'],
+            'item_id' => $resultData['item_id'],
+            'name' => $resultData['name'] ?? '',
+            'is_qualified' => $resultData['is_qualified'] ?? 1,
+            'remark' => $resultData['remark'] ?? '',
+            'status' => $resultData['status'] ?? 1,
+            'createtime' => time(),
+            'updatetime' => time()
+        ];
+        
+        return Db::table('inspection_result')->insertGetId($data);
+    }
+    
+    /**
+     * 保存验货照片
+     * @param int $resultId 结果ID
+     * @param array $photos 照片数组
+     * @return bool
+     */
+    private static function saveInspectionPhotos($resultId, $photos)
+    {
+        if (empty($photos) || !is_array($photos)) {
+            return true;
+        }
+        
+        $photoData = [];
+        foreach ($photos as $photo) {
+            $photoData[] = [
+                'result_id' => $resultId,
+                'photo_url' => $photo['photo_url'] ?? $photo,
+                'upload_time' => $photo['upload_time'] ?? time(),
+                'status' => $photo['status'] ?? 1,
+                'createtime' => time(),
+                'updatetime' => time()
+            ];
+        }
+        
+        return Db::table('inspection_photo')->insertAll($photoData);
+    }
+    
+    /**
+     * 更新任务状态
+     * @param int $taskId 任务ID
+     * @param int $status 状态 1:进行中 2:已完成
+     * @return bool
+     */
+    private static function updateTaskStatus($taskId, $status)
+    {
+        return Db::table('inspection_task')
+            ->where('id', $taskId)
+            ->update([
+                'task_status' => $status,
+                'end_time' => time(),
+                'updatetime' => time()
+            ]);
+    }
+    
+    /**
+     * 获取验货任务详情
+     * @param int $taskId 任务ID
+     * @return array|null
+     */
+    public static function getInspectionTaskDetail($taskId)
+    {
+        // 获取任务基本信息
+        $task = Db::table('inspection_task')
+            ->where('id', $taskId)
+            ->where('deletetime', 'exp', 'IS NULL')
+            ->find();
+            
+        if (!$task) {
+            return null;
+        }
+        
+        // 获取验货结果
+        $results = Db::table('inspection_result')
+            ->where('task_id', $taskId)
+            ->where('deletetime', 'exp', 'IS NULL')
+            ->select();
+            
+        // 为每个结果获取照片
+        foreach ($results as &$result) {
+            $photos = Db::table('inspection_photo')
+                ->where('result_id', $result['id'])
+                ->where('deletetime', 'exp', 'IS NULL')
+                ->select();
+            $result['photos'] = $photos;
+        }
+        
+        $task['results'] = $results;
+        
+        return $task;
+    }
+    
+    /**
+     * 获取验货任务列表
+     * @param array $params 查询参数
+     * @return array
+     */
+    public static function getInspectionTaskList($params = [])
+    {
+        $where = [];
+        $where['deletetime'] = ['exp', 'IS NULL'];
+        
+        // 验货员ID筛选
+        if (isset($params['inspector_id']) && $params['inspector_id'] > 0) {
+            $where['inspector_id'] = $params['inspector_id'];
+        }
+        
+        // 订单ID筛选
+        if (isset($params['order_id']) && $params['order_id'] > 0) {
+            $where['order_id'] = $params['order_id'];
+        }
+        
+        // 任务状态筛选
+        if (isset($params['task_status']) && $params['task_status'] !== '') {
+            $where['task_status'] = $params['task_status'];
+        }
+        
+        // 时间范围筛选
+        if (isset($params['start_time']) && isset($params['end_time'])) {
+            $where['createtime'] = ['between', [$params['start_time'], $params['end_time']]];
+        }
+        
+        $query = Db::name('inspection_task')->where($where);
+        
+        // 排序
+        $order = $params['order'] ?? 'createtime DESC';
+        $query->order($order);
+        
+        // 分页处理
+        if (isset($params['page']) && isset($params['page_size'])) {
+            return $query->paginate([
+                'page' => $params['page'],
+                'list_rows' => $params['page_size']
+            ]);
+        }
+        
+        return $query->select();
+    }
+}

+ 21 - 0
application/common/Service/InspectionService.php

@@ -92,6 +92,27 @@ class InspectionService
     }
 
     /**
+     * 查询用户申请信息
+     * @param int $userId 用户ID
+     * @param bool $withUser 是否关联用户信息
+     * @return InspectionApplication|null
+     */
+    public static function getUserApplication($userId, $withUser = false,$withSupplier = false)
+    {
+        $query = InspectionApplication::where('user_id', $userId);
+        
+        if ($withUser) {
+            $query->with(['user']);
+        }
+        if ($withSupplier) {
+            $query->with(['supplier']);
+        }
+        return $query->order('id', 'desc')->find();
+    }
+
+ 
+
+    /**
      * 修改申请信息
      * @param int $applicationId 申请ID
      * @param int $userId 用户ID

+ 8 - 3
application/common/Service/OrderService.php

@@ -209,6 +209,7 @@ class OrderService
                 // 添加分类和品牌信息用于优惠券计算 (临时字段,不会保存到数据库)
                 // 'category_id'          => $item->goods->category_ids,
                 'brand_id'             => $item->goods->brand_id,
+                'supplier_id'          => $item->goods->supplier_id,
             ];
             
             $orderItem[] = $orderItemData;
@@ -386,7 +387,6 @@ class OrderService
                 $item['goods_price'] = $saleprice;
             }
             unset($item);
-            
             // 批量创建订单商品数据
             if (!empty($orderItem)) {
                 (new OrderGoods())->saveAll($orderItem);
@@ -501,9 +501,9 @@ class OrderService
      * @param $param
      * @return \think\Paginator
      */
-    public static function getOrderList($userId = 0, $param =[],$status = [])
+    public static function getOrderList($userId = 0, $param =[],$status = [],$supplierId = 0)
     {
-        $pageSize = 15;
+        $pageSize = 10;
         if (!empty($param['pageSize'])) {
             $pageSize = $param['pageSize'];
         }
@@ -523,6 +523,11 @@ class OrderService
                         return $query->name('shop_order_goods')->where('order_sn|goods_title', 'like', '%' . $param['q'] . '%')->field('order_sn');
                     });
                 }
+                if (!empty($supplierId)) {
+                    $query->where('order_sn', 'in', function ($query) use ($supplierId) {
+                        return $query->name('shop_order_goods')->where('supplier_id', $supplierId)->field('order_sn');
+                    }); 
+                }
             })
             ->order('createtime desc')
             ->paginate($pageSize, false, ['query' => request()->get()]);

+ 252 - 0
application/common/Service/SupplierService.php

@@ -0,0 +1,252 @@
+<?php
+
+/**
+ * 供应商服务类
+ * 
+ * 使用示例:
+ * 
+ * // 获取单例实例
+ * $supplierService = \app\common\Service\Supplier::getInstance();
+ * 
+ * // 或者直接实例化(普通方式)
+ * $supplierService = new \app\common\Service\Supplier();
+ * 
+ * // 获取供应商列表
+ * $list = $supplierService->getFactoryList(['name' => '测试', 'page' => 1, 'limit' => 10]);
+ * 
+ * // 获取供应商详情
+ * $detail = $supplierService->getFactoryById(1);
+ * 
+ * // 获取启用状态的供应商
+ * $activeList = $supplierService->getActiveFactoryList();
+ * 
+ * // 获取启用状态的供应商(带缓存)
+ * $activeListCached = $supplierService->getActiveFactoryListWithCache(7200);
+ * 
+ * // 搜索供应商
+ * $searchResult = $supplierService->searchFactory('关键词', 20);
+ * 
+ * // 获取统计信息
+ * $stats = $supplierService->getFactoryStats();
+ * 
+ * // 获取下拉选项
+ * $options = $supplierService->getFactoryOptions();
+ * 
+ * // 清除缓存
+ * $supplierService->clearCache();
+ */
+
+namespace app\common\Service;
+
+use app\common\model\supplier\Index as SupplierModel;
+use think\Db;
+use think\Cache;
+
+class SupplierService
+{
+    /**
+     * 单例实例
+     * @var self
+     */
+    private static $instance = null;
+    
+    /**
+     * 获取单例实例
+     * @return self
+     */
+    public static function getInstance()
+    {
+        if (self::$instance === null) {
+            self::$instance = new self();
+        }
+        return self::$instance;
+    }
+    
+    /**
+     * 构造函数
+     */
+    public function __construct()
+    {
+        // 初始化代码
+    }
+    
+    /**
+     * 查询工厂/供应商列表
+     * @param array $params 查询参数
+     * @return array
+     */
+    public function getFactoryList($params = [])
+    {
+        $where = [];
+        $page = $params['page'] ?? 1;
+        $limit = $params['limit'] ?? 10;
+        
+        // 搜索条件
+        if (!empty($params['name'])) {
+            $where[] = ['name', 'like', '%' . $params['name'] . '%'];
+        }
+        
+        if (!empty($params['category_id'])) {
+            $where[] = ['category_id', '=', $params['category_id']];
+        }
+        
+        if (!empty($params['status'])) {
+            $where[] = ['status', '=', $params['status']];
+        }
+        
+        // 查询数据
+        $list = SupplierModel::with(['category'])
+            ->where($where)
+            ->order('weigh desc, id desc')
+            ->paginate($limit, false, ['page' => $page]);
+            
+        return [
+            'list' => $list->items(),
+            'total' => $list->total(),
+            'page' => $page,
+            'limit' => $limit
+        ];
+    }
+    
+    /**
+     * 根据ID获取工厂/供应商详情
+     * @param int $id 供应商ID
+     * @return array|null
+     */
+    public static function getFactoryById($id)
+    {
+        return SupplierModel::where('id', $id)->find();
+    }
+    
+    /**
+     * 获取启用状态的工厂/供应商列表
+     * @return array
+     */
+    public function getActiveFactoryList()
+    {
+        return SupplierModel::where('status', 'normal')
+            ->order('weigh desc, id desc')
+            ->select();
+    }
+    
+    /**
+     * 获取启用状态的工厂/供应商列表(带缓存)
+     * @param int $expire 缓存时间(秒),默认3600秒
+     * @return array
+     */
+    public function getActiveFactoryListWithCache($expire = 3600)
+    {
+        $cacheKey = 'supplier:active_list';
+        
+        $list = Cache::get($cacheKey);
+        if ($list === null) {
+            $list = SupplierModel::where('status', 'normal')
+                ->order('weigh desc, id desc')
+                ->select();
+            Cache::set($cacheKey, $list, $expire);
+        }
+        
+        return $list;
+    }
+    
+    /**
+     * 根据分类ID获取工厂/供应商列表
+     * @param int $categoryId 分类ID
+     * @return array
+     */
+    public function getFactoryByCategoryId($categoryId)
+    {
+        return SupplierModel::where('category_id', $categoryId)
+            ->where('status', 'normal')
+            ->order('weigh desc, id desc')
+            ->select();
+    }
+    
+    /**
+     * 搜索工厂/供应商
+     * @param string $keyword 关键词
+     * @param int $limit 限制数量
+     * @return array
+     */
+    public function searchFactory($keyword, $limit = 10)
+    {
+        return SupplierModel::where('name', 'like', '%' . $keyword . '%')
+            ->where('status', 'normal')
+            ->limit($limit)
+            ->order('weigh desc, id desc')
+            ->select();
+    }
+    
+    /**
+     * 获取供应商统计信息
+     * @return array
+     */
+    public function getFactoryStats()
+    {
+        $total = SupplierModel::count();
+        $active = SupplierModel::where('status', 'normal')->count();
+        $hidden = SupplierModel::where('status', 'hidden')->count();
+        
+        return [
+            'total' => $total,
+            'active' => $active,
+            'hidden' => $hidden
+        ];
+    }
+    
+    /**
+     * 获取供应商选项列表(用于下拉选择)
+     * @return array
+     */
+    public function getFactoryOptions()
+    {
+        $options = SupplierModel::getOptions();
+        return $options;
+    }
+    
+    /**
+     * 批量更新供应商状态
+     * @param array $ids 供应商ID数组
+     * @param string $status 状态
+     * @return bool
+     */
+    public function batchUpdateStatus($ids, $status)
+    {
+        if (empty($ids) || !in_array($status, ['normal', 'hidden'])) {
+            return false;
+        }
+        
+        return SupplierModel::where('id', 'in', $ids)->update(['status' => $status]);
+    }
+    
+    /**
+     * 根据联系方式查找供应商
+     * @param string $contact 联系方式(手机号或座机)
+     * @return mixed
+     */
+    public function getFactoryByContact($contact)
+    {
+        return SupplierModel::where('mobile', $contact)
+            ->whereOr('landline', $contact)
+            ->find();
+    }
+    
+    /**
+     * 清除供应商相关缓存
+     * @return bool
+     */
+    public function clearCache()
+    {
+        $cacheKeys = [
+            'supplier:active_list',
+            'supplier:options',
+            'supplier:stats'
+        ];
+        
+        foreach ($cacheKeys as $key) {
+            Cache::rm($key);
+        }
+        
+        return true;
+    }
+}

+ 7 - 157
application/common/model/Order.php

@@ -30,9 +30,9 @@ class Order extends Model
     protected $updateTime = 'updatetime';
     protected $deleteTime = 'deletetime';
     // 追加属性
-    protected $append = [
-        'order_status_text',
-    ];
+    // protected $append = [
+    //     'order_status_text',
+    // ];
     protected static $config = [];
 
     protected static $tagCount = 0;
@@ -42,160 +42,10 @@ class Order extends Model
         $config = get_addon_config('shop');
         self::$config = $config;
     }
-    public function getOrderStatusTextAttr($value, $data)
-    {
-        return OrderEnum::getOrderStatusText($data['order_status']);
-    }
-    /**
-     * @ 支付
-     * @param string $orderid
-     * @param int    $user_id
-     * @param string $paytype
-     * @param string $method
-     * @param string $openid
-     * @param string $notifyurl
-     * @param string $returnurl
-     * @return \addons\epay\library\Collection|\addons\epay\library\RedirectResponse|\addons\epay\library\Response|null
-     * @throws \Exception
-     */
-    public static function pay($orderid, $user_id, $paytype, $method = 'web', $openid = '', $notifyurl = null, $returnurl = null)
-    {
-        $request = \think\Request::instance();
-        $order = self::getDetail($orderid, $user_id);
-        if (!$order) {
-            throw new \Exception('订单不存在!');
-        }
-        if ($order->paystate) {
-            throw new \Exception('订单已支付!');
-        }
-        if ($order->orderstate) {
-            throw new \Exception('订单已失效!');
-        }
-        //支付金额为0,无需支付
-        if ($order->saleamount == 0) {
-            throw new \Exception('无需支付!');
-        }
-        $order_sn = $order->order_sn;
-        // 启动事务
-        Db::startTrans();
-        try {
-            //支付方式变更
-            if (($order['paytype'] == $paytype && $order['method'] != $method)) {
-                $order_sn = date("Ymdhis") . sprintf("%08d", $user_id) . mt_rand(1000, 9999);
-                //更新电子面单
-                $electronics = $order->order_electronics;
-                foreach ($electronics as $aftersales) {
-                    $aftersales->order_sn = $order_sn;
-                    $aftersales->save();
-                }
-                //更新操作日志
-                $orderAction = $order->order_action;
-                foreach ($orderAction as $action) {
-                    $action->order_sn = $order_sn;
-                    $action->save();
-                }
-                $order->save(['order_sn' => $order_sn]);
-                //更新订单明细
-                foreach ($order->order_goods as $item) {
-                    $item->order_sn = $order_sn;
-                    $item->save();
-                }
-            }
-            //更新支付类型和方法
-            $order->allowField(true)->save(['paytype' => $paytype, 'method' => $method, 'openid' => $openid]);
-            //提交事务
-            Db::commit();
-        } catch (\Exception $e) {
-            // 回滚事务
-            Db::rollback();
-            throw new \Exception($e->getMessage());
-        }
-        $response = null;
-        $epay = get_addon_info('epay');
-
-        if ($epay && $epay['state']) {
-            $notifyurl = $notifyurl ? $notifyurl : $request->root(true) . '/api/shop/order/epay/type/notify/paytype/' . $paytype;
-            $returnurl = $returnurl ? $returnurl : $request->root(true) . '/api/shop/pay//epay/type/return/paytype/' . $paytype . '/order_sn/' . $order_sn;
-
-            //保证取出的金额一致,不一致将导致订单重复错误
-            $amount = sprintf("%.2f", $order->saleamount);
-
-            $params = [
-                'amount'    => $amount,
-                'orderid'   => $order_sn,
-                'type'      => $paytype,
-                'title'     => "支付{$amount}元",
-                'notifyurl' => $notifyurl,
-                'returnurl' => $returnurl,
-                'method'    => $method,
-                'openid'    => $openid
-            ];
-            try {
-                $response = Service::submitOrder($params);
-            } catch (GatewayException $e) {
-                throw new \Exception(config('app_debug') ? $e->getMessage() : "支付失败,请稍后重试");
-            }
-        } else {
-            throw new \Exception("请在后台安装配置微信支付宝整合插件");
-        }
-        return $response;
-    }
-    /**
-     * 
-     * @ 订单结算
-     * @param string $order_sn      订单号
-     * @param float  $payamount     支付金额
-     * @param string $transactionid 流水号
-     * @return bool
-     */
-    public static function settle($order_sn, $payamount, $transactionid = '')
-    {
-        $order = self::with(['orderGoods'])->where('order_sn', $order_sn)->find();
-        if (!$order || $order->paystate == 1) {
-            return false;
-        }
-
-        if ($payamount != $order->saleamount) {
-            \think\Log::write("[shop][pay][{$order_sn}][订单支付金额不一致]");
-            return false;
-        }
-
-        // 启动事务
-        Db::startTrans();
-        try {
-            $order->paystate = 1;
-            $order->transactionid = $transactionid;
-            $order->payamount = $payamount;
-            $order->paytime = time();
-            $order->paytype = !$order->paytype ? 'system' : $order->paytype;
-            $order->method = !$order->method ? 'system' : $order->method;
-            $order->save();
-            if ($order->payamount == $order->saleamount) {
-                //支付完成后,商品销量+1
-                foreach ($order->order_goods as $item) {
-                    $goods = $item->goods;
-                    $sku = $item->sku;
-                    if ($goods) {
-                        $goods->setInc('sales', $item->nums);
-                    }
-                    if ($sku) {
-                        $sku->setInc('sales', $item->nums);
-                    }
-                }
-            }
-            // 提交事务
-            Db::commit();
-        } catch (\Exception $e) {
-            // 回滚事务
-            Db::rollback();
-            return false;
-        }
-        //记录操作
-        OrderAction::push($order_sn, '系统', '订单支付成功');
-        //发送通知
-        TemplateMsg::sendTempMsg(0, $order->order_sn);
-        return true;
-    }
+    // public function getOrderStatusTextAttr($value, $data)
+    // {
+    //     return OrderEnum::getOrderStatusText($data['order_status']);
+    // }
 
     public function user()
     {

+ 5 - 0
application/common/model/User.php

@@ -74,4 +74,9 @@ class User extends Model
         $value = is_object($value) || is_array($value) ? json_encode($value) : $value;
         return $value;
     }
+
+    public function group()
+    {
+        return $this->belongsTo('app\\common\\model\\UserGroup', 'group_id', 'id', [], 'LEFT')->setEagerlyType(0);
+    }
 }

+ 7 - 0
application/common/model/inspection/InspectionApplication.php

@@ -119,6 +119,13 @@ class InspectionApplication extends Model
     }
 
     /**
+     * 关联供应商表
+     */
+    public function supplier()
+    {
+        return $this->belongsTo('app\\common\\model\\supplier\\Index', 'supplier_id', 'id', [], 'LEFT')->setEagerlyType(0);
+    }
+    /**
      * 关联地区表(省)
      */
     public function province()

+ 50 - 0
application/common/model/supplier/Category.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace app\common\model\supplier;
+
+use think\Model;
+use traits\model\SoftDelete;
+
+class Category extends Model
+{
+
+    use SoftDelete;
+
+    
+
+    // 表名
+    protected $name = 'shop_goods_supplier_category';
+    
+    // 自动写入时间戳字段
+    protected $autoWriteTimestamp = 'integer';
+
+    // 定义时间戳字段名
+    protected $createTime = 'createtime';
+    protected $updateTime = 'updatetime';
+    protected $deleteTime = 'deletetime';
+
+    // 追加属性
+    protected $append = [
+
+    ];
+    
+
+    protected static function init()
+    {
+        self::afterInsert(function ($row) {
+            if (!$row['weigh']) {
+                $pk = $row->getPk();
+                $row->getQuery()->where($pk, $row[$pk])->update(['weigh' => $row[$pk]]);
+            }
+        });
+    }
+
+    
+
+
+
+
+
+
+
+}

+ 92 - 0
application/common/model/supplier/Index.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace app\common\model\supplier;
+
+use think\Model;
+use traits\model\SoftDelete;
+use app\common\enum\StatusEnum;
+
+class Index extends Model
+{
+
+    use SoftDelete;
+
+    
+
+    // 表名
+    protected $name = 'shop_goods_supplier';
+    
+    // 自动写入时间戳字段
+    protected $autoWriteTimestamp = 'integer';
+
+    // 定义时间戳字段名
+    protected $createTime = 'createtime';
+    protected $updateTime = 'updatetime';
+    protected $deleteTime = 'deletetime';
+
+    // 追加属性
+    protected $append = [
+        'status_text'
+    ];
+    
+    /**
+     * 获取状态列表
+     */
+    public function getStatusList()
+    {
+        return StatusEnum::getMap();
+    }
+    
+    /**
+     * 获取状态文本
+     */
+    public function getStatusTextAttr($value, $data)
+    {
+        $status = $value ?: ($data['status'] ?? StatusEnum::ENABLED);
+        $list = $this->getStatusList();
+        return $list[$status] ?? '';
+    }
+    
+    /**
+     * 根据名称获取供应商
+     */
+    public static function getByName($name)
+    {
+        return self::where('name', $name)->find();
+    }
+    
+    /**
+     * 获取供应商选项列表
+     */
+    public static function getOptions()
+    {
+        return self::where('status', StatusEnum::ENABLED)
+            ->order('weigh desc, id desc')
+            ->field('id,name')  
+            ->select();
+    }
+
+    protected static function init()
+    {
+        self::afterInsert(function ($row) {
+            if (!$row['weigh']) {
+                $pk = $row->getPk();
+                $row->getQuery()->where($pk, $row[$pk])->update(['weigh' => $row[$pk]]);
+            }
+        });
+    }
+
+    public function category()
+    {
+        return $this->belongsTo('app\common\model\supplier\Category', 'category_id', 'id');
+    }
+
+    
+
+
+
+
+
+
+
+}

+ 8 - 3
application/common/service/OrderService.php

@@ -209,6 +209,7 @@ class OrderService
                 // 添加分类和品牌信息用于优惠券计算 (临时字段,不会保存到数据库)
                 // 'category_id'          => $item->goods->category_ids,
                 'brand_id'             => $item->goods->brand_id,
+                'supplier_id'          => $item->goods->supplier_id,
             ];
             
             $orderItem[] = $orderItemData;
@@ -386,7 +387,6 @@ class OrderService
                 $item['goods_price'] = $saleprice;
             }
             unset($item);
-            
             // 批量创建订单商品数据
             if (!empty($orderItem)) {
                 (new OrderGoods())->saveAll($orderItem);
@@ -501,9 +501,9 @@ class OrderService
      * @param $param
      * @return \think\Paginator
      */
-    public static function getOrderList($userId = 0, $param =[],$status = [])
+    public static function getOrderList($userId = 0, $param =[],$status = [],$supplierId = 0)
     {
-        $pageSize = 15;
+        $pageSize = 10;
         if (!empty($param['pageSize'])) {
             $pageSize = $param['pageSize'];
         }
@@ -523,6 +523,11 @@ class OrderService
                         return $query->name('shop_order_goods')->where('order_sn|goods_title', 'like', '%' . $param['q'] . '%')->field('order_sn');
                     });
                 }
+                if (!empty($supplierId)) {
+                    $query->where('order_sn', 'in', function ($query) use ($supplierId) {
+                        return $query->name('shop_order_goods')->where('supplier_id', $supplierId)->field('order_sn');
+                    }); 
+                }
             })
             ->order('createtime desc')
             ->paginate($pageSize, false, ['query' => request()->get()]);

+ 17 - 2
public/assets/js/backend/inspection/item.js

@@ -26,9 +26,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                     [
                         {checkbox: true},
                         {field: 'id', title: __('Id')},
-                        {field: 'parent_id', title: __('Parent_id')},
+                        // {field: 'parent_id', title: __('Parent_id')},
                         {field: 'name', title: __('Name'), operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
-                        {field: 'is_required', title: __('Is_required')},
+                        {field: 'is_required', title: __('Is_required'),searchList: Controller.api.parseConfigJson('isRequiredList'), formatter: Table.api.formatter.status},
                         {field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
                         {field: 'updatetime', title: __('Updatetime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
                         {field: 'status', title: __('Status'), searchList: {"30":__('Status 30')}, formatter: Table.api.formatter.status},
@@ -108,6 +108,21 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
             Controller.api.bindevent();
         },
         api: {
+              // 解析Config中的JSON字符串的辅助函数
+              parseConfigJson: function(configKey, defaultValue) {
+                var configValue = Config[configKey] || defaultValue || {};
+                
+                // 如果是字符串,尝试解析JSON
+                if (typeof configValue === 'string') {
+                    try {
+                        return JSON.parse(configValue);
+                    } catch (e) {
+                        return defaultValue || {};
+                    }
+                }
+                
+                return configValue;
+            },
             bindevent: function () {
                 Form.api.bindevent($("form[role=form]"));
             }