Browse Source

fix:代理商身份

super-yimizi 1 day ago
parent
commit
7112556d6f

+ 66 - 0
application/admin/lang/en/commission/apply.php

@@ -0,0 +1,66 @@
+<?php
+
+return [
+    'Id' => 'ID',
+    'User' => 'User',
+    'Apply type' => 'Apply Type',
+    'Agent type' => 'Agent Type',
+    'Identity' => 'Identity',
+    'Real name' => 'Real Name',
+    'Company name' => 'Company Name',
+    'Area' => 'Area',
+    'Status' => 'Status',
+    'Createtime' => 'Create Time',
+    'Detail' => 'Detail',
+    'Approve' => 'Approve',
+    'Reject' => 'Reject',
+    'Operate' => 'Operate',
+    
+    // Apply types
+    'Personal apply' => 'Personal Apply',
+    'Company apply' => 'Company Apply',
+    
+    // Agent types
+    'Normal agent' => 'Normal Agent',
+    'Province agent' => 'Province Agent',
+    'City agent' => 'City Agent',
+    'District agent' => 'District Agent',
+    
+    // Status
+    'Pending' => 'Pending',
+    'Approved' => 'Approved',
+    'Rejected' => 'Rejected',
+    
+    // Page titles
+    'Apply details' => 'Apply Details',
+    'Apply info' => 'Apply Information',
+    'Personal info' => 'Personal Information',
+    'Company info' => 'Company Information',
+    'Apply status info' => 'Apply Status Information',
+    
+    // Form fields
+    'Apply user' => 'Apply User',
+    'Agent identity' => 'Agent Identity',
+    'Agent region' => 'Agent Region',
+    'Apply region' => 'Apply Region',
+    'Real name' => 'Real Name',
+    'ID card' => 'ID Card',
+    'Mobile' => 'Mobile',
+    'ID card front' => 'ID Card Front',
+    'ID card back' => 'ID Card Back',
+    'Company name' => 'Company Name',
+    'Legal person' => 'Legal Person',
+    'Legal mobile' => 'Legal Mobile',
+    'Legal ID card' => 'Legal ID Card',
+    'Legal ID front' => 'Legal ID Front',
+    'Legal ID back' => 'Legal ID Back',
+    'Business license' => 'Business License',
+    'Apply time' => 'Apply Time',
+    'Audit time' => 'Audit Time',
+    'Audit admin' => 'Audit Admin',
+    'Reject reason' => 'Reject Reason',
+    
+    // Help text
+    'Regional agent will manage all orders in this area' => 'Regional agent will manage all orders in this area',
+    'Not uploaded' => 'Not uploaded',
+];

+ 47 - 0
application/admin/lang/en/commission/identity.php

@@ -0,0 +1,47 @@
+<?php
+
+return [
+    'Id' => 'ID',
+    'Name' => 'Name',
+    'Level' => 'Level',
+    'Agent type' => 'Agent Type',
+    'Regional rate' => 'Regional Rate',
+    'Manage level' => 'Manage Level',
+    'Description' => 'Description',
+    'Status' => 'Status',
+    'Weigh' => 'Weight',
+    'Createtime' => 'Create Time',
+    'Operate' => 'Operate',
+    
+    // Agent types
+    'Normal agent' => 'Normal Agent',
+    'Province agent' => 'Province Agent',
+    'City agent' => 'City Agent',
+    'District agent' => 'District Agent',
+    
+    // Manage levels
+    'Province level' => 'Province Level',
+    'City level' => 'City Level',
+    'District level' => 'District Level',
+    
+    // Status
+    'Hidden' => 'Hidden',
+    'Shown' => 'Shown',
+    
+    // Form labels
+    'Identity name' => 'Identity Name',
+    'Identity level' => 'Identity Level',
+    'Agent type select' => 'Agent Type',
+    'Regional commission rate' => 'Regional Commission Rate (%)',
+    'Identity description' => 'Identity Description',
+    'Identity status' => 'Identity Status',
+    'Sort weight' => 'Sort Weight',
+    
+    // Help text
+    'Regional rate help' => 'Regional commission rate for regional agents, in percentage',
+    'Normal agent desc' => 'Get commission from direct referral users in traditional distribution mode',
+    'Regional agent desc' => 'Get commission from all orders within the managed area',
+    'Province agent desc' => 'Responsible for agent business in the entire province',
+    'City agent desc' => 'Responsible for agent business in the entire city',
+    'District agent desc' => 'Responsible for agent business in specific districts',
+];

+ 66 - 0
application/admin/lang/zh-cn/commission/apply.php

@@ -0,0 +1,66 @@
+<?php
+
+return [
+    'Id' => 'ID',
+    'User' => '申请用户',
+    'Apply type' => '申请类型',
+    'Agent type' => '代理商类型',
+    'Identity' => '代理商身份',
+    'Real name' => '真实姓名',
+    'Company name' => '企业名称',
+    'Area' => '申请地区',
+    'Status' => '申请状态',
+    'Createtime' => '申请时间',
+    'Detail' => '查看详情',
+    'Approve' => '审核通过',
+    'Reject' => '审核拒绝',
+    'Operate' => '操作',
+    
+    // 申请类型
+    'Personal apply' => '个人申请',
+    'Company apply' => '企业申请',
+    
+    // 代理商类型
+    'Normal agent' => '普通代理商',
+    'Province agent' => '省级代理商',
+    'City agent' => '市级代理商', 
+    'District agent' => '区域代理商',
+    
+    // 申请状态
+    'Pending' => '待审核',
+    'Approved' => '已通过',
+    'Rejected' => '已拒绝',
+    
+    // 操作消息
+    'Apply details' => '申请详情',
+    'Apply info' => '申请信息',
+    'Personal info' => '个人申请信息',
+    'Company info' => '企业申请信息',
+    'Apply status info' => '申请状态信息',
+    
+    // 表单字段
+    'Apply user' => '申请用户',
+    'Agent identity' => '代理商身份',
+    'Agent region' => '管辖区域',
+    'Apply region' => '申请地区',
+    'Real name' => '真实姓名',
+    'ID card' => '身份证号',
+    'Mobile' => '手机号码',
+    'ID card front' => '身份证正面',
+    'ID card back' => '身份证反面',
+    'Company name' => '企业名称',
+    'Legal person' => '法人姓名',
+    'Legal mobile' => '法人手机',
+    'Legal ID card' => '法人身份证',
+    'Legal ID front' => '法人身份证正面',
+    'Legal ID back' => '法人身份证反面',
+    'Business license' => '营业执照',
+    'Apply time' => '申请时间',
+    'Audit time' => '审核时间',
+    'Audit admin' => '审核管理员',
+    'Reject reason' => '拒绝原因',
+    
+    // 提示信息
+    'Regional agent will manage all orders in this area' => '区域代理商将管辖该地区内的所有订单',
+    'Not uploaded' => '未上传',
+];

