Browse Source

fix:身份证

super-yimizi 1 month ago
parent
commit
7312dad203

+ 24 - 6
application/admin/controller/inspection/Application.php

@@ -38,7 +38,7 @@ class Application extends Backend
             list($where, $sort, $order, $offset, $limit) = $this->buildparams();
             
             $list = $this->model
-                ->with(['user'])
+                ->with(['user', 'supplier'])
                 ->where($where)
                 ->order($sort, $order)
                 ->paginate($limit);
@@ -46,6 +46,9 @@ class Application extends Backend
             foreach ($list as $item) {
                 $item->append(['audit_status_text', 'apply_time_text', 'audit_time_text']);
                 $item->user->visible(['id', 'username', 'nickname', 'mobile']);
+                if ($item->supplier) {
+                    $item->supplier->visible(['id', 'name', 'contact', 'mobile']);
+                }
             }
 
             $result = array("total" => $list->total(), "rows" => $list->items());
@@ -64,7 +67,8 @@ class Application extends Backend
             $this->error(__('No Results were found'));
         }
 
-        $row->append(['audit_status_text', 'apply_time_text', 'audit_time_text']);
+        $row->append(['audit_status_text', 'apply_time_text', 'audit_time_text','supplier_name']);
+    
         $this->view->assign("row", $row);
         return $this->view->fetch();
     }
@@ -86,16 +90,30 @@ class Application extends Backend
         if ($this->request->isPost()) {
             $auditStatus = $this->request->post('audit_status');
             $rejectReason = $this->request->post('reject_reason', '', 'trim');
+            $supplierId = $this->request->post('supplier_id', 0, 'intval');
 
-            try {
-                InspectionService::auditApplication($ids, $auditStatus, $rejectReason);
+            // 审核通过时必须选择供应商
+            if ($auditStatus == InspectionApplication::AUDIT_STATUS_PASSED && empty($supplierId)) {
+                $this->error('审核通过时必须选择绑定的供应商');
+            }
+
+            $result = InspectionService::auditApplication($ids, $auditStatus, $rejectReason, $supplierId);
+        
+            if ($result) {
                 $this->success('审核成功');
-            } catch (\Exception $e) {
-                $this->error($e->getMessage());
+            } else {
+                $this->error('审核失败');
             }
+        
         }
 
         $row->append(['audit_status_text', 'apply_time_text']);
+        
+        // 加载供应商信息
+        if ($row->supplier_id) {
+            $row->load(['supplier']);
+        }
+        
         $this->view->assign("row", $row);
         $this->view->assign("auditStatusList", $this->model->getAuditStatusList());
         return $this->view->fetch();

+ 17 - 2
application/admin/view/inspection/application/audit.html

@@ -68,8 +68,6 @@
                             <input id="audit_status-2" name="audit_status" type="radio" value="2" checked /> 
                             <span class="text-success">审核通过</span>
                         </label>
-                    </div>
-                    <div class="radio">
                         <label for="audit_status-3">
                             <input id="audit_status-3" name="audit_status" type="radio" value="3" /> 
                             <span class="text-danger">审核驳回</span>
@@ -77,6 +75,14 @@
                     </div>
                 </div>
             </div>
+
+            <div class="form-group" id="supplier-group">
+                <label class="control-label col-xs-12 col-sm-2">绑定供应商:</label>
+                <div class="col-xs-12 col-sm-8">
+                    <input id="c-supplier_id" data-rule="required" data-source="supplier/index/index" class="form-control selectpage" name="supplier_id" type="text" value="{$row.supplier_id|default=''}" data-field="name" data-primary-key="id" data-order-by="weigh desc,id desc" placeholder="请选择要绑定的供应商">
+                    <div class="help-block">审核通过时必须选择绑定的供应商</div>
+                </div>
+            </div>
             
             <div class="form-group" id="reject-reason-group" style="display: none;">
                 <label class="control-label col-xs-12 col-sm-2">驳回原因:</label>
@@ -105,12 +111,21 @@ $(function() {
     $('input[name="audit_status"]').change(function() {
         var status = $(this).val();
         if (status == '3') {
+            // 审核驳回
             $('#reject-reason-group').show();
             $('#reject_reason').attr('data-rule', 'required');
+            $('#supplier-group').hide();
+            $('#c-supplier_id').removeAttr('data-rule');
         } else {
+            // 审核通过
             $('#reject-reason-group').hide();
             $('#reject_reason').removeAttr('data-rule').val('');
+            $('#supplier-group').show();
+            $('#c-supplier_id').attr('data-rule', 'required');
         }
     });
+    
+    // 初始化状态
+    $('input[name="audit_status"]:checked').trigger('change');
 });
 </script>

+ 13 - 0
application/admin/view/inspection/application/detail.html

@@ -21,6 +21,10 @@
                             <td>{$row.phone}</td>
                         </tr>
                         <tr>
+                            <td>身份证号</td>
+                            <td>{$row.id_card}</td>
+                        </tr>
+                        <tr>
                             <td>省份</td>
                             <td>{$row.province_name}</td>
                         </tr>
@@ -64,6 +68,15 @@
                             <td class="text-danger">{$row.reject_reason}</td>
                         </tr>
                         {/if}
+                        {if condition="$row.supplier_id && $row.supplier"}
+                        <tr>
+                            <td>绑定供应商</td>
+                            <td>
+                                <span class="label label-info">{$row.supplier.name}</span>
+                                <br><small class="text-muted">联系方式:{$row.supplier.contact} {$row.supplier.mobile}</small>
+                            </td>
+                        </tr>
+                        {/if}
                     </tbody>
                 </table>
             </div>

+ 1 - 0
application/api/controller/inspection/Application.php

@@ -33,6 +33,7 @@ class Application extends Base
             'address' => $this->request->post('address', '', 'trim'),
             'id_card_front' => $this->request->post('id_card_front', '', 'trim'),
             'id_card_back' => $this->request->post('id_card_back', '', 'trim'),
+            'id_card' => $this->request->post('id_card', '', 'trim'),
         ];
 
         $application = InspectionService::createApplication($this->auth->id, $data);

