Browse Source

0711-0219-h01

Zory 3 weeks ago
parent
commit
56d7e2f61e

+ 7 - 0
app/controller/v2/Auth.php

@@ -6,6 +6,7 @@ use app\extra\basic\Base;
 use app\middleware\WxMiddleware;
 use app\model\blue\BlueExpert;
 use app\model\blue\BlueExpertGroup;
+use app\model\blue\BlueUserOpen;
 use app\validate\blue\ExpertGroupValidate;
 use app\validate\blue\ExpertValidate;
 use DI\Attribute\Inject;
@@ -47,6 +48,9 @@ class Auth extends Base
                 if ($data['status'] <> 1) return error("请勿重复提交");
             };
             if (!$this->validate->scene('add')->check($param)) return error($this->validate->getError());
+            if (!empty($param['avatar'])) {
+                (new BlueUserOpen)->where("openid",$request->user['openid'])->save(["headimg" => $param['avatar'],"nickname" => $param['nickname']]);
+            }
             $state = $data->setAutoData($param);
             if (!$state) return errorTrans("error.data");
             return successTrans("success.data");
@@ -90,6 +94,9 @@ class Auth extends Base
                 if ($data['status'] <> 1) return error("请勿重复提交");
             };
             if (!$this->groupValidate->scene('add')->check($param)) return error($this->groupValidate->getError());
+            if (!empty($param['avatar'])) {
+                (new BlueUserOpen)->where("openid",$request->user['openid'])->save(["headimg" => $param['avatar'],"nickname" => $param['nickname']]);
+            }
             $state = $data->setAutoData($param);
             if (!$state) return errorTrans("error.data");
             return successTrans("success.data");

+ 6 - 2
app/controller/v2/Bank.php

@@ -88,11 +88,15 @@ class Bank extends Base
     public function bindUserList(Request $request): Response
     {
         try {
-            $param = $request->all();
+            $param = $this->_valid([
+                "page.default"   => 1,
+                "size.default"   => 10,
+            ],$request->method());
+            if (!is_array($param)) return error($param);
             if (empty($param['size'])) return errorTrans("empty.require");
             $param['pageSize'] = $param['size'];
             $param['openid'] = $request->user['openid'];
-            $list = $this->service->getList($param);
+            $list = $this->service->getList($param,"id,bank_name,bank_num,bank_code");
             return successTrans("success.data",pageFormat($list));
         } catch (\Throwable $throwable) {
             return error($throwable->getMessage());

+ 131 - 6
app/controller/v2/Portal.php

@@ -5,10 +5,16 @@ namespace app\controller\v2;
 use app\extra\basic\Base;
 use app\extra\service\blue\ExpertPlatformService;
 use app\extra\service\blue\TaskService;
+use app\extra\tools\IpRegion;
 use app\middleware\WxMiddleware;
 use app\model\blue\BlueBanner;
 use app\model\blue\BlueCategory;
+use app\model\blue\BlueExpertGroup;
 use app\model\blue\BlueExpertPlatform;
+use app\model\blue\BlueIncomeMon;
+use app\model\blue\BlueTaskRevenue;
+use app\model\blue\BlueTaskUser;
+use app\model\blue\BlueUserOpen;
 use DI\Attribute\Inject;
 use LinFly\Annotation\Route\Controller;
 use LinFly\Annotation\Route\Middleware;
@@ -53,7 +59,7 @@ class Portal extends Base
                 "title" => sConf("wechat.share_title")
             ];
             $rank = [];
-            $star = (new BlueExpertPlatform)->order("create_at","desc")->field("source,nickname,avatar,follower_count,create_at")->limit(10)->select()->toArray();
+            $star = (new BlueExpertPlatform)->order("create_at","desc")->field("source,nickname,avatar,follower_count,uid,create_at")->limit(10)->select()->toArray();
             $list = $this->service->getHomeList(['category' => $param['category'],'pageSize' => $param['size'],'page' => $param['page']]);
             $task = pageFormat($list);
             return success("ok",compact("banner","category",'task','share','rank','star'));
@@ -76,14 +82,15 @@ class Portal extends Base
                 "source.default"    => ""
             ],$request->method());
             if (!is_array($param)) return error($param);
-            $data = (new ExpertPlatformService)->getListStar($param,"id,nickname,avatar,follower_count,unique_id,openid");
+            $data = (new ExpertPlatformService)->getListStar($param,"uid,nickname,avatar,follower_count,unique_id,openid,source");
             if (empty($data)) return successTrans("success.data",$data);
-            $return = [];
+            $list = [];
             foreach ($data as $key=>$val) {
-                $return[$key] = [
-                    "id"        => $val['id'],
+                $list[$key] = [
+                    "uid"       => $val['uid'],
                     "nickname"  => $val['nickname'],
                     "avatar"    => $val['avatar'],
+                    "source"    => $val['source'],
                     "follower"  => formatMoneyKw($val['follower_count']),
                     "income"    => 0,
                     "job"       => count($val['job']),
@@ -93,7 +100,125 @@ class Portal extends Base
                     ],
                 ];
             }