+ 47 - 0
application/admin/lang/zh-cn/commission/identity.php

@@ -0,0 +1,47 @@
+<?php
+
+return [
+    'Id' => 'ID',
+    'Name' => '身份名称',
+    'Level' => '身份等级',
+    'Agent type' => '代理商类型',
+    'Regional rate' => '区域分佣比例',
+    'Manage level' => '管辖层级',
+    'Description' => '身份描述',
+    'Status' => '状态',
+    'Weigh' => '排序',
+    'Createtime' => '创建时间',
+    'Operate' => '操作',
+    
+    // 代理商类型
+    'Normal agent' => '普通代理商',
+    'Province agent' => '省级代理商',
+    'City agent' => '市级代理商',
+    'District agent' => '区域代理商',
+    
+    // 管辖层级
+    'Province level' => '省级管辖',
+    'City level' => '市级管辖',
+    'District level' => '区域管辖',
+    
+    // 状态
+    'Hidden' => '禁用',
+    'Shown' => '启用',
+    
+    // 表单标签
+    'Identity name' => '身份名称',
+    'Identity level' => '身份等级',
+    'Agent type select' => '代理商类型',
+    'Regional commission rate' => '区域分佣比例(%)',
+    'Identity description' => '身份描述',
+    'Identity status' => '状态',
+    'Sort weight' => '排序权重',
+    
+    // 帮助文本
+    'Regional rate help' => '区域代理商的分佣比例,单位为百分比',
+    'Normal agent desc' => '按传统分销模式获取直推用户佣金',
+    'Regional agent desc' => '获取管辖区域内所有订单分成',
+    'Province agent desc' => '负责整个省份的代理业务',
+    'City agent desc' => '负责整个城市的代理业务',
+    'District agent desc' => '负责具体区域的代理业务',
+];

+ 4 - 2
application/admin/view/commission/identity/add.html

@@ -16,8 +16,10 @@
         <label class="control-label col-xs-12 col-sm-2">{:__('Agent type')}:</label>
         <div class="col-xs-12 col-sm-8">
             <div class="radio">
-                <label for="row[agent_type]-normal"><input id="row[agent_type]-normal" name="row[agent_type]" type="radio" value="normal" checked> 普通代理商</label> 
-                <label for="row[agent_type]-regional"><input id="row[agent_type]-regional" name="row[agent_type]" type="radio" value="regional"> 区域代理商</label> 
+                <label for="row[agent_type]-normal"><input id="row[agent_type]-normal" name="row[agent_type]" type="radio" value="normal" checked> 普通代理商</label>
+                <label for="row[agent_type]-province"><input id="row[agent_type]-province" name="row[agent_type]" type="radio" value="province"> 省级代理商</label>
+                <label for="row[agent_type]-city"><input id="row[agent_type]-city" name="row[agent_type]" type="radio" value="city"> 市级代理商</label> 
+                <label for="row[agent_type]-district"><input id="row[agent_type]-district" name="row[agent_type]" type="radio" value="district"> 区域代理商</label> 
             </div>
         </div>
     </div>

+ 5 - 3
application/admin/view/commission/identity/edit.html

@@ -16,12 +16,14 @@
         <label class="control-label col-xs-12 col-sm-2">{:__('Agent type')}:</label>
         <div class="col-xs-12 col-sm-8">
             <div class="radio">
-                <label for="row[agent_type]-normal"><input id="row[agent_type]-normal" name="row[agent_type]" type="radio" value="normal" {if condition="$row.agent_type == 'normal' || !$row.agent_type"}checked{/if}> 普通代理商</label> 
-                <label for="row[agent_type]-regional"><input id="row[agent_type]-regional" name="row[agent_type]" type="radio" value="regional" {if condition="$row.agent_type == 'regional'"}checked{/if}> 区域代理商</label> 
+                <label for="row[agent_type]-normal"><input id="row[agent_type]-normal" name="row[agent_type]" type="radio" value="normal" {if condition="$row.agent_type == 'normal' || !$row.agent_type"}checked{/if}> 普通代理商</label>
+                <label for="row[agent_type]-province"><input id="row[agent_type]-province" name="row[agent_type]" type="radio" value="province" {if condition="$row.agent_type == 'province'"}checked{/if}> 省级代理商</label>
+                <label for="row[agent_type]-city"><input id="row[agent_type]-city" name="row[agent_type]" type="radio" value="city" {if condition="$row.agent_type == 'city'"}checked{/if}> 市级代理商</label> 
+                <label for="row[agent_type]-district"><input id="row[agent_type]-district" name="row[agent_type]" type="radio" value="district" {if condition="$row.agent_type == 'district'"}checked{/if}> 区域代理商</label> 
             </div>
         </div>
     </div>