+ 15 - 3
application/api/validate/Inspection.php

@@ -3,7 +3,7 @@
 namespace app\api\validate;
 
 use think\Validate;
-
+use app\common\Rule\IdCardRule;
 class Inspection extends Validate
 {
     /**
@@ -20,6 +20,7 @@ class Inspection extends Validate
         'address'           => 'require|max:255',
         'id_card_front'     => 'require|max:255',
         'id_card_back'      => 'require|max:255',
+        'id_card'           => 'require|checkIdCard',
     ];
 
     /**
@@ -48,6 +49,8 @@ class Inspection extends Validate
         'id_card_front.max'     => '身份证正面照片路径长度不能超过255个字符',
         'id_card_back.require'  => '身份证反面照片不能为空',
         'id_card_back.max'      => '身份证反面照片路径长度不能超过255个字符',
+        'id_card.require'       => '身份证号不能为空',
+        'id_card.checkIdCard'   => '身份证号格式不正确',
     ];
 
     /**
@@ -55,11 +58,11 @@ class Inspection extends Validate
      */
     protected $scene = [
         // 创建申请
-        'create' => ['name', 'phone', 'province_adcode', 'city_adcode', 'district_adcode','address', 'id_card_front', 'id_card_back'],
+        'create' => ['name', 'phone', 'province_adcode', 'city_adcode', 'district_adcode','address', 'id_card_front', 'id_card_back', 'id_card'],
         // 查看详情
         'detail' => ['id'],
         // 修改申请
-        'update' => ['id', 'name', 'phone', 'province_adcode', 'city_adcode', 'district_adcode','address', 'id_card_front', 'id_card_back'],
+        'update' => ['id', 'name', 'phone', 'province_adcode', 'city_adcode', 'district_adcode','address', 'id_card_front', 'id_card_back', 'id_card'],
     ];
 
     /**
@@ -81,4 +84,13 @@ class Inspection extends Validate
         }
         return true;
     }
+
+    /**
+     * 自定义验证方法 - 验证身份证号格式
+     */
+    protected function checkIdCard($value, $rule, $data = [])
+    {
+        $result = IdCardRule::validate($value);
+        return $result['valid'] ? true : $result['message'];
+    }
 } 

+ 143 - 0
application/common/Rule/IdCardRule.php