-            return successTrans("success.data",$return);
+            $monIncome = (new BlueIncomeMon)->where("mon")->sum("money");
+            $lastMonIncome = (new BlueIncomeMon)->where("mon",date("Ym",strtotime("-1 mon")))->sum("money");
+            $total = [
+                "join"      => (new BlueExpertPlatform)->count(),
+                "join_mon"  => (new BlueExpertPlatform)->whereMonth("create_at")->count(),
+                "auth"      => (new BlueExpertPlatform)->where("status",1)->count(),
+                "income"    => $monIncome,
+                "income_rate" => $lastMonIncome > 0 ? (($monIncome - $lastMonIncome) / $lastMonIncome * 100) : 100
+            ];
+            return successTrans("success.data",compact("list","total"));
+        } catch (\Throwable $throwable) {
+            return error($throwable->getMessage());
+        }
+    }
+
+    /**
+     * 个人主页
+     * @param Request $request
+     * @return Response
+     */
+    #[Route(path: "person",methods: "get")]
+    public function getHomePage(Request $request): Response
+    {
+        try {
+            $param = $this->_valid([
+                "uid.require"   => trans("empty.require"),
+            ],$request->method());
+            if (!is_array($param)) return error($param);
+            $data = (new BlueExpertPlatform)->where("uid",$param["uid"])->findOrEmpty();
+            if ($data->isEmpty()) return error("达人不存在");
+            $platform = (new BlueCategory)->where(["type" =>1,"status" => 1])->with(['platform' => function($query) use($data){
+                $query->where("openid",$data['openid'])->field("source,nickname,avatar,follower_count,unique_id");
+            }])->field("name,icon,sign")->select();
+            $userData = (new BlueUserOpen)->where("openid",$data['openid'])->field("nickname,headimg,openid,create_ip")->with(['star' => function($query) {
+                $query->field("openid,group_id,level_exp")->with(['level' => function($query) {
+                    $query->field("id,level,name,exp");
+                }]);
+            }])->append(['level',"tags"])->withAttr([
+                "tags" => function ($query,$resp) {
+                    $fans = (new BlueExpertPlatform)->where("openid",$resp['openid'])->sum("follower_count");
+                    $income = (new BlueTaskRevenue)->where("openid",$resp['openid'])->sum("indicator_agg_data_20022");
+                    return [
+                        [
+                            "name"  => "任务",
+                            "value" => (new BlueTaskUser)->where("openid",$resp['openid'])->where("status",'in',[1,3])->count(),
+                        ],
+                        [
+                            "name"  => "收益(元)",
+                            "value" => formatMoneyKw($income/1000)
+                        ],
+                        [
+                            "name"  => "粉丝",
+                            "value" => formatMoneyKw($fans),
+                        ],
+                        [
+                            "name"  => "消耗",
+                            "value" => "0.00",
+                        ]
+                    ];
+                },
+                "level" => function($query,$resp) {
+                    if ($resp['star']) {
+                        return [
+                            "level_num" => $resp['star']['level']['level']??'0',
+                            "level_name" => $resp['star']['level']['name']??'0'
+                        ];
+                    } else {
+                        return [];
+                    }
+                }
+            ])->findOrEmpty();
+            if ($userData->isEmpty()) return errorTrans("error.data");
+            $user = $userData->toArray();
+            $ip = new IpRegion();
+            $user['ip_address'] = $ip->setIp($user['create_ip'])->getProvince();
+            unset($user['star'],$user['openid'],$user['create_ip']);
+
+            return successTrans("success.data",compact("platform","user"));
+        } catch (\Throwable $throwable) {
+            return error($throwable->getMessage());
+        }
+    }
+
+    /**
+     * 排行榜
+     * @param Request $request
+     * @return Response
+     */
+    #[Route(path: "rank",methods: "get")]
+    public function getRankData(Request $request): Response
+    {
+        try {
+            $param = $this->_valid([
+                "type.default"   => 'income'
+            ],$request->method());
+            if (!is_array($param)) return error($param);
+            $data = [
+                [
+                    "name"      => "迅猛龙",
+                    "avatar"    => "https://p3-pc.douyinpic.com/aweme/1080x1080/aweme-avatar/tos-cn-i-0813_owAAafIQICAgfidek5L06cAeEp0mmDA1GIc2AF.jpeg?from=2956013662",
+                    "val"       => "29.3w",
+                    "index"     => 1
+                ],
+                [
+                    "name"      => "迅猛龙2",
+                    "avatar"    => "https://p3-pc.douyinpic.com/aweme/1080x1080/aweme-avatar/tos-cn-i-0813_owAAafIQICAgfidek5L06cAeEp0mmDA1GIc2AF.jpeg?from=2956013662",
+                    "val"       => "29.1w",
+                    "index"     => 2
+                ]
+            ];
+            $self =  [
+                [
+                    "name"      => "迅猛龙2",
+                    "avatar"    => "https://p3-pc.douyinpic.com/aweme/1080x1080/aweme-avatar/tos-cn-i-0813_owAAafIQICAgfidek5L06cAeEp0mmDA1GIc2AF.jpeg?from=2956013662",
+                    "val"       => "29.1w",
+                    "index"     => 0
+                ]
+            ];
+            return successTrans("success.data",compact("data","self"));
         } catch (\Throwable $throwable) {
             return error($throwable->getMessage());
         }

+ 1 - 2
app/controller/v2/Task.php

@@ -24,8 +24,7 @@ use yzh52521\EasyHttp\Http;
 class Task extends Base
 {
 
-
-    protected array $noNeedLogin = ["getTaskDetail","getTaskList"];
+    protected array $noNeedLogin = ["getTaskList"];
 
 
     #[Inject]

+ 93 - 0
app/controller/v2/Team.php

@@ -0,0 +1,93 @@
+<?php
+
+namespace app\controller\v2;
+
+use app\extra\basic\Base;
+use app\middleware\WxMiddleware;
+use LinFly\Annotation\Route\Controller;
+use LinFly\Annotation\Route\Middleware;
+use LinFly\Annotation\Route\Route;
+use support\Request;
+use support\Response;
+
+/**
+ * 团队管理
+ */
+#[Controller(prefix: "/wx_v2/team"),Middleware(WxMiddleware::class)]
+class Team extends Base
+{
+
+
+    /**
+     * 团队总览
+     * @param Request $request
+     * @return Response
+     */
+    #[Route(path: "total",methods: "get")]
+    public function getTeamList(Request $request): Response
+    {
+        try {
+            $data = [
+                "income"    => "0.00",
+                "cost"      => "0.00",
+                "number"    => 0,
+                "job"       => 0
+            ];
+            return successTrans("success.data",$data);
+        } catch (\Throwable $throwable) {
+            return error($throwable->getMessage());
+        }
+    }
+
+
+
+    /**
+     * 团队总览
+     * @param Request $request
+     * @return Response
+     */
+    #[Route(path: "children",methods: "get")]
+    public function getTeamChildren(Request $request): Response
+    {
+        try {
+            $data = [
+                "total" => 1,
+                "page" => 1,
+                "pageSize" => 10,
+                "rows"  => [
+                    [
+                        "nickname" => "微信用户", // 昵称
+                        "headimg" => "https://blue-data.oss-cn-guangzhou.aliyuncs.com/logo.png", // 头像
+                        "level" => [ // 等级信息
+                            "level_num" => 1, // 等级
+                            "level_name" => "青铜" // 等级名称
+                        ],
+                        "sign" => 0,
+                        "tags"=> [
+                            [
+                                "name"=> "今日收益",
+                                "value"=> 0
+                            ],
+                            [
+                                "name"=> "本月收益",
+                                "value"=> 0
+                            ],
+                            [
+                                "name"=> "消耗",
+                                "value"=> 0
+                            ],
+                            [
+                                "name"=> "任务数",
+                                "value"=> 0
+                            ],
+                        ],
+                    ]
+                ]
+            ];
+            return successTrans("success.data",$data);
+        } catch (\Throwable $throwable) {
+            return error($throwable->getMessage());
+        }
+    }
+
+}

+ 88 - 11
app/controller/v2/User.php

@@ -3,13 +3,19 @@
 namespace app\controller\v2;
 
 use app\extra\basic\Base;
+use app\extra\service\blue\UserLogService;
 use app\extra\tools\CodeExtend;
 use app\extra\weMini\Crypt;
 use app\extra\weMini\UserInfo;
 use app\middleware\WxMiddleware;
 use app\model\blue\BlueExpert;
+use app\model\blue\BlueExpertGroup;
 use app\model\blue\BlueExpertPlatform;
+use app\model\blue\BlueIncomeDay;
+use app\model\blue\BlueIncomeMon;
+use app\model\blue\BlueIncomeTotal;
 use app\model\blue\BlueTaskRevenue;
+use app\model\blue\BlueTaskUser;
 use app\model\blue\BlueUserOpen;
 use DI\Attribute\Inject;
 use LinFly\Annotation\Route\Controller;
@@ -106,6 +112,11 @@ class User extends Base
         }
     }
 