-    <div class="form-group" id="regional-rate-group" {if condition="$row.agent_type != 'regional'"}style="display: none;"{/if}>
+    <div class="form-group" id="regional-rate-group" {if condition="!in_array($row.agent_type, ['province', 'city', 'district'])"}style="display: none;"{/if}>
         <label class="control-label col-xs-12 col-sm-2">{:__('Regional rate')} (%):</label>
         <div class="col-xs-12 col-sm-8">
             <input id="c-regional_commission_rate" class="form-control" name="row[regional_commission_rate]" type="number" step="0.01" min="0" max="100" value="{$row.regional_commission_rate|default='0.00'}">

+ 122 - 63
application/api/controller/commission/Agent.php

@@ -5,8 +5,12 @@ namespace app\api\controller\commission;
 use think\Db;
 use app\common\model\User as UserModel;
 use app\common\model\commission\Agent as AgentModel;
+use app\common\model\commission\Reward as RewardModel;
+use app\common\model\commission\Apply as ApplyModel;
 use app\common\model\Goods as GoodsModel;
 use app\common\Service\Wallet;
+use app\common\Enum\AgentType;
+use app\common\library\BcMath;
 
 
 class Agent extends Commission
@@ -51,71 +55,99 @@ class Agent extends Commission
                 break;
         }
         $data = $this->service->agent;