@@ -0,0 +1,143 @@
+<?php
+
+namespace app\common\Rule;
+
+/**
+ * 身份证验证工具类
+ */
+class IdCardRule
+{
+    /**
+     * 验证身份证号格式
+     * @param string $idCard 身份证号
+     * @return array 返回验证结果 ['valid' => true/false, 'message' => '错误信息']
+     */
+    public static function validate($idCard)
+    {
+        // 去除空格
+        $idCard = trim($idCard);
+        
+        // 检查长度(18位)
+        if (strlen($idCard) !== 18) {
+            return ['valid' => false, 'message' => '身份证号必须为18位'];
+        }
+        
+        // 检查前17位是否为数字
+        if (!ctype_digit(substr($idCard, 0, 17))) {
+            return ['valid' => false, 'message' => '身份证号前17位必须为数字'];
+        }
+        
+        // 检查最后一位(数字或X)
+        $lastChar = strtoupper(substr($idCard, 17, 1));
+        if (!ctype_digit($lastChar) && $lastChar !== 'X') {
+            return ['valid' => false, 'message' => '身份证号最后一位必须为数字或字母X'];
+        }
+        
+        // 验证日期部分(第7-14位)
+        $year = substr($idCard, 6, 4);
+        $month = substr($idCard, 10, 2);
+        $day = substr($idCard, 12, 2);
+        
+        // 检查年份范围(1900-当前年份)
+        $currentYear = date('Y');
+        if ($year < 1900 || $year > $currentYear) {
+            return ['valid' => false, 'message' => '身份证号中的出生年份不正确'];
+        }
+        
+        // 检查月份
+        if ($month < 1 || $month > 12) {
+            return ['valid' => false, 'message' => '身份证号中的出生月份不正确'];
+        }
+        
+        // 检查日期
+        if (!checkdate($month, $day, $year)) {
+            return ['valid' => false, 'message' => '身份证号中的出生日期不正确'];
+        }
+        
+        // 验证校验码
+        $checkResult = self::validateCheckCode($idCard);
+        if (!$checkResult['valid']) {
+            return $checkResult;
+        }
+        
+        return ['valid' => true, 'message' => '身份证号格式正确'];
+    }
+    
+    /**
+     * 验证校验码
+     * @param string $idCard 身份证号
+     * @return array
+     */
+    private static function validateCheckCode($idCard)
+    {
+        $weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
+        $checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
+        
+        $sum = 0;
+        for ($i = 0; $i < 17; $i++) {
+            $sum += intval(substr($idCard, $i, 1)) * $weights[$i];
+        }
+        
+        $checkCode = $checkCodes[$sum % 11];
+        $lastChar = strtoupper(substr($idCard, 17, 1));
+        
+        if ($lastChar !== $checkCode) {
+            return ['valid' => false, 'message' => '身份证号校验码不正确'];
+        }
+        
+        return ['valid' => true, 'message' => '校验码正确'];
+    }
+    
+    /**
+     * 从身份证号获取生日
+     * @param string $idCard 身份证号
+     * @return string|false 生日(Y-m-d)或false
+     */
+    public static function getBirthday($idCard)
+    {
+        $result = self::validate($idCard);
+        if (!$result['valid']) {
+            return false;
+        }
+        
+        $year = substr($idCard, 6, 4);
+        $month = substr($idCard, 10, 2);
+        $day = substr($idCard, 12, 2);
+        
+        return $year . '-' . $month . '-' . $day;
+    }
+    
+    /**
+     * 从身份证号获取年龄
+     * @param string $idCard 身份证号
+     * @return int|false 年龄或false
+     */
+    public static function getAge($idCard)
+    {
+        $birthday = self::getBirthday($idCard);
+        if (!$birthday) {
+            return false;
+        }
+        
+        $birthTime = strtotime($birthday);
+        $age = floor((time() - $birthTime) / (365 * 24 * 3600));
+        
+        return $age;
+    }
+    
+    /**
+     * 从身份证号获取性别
+     * @param string $idCard 身份证号
+     * @return string|false 'male'(男)或'female'(女)或false
+     */
+    public static function getGender($idCard)
+    {
+        $result = self::validate($idCard);
+        if (!$result['valid']) {
+            return false;
+        }
+        
+        $genderCode = intval(substr($idCard, 16, 1));
+        return $genderCode % 2 === 0 ? 'female' : 'male';
+    }
+} 

+ 15 - 1
application/common/Service/InspectionService.php

@@ -204,10 +204,11 @@ class InspectionService
      * @param int $applicationId 申请ID
      * @param int $auditStatus 审核状态
      * @param string $rejectReason 驳回原因(可选)
+     * @param int $supplierId 供应商ID(可选)
      * @return bool
      * @throws Exception
      */
-    public static function auditApplication($applicationId, $auditStatus, $rejectReason = '')
+    public static function auditApplication($applicationId, $auditStatus, $rejectReason = '', $supplierId = 0)
     {
         $application = InspectionApplication::get($applicationId);
         
@@ -234,12 +235,25 @@ class InspectionService
             throw new BusinessException('驳回申请必须填写驳回原因');
         }
 
+        // 如果是审核通过,检查供应商ID
+        if ($auditStatus == InspectionApplication::AUDIT_STATUS_PASSED && empty($supplierId)) {
+            throw new BusinessException('审核通过时必须选择绑定的供应商');
+        }
+
         // 启动事务
         Db::startTrans();
         try {
             $application->audit_status = $auditStatus;
             $application->audit_time = time();
             $application->reject_reason = $rejectReason;
+            
+            // 审核通过时设置供应商ID,驳回时清空供应商ID
+            if ($auditStatus == InspectionApplication::AUDIT_STATUS_PASSED) {
+                $application->supplier_id = $supplierId;
+            } else {
+                $application->supplier_id = 0;
+            }
+            
             $application->save();
             
             // 提交事务

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

@@ -31,6 +31,7 @@ class InspectionApplication extends Model
         'province_name',
         'city_name', 
         'district_name',
+        'supplier_name',
     ];
 
     // 审核状态常量