+    /**
+     * 个人中心数据
+     * @param Request $request
+     * @return Response
+     */
     #[Route(path: "data",methods: "get")]
     public function getUserData(Request $request): Response
     {
@@ -114,22 +125,39 @@ class User extends Base
                 $query->field("openid,group_id,level_exp")->with(['level' => function($query) {
                     $query->field("id,level,name,exp");
                 }]);
-            }])->append(['fans','job','income','level','sign'])->withAttr([
-                "fans"  => function($query,$resp) {
+            }])->append(['level','sign','group',"tags"])->withAttr([
+                "tags" => function ($query,$resp) {
                     $fans = (new BlueExpertPlatform)->where("openid",$resp['openid'])->sum("follower_count");
-                    return formatMoneyKw($fans); // 全网粉丝数
-                },
-                "job"  => function($query,$resp) {
-                    return "0"; // 任务数
-                },
-                "income" => function($query,$resp) {
                     $income = (new BlueTaskRevenue)->where("openid",$resp['openid'])->sum("indicator_agg_data_20022");
-                    return formatMoneyKw($income/1000); // 收益
+                    return [
+                        [
+                            "name"  => "完成任务",
+                            "value" => (new BlueTaskUser)->where("openid",$resp['openid'])->where("status",'in',[1,3])->count(),
+                        ],
+                        [
+                            "name"  => "收益(元)",
+                            "value" => formatMoneyKw($income/1000)
+                        ],
+                        [
+                            "name"  => "粉丝",
+                            "value" => formatMoneyKw($fans),
+                        ],
+                        [
+                            "name"  => "总消耗",
+                            "value" => "0.00",
+                        ]
+                    ];
                 },
                 "sign"  => function($query,$resp) {
                     if ($resp['star']) return 1;
                     return 0;
                 },
+                "group"  => function($query,$resp) {
+                    $group = (new BlueExpertGroup)->where("openid",$resp['openid'])->findOrEmpty();
+                    if ($group->isEmpty()) return 0;
+                    if ($group['status'] == 1) return 1;
+                    return 0;
+                },
                 "level" => function($query,$resp) {
                     if ($resp['star']) {
                         return [
@@ -153,18 +181,67 @@ class User extends Base
     }
 
     /**
-     * 收益
+     * 收益总览
      * @param Request $request
      * @return Response
      */
-    #[Route(path: "income",methods: "get")]
+    #[Route(path: "income/total",methods: "get")]
     public function getIncomeData(Request $request): Response
     {
         try {
+            $param = $this->_valid([
+                "day.default"   => 7
+            ],$request->method());
+            if (!is_array($param)) return error($param);
+            // 累计已结算收益
+            $total = (new BlueIncomeTotal)->where("openid",$request->user['openid'])->sum("money");
+            // 今日收益
+            $day = (new BlueIncomeDay)->where("openid",$request->user['openid'])->sum("money");
+            // 本月收益
+            $mon = (new BlueIncomeMon)->where("openid",$request->user['openid'])->sum("money");
+            // 钱包余额
+            $balance = (new BlueExpert)->where("openid",$request->user['openid'])->value("balance");
+            if ($balance > 0) $balance = format_money($balance/100);
+            // 待结算
+            $echart = [];
+            $fields = ['ROUND(sum(money)/100,2)' => 'total','substr(create_at,1,10)' => 'mday'];
+            $orderNum = (new BlueIncomeDay)->field($fields)->where("openid",$request->user['openid'])->whereTime('create_at', '-'.$param['day'].' days')->group('mday')->select()->column(null, 'mday');
+            for ($i = $param['day']; $i >= 0; $i--) {
+                $date = date('Y-m-d', strtotime("-{$i}days"));
+                $echart[] = [
+                    'day' => date('m-d', strtotime("-{$i}days")),
+                    'money' => ($orderNum[$date] ?? [])['total'] ?? 0,
+                ];
+            }
+            return successTrans("success.data",compact("echart","total","balance","day","mon"));
+        } catch (\Throwable $throwable) {
+            return error($throwable->getMessage());
+        }
+    }
 
+
+    /**
+     * 收益记录
+     * @param Request $request
+     * @return Response
+     */
+    #[Route(path: "income/log",methods: "get")]
+    public function getIncomeLogs(Request $request): Response
+    {
+        try {
+            $param = $this->_valid([
+                "page.default"   => 1,
+                "size.default"   => 10,
+            ],$request->method());
+            if (!is_array($param)) return error($param);
+            $param['pageSize'] = $param['size'];
+            $param['openid'] = $request->user['openid'];
+            $list = (new UserLogService)->getList($param,"type,money,remark,icon,create_at");
+            return successTrans("success.data",pageFormat($list));
         } catch (\Throwable $throwable) {
             return error($throwable->getMessage());
         }
+
     }
 
 }

+ 25 - 1
app/controller/v2/Withdraw.php

@@ -3,6 +3,7 @@
 namespace app\controller\v2;
 
 use app\extra\basic\Base;
+use app\extra\service\blue\WithdrawLogService;
 use app\middleware\WxMiddleware;
 use app\model\blue\BlueExpert;
 use app\model\blue\BlueWithdrawLog;
@@ -58,7 +59,7 @@ class Withdraw extends Base
             if (!isset($bankData['bank_code'])) return error("银行卡数据错误");
             $state = (new BlueWithdrawLog)->insertGetId([
                 "openid"    => $request->user['openid'],
-                "bank_id"   => $bankData['bank_code'],
+                "bank_id"   => $bankData['id'],
                 "money"     => $param['money'] * 100
             ]);
             if (!$state) return errorTrans("error.data");
@@ -70,5 +71,28 @@ class Withdraw extends Base
         }
     }
 
+    /**
+     * 提现记录
+     * @param Request $request
+     * @return Response
+     */
+    #[Route(path: "log",methods: "get")]
+    public function bindUserList(Request $request): Response
+    {
+        try {
+            $param = $this->_valid([
+                "page.default"   => 1,
+                "size.default"   => 10,
+            ],$request->method());
+            if (!is_array($param)) return error($param);
+            $param['pageSize'] = $param['size'];
+            $param['openid'] = $request->user['openid'];
+            $list = (new WithdrawLogService)->getList($param,"bank_id,money,status,create_at");
+            return successTrans("success.data",pageFormat($list));
+        } catch (\Throwable $throwable) {
+            return error($throwable->getMessage());
+        }
+    }
+
 
 }