-
-        $this->success('分销商信息', $data);
-    }
-
-    // 分销商完善个人信息
-    public function form()
-    {
-        if (!$this->service->config->isAgentApplyForm()) {
-            $this->error('未开启分销商申请');
-        }
-
-        $agentForm = $this->service->config->getAgentForm();
-        $protocol = $this->service->config->getApplyProtocol();
-
-        $config = [
-            'form' => $agentForm['content'],
-            'status' => $this->service->getAgentStatus(true),
-            'background' => $agentForm['background_image'],
-            'protocol' => $protocol
-        ];
-
-        $this->success("", $config);
-    }
-
-    // 申请分销商/完善资料
-    public function apply()
-    {
-        if (!$this->service->config->isAgentApplyForm()) {
-            $this->error('未开启分销商申请');
-        }
-        $status = $this->service->getAgentStatus(true);
-
-        if (!in_array($status, [AgentModel::AGENT_STATUS_NEEDINFO, AgentModel::AGENT_STATUS_REJECT, AgentModel::AGENT_STATUS_NORMAL])) {
-            $this->error('您暂时不能申请');
-        }
-        Db::transaction(function () use ($status) {
-            $data = $this->request->param('data/a');
-            // 过滤无效表单字段数据
-            $config = $this->service->config->getAgentForm();
-            $form = (array)$config['content'];
-            $data = array_column($data, 'value', 'name');
-
-            foreach ($form as &$item) {
-                if (!empty($data[$item['name']])) {
-                    $item['value'] = $data[$item['name']];
-                } else {
-                    $this->error($item['name'] . '不能为空');
+        
+        // 增强代理商数据信息
+        if ($data) {
+            $data = $data->toArray();
+            
+            // 添加代理商类型描述(使用枚举类)
+            $data['agent_type_text'] = AgentType::getTypeText($data['agent_type']);
+            
+            // 如果是区域代理商,添加管辖区域信息
+            if (AgentType::isRegionalAgent($data['agent_type'])) {
+                $areaInfo = [];
+                
+                // 获取省份信息
+                if (!empty($data['manage_province_id'])) {
+                    $provinceInfo = \app\common\model\Area::where('id', $data['manage_province_id'])->find();
+                    if ($provinceInfo) {
+                        $areaInfo['province_name'] = $provinceInfo['name'];
+                        $areaInfo['province_id'] = $data['manage_province_id'];
+                    }
+                }
+                
+                // 获取城市信息  
+                if (!empty($data['manage_city_id'])) {
+                    $cityInfo = \app\common\model\Area::where('id', $data['manage_city_id'])->find();
+                    if ($cityInfo) {
+                        $areaInfo['city_name'] = $cityInfo['name'];
+                        $areaInfo['city_id'] = $data['manage_city_id'];
+                    }
                 }
+                
+                // 获取区域信息
+                if (!empty($data['manage_district_id'])) {
+                    $districtInfo = \app\common\model\Area::where('id', $data['manage_district_id'])->find();
+                    if ($districtInfo) {
+                        $areaInfo['district_name'] = $districtInfo['name'];
+                        $areaInfo['district_id'] = $data['manage_district_id'];
+                    }
+                }
+                
+                $data['manage_area'] = $areaInfo;
+                
+                // 生成管辖区域描述文本
+                $areaText = [];
+                if (isset($areaInfo['province_name'])) $areaText[] = $areaInfo['province_name'];
+                if (isset($areaInfo['city_name'])) $areaText[] = $areaInfo['city_name'];  
+                if (isset($areaInfo['district_name'])) $areaText[] = $areaInfo['district_name'];
+                $data['manage_area_text'] = implode('-', $areaText);
+            } else {
+                $data['manage_area'] = null;
+                $data['manage_area_text'] = '-';
             }
-            if ($status === AgentModel::AGENT_STATUS_NEEDINFO) {
-                $this->service->createNewAgent('');
+            
+            // 获取用户基本信息和佣金数据
+            $user = $this->service->user;
+            if ($user) {
+                $data['user_info'] = [
+                    'nickname' => $user->nickname,
+                    'avatar' => cdnurl($user->avatar), // 转换为完整CDN URL
+                    'username' => $user->username,
+                ];
+            }
+            
+            // 获取代理商申请信息
+            $applyInfo = ApplyModel::where('user_id', $this->service->user->id)
+                ->with(['identity'])
+                ->order('id desc')
+                ->find();
+                
+            if ($applyInfo) {
+                $data['apply_info'] = [
+                    'id' => $applyInfo->id,
+                    'apply_type' => $applyInfo->apply_type,
+                    'apply_type_text' => $applyInfo->apply_type_text,
+                    'status' => $applyInfo->status,
+                    'status_text' => $applyInfo->status_text,
+                    'identity_name' => $applyInfo->identity->name ?? '',
+                    'area_text' => implode('-', array_filter([
+                        $applyInfo->province_name,
+                        $applyInfo->city_name,
+                        $applyInfo->district_name
+                    ])),
+                    'createtime' => $applyInfo->createtime ? date('Y-m-d H:i:s', $applyInfo->createtime) : '',
+                    'audit_time' => $applyInfo->audit_time ? date('Y-m-d H:i:s', $applyInfo->audit_time) : '',
+                ];
             } else {
-                // 重置为审核中
-                if ($status === AgentModel::AGENT_STATUS_REJECT) {
-                    $this->service->agent->status = AgentModel::AGENT_STATUS_PENDING;
-                }
-                // 保存分销商状态更新
-                $this->service->agent->save();
+                $data['apply_info'] = null;
             }
-        });
-
+        }
 
-        $this->success('提交成功');
+        $this->success('分销商信息', $data);
     }
 
+
     // 我的团队
     public function team()
     {
@@ -131,18 +163,45 @@ class Agent extends Commission
         $this->success("", $data);
     }
 
-    // 佣金转余额
+    // 佣金转余额/提现
     public function transfer()
     {
         $amount = $this->request->param('amount');
         if ($amount <= 0) {
             $this->error('请输入正确的金额');
         }
-        Db::transaction(function () use ($amount) {
+        
+        $agent = $this->service->agent;
+        if (!$agent) {
+            $this->error('您还不是分销商');
+        }
+        
+        // 使用BcMath工具类检查可提现余额(累计收益 - 已提现金额)
+        $totalIncome = $agent->total_income ?? '0.00';
+        $withdrawnAmount = $agent->withdrawn_amount ?? '0.00';
+        $requestAmount = BcMath::format($amount);
+        
+        $availableBalance = BcMath::sub($totalIncome, $withdrawnAmount);
+        
+        // 使用BcMath比较函数检查余额是否足够
+        if (BcMath::comp($requestAmount, $availableBalance) > 0) {
+            $this->error('提现金额超过可用余额,可用余额:' . $availableBalance . '元');
+        }
+        
+        Db::transaction(function () use ($amount, $agent) {
             $user = auth_user();
-            Wallet::change($user, 'commission', -$amount, 'transfer_to_money');
-            Wallet::change($user, 'money', $amount, 'transfer_by_commission');
+            
+            // 转账到用户余额
+            Wallet::change($user, 'money', $amount, 'commission_withdraw');
+            
+            // 更新代理商的已提现金额
+            AgentModel::where('user_id', $user->id)->setInc('withdrawn_amount', $amount);
         });
-        $this->success('');
+        
+        $this->success('提现成功');
     }
+    
+   
+    
+
 }

+ 6 - 1
application/api/controller/commission/AgentApply.php

@@ -64,7 +64,12 @@ class AgentApply extends Base
                 $this->success('未找到申请记录', null);
             }
             
-            $this->success('获取成功', $apply);
+            // 增强申请数据信息
+            $data = $apply->toArray();
+            
+          
+            
+            $this->success('获取成功', $data);
         } catch (Exception $e) {
             $this->error($e->getMessage());
         }

+ 59 - 0
application/common/Enum/AgentType.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace app\common\Enum;
+
+/**
+ * 代理商类型枚举类
+ */
+class AgentType
+{
+    // 代理商类型常量
+    const NORMAL = 'normal';
+    const PROVINCE = 'province';
+    const CITY = 'city';
+    const DISTRICT = 'district';
+
+    /**
+     * 获取所有代理商类型
+     * @return array
+     */
+    public static function getAll()
+    {
+        return [
+            self::NORMAL => '普通代理商',
+            self::PROVINCE => '省级代理商',
+            self::CITY => '市级代理商',
+            self::DISTRICT => '区域代理商'
+        ];
+    }
+
+    /**
+     * 获取代理商类型描述
+     * @param string $type
+     * @return string
+     */
+    public static function getTypeText($type)
+    {
+        $types = self::getAll();
+        return isset($types[$type]) ? $types[$type] : '普通代理商';
+    }
+
+    /**
+     * 检查是否为区域代理商类型
+     * @param string $type
+     * @return bool
+     */
+    public static function isRegionalAgent($type)
+    {
+        return in_array($type, [self::PROVINCE, self::CITY, self::DISTRICT]);
+    }
+
+    /**
+     * 获取区域代理商类型列表
+     * @return array
+     */
+    public static function getRegionalTypes()
+    {
+        return [self::PROVINCE, self::CITY, self::DISTRICT];
+    }
+}

+ 38 - 0
application/common/Enum/ApplyStatus.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace app\common\Enum;
+
+/**
+ * 申请状态枚举类
+ */
+class ApplyStatus
+{
+    // 申请状态常量
+    const PENDING = 'pending';
+    const APPROVED = 'approved';
+    const REJECTED = 'rejected';
+
+    /**
+     * 获取所有申请状态
+     * @return array
+     */
+    public static function getAll()
+    {
+        return [
+            self::PENDING => '待审核',
+            self::APPROVED => '已通过',
+            self::REJECTED => '已拒绝'
+        ];
+    }
+
+    /**
+     * 获取申请状态描述
+     * @param string $status
+     * @return string
+     */
+    public static function getStatusText($status)
+    {
+        $statuses = self::getAll();
+        return isset($statuses[$status]) ? $statuses[$status] : '待审核';
+    }
+}

+ 36 - 0
application/common/Enum/ApplyType.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace app\common\Enum;
+
+/**
+ * 申请类型枚举类
+ */
+class ApplyType
+{
+    // 申请类型常量
+    const PERSONAL = 'personal';
+    const COMPANY = 'company';
+
+    /**
+     * 获取所有申请类型
+     * @return array
+     */
+    public static function getAll()
+    {
+        return [
+            self::PERSONAL => '个人申请',
+            self::COMPANY => '企业申请'
+        ];
+    }
+
+    /**
+     * 获取申请类型描述
+     * @param string $type
+     * @return string
+     */
+    public static function getTypeText($type)
+    {
+        $types = self::getAll();
+        return isset($types[$type]) ? $types[$type] : '个人申请';
+    }
+}

+ 1 - 1
application/common/Service/Commission/Agent.php

@@ -7,7 +7,7 @@ use app\common\model\User as UserModel;
 use app\common\model\commission\Agent as AgentModel;
 use app\common\model\commission\Level as LevelModel;
 use app\common\model\commission\Log as LogModel;
-use app\common\model\commission\Share as ShareModel;
+use app\common\model\user\Share as ShareModel;
 use app\common\model\Order as OrderModel;
 
 

+ 14 - 5
application/common/Service/Commission/AgentApply.php

@@ -7,6 +7,7 @@ use app\common\model\commission\Identity as IdentityModel;
 use app\common\model\commission\Agent as AgentModel;
 use app\common\model\Area;
 use app\common\Service\ShopConfigService;
+use app\common\Enum\AgentType;
 use think\Db;
 use think\Exception;
 
@@ -214,11 +215,19 @@ class AgentApply
         $agent->status = AgentModel::AGENT_STATUS_NORMAL;
         $agent->become_time = time();
 
-        // 如果是区域代理商,设置管辖区域
-        if ($apply->agent_type == 'regional') {
-            $agent->manage_province_id = $apply->province_id;
-            $agent->manage_city_id = $apply->city_id;
-            $agent->manage_district_id = $apply->district_id;
+        // 如果是区域代理商(省级、市级、区域级),设置管辖区域
+        if (AgentType::isRegionalAgent($apply->agent_type)) {
+            // 根据代理商类型设置对应的管辖区域
+            if ($apply->agent_type == AgentType::PROVINCE) {
+                $agent->manage_province_id = $apply->province_id;
+            } elseif ($apply->agent_type == AgentType::CITY) {
+                $agent->manage_province_id = $apply->province_id;
+                $agent->manage_city_id = $apply->city_id;
+            } elseif ($apply->agent_type == AgentType::DISTRICT) {
+                $agent->manage_province_id = $apply->province_id;
+                $agent->manage_city_id = $apply->city_id;
+                $agent->manage_district_id = $apply->district_id;
+            }
         }
 
         $agent->save();

+ 9 - 11
application/common/Service/Commission/RegionalCommission.php

@@ -6,6 +6,7 @@ use app\common\model\commission\Agent as AgentModel;
 use app\common\model\commission\Reward as RewardModel;
 use app\common\model\commission\Log as LogModel;
 use app\common\model\User as UserModel;
+use app\common\Enum\AgentType;
 use think\Db;
 
 /**
@@ -76,9 +77,9 @@ class RegionalCommission
 
         // 查找区域代理商:按管辖范围从小到大查找(区 -> 市 -> 省)
         
-        // 1. 查找管辖该区的代理商
+        // 1. 查找区域级代理商(district类型)
         if ($userArea['district_id'] > 0) {
-            $districtAgents = AgentModel::where('agent_type', 'regional')
+            $districtAgents = AgentModel::where('agent_type', AgentType::DISTRICT)
                                        ->where('manage_district_id', $userArea['district_id'])
                                        ->where('status', AgentModel::AGENT_STATUS_NORMAL)
                                        ->with(['identity'])
@@ -86,23 +87,20 @@ class RegionalCommission
             $agents = array_merge($agents, $districtAgents->toArray());
         }
 
-        // 2. 查找管辖该市的代理商(如果还没有区级代理商)
-        if ($userArea['city_id'] > 0) {
-            $cityAgents = AgentModel::where('agent_type', 'regional')
+        // 2. 查找市级代理商(city类型),如果还没有区级代理商
+        if (empty($agents) && $userArea['city_id'] > 0) {
+            $cityAgents = AgentModel::where('agent_type', AgentType::CITY)
                                    ->where('manage_city_id', $userArea['city_id'])
-                                   ->where('manage_district_id', 0) // 市级代理商不管具体区
                                    ->where('status', AgentModel::AGENT_STATUS_NORMAL)
                                    ->with(['identity'])
                                    ->select();
             $agents = array_merge($agents, $cityAgents->toArray());
         }
 
-        // 3. 查找管辖该省的代理商(如果还没有市级代理商)
-        if ($userArea['province_id'] > 0) {
-            $provinceAgents = AgentModel::where('agent_type', 'regional')
+        // 3. 查找省级代理商(province类型),如果还没有市级代理商
+        if (empty($agents) && $userArea['province_id'] > 0) {
+            $provinceAgents = AgentModel::where('agent_type', AgentType::PROVINCE)
                                        ->where('manage_province_id', $userArea['province_id'])
-                                       ->where('manage_city_id', 0)
-                                       ->where('manage_district_id', 0)
                                        ->where('status', AgentModel::AGENT_STATUS_NORMAL)
                                        ->with(['identity'])
                                        ->select();

+ 162 - 0
application/common/library/BcMath.php

@@ -0,0 +1,162 @@
+<?php
+
+namespace app\common\library;
+
+/**
+ * BC数学函数工具类
+ * 用于高精度财务计算
+ */
+class BcMath
+{
+    /**
+     * 默认小数位数
+     */
+    const DEFAULT_SCALE = 2;
+
+    /**
+     * 加法运算
+     * @param string|float|int $left
+     * @param string|float|int $right
+     * @param int $scale
+     * @return string
+     */
+    public static function add($left, $right, $scale = self::DEFAULT_SCALE)
+    {
+        return bcadd(strval($left), strval($right), $scale);
+    }
+
+    /**
+     * 减法运算
+     * @param string|float|int $left
+     * @param string|float|int $right
+     * @param int $scale
+     * @return string
+     */
+    public static function sub($left, $right, $scale = self::DEFAULT_SCALE)
+    {
+        return bcsub(strval($left), strval($right), $scale);
+    }
+
+    /**
+     * 乘法运算
+     * @param string|float|int $left
+     * @param string|float|int $right
+     * @param int $scale
+     * @return string
+     */
+    public static function mul($left, $right, $scale = self::DEFAULT_SCALE)
+    {
+        return bcmul(strval($left), strval($right), $scale);
+    }
+
+    /**
+     * 除法运算
+     * @param string|float|int $left
+     * @param string|float|int $right
+     * @param int $scale
+     * @return string
+     */
+    public static function div($left, $right, $scale = self::DEFAULT_SCALE)
+    {
+        if (strval($right) === '0' || strval($right) === '0.00') {
+            return '0.00';
+        }
+        return bcdiv(strval($left), strval($right), $scale);
+    }
+
+    /**
+     * 比较运算
+     * @param string|float|int $left
+     * @param string|float|int $right
+     * @param int $scale
+     * @return int 1表示left>right,0表示相等,-1表示left<right
+     */
+    public static function comp($left, $right, $scale = self::DEFAULT_SCALE)
+    {
+        return bccomp(strval($left), strval($right), $scale);
+    }
+
+    /**
+     * 格式化金额为标准格式
+     * @param string|float|int $amount
+     * @param int $scale
+     * @return string
+     */
+    public static function format($amount, $scale = self::DEFAULT_SCALE)
+    {
+        return bcadd(strval($amount), '0', $scale);
+    }
+
+    /**
+     * 确保金额不为负数
+     * @param string|float|int $amount
+     * @param int $scale
+     * @return string
+     */
+    public static function max($amount, $scale = self::DEFAULT_SCALE)
+    {
+        $formatted = self::format($amount, $scale);
+        if (self::comp($formatted, '0', $scale) >= 0) {
+            return $formatted;
+        }
+        
+        // 返回0.00格式
+        return $scale > 0 ? '0.' . str_repeat('0', $scale) : '0';
+    }
+
+    /**
+     * 计算百分比
+     * @param string|float|int $amount
+     * @param string|float|int $percentage
+     * @param int $scale
+     * @return string
+     */
+    public static function percentage($amount, $percentage, $scale = self::DEFAULT_SCALE)
+    {
+        return self::div(self::mul($amount, $percentage, $scale + 2), '100', $scale);
+    }
+
+    /**
+     * 检查金额是否大于0
+     * @param string|float|int $amount
+     * @return bool
+     */
+    public static function isPositive($amount)
+    {
+        return self::comp($amount, '0') > 0;
+    }
+
+    /**
+     * 检查金额是否等于0
+     * @param string|float|int $amount
+     * @return bool
+     */
+    public static function isZero($amount)
+    {
+        return self::comp($amount, '0') === 0;
+    }
+
+    /**
+     * 获取两个金额中的最大值
+     * @param string|float|int $left
+     * @param string|float|int $right
+     * @param int $scale
+     * @return string
+     */
+    public static function maxValue($left, $right, $scale = self::DEFAULT_SCALE)
+    {
+        return self::comp($left, $right, $scale) >= 0 ? self::format($left, $scale) : self::format($right, $scale);
+    }
+
+    /**
+     * 获取两个金额中的最小值
+     * @param string|float|int $left
+     * @param string|float|int $right
+     * @param int $scale
+     * @return string
+     */
+    public static function minValue($left, $right, $scale = self::DEFAULT_SCALE)
+    {
+        return self::comp($left, $right, $scale) <= 0 ? self::format($left, $scale) : self::format($right, $scale);
+    }
+}

+ 44 - 7
application/common/model/commission/Agent.php

@@ -3,6 +3,8 @@
 namespace app\common\model\commission;
 
 use app\common\model\User;
+use app\common\Enum\AgentType;
+use app\common\library\BcMath;
 use think\Model;
 class Agent  extends Model
 {
@@ -17,7 +19,9 @@ class Agent  extends Model
     ];
     protected $append = [
         'status_text',
-        'pending_reward'
+        'agent_type_text',
+        'pending_reward',
+        'commission_balance'
     ];
 
     // 分销商状态 AGENT_STATUS
@@ -37,15 +41,34 @@ class Agent  extends Model
     public function statusList()
     {
         return [
-            'normal' => '正常',
-            'pending' => '审核中',
-            'freeze' => '冻结',
-            'forbidden' => '禁用',
-            'reject' => '拒绝'
+            self::AGENT_STATUS_NORMAL => '正常',
+            self::AGENT_STATUS_PENDING => '审核中',
+            self::AGENT_STATUS_FREEZE => '冻结',
+            self::AGENT_STATUS_FORBIDDEN => '禁用',
+            self::AGENT_STATUS_REJECT => '拒绝'
         ];
     }
 
     /**
+     * 获取状态文本
+     */
+    public function getStatusTextAttr($value, $data)
+    {
+        $value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
+        $statusList = $this->statusList();
+        return isset($statusList[$value]) ? $statusList[$value] : '正常';
+    }
+
+    /**
+     * 获取代理商类型文本
+     */
+    public function getAgentTypeTextAttr($value, $data)
+    {
+        $value = $value ? $value : (isset($data['agent_type']) ? $data['agent_type'] : 'normal');
+        return AgentType::getTypeText($value);
+    }
+
+    /**
      * 可用分销商
      */
     public function scopeAvaliable($query)
@@ -66,7 +89,21 @@ class Agent  extends Model
     public function getPendingRewardAttr($value, $data)
     {
         $amount = Reward::pending()->where('agent_id', $data['user_id'])->sum('commission');
-        return number_format($amount, 2, '.', '');
+        // 使用BcMath工具类格式化金额,确保精度
+        return BcMath::format($amount);
+    }
+
+    /**
+     * 获取佣金余额(累计收益 - 已提现金额)
+     */
+    public function getCommissionBalanceAttr($value, $data)
+    {
+        $totalIncome = $data['total_income'] ?? '0.00';
+        $withdrawnAmount = $data['withdrawn_amount'] ?? '0.00';
+        
+        // 使用BcMath工具类计算余额,并确保不为负数
+        $balance = BcMath::sub($totalIncome, $withdrawnAmount);
+        return BcMath::max($balance);
     }
 
     public function levelStatusInfo()

+ 21 - 29
application/common/model/commission/Apply.php

@@ -2,6 +2,9 @@
 
 namespace app\common\model\commission;
 
+use app\common\Enum\AgentType;
+use app\common\Enum\ApplyType;
+use app\common\Enum\ApplyStatus;
 use think\Model;
 
 class Apply extends Model
@@ -22,63 +25,52 @@ class Apply extends Model
         'status_text'
     ];
 
-    // 申请类型
-    const APPLY_TYPE_PERSONAL = 'personal';
-    const APPLY_TYPE_COMPANY = 'company';
+    // 申请类型(使用枚举类常量)
+    const APPLY_TYPE_PERSONAL = ApplyType::PERSONAL;
+    const APPLY_TYPE_COMPANY = ApplyType::COMPANY;
 
-    // 代理商类型
-    const AGENT_TYPE_NORMAL = 'normal';
-    const AGENT_TYPE_REGIONAL = 'regional';
+    // 代理商类型(使用枚举类常量)
+    const AGENT_TYPE_NORMAL = AgentType::NORMAL;
+    const AGENT_TYPE_PROVINCE = AgentType::PROVINCE;
+    const AGENT_TYPE_CITY = AgentType::CITY;
+    const AGENT_TYPE_DISTRICT = AgentType::DISTRICT;
 
-    // 申请状态
-    const STATUS_PENDING = 'pending';
-    const STATUS_APPROVED = 'approved';
-    const STATUS_REJECTED = 'rejected';
+    // 申请状态(使用枚举类常量)
+    const STATUS_PENDING = ApplyStatus::PENDING;
+    const STATUS_APPROVED = ApplyStatus::APPROVED;
+    const STATUS_REJECTED = ApplyStatus::REJECTED;
 
     public function getApplyTypeList()
     {
-        return [
-            self::APPLY_TYPE_PERSONAL => '个人申请',
-            self::APPLY_TYPE_COMPANY => '企业申请'
-        ];
+        return ApplyType::getAll();
     }
 
     public function getAgentTypeList()
     {
-        return [
-            self::AGENT_TYPE_NORMAL => '普通代理商',
-            self::AGENT_TYPE_REGIONAL => '区域代理商'
-        ];
+        return AgentType::getAll();
     }
 
     public function getStatusList()
     {
-        return [
-            self::STATUS_PENDING => '待审核',
-            self::STATUS_APPROVED => '已通过',
-            self::STATUS_REJECTED => '已拒绝'
-        ];
+        return ApplyStatus::getAll();
     }
 
     public function getApplyTypeTextAttr($value, $data)
     {
         $value = $value ? $value : (isset($data['apply_type']) ? $data['apply_type'] : '');
-        $list = $this->getApplyTypeList();
-        return isset($list[$value]) ? $list[$value] : '';
+        return ApplyType::getTypeText($value);
     }
 
     public function getAgentTypeTextAttr($value, $data)
     {
         $value = $value ? $value : (isset($data['agent_type']) ? $data['agent_type'] : '');
-        $list = $this->getAgentTypeList();
-        return isset($list[$value]) ? $list[$value] : '';
+        return AgentType::getTypeText($value);
     }
 
     public function getStatusTextAttr($value, $data)
     {
         $value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
-        $list = $this->getStatusList();
-        return isset($list[$value]) ? $list[$value] : '';
+        return ApplyStatus::getStatusText($value);
     }
 
     /**

+ 8 - 9
application/common/model/commission/Identity.php

@@ -2,6 +2,7 @@
 
 namespace app\common\model\commission;
 
+use app\common\Enum\AgentType;
 use think\Model;
 
 class Identity extends Model
@@ -25,9 +26,11 @@ class Identity extends Model
     const STATUS_DISABLED = 0;
     const STATUS_ENABLED = 1;
 
-    // 代理商类型
-    const AGENT_TYPE_NORMAL = 'normal';
-    const AGENT_TYPE_REGIONAL = 'regional';
+    // 代理商类型(使用枚举类常量)
+    const AGENT_TYPE_NORMAL = AgentType::NORMAL;
+    const AGENT_TYPE_PROVINCE = AgentType::PROVINCE;
+    const AGENT_TYPE_CITY = AgentType::CITY;
+    const AGENT_TYPE_DISTRICT = AgentType::DISTRICT;
 
     public function getStatusList()
     {
@@ -39,10 +42,7 @@ class Identity extends Model
 
     public function getAgentTypeList()
     {
-        return [
-            self::AGENT_TYPE_NORMAL => '普通代理商',
-            self::AGENT_TYPE_REGIONAL => '区域代理商'
-        ];
+        return AgentType::getAll();
     }
 
     public function getStatusTextAttr($value, $data)
@@ -55,8 +55,7 @@ class Identity extends Model
     public function getAgentTypeTextAttr($value, $data)
     {
         $value = $value ? $value : (isset($data['agent_type']) ? $data['agent_type'] : '');
-        $list = $this->getAgentTypeList();
-        return isset($list[$value]) ? $list[$value] : '';
+        return AgentType::getTypeText($value);
     }
 
     /**

+ 13 - 16
public/assets/js/backend/commission/apply.js

@@ -33,12 +33,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                                 return '<span class="label label-info">' + value + '</span>';
                             }
                         }},
-                        {field: 'agent_type_text', title: __('Agent type'), searchList: {"normal": "普通代理商", "regional": "区域代理商"}, formatter: function(value, row, index) {
-                            if (row.agent_type === 'regional') {
-                                return '<span class="label label-warning">' + value + '</span>';
-                            } else {
-                                return '<span class="label label-default">' + value + '</span>';
-                            }
+                        {field: 'agent_type_text', title: __('Agent type'), searchList: {"normal": "普通代理商", "province": "省级代理商", "city": "市级代理商", "district": "区域代理商"}, formatter: function(value, row, index) {
+                            var colorMap = {
+                                'province': 'danger',   // 省级-红色
+                                'city': 'warning',      // 市级-橙色  
+                                'district': 'info',     // 区域-蓝色
+                                'normal': 'default'     // 普通-默认
+                            };
+                            var color = colorMap[row.agent_type] || 'default';
+                            return '<span class="label label-' + color + '">' + value + '</span>';
                         }},
                         {field: 'identity.name', title: __('Identity'), operate: false},
                         {field: 'real_name', title: __('Real name'), visible: false},
@@ -61,18 +64,12 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                             var html = [];
                             
                             // 详情按钮
-                            if (Table.api.checkAuth('detail')) {
-                                html.push('<a href="' + Fast.api.fixurl("commission/apply/detail/ids/" + row.id) + '" class="btn btn-xs btn-info btn-dialog" data-area=\'["80%","80%"]\' title="' + __('Detail') + '"><i class="fa fa-list"></i></a>');
-                            }
+                            html.push('<a href="' + Fast.api.fixurl("commission/apply/detail/ids/" + row.id) + '" class="btn btn-xs btn-info btn-dialog" data-area=\'["80%","80%"]\' title="' + __('Detail') + '"><i class="fa fa-list"></i></a>');
                             
-                            // 审核按钮
+                            // 审核按钮 - 只在待审核状态显示
                             if (row.status === 'pending') {
-                                if (Table.api.checkAuth('approve')) {
-                                    html.push('<a href="javascript:;" class="btn btn-xs btn-success btn-approve-one" data-id="' + row.id + '" title="' + __('Approve') + '"><i class="fa fa-check"></i></a>');
-                                }
-                                if (Table.api.checkAuth('reject')) {
-                                    html.push('<a href="javascript:;" class="btn btn-xs btn-danger btn-reject-one" data-id="' + row.id + '" title="' + __('Reject') + '"><i class="fa fa-times"></i></a>');
-                                }
+                                html.push('<a href="javascript:;" class="btn btn-xs btn-success btn-approve-one" data-id="' + row.id + '" title="' + __('Approve') + '"><i class="fa fa-check"></i></a>');
+                                html.push('<a href="javascript:;" class="btn btn-xs btn-danger btn-reject-one" data-id="' + row.id + '" title="' + __('Reject') + '"><i class="fa fa-times"></i></a>');
                             }
                             
                             return html.join(' ');

+ 17 - 11
public/assets/js/backend/commission/identity.js

@@ -28,18 +28,22 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                         {field: 'id', title: __('Id'), sortable: true},
                         {field: 'name', title: __('Name'), operate: 'LIKE', formatter: Table.api.formatter.search},
                         {field: 'level', title: __('Level'), sortable: true},
-                        {field: 'agent_type_text', title: __('Agent type'), searchList: {"normal": "普通代理商", "regional": "区域代理商"}, formatter: function(value, row, index) {
-                            if (row.agent_type === 'regional') {
-                                return '<span class="label label-warning">' + value + '</span>';
-                            } else {
-                                return '<span class="label label-default">' + value + '</span>';
-                            }
+                        {field: 'agent_type_text', title: __('Agent type'), searchList: {"normal": "普通代理商", "province": "省级代理商", "city": "市级代理商", "district": "区域代理商"}, formatter: function(value, row, index) {
+                            var colorMap = {
+                                'province': 'danger',   // 省级-红色
+                                'city': 'warning',      // 市级-橙色  
+                                'district': 'info',     // 区域-蓝色
+                                'normal': 'default'     // 普通-默认
+                            };
+                            var color = colorMap[row.agent_type] || 'default';
+                            return '<span class="label label-' + color + '">' + value + '</span>';
                         }},
                         {field: 'regional_commission_rate', title: __('Regional rate'), operate: false, formatter: function(value, row, index) {
-                            if (row.agent_type === 'regional' && value > 0) {
-                                return value + '%';
+                            // 区域代理商(非normal类型)显示分佣比例
+                            if (['province', 'city', 'district'].indexOf(row.agent_type) !== -1) {
+                                return (value || 0) + '%';
                             }
-                            return row.agent_type === 'regional' ? '0.00%' : '-';
+                            return '-';
                         }},
                         {field: 'description', title: __('Description'), operate: 'LIKE'},
                         {field: 'status', title: __('Status'), searchList: {"0": __('Hidden'), "1": __('Shown')}, formatter: Table.api.formatter.status},
@@ -67,8 +71,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 $(document).on('change', 'input[name="row[agent_type]"]', function() {
                     var agentType = $(this).val();
                     var rateGroup = $('#regional-rate-group');
+                    var regionalTypes = ['province', 'city', 'district'];
                     
-                    if (agentType === 'regional') {
+                    if (regionalTypes.indexOf(agentType) !== -1) {
                         rateGroup.show();
                         rateGroup.find('input').attr('data-rule', 'required;range(0~100)');
                     } else {
@@ -80,7 +85,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
                 
                 // 页面加载时初始化显示状态
                 var checkedAgentType = $('input[name="row[agent_type]"]:checked').val();
-                if (checkedAgentType === 'regional') {
+                var regionalTypes = ['province', 'city', 'district'];
+                if (regionalTypes.indexOf(checkedAgentType) !== -1) {
                     $('#regional-rate-group').show();
                     $('#regional-rate-group').find('input').attr('data-rule', 'required;range(0~100)');
                 } else {