@@ -79,6 +80,18 @@ class InspectionApplication extends Model
     }
 
     /**
+     * 获取供应商名称
+     */
+    public function getSupplierNameAttr($value, $data)
+    {
+        if (!empty($data['supplier_id'])) {
+            $supplier = \app\common\model\supplier\Index::where('id', $data['supplier_id'])->find();
+            return $supplier ? $supplier['name'] : '';
+        }
+        return '';
+    }
+
+    /**
      * 获取身份证正面图片完整URL
      */
     public function getIdCardFrontAttr($value)

+ 32 - 14
public/assets/js/backend/inspection/application.js

@@ -22,24 +22,33 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 pk: 'id',
                 sortName: 'id',
                 sortOrder: 'desc',
+                fixedColumns: true,
+                fixedRightNumber: 1,
                 columns: [
                     [
-                        {checkbox: true},
-                        {field: 'id', title: __('Id'), operate: false, sortable: true},
-                        {field: 'name', title: '姓名', operate: 'LIKE'},
-                        {field: 'phone', title: '联系电话', operate: 'LIKE'},
-                        {field: 'user.nickname', title: '用户昵称', operate: false},
-                        {field: 'user.mobile', title: '用户手机', operate: false},
-                        {field: 'province_name', title: '省份', operate: false},
-                        {field: 'city_name', title: '城市', operate: false},
-                        {field: 'district_name', title: '区县', operate: false},
-                        {field: 'apply_time_text', title: '申请时间', operate: false, sortable: true},
-                        {field: 'audit_status', title: '审核状态', searchList: {"1":"审核中","2":"审核通过","3":"审核驳回"}, formatter: Table.api.formatter.status, custom: {"1":"warning","2":"success","3":"danger"}},
-                        {field: 'audit_time_text', title: '审核时间', operate: false},
-                        {field: 'reject_reason', title: '驳回原因', operate: false, formatter: function(value, row, index) {
+                        {checkbox: true, width: 50},
+                        {field: 'id', title: __('Id'), operate: false, sortable: true, width: 80},
+                        {field: 'name', title: '姓名', operate: 'LIKE', width: 100},
+                        {field: 'phone', title: '联系电话', operate: 'LIKE', width: 120},
+                        {field: 'user.nickname', title: '用户昵称', operate: false, width: 100},
+                        {field: 'user.mobile', title: '用户手机', operate: false, width: 120},
+                        {field: 'supplier.name', title: '绑定供应商', operate: false, width: 120, formatter: function(value, row, index) {
+                            if (row.supplier && row.supplier.name) {
+                                return '<span class="label label-info">' + row.supplier.name + '</span>';
+                            }
+                            return '<span class="text-muted">未绑定</span>';
+                        }},
+                        {field: 'id_card', title: '身份证号', operate: false, width: 150},
+                        {field: 'province_name', title: '省份', operate: false, width: 80},
+                        {field: 'city_name', title: '城市', operate: false, width: 80},
+                        {field: 'district_name', title: '区县', operate: false, width: 80},
+                        {field: 'apply_time_text', title: '申请时间', operate: false, sortable: true, width: 140},
+                        {field: 'audit_status', title: '审核状态', searchList: {"1":"审核中","2":"审核通过","3":"审核驳回"}, formatter: Table.api.formatter.status, custom: {"1":"warning","2":"success","3":"danger"}, width: 100},
+                        {field: 'audit_time_text', title: '审核时间', operate: false, width: 140},
+                        {field: 'reject_reason', title: '驳回原因', operate: false, width: 200, formatter: function(value, row, index) {
                             return value ? '<span class="text-danger">' + value + '</span>' : '-';
                         }},
-                        {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, 
+                        {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, width: 150, fixed: 'right',
                             buttons: [
                                 {
                                     name: 'detail',
@@ -173,13 +182,22 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
             $(document).on('change', 'input[name="audit_status"]', function() {
                 var status = $(this).val();
                 if (status == '3') {
+                    // 审核驳回
                     $('#reject-reason-group').show();
                     $('#reject_reason').attr('data-rule', 'required');
+                    $('#supplier-group').hide();
+                    $('#c-supplier_id').removeAttr('data-rule');
                 } else {
+                    // 审核通过
                     $('#reject-reason-group').hide();
                     $('#reject_reason').removeAttr('data-rule').val('');
+                    $('#supplier-group').show();
+                    $('#c-supplier_id').attr('data-rule', 'required');
                 }
             });
+            
+            // 初始化状态
+            $('input[name="audit_status"]:checked').trigger('change');
         },
         
         api: {