+ 1 - 1
app/extra/service/blue/TaskService.php

@@ -37,7 +37,7 @@ class TaskService extends Service
             if ($resp['sign_number'] == 0) return $resp['sign_number'];
             return ceil($resp['sign_number']/$resp['need_number'] * 100);
         },'total_budget_format' => function($data,$resp) {
-            return formatMoneyKw($resp['total_budget']/100);
+            return formatMoneyKw($resp['total_budget']);
         }])->with(['categoryJoin' => function ($query) {
             $query->field("sign,name,icon,small_icon");
         },'levelJoin' => function($query){

+ 2 - 2
app/extra/service/blue/UserBankService.php

@@ -13,12 +13,12 @@ class UserBankService extends Service
      * 列表
      * @param array $param
      */
-    public function getList(array $param = [])
+    public function getList(array $param = [],string $field = "*")
     {
         $this->mode = new BlueUserBank();
         return $this->searchVal($param,$this->searchFilter($param))->append(['bank_img'])->withAttr(['bank_img' => function($data,$resp){
             return "https://apimg.alipay.com/combo.png?d=cashier&t={$resp['bank_code']}";
-        }])->paginate([
+        }])->field($field)->paginate([
             "list_rows" => $param['pageSize'],
             "page"      => $param['page']
         ]);

+ 39 - 0
app/extra/service/blue/UserLogService.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace app\extra\service\blue;
+
+use app\extra\basic\Service;
+use app\model\blue\BlueUserLog;
+
+class UserLogService extends Service
+{
+
+    /**
+     * 列表
+     * @param array $param
+     */
+    public function getList(array $param = [],string $field = "*")
+    {
+        $this->mode = new BlueUserLog();
+        return $this->searchVal($param,$this->searchFilter($param))->field($field)->paginate([
+            "list_rows" => $param['pageSize'],
+            "page"      => $param['page']
+        ]);
+    }
+
+    /**
+     *
+     * @param array $param
+     * @return array
+     */
+    public function searchFilter(array $param = []): array
+    {
+        $filter = [];
+        !empty($param['openid']) && $filter[] = ["openid", '=', $param['openid']];
+        !empty($param['type']) && $filter[] = ["type", '=', $param['type']];
+        !empty($param['status']) && $filter[] = ["status", '=', $param['status']];
+        !empty($param['name']) && $filter[] = ["name", 'like', "%{$param['name']}%"];
+        return $filter;
+    }
+
+}

+ 39 - 0
app/extra/service/blue/WithdrawLogService.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace app\extra\service\blue;
+
+use app\extra\basic\Service;
+use app\model\blue\BlueWithdrawLog;
+
+class WithdrawLogService extends Service
+{
+    /**
+     * 列表
+     * @param array $param
+     */
+    public function getList(array $param = [],string $field = "*")
+    {
+        $this->mode = new BlueWithdrawLog();
+        return $this->searchVal($param,$this->searchFilter($param))->with(['bank' => function ($query) {
+            $query->field("id,bank_code,bank_name")->append(['bank_img'])->withAttr(['bank_img' => function($data,$resp){
+                return "https://apimg.alipay.com/combo.png?d=cashier&t={$resp['bank_code']}";
+            }]);
+        }])->field($field)->paginate([
+            "list_rows" => $param['pageSize'],
+            "page"      => $param['page']
+        ]);
+    }
+
+    /**
+     *
+     * @param array $param
+     * @return array
+     */
+    public function searchFilter(array $param = []): array
+    {
+        $filter = [];
+        !empty($param['openid']) && $filter[] = ["openid", '=', $param['openid']];
+        return $filter;
+    }
+
+}

+ 481 - 0
app/extra/tools/IpRegion.php

@@ -0,0 +1,481 @@
+<?php
+
+namespace app\extra\tools;
+
+class IpRegion
+{
+    const IPV4_VERSION_NO = 4;
+    const IPV6_VERSION_NO = 6;
+    const XDB_HEADER_LENGTH = 256;
+    const VECTOR_INDEX_ROWS = 256;
+    const VECTOR_INDEX_COLS = 256;
+    const VECTOR_INDEX_SIZE = 8;
+
+    /**
+     * @var string
+     */
+    private $dbFileV4;
+
+    /**
+     * @var string
+     */
+    private $dbFileV6;
+
+    /**
+     * @var string|null
+     */
+    private $contentBuffV4 = null;
+
+    /**
+     * @var string|null
+     */
+    private $contentBuffV6 = null;
+
+    /**
+     * ipRegion info
+     */
+    private $ip = '';
+    private $ip_address = '';
+    private $ip_address_list = array();
+    private $country = '';
+    private $province = '';
+    private $city = '';
+    private $isp = '';
+    private $isoCode = '';
+
+    /**
+     * @param string|null $ipv4DbFile
+     * @param string|null $ipv6DbFile
+     */
+    public function __construct($ipv4DbFile = null, $ipv6DbFile = null)
+    {
+        $baseDir = __DIR__;
+
+        $this->dbFileV4 = $ipv4DbFile ?: $baseDir . '/ip2region_v4.xdb';
+        $this->dbFileV6 = $ipv6DbFile ?: $baseDir . '/ip2region_v6.xdb';
+    }
+
+    /**
+     * @param string $ip
+     * @return $this|null
+     */
+    public function setIp($ip)
+    {
+        $this->resetRegion();
+        $this->ip = $ip;
+
+        $ipBytes = $this->parseIP($ip);
+        if ($ipBytes === null) {
+            throw new \InvalidArgumentException("Invalid ip address: {$ip}");
+        }
+
+        $version = $this->getVersionMeta($ipBytes);
+        $contentBuff = $this->loadContentBuffer($version['version_no'], $version['db_file']);
+        $region = $this->searchByBytes($version, $contentBuff, $ipBytes);
+
+        if ($region === '') {
+            return null;
+        }
+
+        $this->fillRegion($region);
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getIpAddress()
+    {
+        return $this->ip_address;
+    }
+
+    /**
+     * @return string
+     */
+    public function getCountry()
+    {
+        return $this->country;
+    }
+
+    /**
+     * @return string
+     */
+    public function getProvince()
+    {
+        return $this->province;
+    }
+
+    /**
+     * @return string
+     */
+    public function getCity()
+    {
+        return $this->city;
+    }
+
+    /**
+     * @return string
+     */
+    public function getIsp()
+    {
+        return $this->isp;
+    }
+
+    /**
+     * @return string
+     */
+    public function getIsoCode()
+    {
+        return $this->isoCode;
+    }
+
+    /**
+     * @return array
+     */
+    public function getIpAddressList()
+    {
+        return $this->ip_address_list;
+    }
+
+    /**
+     * @param string $ipString
+     * @return string|null
+     */
+    private function parseIP($ipString)
+    {
+        $flag = FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6;
+        if (!filter_var($ipString, FILTER_VALIDATE_IP, $flag)) {
+            return null;
+        }
+
+        return inet_pton($ipString);
+    }
+
+    /**
+     * @param string $ipBytes
+     * @return array
+     */
+    private function getVersionMeta($ipBytes)
+    {
+        if (strlen($ipBytes) === 4) {
+            return array(
+                'version_no' => self::IPV4_VERSION_NO,
+                'bytes' => 4,
+                'segment_index_size' => 14,
+                'db_file' => $this->dbFileV4,
+            );
+        }
+
+        return array(
+            'version_no' => self::IPV6_VERSION_NO,
+            'bytes' => 16,
+            'segment_index_size' => 38,
+            'db_file' => $this->dbFileV6,
+        );
+    }
+
+    /**
+     * @param int $versionNo
+     * @param string $dbFile
+     * @return string
+     */
+    private function loadContentBuffer($versionNo, $dbFile)
+    {
+        if ($versionNo === self::IPV4_VERSION_NO) {
+            if ($this->contentBuffV4 === null) {
+                $this->contentBuffV4 = $this->loadContentFromFile($dbFile);
+            }
+
+            return $this->contentBuffV4;
+        }
+
+        if ($this->contentBuffV6 === null) {
+            $this->contentBuffV6 = $this->loadContentFromFile($dbFile);
+        }
+
+        return $this->contentBuffV6;
+    }
+
+    /**
+     * @param string $dbFile
+     * @return string
+     */
+    private function loadContentFromFile($dbFile)
+    {
+        $handle = fopen($dbFile, 'rb');
+        if ($handle === false) {
+            throw new \RuntimeException("Fail to open xdb file {$dbFile}");
+        }
+
+        $verifyError = $this->verifyHandle($handle);
+        if ($verifyError !== null) {
+            fclose($handle);
+            throw new \RuntimeException("Invalid xdb file {$dbFile}: {$verifyError}");
+        }
+
+        if (fseek($handle, 0, SEEK_END) === -1) {
+            fclose($handle);
+            throw new \RuntimeException("Fail to seek xdb file {$dbFile}");
+        }
+
+        $size = ftell($handle);
+        if ($size === false) {
+            fclose($handle);
+            throw new \RuntimeException("Fail to stat xdb file {$dbFile}");
+        }
+
+        if (fseek($handle, 0) === -1) {
+            fclose($handle);
+            throw new \RuntimeException("Fail to rewind xdb file {$dbFile}");
+        }
+
+        $contentBuff = fread($handle, $size);
+        fclose($handle);
+
+        if ($contentBuff === false || strlen($contentBuff) != $size) {
+            throw new \RuntimeException("Fail to load xdb file {$dbFile}");
+        }
+
+        return $contentBuff;
+    }
+
+    /**
+     * @param resource $handle
+     * @return string|null
+     */
+    private function verifyHandle($handle)
+    {
+        $header = $this->loadHeader($handle);
+        if ($header === null) {
+            return 'failed to load the header';
+        }
+
+        if ($header['version'] == 2) {
+            $runtimePtrBytes = 4;
+        } elseif ($header['version'] == 3) {
+            $runtimePtrBytes = $header['runtimePtrBytes'];
+        } else {
+            return "invalid structure version `{$header['version']}`";
+        }
+
+        $stat = fstat($handle);
+        if ($stat === false) {
+            return 'failed to stat the xdb file';
+        }
+
+        $maxFilePtr = (1 << ($runtimePtrBytes * 8)) - 1;
+        if ($stat['size'] > $maxFilePtr) {
+            return "xdb file exceeds the maximum supported bytes: {$maxFilePtr}";
+        }
+
+        return null;
+    }
+
+    /**
+     * @param resource $handle
+     * @return array|null
+     */
+    private function loadHeader($handle)
+    {
+        if (fseek($handle, 0) === -1) {
+            return null;
+        }
+
+        $buff = fread($handle, self::XDB_HEADER_LENGTH);
+        if ($buff === false || strlen($buff) != self::XDB_HEADER_LENGTH) {
+            return null;
+        }
+
+        return array(
+            'version' => $this->leGetUint16($buff, 0),
+            'indexPolicy' => $this->leGetUint16($buff, 2),
+            'createdAt' => $this->leGetUint32($buff, 4),
+            'startIndexPtr' => $this->leGetUint32($buff, 8),
+            'endIndexPtr' => $this->leGetUint32($buff, 12),
+            'ipVersion' => $this->leGetUint16($buff, 16),
+            'runtimePtrBytes' => $this->leGetUint16($buff, 18),
+        );
+    }
+
+    /**
+     * @param array $version
+     * @param string $contentBuff
+     * @param string $ipBytes
+     * @return string
+     */
+    private function searchByBytes(array $version, $contentBuff, $ipBytes)
+    {
+        if (strlen($ipBytes) != $version['bytes']) {
+            throw new \InvalidArgumentException('invalid ip address version');
+        }
+
+        $il0 = ord($ipBytes[0]) & 0xFF;
+        $il1 = ord($ipBytes[1]) & 0xFF;
+        $idx = $il0 * self::VECTOR_INDEX_COLS * self::VECTOR_INDEX_SIZE + $il1 * self::VECTOR_INDEX_SIZE;
+        $sPtr = $this->leGetUint32($contentBuff, self::XDB_HEADER_LENGTH + $idx);
+        $ePtr = $this->leGetUint32($contentBuff, self::XDB_HEADER_LENGTH + $idx + 4);
+
+        if ($sPtr == 0 || $ePtr == 0) {
+            return '';
+        }
+
+        $bytes = $version['bytes'];
+        $dataOffset = $bytes << 1;
+        $idxSize = $version['segment_index_size'];
+        $dataLen = 0;
+        $dataPtr = 0;
+        $l = 0;
+        $h = ($ePtr - $sPtr) / $idxSize;
+
+        while ($l <= $h) {
+            $m = ($l + $h) >> 1;
+            $p = $sPtr + $m * $idxSize;
+            $buff = substr($contentBuff, $p, $idxSize);
+
+            if ($this->compareIpBytes($version['version_no'], $ipBytes, $buff, 0) < 0) {
+                $h = $m - 1;
+            } elseif ($this->compareIpBytes($version['version_no'], $ipBytes, $buff, $bytes) > 0) {
+                $l = $m + 1;
+            } else {
+                $dataLen = $this->leGetUint16($buff, $dataOffset);
+                $dataPtr = $this->leGetUint32($buff, $dataOffset + 2);
+                break;
+            }
+        }
+
+        if ($dataLen == 0) {
+            return '';
+        }
+
+        return substr($contentBuff, $dataPtr, $dataLen);
+    }
+
+    /**
+     * @param int $versionNo
+     * @param string $ipBytes
+     * @param string $buff
+     * @param int $offset
+     * @return int
+     */
+    private function compareIpBytes($versionNo, $ipBytes, $buff, $offset)
+    {
+        if ($versionNo === self::IPV4_VERSION_NO) {
+            $len = strlen($ipBytes);
+            $end = $offset + $len;
+            for ($i = 0, $j = $end - 1; $i < $len; $i++, $j--) {
+                $left = ord($ipBytes[$i]) & 0xFF;
+                $right = ord($buff[$j]) & 0xFF;
+                if ($left > $right) {
+                    return 1;
+                }
+                if ($left < $right) {
+                    return -1;
+                }
+            }
+
+            return 0;
+        }
+
+        $result = strcmp($ipBytes, substr($buff, $offset, strlen($ipBytes)));
+        if ($result < 0) {
+            return -1;
+        }
+        if ($result > 0) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+    /**
+     * @param string $region
+     */
+    private function fillRegion($region)
+    {
+        $parts = explode('|', $region);
+
+        $this->country = isset($parts[0]) ? $this->normalizeField($parts[0]) : '';
+        $this->province = isset($parts[1]) ? $this->normalizeField($parts[1]) : '';
+        $this->city = isset($parts[2]) ? $this->normalizeField($parts[2]) : '';
+        $this->isp = isset($parts[3]) ? $this->normalizeField($parts[3]) : '';
+        $this->isoCode = isset($parts[4]) ? $this->normalizeField($parts[4]) : '';
+
+        $addressParts = array_filter(
+            array($this->country, $this->province, $this->city),
+            function ($value) {
+                return $value !== '';
+            }
+        );
+
+        $this->ip_address = implode(' ', $addressParts);
+        $this->ip_address_list = array(
+            'ip_address' => $this->ip_address,
+            'country' => $this->country,
+            'province' => $this->province,
+            'city' => $this->city,
+            'isp' => $this->isp,
+            'iso_code' => $this->isoCode,
+        );
+    }
+
+    private function resetRegion()
+    {
+        $this->ip_address = '';
+        $this->ip_address_list = array();
+        $this->country = '';
+        $this->province = '';
+        $this->city = '';
+        $this->isp = '';
+        $this->isoCode = '';
+    }
+
+    /**
+     * @param string $value
+     * @return string
+     */
+    private function normalizeField($value)
+    {
+        $value = trim($value);
+
+        if ($value === '0') {
+            return '';
+        }
+
+        return $value;
+    }
+
+    /**
+     * @param string $buffer
+     * @param int $offset
+     * @return int|string
+     */
+    private function leGetUint32($buffer, $offset)
+    {
+        $value = (ord($buffer[$offset])) | (ord($buffer[$offset + 1]) << 8)
+            | (ord($buffer[$offset + 2]) << 16) | (ord($buffer[$offset + 3]) << 24);
+
+        if ($value < 0 && PHP_INT_SIZE == 4) {
+            $value = sprintf('%u', $value);
+        }
+
+        return $value;
+    }
+
+    /**
+     * @param string $buffer
+     * @param int $offset
+     * @return int
+     */
+    private function leGetUint16($buffer, $offset)
+    {
+        return (ord($buffer[$offset])) | (ord($buffer[$offset + 1]) << 8);
+    }
+
+    public function __destruct()
+    {
+        $this->contentBuffV4 = null;
+        $this->contentBuffV6 = null;
+    }
+
+}

BIN
app/extra/tools/ip2region_v4.xdb


BIN
app/extra/tools/ip2region_v6.xdb


+ 48 - 0
app/model/blue/BlueIncomeDay.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace app\model\blue;
+
+use app\extra\basic\Model;
+
+
+/**
+ * @property integer $id (主键)
+ * @property mixed $openid 
+ * @property mixed $job_id 
+ * @property mixed $star_id 
+ * @property integer $money 
+ * @property mixed $day 
+ * @property mixed $create_at 创建时间
+ */
+class BlueIncomeDay extends Model
+{
+    /**
+     * The connection name for the model.
+     *
+     * @var string|null
+     */
+    protected $connection = 'mysql';
+    
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected string $table = "blue_income_day";
+    
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected string $primaryKey = "id";
+    
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public bool $timestamps = false;
+
+
+}

+ 48 - 0
app/model/blue/BlueIncomeMon.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace app\model\blue;
+
+use app\extra\basic\Model;
+
+
+/**
+ * @property integer $id (主键)
+ * @property mixed $openid 
+ * @property mixed $job_id 
+ * @property mixed $star_id 
+ * @property integer $money 
+ * @property mixed $mon 
+ * @property mixed $create_at 创建时间
+ */
+class BlueIncomeMon extends Model
+{
+    /**
+     * The connection name for the model.
+     *
+     * @var string|null
+     */
+    protected $connection = 'mysql';
+    
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected string $table = "blue_income_mon";
+    
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected string $primaryKey = "id";
+    
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public bool $timestamps = false;
+
+
+}

+ 47 - 0
app/model/blue/BlueIncomeTotal.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace app\model\blue;
+
+use app\extra\basic\Model;
+
+
+/**
+ * @property integer $id (主键)
+ * @property mixed $openid 
+ * @property mixed $job_id 
+ * @property mixed $star_id 
+ * @property integer $money 
+ * @property mixed $create_at 创建时间
+ */
+class BlueIncomeTotal extends Model
+{
+    /**
+     * The connection name for the model.
+     *
+     * @var string|null
+     */
+    protected $connection = 'mysql';
+    
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected string $table = "blue_income_total";
+    
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected string $primaryKey = "id";
+    
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public bool $timestamps = false;
+
+
+}

+ 4 - 4
app/model/blue/BlueTask.php

@@ -47,10 +47,10 @@ class BlueTask extends Model
      */
     public bool $timestamps = false;
 
-    public function getTotalBudgetAttr($val): string
-    {
-        return format_money($val/100);
-    }
+//    public function getTotalBudgetAttr($val): string
+//    {
+//        return formatMoneyKw($val);
+//    }
 
     public function getExpirationTimeEndAttr($val): int
     {

+ 51 - 0
app/model/blue/BlueUserLog.php

@@ -0,0 +1,51 @@
+<?php
+
+namespace app\model\blue;
+
+use app\extra\basic\Model;
+
+
+/**
+ * @property integer $id (主键)
+ * @property mixed $openid 
+ * @property integer $type 1收入2支持
+ * @property integer $money 
+ * @property string $remark 
+ * @property mixed $create_at 创建时间
+ */
+class BlueUserLog extends Model
+{
+    /**
+     * The connection name for the model.
+     *
+     * @var string|null
+     */
+    protected $connection = 'mysql';
+    
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected string $table = "blue_user_log";
+    
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected string $primaryKey = "id";
+    
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public bool $timestamps = false;
+
+    public function getMoneyAttr($value): string
+    {
+        return $value==0?'0.00':format_money($value/100);
+    }
+
+}

+ 16 - 6
app/model/blue/BlueWithdrawLog.php

@@ -3,15 +3,16 @@
 namespace app\model\blue;
 
 use app\extra\basic\Model;
+use think\model\relation\HasOne;
 
 
 /**
- * @property integer $id (主键)
- * @property mixed $openid 
- * @property integer $bank_id 
- * @property integer $money 
- * @property integer $status 0审核1到账2失败
- * @property string $remark 
+ * @property integer $id (主键)
+ * @property mixed $openid 
+ * @property integer $bank_id 
+ * @property integer $money 
+ * @property integer $status 0审核1到账2失败
+ * @property string $remark 
  * @property mixed $create_at 创建时间
  */
 class BlueWithdrawLog extends Model
@@ -44,5 +45,14 @@ class BlueWithdrawLog extends Model
      */
     public bool $timestamps = false;
 
+    public function getMoneyAttr($value): string
+    {
+        return $value == 0 ? "0.00" : format_money($value/100);
+    }
+
+    public function bank(): HasOne
+    {
+        return $this->hasOne(BlueUserBank::class,"id","bank_id");
+    }
 
 }

+ 9 - 5
app/validate/blue/ExpertGroupValidate.php

@@ -8,25 +8,29 @@ class ExpertGroupValidate extends Validate
 {
 
 
+
+
     protected $rule = [
-        "truenname"     => "require",
+        "truename"     => "require",
+        "idcard"        => "require|idCard",
         "mobile"        => "require|mobile",
         "city"          => "require",
         "city_path"     => "require",
-        "team"          => "require",
     ];
 
 
     protected $message = [
-        "truenname.require"     => "请输入姓名",
+        "truename.require"     => "请输入姓名",
+        "idcard.require"        => "请输入身份证号",
+        "idcard.idCard"         => "身份证号有误",
         "mobile.require"        => "请输入手机号码",
         "mobile.mobile"         => "手机号有误",
         "city.require"          => "请选择城市",
         "city_path.require"     => "请选择城市",
-        "team.require"          => "请选择团队",
     ];
+
     protected $scene = [
-        'add'  =>  ['truenname','mobile','city','city_path','team'],
+        'add'  =>  ['truename','idcard','mobile','city','city_path'],
     ];