瀏覽代碼

Merge branch 'raccount' into rchannel

xiaoyu 2 年之前
父節點
當前提交
51758dc435
共有 100 個文件被更改,包括 4861 次插入723 次删除
  1. 2 1
      admin/config/config.ini.php
  2. 25 0
      admin/control/control.php
  3. 9 1
      admin/control/merchant.php
  4. 2 2
      admin/control/ordersendlist.php
  5. 114 0
      admin/control/provider.php
  6. 90 4
      admin/control/refill_analysis.php
  7. 425 0
      admin/control/refill_company.php
  8. 0 12
      admin/control/refill_order.php
  9. 1 0
      admin/include/limit.php
  10. 2 1
      admin/include/menu.php
  11. 166 60
      admin/templates/default/analysis.new_version.php
  12. 363 0
      admin/templates/default/analysis.new_version.provider.php
  13. 345 0
      admin/templates/default/analysis.new_version.system.php
  14. 4 1
      admin/templates/default/analysis.provider.php
  15. 4 1
      admin/templates/default/analysis.system.php
  16. 15 0
      admin/templates/default/merchant.edit.php
  17. 2 0
      admin/templates/default/merchant.index.php
  18. 3 1
      admin/templates/default/merchant.ratios.php
  19. 3 2
      admin/templates/default/provider.amount.php
  20. 15 0
      admin/templates/default/provider.edit.php
  21. 3 0
      admin/templates/default/provider.index.php
  22. 230 0
      admin/templates/default/provider.remit.edit.php
  23. 227 0
      admin/templates/default/provider.remit.php
  24. 225 0
      admin/templates/default/refill.company.add.php
  25. 255 0
      admin/templates/default/refill.company.edit.php
  26. 153 0
      admin/templates/default/refill.company.php
  27. 173 0
      admin/templates/default/refill.company.remit.php
  28. 58 0
      admin/templates/default/remit.config.php
  29. 43 11
      crontab/control/minutes.php
  30. 84 40
      data/config/xyz/refill.ini.php
  31. 76 32
      data/config/yl/refill.ini.php
  32. 41 0
      data/model/refill_company.model.php
  33. 41 0
      data/model/refill_company_remit.model.php
  34. 10 0
      data/model/refill_detail.model.php
  35. 1 1
      docker/compose/homecuda/cli/docker-compose.yml
  36. 5 1
      docker/compose/homecuda/statsec/docker-compose.yml
  37. 5 1
      docker/compose/homecuda/storage/docker-compose.yml
  38. 13 0
      docker/compose/workcuda/sdatacalc/docker-compose.yml
  39. 0 12
      docker/compose/workcuda/statsec/docker-compose.yml
  40. 12 1
      docker/compose/workcuda/slave-crond/docker-compose.yml
  41. 6 2
      docker/compose/xyz/statsec/docker-compose.yml
  42. 16 0
      docker/compose/yl/ylslave-crond/docker-compose.yml
  43. 1 1
      docker/compose/yl/ylstatsec/docker-compose.yml
  44. 10 8
      helper/refill/RefillBase.php
  45. 二進制
      helper/refill/api/xyz/guochuang/20220630广东移动调价函.png
  46. 二進制
      helper/refill/api/xyz/guochuang/20220630辽宁移动调价函.jpg
  47. 二進制
      helper/refill/api/xyz/guochuang/20220701广东调价函.png
  48. 二進制
      helper/refill/api/xyz/guochuang/20220701辽宁移动调价函.png
  49. 二進制
      helper/refill/api/xyz/guochuang/20220702陕西电信调价函.png
  50. 二進制
      helper/refill/api/xyz/guochuang/20220704辽宁移动调价函.png
  51. 二進制
      helper/refill/api/xyz/guochuang/20220705广东移动调价函.png
  52. 二進制
      helper/refill/api/xyz/guochuang/20220706辽宁移动调价函.png
  53. 二進制
      helper/refill/api/xyz/guochuang/20220708辽宁 青海 贵州调价函.png
  54. 二進制
      helper/refill/api/xyz/guochuang/20220710河南移动调价函.png
  55. 二進制
      helper/refill/api/xyz/guochuang/20220710辽宁移动调价函.png
  56. 二進制
      helper/refill/api/xyz/guochuang/20220711吉林移动调价函.png
  57. 二進制
      helper/refill/api/xyz/guochuang/20220713辽宁移动调价函.png
  58. 二進制
      helper/refill/api/xyz/guochuang/20220714辽宁移动调价函.png
  59. 二進制
      helper/refill/api/xyz/guochuang/20220715广东移动调价函.png
  60. 7 7
      helper/refill/api/xyz/guochuang/config.php
  61. 67 0
      helper/refill/api/xyz/huoshenguo_fs/RefillCallBack.php
  62. 155 0
      helper/refill/api/xyz/huoshenguo_fs/RefillPhone.php
  63. 36 0
      helper/refill/api/xyz/huoshenguo_fs/config.php
  64. 28 0
      helper/refill/api/xyz/huoshenguo_fs/开户信息.txt
  65. 17 23
      helper/refill/api/xyz/yamiao_high/config.php
  66. 23 30
      helper/refill/api/xyz/yamiao_high/开户信息.txt
  67. 17 23
      helper/refill/api/xyz/yamiao_normal/config.php
  68. 23 29
      helper/refill/api/xyz/yamiao_normal/开户信息.txt
  69. 17 19
      helper/refill/api/xyz/yunchonggong/config.php
  70. 26 9
      helper/refill/api/xyz/yunchonggong/开户信息.txt
  71. 15 57
      helper/refill/api/xyz/yunchonggongfs/config.php
  72. 22 11
      helper/refill/api/xyz/yunchonggongfs/开户信息.txt
  73. 7 7
      helper/refill/api/yl/guochuang/config.php
  74. 67 0
      helper/refill/api/yl/huoshenguo_fs/RefillCallBack.php
  75. 155 0
      helper/refill/api/yl/huoshenguo_fs/RefillPhone.php
  76. 36 0
      helper/refill/api/yl/huoshenguo_fs/config.php
  77. 28 0
      helper/refill/api/yl/huoshenguo_fs/开户信息.txt
  78. 17 23
      helper/refill/api/yl/yamiao_high/config.php
  79. 23 30
      helper/refill/api/yl/yamiao_high/开户信息.txt
  80. 17 23
      helper/refill/api/yl/yamiao_normal/config.php
  81. 23 29
      helper/refill/api/yl/yamiao_normal/开户信息.txt
  82. 17 17
      helper/refill/api/yl/yunchonggong/config.php
  83. 12 10
      helper/refill/api/yl/yunchonggong/开户信息.txt
  84. 17 59
      helper/refill/api/yl/yunchonggongfs/config.php
  85. 12 11
      helper/refill/api/yl/yunchonggongfs/开户信息.txt
  86. 9 8
      helper/refill/util.php
  87. 4 0
      mobile/callback/refill_huoshenguo_fs.php
  88. 88 29
      plot/app.py
  89. 78 20
      plot/plot_control.py
  90. 1 1
      plot/qreader.py
  91. 49 17
      plot/refill/ChannelPainter.py
  92. 2 3
      plot/refill/ChannelReader.py
  93. 33 11
      plot/refill/ChannelWriter.py
  94. 8 3
      plot/refill/DataStream.py
  95. 296 0
      plot/refill/MerchantPainter.py
  96. 68 2
      plot/refill/MerchantReader.py
  97. 32 9
      plot/refill/MerchantWriter.py
  98. 14 5
      plot/refill/NetchkWriter.py
  99. 17 2
      plot/refill/QueueListener.py
  100. 0 0
      plot/refill/__init__.py

+ 2 - 1
admin/config/config.ini.php

@@ -16,7 +16,8 @@ $config['receive_bank'] = [
         '椰子交行',
         '国研交行',
         '椰林招行',
-        '椰子浙商银行'
+        '椰子浙商银行',
+        '趣带娃招行'
     ],
     'LZKJ_COMPANY' => [
         '琳珠收款'

+ 25 - 0
admin/control/control.php

@@ -10,6 +10,8 @@ defined('InShopNC') or exit('Access Invalid!');
 require_once(BASE_HELPER_PATH . '/mtopcard/mtopcard.php');
 require_once(BASE_HELPER_PATH . '/refill/RefillFactory.php');
 require_once(BASE_DATA_PATH . '/model/merchant.model.php');
+require_once(BASE_DATA_PATH . '/model/refill_company.model.php');
+
 class SystemControl
 {
     const STATE_TEXT = ['使用中', '已禁用'];
@@ -503,4 +505,27 @@ class SystemControl
         }
         return $order_list;
     }
+
+    protected function refill_companys($cond)
+    {
+        $data = [];
+        $cond['opened'] = refill_companyModel::opened_start;
+        $refill_company = Model('refill_company')->getCompanyList($cond);
+        foreach ($refill_company as $company)
+        {
+            $data[$company['co_id']] = $company;
+        }
+        return $data;
+    }
+
+    protected function remit_cfg()
+    {
+        $config = rcache('remit', 'refill-');
+        if (empty($config)) {
+            $config = [];
+        } else {
+            $config = unserialize($config['cfg']);
+        }
+        return $config;
+    }
 }

+ 9 - 1
admin/control/merchant.php

@@ -36,10 +36,13 @@ class merchantControl extends SystemControl
         $debt_total = 0;
         $available_total = 0;
         $merchant_list = $model_merchant->getMerchantList($condition, 200, 'available_predeposit desc,merchant_state asc,mchid desc', true);
+        $refill_company = $this->refill_companys(['co_type' => refill_companyModel::co_type_merchant]);
         foreach ($merchant_list as $key => $merchant) {
             $mchid = $merchant['mchid'];
             $available_predeposit = $merchant['available_predeposit'] - $merchant['credit_bonus'];
-            $merchant_list[$key]['available_predeposit'] = number_format($available_predeposit,4,'.',',');;
+            $merchant_list[$key]['available_predeposit'] = number_format($available_predeposit,4,'.',',');
+            $merchant_list[$key]['co_name'] = $refill_company[$merchant['co_id']]['co_name'] ?? '/';
+
             if(!in_array($mchid, $config['test_mchid']) && $merchant['merchant_state'] == 1) {
                 if($available_predeposit >= 0) {
                     $available_total += $available_predeposit;
@@ -194,6 +197,7 @@ class merchantControl extends SystemControl
             $update['password'] = md5($update['org_pwd']);
             $update['alarm_amount'] = $_POST['alarm_amount'] ?? 0;
             $update['manual_recharge'] = $_POST['manual_recharge'];
+            $update['co_id'] = $_POST['co_id'] ?? 0;
 
             $day_timeout = intval($_POST['day_timeout']);
             $night_timeout = intval($_POST['night_timeout']);
@@ -244,6 +248,8 @@ class merchantControl extends SystemControl
                 showMessage('机构编辑失败', 'index.php?act=merchant&op=merchant');
             }
         }
+        $refill_company = $this->refill_companys(['co_type' => refill_companyModel::co_type_merchant]);
+        Tpl::output('refill_company', $refill_company);
         Tpl::output('merchant', $merchant);
         Tpl::showpage('merchant.edit');
     }
@@ -999,6 +1005,8 @@ class merchantControl extends SystemControl
             showMessage('通道信息有误');
         }
         $type_text = ['油卡', '手机充值卡'];
+        $refill_company = $this->refill_companys(['co_type' => refill_companyModel::co_type_provider]);
+        Tpl::output('refill_company', $refill_company);
         Tpl::output('type_text', $type_text);
         Tpl::output('provider', $provider);
         Tpl::showpage('provider.edit');

+ 2 - 2
admin/control/ordersendlist.php

@@ -455,7 +455,7 @@ class ordersendlistControl extends SystemControl
         $excel_data[0][] = array('styleid' => 's_title', 'data' => '完成日期');
         $excel_data[0][] = array('styleid' => 's_title', 'data' => '官方流水号');
         $excel_data[0][] = array('styleid' => 's_title', 'data' => '订单状态');
-        $excel_data[0][] = array('styleid' => 's_title', 'data' => '扣款金额');
+//        $excel_data[0][] = array('styleid' => 's_title', 'data' => '扣款金额');
         //data
         foreach ((array)$data as $v) {
             $tmp = array();
@@ -474,7 +474,7 @@ class ordersendlistControl extends SystemControl
 
             $tmp[] = array('data' => $v['official_sn']);
             $tmp[] = array('data' => orderState($v));
-            $tmp[] = array('data' => $v['mch_amount']);
+//            $tmp[] = array('data' => $v['mch_amount']);
             $excel_data[] = $tmp;
         }
         $excel_data = $excel_obj->charset($excel_data, CHARSET);

+ 114 - 0
admin/control/provider.php

@@ -30,6 +30,7 @@ class providerControl extends SystemControl
             $condition['opened'] = 1;
         }
 
+        $refill_company = $this->refill_companys(['co_type' => refill_companyModel::co_type_provider]);
         $provider_items = $provider_model->table('refill_provider,store')
             ->field('refill_provider.*,store.store_name,store.member_id')
             ->join('inner')
@@ -49,6 +50,7 @@ class providerControl extends SystemControl
             $providers[$pid]['available_predeposit'] = 0;
             $quality_text = $provider['type'] == mtopcard\OilCardPaper ? $config['oil_quality_text'] : $config['phone_quality_text'];
             $providers[$pid]['quality_text'] = $quality_text[$provider['qualitys']];
+            $providers[$pid]['co_name'] = $refill_company[$provider['co_id']]['co_name'] ?? '/';
             $account_id = intval($provider['account_id']);
             if($account_id > 0) {
                 $mid_pids[$account_id] = $pid;
@@ -620,4 +622,116 @@ class providerControl extends SystemControl
         $excel_obj->addWorksheet($excel_obj->charset(L('exp_od_order'), CHARSET));
         $excel_obj->generateXML('通道余额明细导出-' . date('Y-m-d-H', time()));
     }
+
+    public function provider_remitOp()
+    {
+        $refill_company = $this->refill_companys(['co_type' => refill_companyModel::co_type_provider]);
+        if (chksubmit())
+        {
+            $remits = $_POST['remits'];
+            $strs = $_POST['strs'];
+            $operation = $_POST['operation'];
+            $title = '';
+            $remit_total = 0;
+            foreach ($strs as $key => $str)
+            {
+                $remit = $remits[$key];
+                if(empty($remit)) continue;
+                $item = explode('-', $str);
+                $co_id = $item[0];
+                $pid = $item[1];
+                $data[$co_id][$pid] = $remit;
+                $remit_total += $remit;
+            }
+            if(empty($data)) {
+                showMessage('未提交数据');
+            }
+            if(ADMIN_NAME === 'YEZI') {
+                $platform = '椰子';
+            }else{
+                $platform = '椰林';
+            }
+            foreach ($data as $co_id => $valuue)
+            {
+                $title .= "{$refill_company[$co_id]['co_name']}-";
+            }
+            $cur_time = time();
+            $date = date("YmdHi", $cur_time);
+            $title = "{$platform}-{$date}";
+
+            $remit_record = [
+                'title' => $title,
+                'amount' => $remit_total,
+                'params' => json_encode($data),
+                'operation' => $operation,
+                'add_time' => $cur_time,
+                'oper_time' => $cur_time
+            ];
+            Model('refill_company_remit')->addRemit($remit_record);
+            showMessage('操作成功', 'index.php?act=refill_company&op=remit_record');
+        }
+        else
+        {
+            $provider_items = $this->providers();
+            $result = $this->remit_data($provider_items, $refill_company);
+
+            Tpl::output('remit_data',$result);
+            Tpl::showpage('provider.remit');
+        }
+    }
+
+    private function remit_data($items, $refill_company): array
+    {
+        $providers = $mid_pids = $mids = $datas = $result =[];
+        foreach ($items as $item)
+        {
+            $co_id = $item['co_id'];
+            if(empty($co_id)) continue;
+            $pid = $item['provider_id'];
+            $account_id = intval($item['account_id']);
+            if($account_id > 0) {
+                $mid_pids[$account_id] = $pid;
+                $mids[] = $account_id;
+            }
+            $item['available_predeposit'] = 0;
+            $providers[$pid] = $item;
+        }
+        if(!empty($mids))
+        {
+            $member_data = Model('member')->field('member_id,available_predeposit')->where(['member_id' => ['in',$mids]])->select();
+            foreach ($member_data as $member)
+            {
+                $mid = intval($member['member_id']);
+                if(array_key_exists($mid,$mid_pids)) {
+                    $pid = $mid_pids[$mid];
+                    $providers[$pid]['available_predeposit'] = $member['available_predeposit'];
+                }
+            }
+        }
+        foreach ($providers as $provider)
+        {
+            $datas[$provider['co_id']][] = $provider;
+        }
+        $remit_cfg = $this->remit_cfg();
+        foreach ($datas as $co_id => $data)
+        {
+            $available_total = 0;
+            foreach ($data as $key => $value)
+            {
+                $remit = abs($value['available_predeposit'] - $remit_cfg['remit_money']);
+                if ($remit > 1000 && $value['available_predeposit'] < $remit_cfg['remit_money']) {
+                    $data[$key]['remit'] = intval($remit - ($remit % 1000));
+                } else {
+                    $data[$key]['remit'] = 0;
+                }
+                $available_total += $value['available_predeposit'];
+            }
+            if($available_total > $remit_cfg['remit_money'] || !array_key_exists($co_id, $refill_company)) continue;
+            $result[] = [
+                'co_name' => $refill_company[$co_id]['co_name'],
+                'providers' => $data
+            ];
+        }
+        return $result;
+    }
 }

+ 90 - 4
admin/control/refill_analysis.php

@@ -3,7 +3,7 @@ include(BASE_CONFIG_PATH . CONFIG_PREFIX . '/refill.ini.php');
 require_once(BASE_ROOT_PATH . '/core/framework/function/http.php');
 class refill_analysisControl extends SystemControl
 {
-    private $ANALYSIS_URL = BASE_SITE_URL;
+    private $ANALYSIS_URL = 'https://ylweb.xyzshops.cn';
     
     public function __construct()
     {
@@ -157,21 +157,107 @@ class refill_analysisControl extends SystemControl
 
     public function new_versionOp()
     {
-        Tpl::showpage('analysis.new_version');
+        $type = $_GET['type'] ?? 'provider';
+        $page = "analysis.new_version.{$type}";
+        if($type == 'provider')
+        {
+            global $config;
+            $cond['type'] = ['in', [mtopcard\OilCardPaper, mtopcard\PhoneCardPaper]];
+            $cond['opened'] = 1;
+            $open_providers = $this->providers($cond);
+            $cond['opened'] = 2;
+            $cond['oper_time'] = ['gt', time() - 86400 * 7];
+            $close_providers = $this->providers($cond);
+            $provider_items = array_merge($open_providers, $close_providers);
+
+            foreach ($provider_items as $item) {
+                $provider_list[$item['type']][] = $item;
+            }
+            foreach ($provider_list as $provider_type => $providers)
+            {
+                $data = [];
+                foreach ($providers as $provider) {
+                    $quality = $provider['qualitys'];
+                    if (empty($data[$quality]['name'])) {
+                        $quality_text = $provider['type'] == mtopcard\OilCardPaper ? $config['oil_quality_text'] : $config['phone_quality_text'];
+                        $data[$quality]['name'] = $quality_text[$quality];
+                    }
+                    $data[$quality]['params'][] = [
+                        'name' => $provider['store_name'],
+                        'value' => $provider['name']
+                    ];
+                }
+                ksort($data);
+                $result[$provider_type] = $data;
+            }
+            ksort($result);
+            Tpl::output('providers', $result);
+        }
+        Tpl::showpage($page);
     }
 
     public function provider_dataOp()
     {
-        $provider_list = $this->providers();
+        $cond = [];
+        if(!empty($_GET['quality'])){
+            $cond['qualitys'] = $_GET['quality'];
+        }
+        $url = $this->ANALYSIS_URL . '/plot/channels';
+        Log::record("analysis get provider_data url : {$url}", Log::DEBUG);
+        $resp = http_request($url);
+        preg_match_all('/[a-z]+_*[a-z]*/', $resp, $matches);
+        if(empty($resp) || empty($matches)) {
+            echo(json_encode(''));
+            return;
+        }
+        $cond['name'] = ['in', $matches[0]];
+        $provider_list = $this->providers($cond);
+
         $result = [];
         foreach ($provider_list as $value) {
-            $data['name'] = $value['store_name'] ?? $value['name'];
+            $data['name'] = "{$value['store_name']}:{$value['name']}";
             $data['value'] = $value['name'];
             $result[] = $data;
         }
         echo json_encode($result);
     }
 
+    public function merchant_dataOp()
+    {
+        $cond = [];
+        $url = $this->ANALYSIS_URL . '/plot/mchids';
+        Log::record("analysis get merchant_data url : {$url}", Log::DEBUG);
+        $resp = http_request($url);
+        preg_match_all('/\d{2,6}/', $resp, $matches);
+        if(empty($resp) || empty($matches)) {
+            echo(json_encode(''));
+            return;
+        }
+        $cond['mchid'] = ['in', $matches[0]];
+        $merchant_list = $this->merchants($cond);
+
+        $result = [];
+        foreach ($merchant_list as $value) {
+            $name = $value['company_name'] ?? $value['name'];
+            $data['name'] = $name .' : '. $value['mchid'] .'-'. $value['time_out'];
+            $data['value'] = $value['mchid'];
+            $result[] = $data;
+        }
+        echo json_encode($result);
+    }
+
+    public function card_type_dataOp()
+    {
+        $result = [
+            ['name' => '中石油', 'value' => mtopcard\PetroChinaCard],
+            ['name' => '中石化', 'value' => mtopcard\SinopecCard],
+            ['name' => '中国移动', 'value' => mtopcard\ChinaMobileCard],
+            ['name' => '中国联通', 'value' => mtopcard\ChinaUnicomCard],
+            ['name' => '中国电信', 'value' => mtopcard\ChinaTelecomCard],
+        ];
+        echo json_encode($result);
+    }
+
     private function object_array($array)
     {
         if(is_object($array))

+ 425 - 0
admin/control/refill_company.php

@@ -0,0 +1,425 @@
+<?php
+
+class refill_companyControl extends SystemControl
+{
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    public function indexOp()
+    {
+        $cond = [];
+        $company_mod = Model('refill_company');
+        if(!empty($_GET['co_name'])) {
+            $cond['co_name'] = ['like', '%'.$_GET['co_name'].'%'];
+        }
+        if(!empty($_GET['co_type'])) {
+            $cond['params'] = $_GET['co_type'];
+        }
+        if(!empty($_GET['opened'])) {
+            $cond['opened'] = $_GET['opened'];
+        }
+        $list = $company_mod->getCompanyList($cond);
+
+        Tpl::output('list', $list);
+        Tpl::output('show_page', $company_mod->showpage());
+        Tpl::showpage('refill.company');
+    }
+
+    public function changeStateOp()
+    {
+        $co_id = intval($_GET['co_id']);
+        $opened = intval($_GET['opened']);
+        $company_mod = Model('refill_company');
+        $company_info = $company_mod->getCompanyInfo(['co_id' => $co_id]);
+        if (empty($company_info) || !in_array($opened, [1, 2])) {
+            showMessage('操作成功');
+        }
+        $resp = $company_mod->editCompany(['opened' => $opened], ['co_id' => $co_id]);
+        if (!$resp) {
+            showMessage('操作失败', 'index.php?act=refill_company&op=index', 'html', 'error');
+        }
+        showMessage('操作成功');
+    }
+
+    public function addOp()
+    {
+        $company_mod = Model('refill_company');
+        if (chksubmit())
+        {
+            $obj_validate = new Validator();
+            $obj_validate->validateparam = [
+                ["input" => $_POST["co_type"], "require" => "true", "message" => '必须选择公司类型'],
+                ["input" => $_POST["co_name"], "require" => "true", "message" => '公司名称不能为空'],
+                ["input" => $_POST["bank_name"], "require" => "true", "message" => '收款银行名称不能为空'],
+                ["input" => $_POST["bank_username"], "require" => "true", "message" => '开户人名称不能为空'],
+                ["input" => $_POST["bank_card_no"], "require" => "true", "message" => '收款卡号不能为空']
+            ];
+            $error = $obj_validate->validate();
+            if ($error != '') {
+                showMessage($error);
+            } else {
+                $insert_array['co_name'] = $_POST['co_name'];
+                $insert_array['co_type'] = $_POST['co_type'];
+                $insert_array['bank_name'] = $_POST['bank_name'];
+                $insert_array['bank_username'] = $_POST['bank_username'];
+                $insert_array['bank_card_no'] = $_POST['bank_card_no'];
+                $insert_array['max_debt'] = $_POST['max_debt'] ?? 0;
+                $insert_array['province'] = $_POST['province'] ?? '';
+                $insert_array['city'] = $_POST['city'] ?? '';
+                $insert_array['bank_code'] = $_POST['bank_code'] ?? '';
+                $insert_array['remark'] = $_POST['remark'] ?? '';
+                $insert_array['oper_time'] = time();
+                $co_id = $company_mod->addCompany($insert_array);
+                if ($co_id) {
+                    $cid = $_POST['cid'] ?? '';
+                    $this->co_id_bind($cid, $co_id, $insert_array['co_type']);
+                    showMessage('添加成功', 'index.php?act=refill_company&op=index');
+                } else {
+                    showMessage('添加失败');
+                }
+            }
+        }
+        else
+        {
+            Tpl::showpage('refill.company.add');
+        }
+    }
+
+    public function editOp()
+    {
+        $co_id = $_GET['co_id'] ?? $_POST['co_id'];
+        $company_mod = Model('refill_company');
+        $company_info = $company_mod->getCompanyInfo(['co_id' => $co_id]);
+        if (empty($company_info)) {
+            showMessage('公司信息不存在');
+        }
+        if (chksubmit()) {
+            $update['co_type'] = $_POST['co_type'];
+            $update['co_name'] = $_POST['co_name'];
+            $update['bank_name'] = trim($_POST['bank_name']);
+            $update['bank_username'] = trim($_POST['bank_username']);
+            $update['bank_card_no'] = trim($_POST['bank_card_no']);
+            $update['max_debt'] = trim($_POST['max_debt']);
+            $update['province'] = trim($_POST['province']);
+            $update['city'] = trim($_POST['city']);
+            $update['bank_code'] = trim($_POST['bank_code']);
+            $update['remark'] = trim($_POST['remark']);
+            $update['oper_time'] = time();
+
+            $result = $company_mod->editCompany($update, ['co_id' => $co_id]);
+            if (!$result) {
+                showMessage('编辑失败');
+            }
+            $cid = $_POST['cid'] ?? '';
+            $this->co_id_bind($cid, $co_id, $company_info['co_type']);
+            $this->log("修改公司信息,公司ID:{$co_id},公司名称:{$company_info['co_name']}");
+            showMessage('编辑成功','index.php?act=refill_company&op=index');
+        }
+        else
+        {
+            $cid = [];
+            if($company_info['co_type'] == 'merchant') {
+                $cid = Model('')->table('merchant')->where(['co_id' => $co_id])->field('mchid')->select();
+                $cid = array_column($cid, 'mchid');
+            }elseif ($company_info['co_type'] == 'provider') {
+                $cid = Model('')->table('refill_provider')->where(['co_id' => $co_id])->field('store_id')->select();
+                $cid = array_column($cid, 'store_id');
+            }
+            Tpl::output('cid', implode(',', $cid));
+            Tpl::output('company_info', $company_info);
+            Tpl::showpage('refill.company.edit');
+        }
+    }
+
+    private function co_id_bind($cid, $co_id, $co_type)
+    {
+        if(!empty($cid)) {
+            $cid = explode(',', $cid);
+            if($co_type == 'merchant'){
+                $cond['mchid'] = ['in', $cid];
+                Model('')->table('merchant')->where(['co_id' => $co_id])->update(['co_id' => 0]);
+                Model('')->table('merchant')->where($cond)->update(['co_id' => $co_id]);
+            }elseif ($co_type == 'provider'){
+                $cond['store_id'] = ['in', $cid];
+                Model('')->table('refill_provider')->where(['co_id' => $co_id])->update(['co_id' => 0]);
+                Model('')->table('refill_provider')->where($cond)->update(['co_id' => $co_id]);
+            }
+        }
+    }
+
+    public function remit_cfgOp()
+    {
+        if(chksubmit())
+        {
+            unset($_POST['form_submit']);
+            $cache = [];
+            foreach ($_POST as $key => $value) {
+                $cache[$key] = $value;
+            }
+            wcache('remit', ['cfg' => serialize($cache)], 'refill-');
+            showMessage('编辑成功');
+        }
+        else
+        {
+            $config = rcache('remit', 'refill-');
+            if (empty($config)) {
+                $config = [];
+            } else {
+                $config = unserialize($config['cfg']);
+            }
+            Tpl::output('config', $config);
+            Tpl::showpage('remit.config');
+        }
+    }
+
+    public function remit_recordOp()
+    {
+        $mod_remit = Model('refill_company_remit');
+        $cond = [];
+        $start_unixtime = intval(strtotime($_GET['query_start_time']));
+        $end_unixtime = intval(strtotime($_GET['query_end_time']));
+        if ($start_unixtime > 0 && $end_unixtime > $start_unixtime) {
+            $cond['add_time'] = [['egt', $start_unixtime], ['lt', $end_unixtime], 'and'];
+        } elseif ($start_unixtime > 0) {
+            $cond['add_time'] = ['egt', $start_unixtime];
+        } elseif ($end_unixtime > 0) {
+            $cond['add_time'] = ['lt', $end_unixtime];
+        }
+        $list = $mod_remit->getRemitList($cond);
+        foreach ($list as $key => $value)
+        {
+            $list[$key]['amount'] = number_format($value['amount'],4,'.',',');
+        }
+        $refill_company = $this->refill_companys([]);
+
+        Tpl::output('list', $list);
+        Tpl::output('refill_company', $refill_company);
+        Tpl::output('show_page', $mod_remit->showpage());
+        Tpl::showpage('refill.company.remit');
+    }
+
+    public function remit_delOp()
+    {
+        $mod_remit = Model('refill_company_remit');
+        $remit_id = $_GET['remit_id'];
+        $this->check_remit($remit_id);
+        $result = $mod_remit->DelRemit($remit_id);
+        if ($result) {
+            showMessage('删除成功');
+        } else {
+            showMessage('删除失败');
+        }
+    }
+
+    public function remit_editOp()
+    {
+        $remit_id = $_GET['remit_id'] ?? $_POST['remit_id'];
+        $remit = $this->check_remit($remit_id);
+        $params = json_decode($remit['params'], true);
+        $provider_list = $this->providers();
+        foreach ($provider_list as $provider) {
+            $co_id = $provider['co_id'];
+            if(empty($co_id)) continue;
+            $pid = $provider['provider_id'];
+            $account_id = intval($provider['account_id']);
+            if($account_id > 0) {
+                $mid_pids[$account_id] = $pid;
+                $mids[] = $account_id;
+            }
+            $provider['available_predeposit'] = 0;
+            $providers[$pid] = $provider;
+        }
+        $refill_company = $this->refill_companys(['co_type' => refill_companyModel::co_type_provider]);
+        if(chksubmit())
+        {
+            $remits = $_POST['remits'];
+            $strs = $_POST['strs'];
+            $operation = $_POST['operation'];
+            $remit_total = 0;
+            foreach ($strs as $key => $str)
+            {
+                $remit = $remits[$key];
+                if(empty($remit)) continue;
+                $item = explode('-', $str);
+                $co_id = $item[0];
+                $pid = $item[1];
+                $data[$co_id][$pid] = $remit;
+                $remit_total += $remit;
+            }
+            if(empty($data)) {
+                showMessage('未提交数据');
+            }
+            $remit_record = [
+                'amount' => $remit_total,
+                'params' => json_encode($data),
+                'operation' => $operation,
+                'oper_time' => time()
+            ];
+            Model('refill_company_remit')->editRemit($remit_record, ['remit_id' => $remit_id]);
+            showMessage('操作成功', 'index.php?act=refill_company&op=remit_record');
+        }
+        else
+        {
+            $member_data = Model('member')->field('member_id,available_predeposit')->where(['member_id' => ['in',$mids]])->select();
+            foreach ($member_data as $member)
+            {
+                $mid = intval($member['member_id']);
+                if(array_key_exists($mid,$mid_pids)) {
+                    $pid = $mid_pids[$mid];
+                    $providers[$pid]['available_predeposit'] = $member['available_predeposit'];
+                }
+            }
+            foreach ($params as $co_id => $item)
+            {
+                $data = [];
+                $data['co_name'] = $refill_company[$co_id]['co_name'];
+                foreach ($item as $pid => $remit_money)
+                {
+                    $providers[$pid]['remit'] = $remit_money;
+                    $data['providers'][] = $providers[$pid];
+                }
+                $result[] = $data;
+            }
+            Tpl::output('remit_data', $result);
+            Tpl::output('remit', $remit);
+            Tpl::showpage('provider.remit.edit');
+        }
+    }
+
+    public function remit_commitOp()
+    {
+        $mod = Model('refill_company_remit');
+
+        $remit_id = $_GET['remit_id'];
+        $remit = $this->check_remit($remit_id);
+        $params = json_decode($remit['params'], true);
+        $provider_list = $this->providers();
+        foreach ($provider_list as $provider) {
+            $providers[$provider['provider_id']] = $provider;
+        }
+        $bz = '批量打款';
+
+        foreach ($params as $item)
+        {
+            try {
+                $trans = new trans_wapper($mod, __METHOD__);
+                $remit_total = 0;
+                foreach ($item as $pid => $money)
+                {
+                    $amount_data = [
+                        'pointsnum' => $money,
+                        'operation' => $remit['operation'],
+                        'bz' => $bz
+                    ];
+                    $this->credit_save_money($money, 'add', $providers[$pid]['account_id'], $bz);
+                    $this->ct_provider_amount($amount_data, $providers[$pid]);
+                    $remit_total += $money;
+                }
+                $trans->commit();
+            } catch (Exception $e) {
+                $trans->rollback();
+                Log::record("remit_commit err: {$e->getMessage()}", Log::ERR);
+                showMessage('提交失败');
+            }
+        }
+        $mod->editRemit(['remit_state' => refill_company_remitModel::remit_have], ['remit_id' => $remit_id]);
+        showMessage('操作成功!');
+    }
+
+    private function ct_provider_amount($params, $provider_info)
+    {
+        $input['provider_id'] = $provider_info['provider_id'];
+        $input['memeber_id'] = $provider_info['account_id'];
+        $input['amount'] = $params['pointsnum'];
+        $input['operation'] = $params['operation'];
+        $input['add_time'] = time();
+        $input['bz'] = $params['bz'] ?? '';
+
+        return Model('provider_amount')->addAmount($input);
+    }
+
+    private function check_remit($remit_id)
+    {
+        $remit = Model('refill_company_remit')->getRemit($remit_id);
+        if(empty($remit)) {
+            showMessage('记录不存在');
+        }
+        return $remit;
+    }
+
+    public function remit_exportOp()
+    {
+        $remit_id = $_GET['remit_id'];
+        $remit = $this->check_remit($remit_id);
+        $params = json_decode($remit['params']);
+        $remit_cfg = $this->remit_cfg();
+        $remit_max = intval($remit_cfg['remit_max']);
+        $refill_company = $this->refill_companys(['co_type' => refill_companyModel::co_type_provider]);
+
+        foreach ($params as $co_id => $item)
+        {
+            $remit_total = 0;
+            foreach ($item as $money)
+            {
+                $remit_total += $money;
+            }
+            if( $remit_total < $remit_max) {
+                $refill_company[$co_id]['money'] = $remit_total;
+                $remit_data[] = $refill_company[$co_id];
+            }else{
+                for ( $i = $remit_total / $remit_max; $i>=0; --$i)
+                {
+                    if($i < 1) {
+                        $refill_company[$co_id]['money'] = $remit_total % $remit_max;
+                    } else {
+                        $refill_company[$co_id]['money'] = $remit_max;
+                    }
+                    $remit_data[] = $refill_company[$co_id];
+                }
+            }
+        }
+        $this->Export_file($remit['title'], $remit_data);
+    }
+
+    private function Export_file($file_name, $remit_data)
+    {
+        Language::read('export');
+        import('libraries.excel');
+        $excel_obj = new Excel();
+        $excel_data = [];
+        //设置样式
+        $excel_obj->setStyle(['id' => 's_title', 'Font' => ['FontName' => '宋体', 'Size' => '12', 'Bold' => '1']]);
+        //header
+        $excel_data[0][] = ['styleid' => 's_title', 'data' => '序号'];
+        $excel_data[0][] = ['styleid' => 's_title', 'data' => '收款人姓名'];
+        $excel_data[0][] = ['styleid' => 's_title', 'data' => '银行卡号'];
+        $excel_data[0][] = ['styleid' => 's_title', 'data' => '银行编码'];
+        $excel_data[0][] = ['styleid' => 's_title', 'data' => '省/直辖市'];
+        $excel_data[0][] = ['styleid' => 's_title', 'data' => '城市'];
+        $excel_data[0][] = ['styleid' => 's_title', 'data' => '开户行名称'];
+        $excel_data[0][] = ['styleid' => 's_title', 'data' => '付款金额'];
+        $excel_data[0][] = ['styleid' => 's_title', 'data' => '0(对私付款)/1(对公付款)'];
+
+        //data
+        foreach ($remit_data as $key => $data) {
+            if($data['money'] <= 0) continue;
+            $tmp = [];
+            $tmp[] = ['data' => $key+1];
+            $tmp[] = ['data' => $data['bank_username']];
+            $tmp[] = ['data' => $data['bank_card_no']];
+            $tmp[] = ['data' => $data['bank_code']];
+            $tmp[] = ['data' => $data['province']];
+            $tmp[] = ['data' => $data['city']];
+            $tmp[] = ['data' => $data['bank_name']];
+            $tmp[] = ['data' => $data['money']];
+            $tmp[] = ['data' => 1];
+            $excel_data[] = $tmp;
+        }
+        $excel_data = $excel_obj->charset($excel_data, CHARSET);
+        $excel_obj->addArray($excel_data);
+        $excel_obj->addWorksheet($excel_obj->charset(L('exp_od_order'), CHARSET));
+        $excel_obj->generateXML($file_name);
+    }
+}

+ 0 - 12
admin/control/refill_order.php

@@ -350,18 +350,6 @@ class refill_orderControl extends SystemControl
         echo json_encode($result);
     }
 
-    public function card_type_dataOp()
-    {
-        $result = [
-            ['name' => '中石油', 'value' => mtopcard\PetroChinaCard],
-            ['name' => '中石化', 'value' => mtopcard\SinopecCard],
-            ['name' => '中国移动', 'value' => mtopcard\ChinaMobileCard],
-            ['name' => '中国联通', 'value' => mtopcard\ChinaUnicomCard],
-            ['name' => '中国电信', 'value' => mtopcard\ChinaTelecomCard],
-        ];
-        echo json_encode($result);
-    }
-
     public function refill_third_infoOp()
     {
         $order_id = $_GET['order_id'];

+ 1 - 0
admin/include/limit.php

@@ -39,6 +39,7 @@ $_limit =  array(
         array('name'=> '通道组管理', 'op'=> null, 'act'=>'provider_group'),
         array('name'=> '订单监控', 'op'=>null, 'act'=>'ordersendlist'),
         array('name'=> '对账管理', 'op'=>null, 'act'=>'orderstats'),
+        array('name'=> '公司信息管理', 'op'=>null, 'act'=>'refill_company'),
         array('name'=> '充值拦截设置', 'op'=>null, 'act'=>'refill_config'),
         array('name'=> '卡密管理', 'op'=>null, 'act'=>'card_key'),
         array('name'=> '库存管理', 'op'=>null, 'act'=>'refill_stock'),

+ 2 - 1
admin/include/menu.php

@@ -102,7 +102,8 @@ $arr = array(
 					array('args'=>'index,provider_group,merchant',			'text'=>'通道组管理'),
 					array('args'=>'index,ordersendlist,merchant',			'text'=>'订单监控'),
 					array('args'=>'index,orderstats,merchant',				'text'=>'对账管理'),
-					array('args'=>'intercept,refill_config,merchant',			'text'=>'充值拦截设置'),
+					array('args'=>'index,refill_company,merchant',				'text'=>'公司信息管理'),
+					array('args'=>'intercept,refill_config,merchant',		'text'=>'充值拦截设置'),
 					array('args'=>'stats,card_key,merchant',				'text'=>'卡密管理'),
 					array('args'=>'index,refill_third,merchant',			'text'=>'增值业务管理'),
 					array('args'=>'index,refill_stock,merchant',			'text'=>'库存管理'),

+ 166 - 60
admin/templates/default/analysis.new_version.php

@@ -1,3 +1,50 @@
+<style>
+    #checkChannel {
+        border-spacing: 0;
+        border-collapse: collapse;
+    }
+
+    #checkChannel td {
+        height: 20px;
+        padding: 2px;
+        background: #F3FBFE;
+        border: 1px solid #fff;
+        display: block;
+        white-space: nowrap;
+        font-size: 10px;
+    }
+
+    #checkChannel tr {
+        height: 20px;
+    }
+
+    #checkChannel thead tr {
+        table-layout: fixed;
+        top: 0;
+        left: 0;
+    }
+
+    #checkChannel tbody {
+        height: calc(100vh - 210px);
+        display: block;
+        overflow-y: scroll;
+    }
+
+    .echartsContent {
+        display: flex;
+        height: calc(100vh - 150px);
+    }
+
+    #echart {
+        flex: 1;
+        margin-left: 5px;
+    }
+
+    #echart img {
+        width: 100%;
+    }
+</style>
+
 <div class="page">
     <div class="fixed-bar">
         <div class="item-title">
@@ -6,7 +53,9 @@
                 <li><a href="?index.php&act=refill_analysis&op=index&type=provider"><span>通道成功率监控</span></a></li>
                 <li><a href="?index.php&act=refill_analysis&op=index&type=system"><span>平台成功率监控</span></a></li>
                 <li><a href="?index.php&act=refill_analysis&op=merchant_ratios"><span>机构成功率统计</span></a></li>
-                <li><a href="JavaScript:void(0);" class="current"><span>新通道成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=provider"><span>新通道成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=system"><span>新平台成功率监控</span></a></li>
+                <li><a href="JavaScript:void(0);" class="current"><span>机构单量监控</span></a></li>
             </ul>
         </div>
     </div>
@@ -19,15 +68,17 @@
             <tr>
                 <th><label for="query_start_time">统计时间</label></th>
                 <td>
-                    <input class="txt date" type="text" value="<?php echo $_GET['query_start_time']; ?>"
-                           id="startTime" name="query_start_time" autocomplete="off" style="width:120px" />
+                    <input class="txt date" type="text" value="<?php echo $_GET['query_start_time']; ?>" id="startTime" name="query_start_time" autocomplete="off" style="width:120px" />
                     <label for="query_start_time">~</label>
-                    <input class="txt date" type="text" value="<?php echo $_GET['query_end_time']; ?>"
-                           id="endTime" name="query_end_time" autocomplete="off" style="width:120px" />
+                    <input class="txt date" type="text" value="<?php echo $_GET['query_end_time']; ?>" id="endTime" name="query_end_time" autocomplete="off" style="width:120px" />
                 </td>
-                <th><label>通道选择</label></th>
+                <!-- <th><label>机构选择</label></th>
+                <td>
+                    <div id="select_merchants"></div>
+                </td> -->
+                <th><label>卡类型</label></th>
                 <td>
-                    <div id="selest_chnames"></div>
+                    <div id="select_cardtypes"></div>
                 </td>
                 <th><label>面额</label></th>
                 <td>
@@ -45,10 +96,6 @@
                         <option value="2000" <?php if ($_GET['refill_amount'] == '2000') { ?>selected<?php } ?>>2000</option>
                     </select>
                 </td>
-                <th><label>卡类型</label></th>
-                <td>
-                    <div id="select_cardtype"></div>
-                </td>
                 <th><label>滤波器</label></th>
                 <td>
                     <select name="filter_wave">
@@ -61,13 +108,32 @@
                     </select>
                 </td>
                 <td>
-                    <a href="javascript:void(0);" id="ncsubmit" class="btn-search"
-                       title="<?php echo $lang['nc_query']; ?>">&nbsp;
+                    <a href="javascript:void(0);" id="ncsubmit" class="btn-search" title="<?php echo $lang['nc_query']; ?>">&nbsp;
                     </a>
                 </td>
             </tr>
         </table>
     </form>
+    <div class="echartsContent">
+        <table id="checkChannel">
+            <thead>
+                <tr>
+                    <td>
+                        <label>
+                            <input type="checkbox" id="checkAllChannel">
+                            编号(机构列表)
+                        </label>
+                    </td>
+                </tr>
+            </thead>
+            <tbody id="checkChannelContent">
+
+            </tbody>
+        </table>
+        <div id="echart">
+
+        </div>
+    </div>
     <div id="box">
         <!-- <iframe
             src="https://www.xyzshops.cn/plot/index?time_stamp=1621488600&interval=60" scrolling="no" id="Iframe" frameborder="0"></iframe> -->
@@ -75,15 +141,13 @@
 </div>
 <script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/laydate/laydate.js"></script>
 <script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/jquery.ui.js"></script>
-<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/i18n/zh-CN.js"
-        charset="utf-8"></script>
-<script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL;?>/js/xm-select.js"></script>
-<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL;?>/refill/layer.js"></script>
-<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL;?>/refill/moment-with-locales.js"></script>
-<link rel="stylesheet" type="text/css"
-      href="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/themes/ui-lightness/jquery.ui.css"/>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/i18n/zh-CN.js" charset="utf-8"></script>
+<script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL; ?>/js/xm-select.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/refill/layer.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/refill/moment-with-locales.js"></script>
+<link rel="stylesheet" type="text/css" href="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/themes/ui-lightness/jquery.ui.css" />
 <script type="text/javascript">
-    $(function () {
+    $(function() {
         laydate.render({
             elem: '#startTime',
             type: 'datetime'
@@ -93,29 +157,48 @@
             type: 'datetime'
         });
 
-        let selest_chnames
-        $.get('index.php?act=refill_analysis&op=provider_data', function (data) {
-            data = JSON.parse(data)
-            selest_chnames = xmSelect.render({
-                el: '#selest_chnames',
-                size: 'mini',
-                filterable: true,
-                style: {
-                    minHeight: '27px',
-                    lineHeight: '27px',
-                    marginLeft: '4px',
-                    width: '250px'
-                },
-                language: 'zn',
-                data: data
+        function formatChannelTable(tableData) {
+            let data;
+            if (typeof tableData == 'object') {
+                data = tableData;
+            } else {
+                data = JSON.parse(tableData)
+            }
+            let tableHTML = '';
+            data.map(item => {
+                tableHTML += `
+                    <tr>
+                        <td><label><input type="checkbox" name="channelValue"" value="${item.value}" />${item.name}</label></td>
+                    </tr>
+                `;
             })
+            $('#checkChannelContent').append(tableHTML);
+        }
+
+        // let select_merchants
+        $.get('index.php?act=refill_analysis&op=merchant_data', function(data) {
+            data = JSON.parse(data)
+            formatChannelTable(data)
+            // select_merchants = xmSelect.render({
+            //     el: '#select_merchants',
+            //     size: 'mini',
+            //     filterable: true,
+            //     style: {
+            //         minHeight: '27px',
+            //         lineHeight: '27px',
+            //         marginLeft: '4px',
+            //         width: '250px'
+            //     },
+            //     language: 'zn',
+            //     data: data
+            // })
         })
 
-        let select_cardtype
-        $.get('index.php?act=refill_order&op=card_type_data', function (data) {
+        let select_cardtypes
+        $.get('index.php?act=refill_analysis&op=card_type_data', function(data) {
             data = JSON.parse(data)
-            select_cardtype = xmSelect.render({
-                el: '#select_cardtype',
+            select_cardtypes = xmSelect.render({
+                el: '#select_cardtypes',
                 size: 'mini',
                 filterable: true,
                 style: {
@@ -129,39 +212,63 @@
             })
         })
 
-        function select_set(selectArr){
+        function select_set(selectArr) {
             let selectStr = ''
             for (let i = 0; i < selectArr.length; i++) {
-                selectStr += selectArr[i].value+','
+                selectStr += selectArr[i].value + ','
             }
-            selectStr = selectStr.substr(0, selectStr.length-1)
+            selectStr = selectStr.substr(0, selectStr.length - 1)
             return selectStr
         }
 
-        $('#ncsubmit').click(function () {
+        $('#checkAllChannel').click(function() {
+            if ($(this).get(0).checked) {
+                $('input[name="channelValue"]').attr('checked', 'checked')
+            } else {
+                $('input[name="channelValue"]').removeAttr('checked')
+            }
+        })
+
+
+        $('#ncsubmit').click(function() {
             let query_start_time = $("input[name=query_start_time]").val()
-            let start_time = parseInt((new Date(query_start_time)).getTime()/1000);
+            let start_time = parseInt((new Date(query_start_time)).getTime() / 1000);
             let query_end_time = $("input[name=query_end_time]").val()
-            let end_time = parseInt((new Date(query_end_time)).getTime()/1000);
+            let end_time = parseInt((new Date(query_end_time)).getTime() / 1000);
+
+            if (!start_time && !end_time) {
+                start_time = Date.parse(new Date()) / 1000 - 7200;
+                end_time = Date.parse(new Date()) / 1000;
+            }
+
+            // let mchids = select_set(select_merchants.getValue())
+
+            let mchidList = [];
+            $('input[name="channelValue"]').each(function() {
+                if ($(this).attr('checked')) {
+                    mchidList.push($(this).attr('value'))
+                }
+            })
+
+            let mchids = mchidList.join(',');
+
 
-            let chnames = select_set(selest_chnames.getValue())
-            let card_types = select_set(select_cardtype.getValue())
+            let card_types = select_cardtypes && select_set(select_cardtypes.getValue())
             let spec = $("select[name=amount]").val()
             let filter_wave = $("select[name=filter_wave]").val()
-            let src = window.location.origin + "/plot/ch_ratio?"
+            let src = window.location.origin + "/plot/mch_order_send?"
             if (start_time) {
                 src += "&start_time=" + start_time;
             }
             if (end_time) {
-                if(end_time < start_time || !start_time)
-                {
+                if (end_time < start_time || !start_time) {
                     layer.msg('日期有误,结束日期需大于开始日期');
                     return
                 }
                 src += "&end_time=" + end_time;
             }
-            if (chnames) {
-                src += "&chnames=" + chnames;
+            if (mchids) {
+                src += "&mchids=" + mchids;
             }
             if (card_types) {
                 src += "&card_types=" + card_types;
@@ -169,15 +276,14 @@
             if (spec) {
                 src += "&spec=" + spec;
             }
-            if(filter_wave > 0) {
+            if (filter_wave > 0) {
                 src += '&filter_wave=' + filter_wave;
             }
-            $.get(src, function (data){
-                if (!data) {
-                    return
-                }
-                $('#box').html(data)
+            $.get(src, function(data) {
+                $('#echart').html(data)
             });
         });
+
+        $('#ncsubmit').trigger('click');
     })
-</script> 
+</script>

+ 363 - 0
admin/templates/default/analysis.new_version.provider.php

@@ -0,0 +1,363 @@
+<style>
+    #checkChannel {
+        border-spacing: 0;
+        border-collapse: collapse;
+    }
+
+    #checkChannel td {
+        min-width: 110px;
+        height: 20px;
+        padding: 2px;
+        background: #F3FBFE;
+        border: 1px solid #fff;
+        display: block;
+        white-space: nowrap;
+        font-size: 10px;
+    }
+
+    #checkChannel tr {
+        height: 20px;
+    }
+
+    #checkChannel thead tr {
+        table-layout: fixed;
+        top: 0;
+        left: 0;
+    }
+
+    #checkChannel tbody {
+        height: calc(100vh - 210px);
+        display: block;
+        overflow-y: scroll;
+    }
+
+    .echartsContent {
+        display: flex;
+        height: calc(100vh - 150px);
+    }
+
+    #echart {
+        flex: 1;
+        margin-left: 5px;
+    }
+
+    #echart img {
+        width: 100%;
+    }
+</style>
+
+<div class="page">
+    <div class="fixed-bar">
+        <div class="item-title">
+            <h3>成功率监控列表</h3>
+            <ul class="tab-base">
+                <li><a href="?index.php&act=refill_analysis&op=index&type=provider"><span>通道成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=index&type=system"><span>平台成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=merchant_ratios"><span>机构成功率统计</span></a></li>
+                <li><a href="JavaScript:void(0);" class="current"><span>新通道成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=system"><span>新平台成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=mch_order_send"><span>机构单量监控</span></a></li>
+            </ul>
+        </div>
+    </div>
+    <div class="fixed-empty"></div>
+    <div style="margin-top: 10px;color: #e60d0d;">
+        请先选择时间
+    </div>
+    <form method="get" action="index.php" name="formSearch" id="formSearch" style="min-width: 1200px;">
+        <table class="tb-type1 noborder search tableFixed">
+            <tr>
+                <th><label for="query_start_time">统计时间</label></th>
+                <td>
+                    <input class="txt date" type="text" value="<?php echo $_GET['query_start_time']; ?>" id="startTime" name="query_start_time" autocomplete="off" style="width:120px" />
+                    <label for="query_start_time">~</label>
+                    <input class="txt date" type="text" value="<?php echo $_GET['query_end_time']; ?>" id="endTime" name="query_end_time" autocomplete="off" style="width:120px" />
+                </td>
+                <th><label>通道质量</label></th>
+                <td>
+                    <select name="quality" class="querySelect">
+                        <option value=""><?php echo $lang['nc_please_choose']; ?></option>
+                        <option value="">全部</option>
+                        <option value="<?php echo refill\Quality::Normal; ?>">普充(无流水)
+                        </option>
+                        <option value="<?php echo refill\Quality::Quick; ?>">快充
+                        </option>
+                        <option value="<?php echo refill\Quality::CardKey; ?>">卡密
+                        </option>
+                        <option value="<?php echo refill\Quality::ThirdShop; ?>">三方
+                        </option>
+                        <option value="<?php echo refill\Quality::SlowTwentyFour; ?>">慢24(有流水)
+                        </option>
+                        <option value="<?php echo refill\Quality::SlowSix; ?>">慢6
+                        </option>
+                        <option value="<?php echo refill\Quality::SlowTwo; ?>">慢2
+                        </option>
+                        <option value="<?php echo refill\Quality::SlowFortyEight; ?>">慢48
+                        </option>
+                        <option value="<?php echo refill\Quality::SlowSeventyTwo; ?>">慢72
+                        </option>
+                        <option value="<?php echo refill\Quality::Fastest; ?>">速充
+                        </option>
+                    </select>
+                </td>
+                <th><label>卡类型</label></th>
+                <td>
+                    <div id="select_cardtypes"></div>
+                </td>
+                <th><label>面额</label></th>
+                <td>
+                    <select name="amount">
+                        <option value=""><?php echo $lang['nc_please_choose']; ?></option>
+                        <option value="10" <?php if ($_GET['refill_amount'] == '10') { ?>selected<?php } ?>>10</option>
+                        <option value="20" <?php if ($_GET['refill_amount'] == '20') { ?>selected<?php } ?>>20</option>
+                        <option value="30" <?php if ($_GET['refill_amount'] == '30') { ?>selected<?php } ?>>30</option>
+                        <option value="50" <?php if ($_GET['refill_amount'] == '50') { ?>selected<?php } ?>>50</option>
+                        <option value="100" <?php if ($_GET['refill_amount'] == '100') { ?>selected<?php } ?>>100</option>
+                        <option value="200" <?php if ($_GET['refill_amount'] == '200') { ?>selected<?php } ?>>200</option>
+                        <option value="300" <?php if ($_GET['refill_amount'] == '300') { ?>selected<?php } ?>>300</option>
+                        <option value="500" <?php if ($_GET['refill_amount'] == '500') { ?>selected<?php } ?>>500</option>
+                        <option value="1000" <?php if ($_GET['refill_amount'] == '1000') { ?>selected<?php } ?>>1000</option>
+                        <option value="2000" <?php if ($_GET['refill_amount'] == '2000') { ?>selected<?php } ?>>2000</option>
+                    </select>
+                </td>
+                <th><label>滤波器</label></th>
+                <td>
+                    <select name="filter_wave">
+                        <option value=""><?php echo $lang['nc_please_choose']; ?></option>
+                        <option value="60">1分钟</option>
+                        <option value="300">5分钟</option>
+                        <option value="600">10分钟</option>
+                        <option value="900">15分钟</option>
+                        <option value="0" selected>关闭</option>
+                    </select>
+                </td>
+                <td>
+                    <a href="javascript:void(0);" id="ncsubmit" class="btn-search" title="<?php echo $lang['nc_query']; ?>">&nbsp;
+                    </a>
+                </td>
+            </tr>
+        </table>
+
+        <div class="echartsContent">
+            <table id="checkChannel">
+                <thead>
+                    <tr>
+                        <td>
+                            <label>
+                                <input type="checkbox" id="checkAllChannel">
+                                编号(通道列表)
+                            </label>
+                        </td>
+                    </tr>
+                </thead>
+                <tbody id="checkChannelContent">
+
+                </tbody>
+            </table>
+            <div id="echart">
+
+            </div>
+        </div>
+
+
+
+    </form>
+    <div id="box">
+        <!-- <iframe
+            src="https://www.xyzshops.cn/plot/index?time_stamp=1621488600&interval=60" scrolling="no" id="Iframe" frameborder="0"></iframe> -->
+    </div>
+</div>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/laydate/laydate.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/jquery.ui.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/i18n/zh-CN.js" charset="utf-8"></script>
+<script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL; ?>/js/xm-select.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/refill/layer.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/refill/moment-with-locales.js"></script>
+<link rel="stylesheet" type="text/css" href="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/themes/ui-lightness/jquery.ui.css" />
+<script type="text/javascript">
+    $(function() {
+
+        var provider = <?php echo json_encode($output['providers']) ?>
+
+        let ratios = [];
+
+        let qualitys = [];
+
+        const defaultChannelType = <?php echo refill\Quality::Normal; ?>;
+
+        $.get(`index.php?act=refill_analysis&op=provider_data`, function(data) {
+            data = JSON.parse(data)
+            if (data.length > 0) {
+                qualitys = data;
+                formatChannelTable(data);
+            }
+        })
+
+        function formatChannelTable(tableData) {
+            $('#checkChannelContent').children().remove();
+            let data;
+            if (typeof tableData == 'object') {
+                data = tableData;
+            } else {
+                data = JSON.parse(tableData)
+            }
+
+            let tableHTML = '';
+            data.map(item => {
+                tableHTML += `
+                    <tr>
+                        <td><label><input type="checkbox" name="channelValue" ${item.checked?'checked="checked"':''}  value="${item.value}" />${item.name}${item.ratio?`<span style="color:red;">(${item.ratio})</span>`:''}</label></td>
+                    </tr>
+                `;
+            })
+            $('#checkChannelContent').append(tableHTML);
+        }
+
+        laydate.render({
+            elem: '#startTime',
+            type: 'datetime'
+        });
+        laydate.render({
+            elem: '#endTime',
+            type: 'datetime'
+        });
+
+
+        let select_cardtypes
+        $.get('index.php?act=refill_analysis&op=card_type_data', function(data) {
+            data = JSON.parse(data)
+            select_cardtypes = xmSelect.render({
+                el: '#select_cardtypes',
+                size: 'mini',
+                filterable: true,
+                style: {
+                    minHeight: '27px',
+                    lineHeight: '27px',
+                    marginLeft: '4px',
+                    width: '250px'
+                },
+                language: 'zn',
+                data: data
+            })
+        })
+
+        function select_set(selectArr) {
+            let selectStr = ''
+            for (let i = 0; i < selectArr.length; i++) {
+                selectStr += selectArr[i].value + ','
+            }
+            selectStr = selectStr.substr(0, selectStr.length - 1)
+            return selectStr
+        }
+
+        function updateQualityTable() {
+            const allQualityList = JSON.parse(JSON.stringify(qualitys));
+
+            allQualityList.map(item => {
+                item.checked = false;
+            })
+
+
+            function findItem(value) {
+                const item = allQualityList.filter(item => {
+                    return item.value == value;
+                })
+                if (item.length > 0) {
+                    return item[0].name
+                }
+                return false
+            }
+            const ratioList = ratios.map(item => {
+                return {
+                    name: findItem(item.split(':')[0]) || item.split(':')[0],
+                    value: item.split(':')[0],
+                    ratio: item.split(':')[1],
+                    checked: parseFloat(item.split(':')[1]) == 0 ? false : true
+                }
+            });
+
+
+            let mergeQualitys = [...ratioList, ...allQualityList];
+
+            const newArr = [];
+            const obj = {};
+
+            for (let i = 0; i < mergeQualitys.length; i++) {
+                if (!obj[mergeQualitys[i].value]) {
+                    newArr.push(mergeQualitys[i]);
+                    obj[mergeQualitys[i].value] = true;
+                }
+            }
+
+            formatChannelTable(newArr);
+        }
+
+        $('#ncsubmit').click(function() {
+            let query_start_time = $("input[name=query_start_time]").val()
+            let start_time = parseInt((new Date(query_start_time)).getTime() / 1000);
+            let query_end_time = $("input[name=query_end_time]").val()
+            let end_time = parseInt((new Date(query_end_time)).getTime() / 1000);
+
+            if (!start_time && !end_time) {
+                start_time = Date.parse(new Date()) / 1000 - 7200;
+                end_time = Date.parse(new Date()) / 1000;
+            }
+
+            let chnamesList = [];
+            $('input[name="channelValue"]').each(function() {
+                if ($(this).attr('checked')) {
+                    chnamesList.push($(this).attr('value'))
+                }
+            })
+
+            let chnames = chnamesList.join(',');
+
+
+            let card_types = select_cardtypes && select_set(select_cardtypes.getValue())
+            let spec = $("select[name=amount]").val()
+            let filter_wave = $("select[name=filter_wave]").val()
+            let src = window.location.origin + "/plot/ch_ratio?"
+            if (start_time) {
+                src += "&start_time=" + start_time;
+            }
+            if (end_time) {
+                if (end_time < start_time || !start_time) {
+                    layer.msg('日期有误,结束日期需大于开始日期');
+                    return
+                }
+                src += "&end_time=" + end_time;
+            }
+            if (chnames) {
+                src += "&chnames=" + chnames;
+            }
+            if (card_types) {
+                src += "&card_types=" + card_types;
+            }
+            if (spec) {
+                src += "&spec=" + spec;
+            }
+            if (filter_wave > 0) {
+                src += '&filter_wave=' + filter_wave;
+            }
+            $.get(src, function(data)
+            {
+                if (data.state == 'success') {
+                    $('#echart').html(`<img src='data:image/png;base64,${data.img}'/>`)
+                    ratios = data.ratios;
+                    updateQualityTable()
+                }
+            });
+        });
+
+        $('#checkAllChannel').click(function() {
+            if ($(this).get(0).checked) {
+                $('input[name="channelValue"]').attr('checked', 'checked')
+            } else {
+                $('input[name="channelValue"]').removeAttr('checked')
+            }
+        })
+
+        $('.querySelect').trigger('change');
+        $('#ncsubmit').trigger('click');
+    })
+</script>

+ 345 - 0
admin/templates/default/analysis.new_version.system.php

@@ -0,0 +1,345 @@
+<style>
+    #checkChannel {
+        border-spacing: 0;
+        border-collapse: collapse;
+    }
+
+    #checkChannel td {
+        height: 20px;
+        padding: 2px;
+        background: #F3FBFE;
+        border: 1px solid #fff;
+        display: block;
+        white-space: nowrap;
+        font-size: 10px;
+    }
+
+    #checkChannel tr {
+        height: 20px;
+    }
+
+    #checkChannel thead tr {
+        table-layout: fixed;
+        top: 0;
+        left: 0;
+    }
+
+    #checkChannel tbody {
+        height: calc(100vh - 210px);
+        display: block;
+        overflow-y: scroll;
+    }
+
+    .echartsContent {
+        display: flex;
+        height: calc(100vh - 150px);
+    }
+
+    #echart {
+        flex: 1;
+        margin-left: 5px;
+    }
+
+    #echart img {
+        width: 100%;
+    }
+</style>
+<div class="page">
+    <div class="fixed-bar">
+        <div class="item-title">
+            <h3>成功率监控列表</h3>
+            <ul class="tab-base">
+                <li><a href="?index.php&act=refill_analysis&op=index&type=provider"><span>通道成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=index&type=system"><span>平台成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=merchant_ratios"><span>机构成功率统计</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=provider"><span>新通道成功率监控</span></a></li>
+                <li><a href="JavaScript:void(0);" class="current"><span>新平台成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=mch_order_send"><span>机构单量监控</span></a></li>
+            </ul>
+        </div>
+    </div>
+    <div class="fixed-empty"></div>
+    <div style="margin-top: 10px;color: #e60d0d;">
+        请先选择时间
+    </div>
+    <form method="get" action="index.php" name="formSearch" id="formSearch" style="min-width: 1200px;">
+        <table class="tb-type1 noborder search tableFixed">
+            <tr>
+                <th><label for="query_start_time">统计时间</label></th>
+                <td>
+                    <input class="txt date" type="text" value="<?php echo $_GET['query_start_time']; ?>" id="startTime" name="query_start_time" autocomplete="off" style="width:120px" />
+                    <label for="query_start_time">~</label>
+                    <input class="txt date" type="text" value="<?php echo $_GET['query_end_time']; ?>" id="endTime" name="query_end_time" autocomplete="off" style="width:120px" />
+                </td>
+                <!-- <th><label>机构选择</label></th>
+                <td>
+                    <div id="select_merchants"></div>
+                </td> -->
+                <th><label>卡类型</label></th>
+                <td>
+                    <div id="select_cardtypes"></div>
+                </td>
+                <th><label>面额</label></th>
+                <td>
+                    <select name="amount">
+                        <option value=""><?php echo $lang['nc_please_choose']; ?></option>
+                        <option value="10" <?php if ($_GET['refill_amount'] == '10') { ?>selected<?php } ?>>10</option>
+                        <option value="20" <?php if ($_GET['refill_amount'] == '20') { ?>selected<?php } ?>>20</option>
+                        <option value="30" <?php if ($_GET['refill_amount'] == '30') { ?>selected<?php } ?>>30</option>
+                        <option value="50" <?php if ($_GET['refill_amount'] == '50') { ?>selected<?php } ?>>50</option>
+                        <option value="100" <?php if ($_GET['refill_amount'] == '100') { ?>selected<?php } ?>>100</option>
+                        <option value="200" <?php if ($_GET['refill_amount'] == '200') { ?>selected<?php } ?>>200</option>
+                        <option value="300" <?php if ($_GET['refill_amount'] == '300') { ?>selected<?php } ?>>300</option>
+                        <option value="500" <?php if ($_GET['refill_amount'] == '500') { ?>selected<?php } ?>>500</option>
+                        <option value="1000" <?php if ($_GET['refill_amount'] == '1000') { ?>selected<?php } ?>>1000</option>
+                        <option value="2000" <?php if ($_GET['refill_amount'] == '2000') { ?>selected<?php } ?>>2000</option>
+                    </select>
+                </td>
+                <th><label>滤波器</label></th>
+                <td>
+                    <select name="filter_wave">
+                        <option value=""><?php echo $lang['nc_please_choose']; ?></option>
+                        <option value="60">1分钟</option>
+                        <option value="300">5分钟</option>
+                        <option value="600">10分钟</option>
+                        <option value="900">15分钟</option>
+                        <option value="0" selected>关闭</option>
+                    </select>
+                </td>
+                <td>
+                    <a href="javascript:void(0);" id="ncsubmit" class="btn-search" title="<?php echo $lang['nc_query']; ?>">&nbsp;
+                    </a>
+                </td>
+            </tr>
+        </table>
+    </form>
+
+    <div class="echartsContent">
+        <table id="checkChannel">
+            <thead>
+                <tr>
+                    <td>
+                        <label>
+                            <input type="checkbox" id="checkAllChannel">
+                            编号(机构列表)
+                        </label>
+                    </td>
+                </tr>
+            </thead>
+            <tbody id="checkChannelContent">
+
+            </tbody>
+        </table>
+        <div id="echart">
+
+        </div>
+    </div>
+
+    <div id="box">
+        <!-- <iframe
+            src="https://www.xyzshops.cn/plot/index?time_stamp=1621488600&interval=60" scrolling="no" id="Iframe" frameborder="0"></iframe> -->
+    </div>
+</div>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/laydate/laydate.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/jquery.ui.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/i18n/zh-CN.js" charset="utf-8"></script>
+<script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL; ?>/js/xm-select.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/refill/layer.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/refill/moment-with-locales.js"></script>
+<link rel="stylesheet" type="text/css" href="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/themes/ui-lightness/jquery.ui.css" />
+<script type="text/javascript">
+    $(function() {
+
+        let ratios = [];
+
+        let qualitys = [];
+
+
+        laydate.render({
+            elem: '#startTime',
+            type: 'datetime'
+        });
+        laydate.render({
+            elem: '#endTime',
+            type: 'datetime'
+        });
+
+
+
+        function formatChannelTable(tableData) {
+            $('#checkChannelContent').children().remove();
+            let data;
+            if (typeof tableData == 'object') {
+                data = tableData;
+            } else {
+                data = JSON.parse(tableData)
+            }
+            let tableHTML = '';
+            data.map(item => {
+                tableHTML += `
+                    <tr>
+                        <td><label><input type="checkbox" name="channelValue" ${item.checked?'checked="checked"':''}  value="${item.value}" />${item.name}${item.ratio?`<span style="color:red;">(${item.ratio})</span>`:''}</label></td>
+                    </tr>
+                `;
+            })
+            $('#checkChannelContent').append(tableHTML);
+        }
+
+        function updateQualityTable() {
+            const allQualityList = JSON.parse(JSON.stringify(qualitys));
+
+            allQualityList.map(item => {
+                item.checked = false;
+            })
+
+
+            function findItem(value) {
+                const item = allQualityList.filter(item => {
+                    return item.value == value;
+                })
+                if (item.length > 0) {
+                    return item[0].name
+                }
+                return false
+            }
+            const ratioList = ratios.map(item => {
+                return {
+                    name: findItem(item.split(':')[0]) || item.split(':')[0],
+                    value: item.split(':')[0],
+                    ratio: item.split(':')[1],
+                    checked: parseFloat(item.split(':')[1]) == 0 ? false : true
+                }
+            });
+
+
+            let mergeQualitys = [...ratioList, ...allQualityList];
+
+            const newArr = [];
+            const obj = {};
+
+            for (let i = 0; i < mergeQualitys.length; i++) {
+                if (!obj[mergeQualitys[i].value]) {
+                    newArr.push(mergeQualitys[i]);
+                    obj[mergeQualitys[i].value] = true;
+                }
+            }
+
+            formatChannelTable(newArr);
+        }
+
+        // let select_merchants
+        $.get('index.php?act=refill_analysis&op=merchant_data', function(data) {
+            data = JSON.parse(data)
+            qualitys = data;
+            formatChannelTable(data)
+            // select_merchants = xmSelect.render({
+            //     el: '#select_merchants',
+            //     size: 'mini',
+            //     filterable: true,
+            //     style: {
+            //         minHeight: '27px',
+            //         lineHeight: '27px',
+            //         marginLeft: '4px',
+            //         width: '250px'
+            //     },
+            //     language: 'zn',
+            //     data: data
+            // })
+        })
+
+        let select_cardtypes
+        $.get('index.php?act=refill_analysis&op=card_type_data', function(data) {
+            data = JSON.parse(data)
+            select_cardtypes = xmSelect.render({
+                el: '#select_cardtypes',
+                size: 'mini',
+                filterable: true,
+                style: {
+                    minHeight: '27px',
+                    lineHeight: '27px',
+                    marginLeft: '4px',
+                    width: '250px'
+                },
+                language: 'zn',
+                data: data
+            })
+        })
+
+        function select_set(selectArr) {
+            let selectStr = ''
+            for (let i = 0; i < selectArr.length; i++) {
+                selectStr += selectArr[i].value + ','
+            }
+            selectStr = selectStr.substr(0, selectStr.length - 1)
+            return selectStr
+        }
+
+        $('#checkAllChannel').click(function() {
+            if ($(this).get(0).checked) {
+                $('input[name="channelValue"]').attr('checked', 'checked')
+            } else {
+                $('input[name="channelValue"]').removeAttr('checked')
+            }
+        })
+
+        $('#ncsubmit').click(function() {
+            let query_start_time = $("input[name=query_start_time]").val()
+            let start_time = parseInt((new Date(query_start_time)).getTime() / 1000);
+            let query_end_time = $("input[name=query_end_time]").val()
+            let end_time = parseInt((new Date(query_end_time)).getTime() / 1000);
+
+            if (!start_time && !end_time) {
+                start_time = Date.parse(new Date()) / 1000 - 7200;
+                end_time = Date.parse(new Date()) / 1000;
+            }
+
+
+            // let mchids = select_set(select_merchants.getValue())
+            let mchidList = [];
+            $('input[name="channelValue"]').each(function() {
+                if ($(this).attr('checked')) {
+                    mchidList.push($(this).attr('value'))
+                }
+            })
+
+            let mchids = mchidList.join(',');
+
+
+            let card_types = select_cardtypes && select_set(select_cardtypes.getValue())
+            let spec = $("select[name=amount]").val()
+            let filter_wave = $("select[name=filter_wave]").val()
+            let src = window.location.origin + "/plot/mch_ratio?"
+            if (start_time) {
+                src += "&start_time=" + start_time;
+            }
+            if (end_time) {
+                if (end_time < start_time || !start_time) {
+                    layer.msg('日期有误,结束日期需大于开始日期');
+                    return
+                }
+                src += "&end_time=" + end_time;
+            }
+            if (mchids) {
+                src += "&mchids=" + mchids;
+            }
+            if (card_types) {
+                src += "&card_types=" + card_types;
+            }
+            if (spec) {
+                src += "&spec=" + spec;
+            }
+            if (filter_wave > 0) {
+                src += '&filter_wave=' + filter_wave;
+            }
+            $.get(src, function(data) {
+                if (data.state == 'success') {
+                    $('#echart').html(`<img src='data:image/png;base64,${data.img}'/>`)
+                    ratios = data.ratios;
+                    updateQualityTable()
+                }
+            });
+        });
+
+        $('#ncsubmit').trigger('click');
+    })
+</script>

+ 4 - 1
admin/templates/default/analysis.provider.php

@@ -6,7 +6,10 @@
                 <li><a href="JavaScript:void(0);" class="current" ><span>通道成功率监控</span></a></li>
                 <li><a href="?index.php&act=refill_analysis&op=index&type=system"><span>平台成功率监控</span></a></li>
                 <li><a href="?index.php&act=refill_analysis&op=merchant_ratios"><span>机构成功率统计</span></a></li>
-                <li><a href="?index.php&act=refill_analysis&op=new_version"><span>新通道成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=provider"><span>新通道成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=system"><span>新平台成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=mch_order_send"><span>机构单量监控</span></a></li>
+
             </ul>
         </div>
     </div>

+ 4 - 1
admin/templates/default/analysis.system.php

@@ -6,7 +6,10 @@
                 <li><a href="?index.php&act=refill_analysis&op=index&type=provider"><span>通道成功率监控</span></a></li>
                 <li><a href="JavaScript:void(0);" class="current"><span>平台成功率监控</span></a></li>
                 <li><a href="?index.php&act=refill_analysis&op=merchant_ratios"><span>机构成功率统计</span></a></li>
-                <li><a href="?index.php&act=refill_analysis&op=new_version"><span>新通道成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=provider"><span>新通道成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=system"><span>新平台成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=mch_order_send"><span>机构单量监控</span></a></li>
+
             </ul>
         </div>
     </div>

+ 15 - 0
admin/templates/default/merchant.edit.php

@@ -91,6 +91,21 @@
                     </label>关闭
                 </td>
             </tr>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="co_type">公司绑定:</label></td>
+            </tr>
+            <tr class="">
+                <td class="vatop rowform">
+                    <label for="co_id"></label>
+                    <select name="co_id" id="co_id">
+                        <option value="">请选择...</option>
+                        <?php foreach ($output['refill_company'] as $company){ ?>
+                            <option value="<?php echo $company['co_id'];?>" <?php if($output['provider']['co_id'] == $company['co_id']){ echo 'selected';}?>><?php echo $company['co_name'];?></option>
+                        <?php }?>
+                    </select>
+                </td>
+                <td class="vatop tips"></td>
+            </tr>
             </tbody>
             <tfoot>
             <tr class="tfoot">

+ 2 - 0
admin/templates/default/merchant.index.php

@@ -81,6 +81,7 @@ defined('InShopNC') or exit('Access Invalid!'); ?>
                         <th class="align-left" style="text-align: left">机构账号</th>
                         <th class="align-center">会员ID</th>
                         <th class="align-left">机构公司名称</th>
+                        <th class="align-left">绑定公司名称</th>
                         <th class="align-right">所剩余额</th>
                         <th class="align-right">授信额度</th>
                         <th class="align-right">预警余额</th>
@@ -102,6 +103,7 @@ defined('InShopNC') or exit('Access Invalid!'); ?>
                                     <td class="align-left"><?php echo $v['name']; ?></td>
                                     <td class="align-center"><?php echo $v['admin_id']; ?></td>
                                     <td class="align-left"><?php echo $v['company_name']; ?></td>
+                                    <td class="align-left"><?php echo $v['co_name']; ?></td>
                                     <td id="just" class="align-right">
                                         <?php if ($v['available_predeposit'] > 0) { ?>
                                             <span style="color: #0bb20c">

+ 3 - 1
admin/templates/default/merchant.ratios.php

@@ -50,7 +50,9 @@
                 <li><a href="?index.php&act=refill_analysis&op=index&type=provider"><span>通道成功率监控</span></a></li>
                 <li><a href="?index.php&act=refill_analysis&op=index&type=system"><span>平台成功率监控</span></a></li>
                 <li><a href="JavaScript:void(0);" class="current" ><span>机构成功率统计</span></a></li>
-                <li><a href="?index.php&act=refill_analysis&op=new_version"><span>新通道成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=provider"><span>新通道成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=system"><span>新平台成功率监控</span></a></li>
+                <li><a href="?index.php&act=refill_analysis&op=new_version&type=mch_order_send"><span>机构单量监控</span></a></li>
             </ul>
         </div>
     </div>

+ 3 - 2
admin/templates/default/provider.amount.php

@@ -33,6 +33,7 @@
             <ul class="tab-base">
                 <li><a href="index.php?act=provider&op=index"><span><?php echo $lang['nc_manage'] ?></span></a></li>
                 <li><a href="JavaScript:void(0);" class="current"><span>调款记录</span></a></li>
+                <li><a href="index.php?act=provider&op=provider_remit"><span>打款</span></a></li>
             </ul>
         </div>
     </div>
@@ -96,9 +97,9 @@
             <thead>
             <tr class="thead">
                 <th>序号</th>
+                <th>通道ID</th>
                 <th>记录ID</th>
                 <th>通道名称</th>
-                <th>通道ID</th>
                 <th class="align-right">调整金额</th>
                 <th class="align-left">操作人</th>
                 <th class="align-left">操作日期</th>
@@ -111,9 +112,9 @@
                 <?php foreach ($output['info_list'] as $k => $v) { ?>
                     <tr class="trFlex">
                         <td><?php echo $k+1;?></td>
+                        <td><?php echo $v['provider_id']; ?></td>
                         <td><?php echo $v['id']; ?></td>
                         <td><?php echo $v['provider_name']; ?> (<?php echo $v['store_name'];?>)</td>
-                        <td><?php echo $v['provider_id']; ?></td>
                         <td class="align-right"><?php echo $v['amount']; ?></td>
                         <td class="align-left"><?php echo $v['operation']; ?></td>
                         <td class="align-left"><?php echo $v['add_time'] ? date('Y-m-d H:i', $v['add_time']) : $lang['no_limit']; ?></td>

+ 15 - 0
admin/templates/default/provider.edit.php

@@ -74,6 +74,21 @@
                 <td class="vatop rowform"><input type="text" value="<?php echo $output['provider']['end_period']?>" name="end_period" id="end_period" class="txt"></td>
                 <td class="vatop tips"></td>
             </tr>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="co_type">公司绑定:</label></td>
+            </tr>
+            <tr class="">
+                <td class="vatop rowform">
+                    <label for="co_id"></label>
+                    <select name="co_id" id="co_id">
+                        <option value="">请选择...</option>
+                        <?php foreach ($output['refill_company'] as $company){ ?>
+                            <option value="<?php echo $company['co_id'];?>" <?php if($output['provider']['co_id'] == $company['co_id']){ echo 'selected';}?>><?php echo $company['co_name'];?></option>
+                        <?php }?>
+                    </select>
+                </td>
+                <td class="vatop tips"></td>
+            </tr>
             </tbody>
             <tfoot>
             <tr class="tfoot">

+ 3 - 0
admin/templates/default/provider.index.php

@@ -17,6 +17,7 @@
             <ul class="tab-base">
                 <li><a href="JavaScript:void(0);" class="current"><span><?php echo $lang['nc_manage'] ?></span></a></li>
                 <li><a href="index.php?act=provider&op=provider_amount"><span>调款记录</span></a></li>
+                <li><a href="index.php?act=provider&op=provider_remit"><span>打款</span></a></li>
             </ul>
         </div>
     </div>
@@ -127,6 +128,7 @@
                     <th>通道名称</th>
                     <th>店铺ID</th>
                     <th>会员ID</th>
+                    <th>绑定公司名称</th>
                     <th>通道类型</th>
                     <th>通道质量</th>
                     <th class="align-center">通道状态</th>
@@ -146,6 +148,7 @@
                             <td><?php echo $v['name']; ?> (<?php echo $v['store_name']; ?>)</td>
                             <td><?php echo $v['store_id']; ?></td>
                             <td><?php echo $v['account_id']; ?></td>
+                            <td><?php echo $v['co_name']; ?></td>
                             <td><?php echo $output['type_text'][$v['type'] - 1]; ?></td>
                             <td><?php echo $v['quality_text']; ?></td>
                             <td class="align-center">

+ 230 - 0
admin/templates/default/provider.remit.edit.php

@@ -0,0 +1,230 @@
+<?php defined('InShopNC') or exit('Access Invalid!'); ?>
+<style>
+</style>
+<div class="page">
+    <div class="fixed-bar">
+        <div class="item-title">
+            <h3>公司信息管理</h3>
+            <ul class="tab-base">
+                <li><a href="index.php?act=refill_company&op=index"><span>公司信息管理</span></a></li>
+                <li><a href="index.php?act=refill_company&op=add"><span>新增</span></a></li>
+                <li><a href="index.php?act=refill_company&op=remit_cfg"><span>打款配置</span></a></li>
+                <li><a href="index.php?act=refill_company&op=remit_record"><span>公司打款记录</span></a></li>
+                <li><a href="JavaScript:void(0);" class="current"><span>打款记录编辑</span></a></li>
+            </ul>
+        </div>
+    </div>
+    <div class="fixed-empty"></div>
+    <form id="price_form" enctype="multipart/form-data" method="post">
+        <input type="hidden" name="form_submit" value="ok" />
+        <input type="hidden" name="remit_id" value="<?php echo $output['remit']['remit_id'];?>">
+        <table class="table tb-type2">
+            <tbody>
+                <tr class="noborder">
+                    <td colspan="2" class="required"><label class="validation" for="mchid">操作人:</label></td>
+                </tr>
+                <tr class="noborder">
+                    <td class="vatop rowform"><input type="text" name="operation" id="operation" class="txt" value="<?php echo $output['remit']['operation'];?>">
+                    </td>
+                    <td class="vatop tips"></td>
+                </tr>
+                <tr>
+                    <td colspan="2" class="required"><label class="validation" for="password">打款:</label></td>
+                </tr>
+                <?php foreach ($output['remit_data'] as $data) { ?>
+                <tr class="noborder">
+                    <td>
+                        <table class="spec_table tb-type2 setTable" style="width: 780px">
+                            <tr>
+                                <th>公司名称:<?php echo $data['co_name'];?></th>
+                            </tr>
+                            <tr class="w500">
+                                <th class="w150 align-center">通道名称</th>
+                                <th class="w150 align-center">当前余额</th>
+                                <th class="w150 align-center">打款金额</th>
+                            </tr>
+                            <?php foreach ($data['providers'] as $v){?>
+
+                            <tbody class="tbody">
+                                <tr class="w500" style="height: 50px;">
+                                    <td class="w100 align-center">
+                                        <?php echo $v['store_name']; ?>
+                                    </td>
+                                    <td class="w100 align-center" id="available">
+                                        <span><?php echo $v['available_predeposit']; ?></span>
+                                        <div style="color:red;"></div>
+                                    </td>
+                                    <td class="w100 align-center">
+                                        <input type="hidden" name="strs[]" value="<?php echo $v['co_id']?>-<?php echo $v['provider_id']?>">
+                                        <input type="number" name="remits[]" class="priceInput" value="<?php echo $v['remit'];?>">
+                                        <div id="money" style="color:red;"></div>
+                                    </td>
+                                </tr>
+                            </tbody>
+                            <?php }?>
+                        </table>
+                    </td>
+                </tr>
+                <?php } ?>
+                <tr>
+                    <th></th>
+                    <td text-align="right">总计:<span id="total" style="color:red;">0</span></td>
+                </tr>
+            </tbody>
+            <tfoot>
+                <tr class="tfoot">
+                    <td colspan="15"><a href="JavaScript:void(0);" class="btn" id="submitBtn"><span><?php echo $lang['nc_submit']; ?></span></a></td>
+                </tr>
+            </tfoot>
+        </table>
+    </form>
+</div>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/dialog/dialog.js" id="dialog_js" charset="utf-8"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/jquery.ui.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/ajaxfileupload/ajaxfileupload.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery.Jcrop/jquery.Jcrop.js"></script>
+<link href="<?php echo RESOURCE_SITE_URL; ?>/js/jquery.Jcrop/jquery.Jcrop.min.css" rel="stylesheet" type="text/css" id="cssfile2" />
+<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.16.0/math.min.js"></script>
+<script>
+    math.config({
+        number: 'BigNumber',
+        precision: 20
+    });
+</script>
+<script type="text/javascript">
+    $(function() {
+        total_calculation()
+        function total_calculation()
+        {
+            let total = 0;
+            var $priceInput = $('.priceInput');
+         
+            for(let i=0;i<$priceInput.length;i++){
+                if($priceInput.eq(i).val() && !isNaN($priceInput.eq(i).val())){
+                    const value = parseFloat($priceInput.eq(i).val());
+                    total = math.add(math.bignumber(total),math.bignumber(value)).toNumber();
+                }
+            }
+
+            total = parseFloat(total);
+            let num = total % 1000;
+            total = total - num;
+            let total_chineseStr = cnMoneyFormat(total);
+            total = numFormat(total);
+            let total_text = total + '('+ total_chineseStr +')';
+            $('#total').html(total_text)
+        }
+
+        function numFormat(num){
+            return num.toString().replace(/\d+/, function (n) { // 先提取小数点前后的整数部分
+                //(\d)(?=(\d{3})正则的意思是匹配连续三个数结尾的数字,例如1234,1后面有234连续三个数的数字,就可以匹配上,匹配的是1这个数字。如果是123,因为1后面是两位数,所以就匹配不上了
+                return n.replace(/(\d)(?=(\d{3})+$)/g, function ($1) {
+                    return $1 + ",";
+                });
+            });
+        }
+
+        //接口查询余额
+        $('#available div').each(function(index, item) {
+            let txt = $(item).prev().text()
+            txt = parseFloat(txt)
+            if (txt < 0 && txt < -10000) {
+                $(item).text('(' + '-' + cnMoneyFormat(txt) + ')')
+            } else if (txt > 0 && txt > 10000) {
+                $(item).text('(' + cnMoneyFormat(txt) + ')')
+            } else {
+                $(item).text(cnMoneyFormat(txt))
+            }
+        })
+
+        $("#submitBtn").click(function() {
+            if ($("#price_form").valid()) {
+                $("#price_form").submit();
+            }
+        });
+        $('.priceInput').blur(function (){
+            let money = $(this).val();
+            money = parseFloat(money)
+            console.log(money)
+            let chineseStr = cnMoneyFormat(money);
+            $(this).next().html(chineseStr)
+            total_calculation()
+        })
+
+        $('#price_form').validate({
+            errorPlacement: function (error, element) {
+                error.appendTo(element.parent().parent().prev().find('td:first'));
+            },
+            rules: {
+                operation: {
+                    required: true,
+                },
+            },
+            messages: {
+                operation: {
+                    required: '操作人不能为空',
+                },
+            }
+        });
+    });
+    function cnMoneyFormat(money) {
+        let number_data = money;
+        if (number_data < 0) {
+            number_data = number_data.toString();
+            let num_data = number_data.substring(1, number_data.length)
+            number_data = parseInt(num_data);
+        } else {
+            number_data = parseInt(number_data);
+        }
+        let yi = 0; //亿
+        let wan = 0; //万
+        let wan_s = 10000; //万
+        let yi_s = 100000000; //亿
+        //取整
+        function qz(data) {
+            data = Math.floor(data);
+            return data;
+        }
+
+        //为0判断输出
+        function data_if(data, amount) {
+            if (data === 0) {
+                return '';
+            } else {
+                return data + amount;
+            }
+        }
+
+        //亿
+        function yi_f(data) {
+            yi = qz(data / 100000000);
+            data = data - (yi * yi_s);
+            let data_json = {
+                data1: data_if(yi, '亿'),
+                data2: data,
+            }
+            return data_json;
+        }
+
+        //万
+        function wan_f(data) {
+            wan = qz(data / 10000);
+            data = data - (wan * wan_s);
+            let data_json = {
+                data1: data_if(wan, '万'),
+                data2: data,
+            }
+            return data_json;
+        }
+
+        yi = yi_f(number_data);
+        number_data = yi.data2;
+        wan = wan_f(number_data);
+        number_data = wan.data2;
+        let result = yi.data1 + wan.data1;
+        if (result == 0) {
+            return ''
+        }
+        return result
+    }
+</script>

+ 227 - 0
admin/templates/default/provider.remit.php

@@ -0,0 +1,227 @@
+<?php defined('InShopNC') or exit('Access Invalid!'); ?>
+<style>
+</style>
+<div class="page">
+    <div class="fixed-bar">
+        <div class="item-title">
+            <h3>通道管理</h3>
+            <ul class="tab-base">
+                <li><a href="index.php?act=provider&op=index"><span><?php echo $lang['nc_manage'] ?></span></a></li>
+                <li><a href="index.php?act=provider&op=provider_amount"><span>调款记录</span></a></li>
+                <li><a href="JavaScript:void(0);" class="current"><span>打款</span></a></li>
+            </ul>
+        </div>
+    </div>
+    <div class="fixed-empty"></div>
+    <form id="price_form" enctype="multipart/form-data" method="post">
+        <input type="hidden" name="form_submit" value="ok" />
+        <table class="table tb-type2">
+            <tbody>
+                <tr class="noborder">
+                    <td colspan="2" class="required"><label class="validation" for="mchid">操作人:</label></td>
+                </tr>
+                <tr class="noborder">
+                    <td class="vatop rowform"><input type="text" name="operation" id="operation" class="txt" value="">
+                    </td>
+                    <td class="vatop tips"></td>
+                </tr>
+                <tr>
+                    <td colspan="2" class="required"><label class="validation" for="password">打款:</label></td>
+                </tr>
+                <?php foreach ($output['remit_data'] as $data) { ?>
+                <tr class="noborder">
+                    <td>
+                        <table class="spec_table tb-type2 setTable" style="width: 780px">
+                            <tr>
+                                <th>公司名称:<?php echo $data['co_name'];?></th>
+                            </tr>
+                            <tr class="w500">
+                                <th class="w150 align-center">通道名称</th>
+                                <th class="w150 align-center">当前余额</th>
+                                <th class="w150 align-center">打款金额</th>
+                            </tr>
+                            <?php foreach ($data['providers'] as $v){?>
+                                <tbody class="tbody">
+                                    <tr class="w500" style="height: 50px;">
+                                        <td class="w100 align-center">
+                                            <?php echo $v['store_name']; ?>
+                                        </td>
+                                        <td id="available" class="align-center">
+                                            <span><?php echo $v['available_predeposit'] ?? 0; ?></span>
+                                            <div style=" display: inline-block;margin-left: 7px; color:red;"></div>
+                                        </td>
+                                        <td class="w100 align-center">
+                                            <input type="hidden" name="strs[]" value="<?php echo $v['co_id']?>-<?php echo $v['provider_id']?>">
+                                            <input type="text" name="remits[]" class="priceInput" value="<?php echo $v['remit'];?>">
+                                            <div id="money" style="color:red;"></div>
+                                        </td>
+                                    </tr>
+                                </tbody>
+                            <?php }?>
+                        </table>
+                    </td>
+                </tr>
+                <?php } ?>
+                <tr>
+                    <th></th>
+                    <td text-align="right">总计:<span id="total" style="color:red;">0</span></td>
+                </tr>
+            </tbody>
+            <tfoot>
+                <tr class="tfoot">
+                    <td colspan="15"><a href="JavaScript:void(0);" class="btn" id="submitBtn"><span><?php echo $lang['nc_submit']; ?></span></a></td>
+                </tr>
+            </tfoot>
+        </table>
+    </form>
+</div>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/dialog/dialog.js" id="dialog_js" charset="utf-8"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/jquery.ui.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/ajaxfileupload/ajaxfileupload.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery.Jcrop/jquery.Jcrop.js"></script>
+<link href="<?php echo RESOURCE_SITE_URL; ?>/js/jquery.Jcrop/jquery.Jcrop.min.css" rel="stylesheet" type="text/css" id="cssfile2" />
+<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.16.0/math.min.js"></script>
+<script>
+    math.config({
+        number: 'BigNumber',
+        precision: 20
+    });
+</script>
+<script type="text/javascript">
+    $(function() {
+
+        total_calculation()
+        function total_calculation()
+        {
+            let total = 0;
+            var $priceInput = $('.priceInput');
+         
+            for(let i=0;i<$priceInput.length;i++){
+                if($priceInput.eq(i).val() && !isNaN($priceInput.eq(i).val())){
+                    const value = parseFloat($priceInput.eq(i).val());
+                    // total = math.parser().eval(total + "+" + value);
+                    total = math.add(math.bignumber(total),math.bignumber(value)).toNumber();
+                }
+            }
+            total = parseFloat(total);
+            let num = total % 1000;
+            total = total - num;
+            let total_chineseStr = cnMoneyFormat(total);
+            total = numFormat(total);
+            let total_text = total + '('+ total_chineseStr +')';
+            $('#total').html(total_text)
+        }
+
+        function numFormat(num){
+            return num.toString().replace(/\d+/, function (n) { // 先提取小数点前后的整数部分
+                //(\d)(?=(\d{3})正则的意思是匹配连续三个数结尾的数字,例如1234,1后面有234连续三个数的数字,就可以匹配上,匹配的是1这个数字。如果是123,因为1后面是两位数,所以就匹配不上了
+                return n.replace(/(\d)(?=(\d{3})+$)/g, function ($1) {
+                    return $1 + ",";
+                });
+            });
+        }
+
+        //接口查询余额
+        $('#available div').each(function(index, item) {
+            let txt = $(item).prev().text()
+            txt = parseFloat(txt)
+            if (txt < 0 && txt < -10000) {
+                $(item).text('(' + '-' + cnMoneyFormat(txt) + ')')
+            } else if (txt > 0 && txt > 10000) {
+                $(item).text('(' + cnMoneyFormat(txt) + ')')
+            } else {
+                $(item).text(cnMoneyFormat(txt))
+            }
+        })
+
+        $("#submitBtn").click(function() {
+            if ($("#price_form").valid()) {
+                $("#price_form").submit();
+            }
+        });
+        $('.priceInput').blur(function (){
+            let money = $(this).val();
+            money = parseFloat(money)
+            let chineseStr = cnMoneyFormat(money);
+            $(this).next().html(chineseStr)
+            total_calculation()
+        })
+
+        $('#price_form').validate({
+            errorPlacement: function (error, element) {
+                error.appendTo(element.parent().parent().prev().find('td:first'));
+            },
+            rules: {
+                operation: {
+                    required: true,
+                },
+            },
+            messages: {
+                operation: {
+                    required: '操作人不能为空',
+                },
+            }
+        });
+    });
+
+    function cnMoneyFormat(money) {
+        let number_data = money;
+        if (number_data < 0) {
+            number_data = number_data.toString();
+            let num_data = number_data.substring(1, number_data.length)
+            number_data = parseInt(num_data);
+        } else {
+            number_data = parseInt(number_data);
+        }
+        let yi = 0; //亿
+        let wan = 0; //万
+        let wan_s = 10000; //万
+        let yi_s = 100000000; //亿
+        //取整
+        function qz(data) {
+            data = Math.floor(data);
+            return data;
+        }
+
+        //为0判断输出
+        function data_if(data, amount) {
+            if (data === 0) {
+                return '';
+            } else {
+                return data + amount;
+            }
+        }
+
+        //亿
+        function yi_f(data) {
+            yi = qz(data / 100000000);
+            data = data - (yi * yi_s);
+            let data_json = {
+                data1: data_if(yi, '亿'),
+                data2: data,
+            }
+            return data_json;
+        }
+
+        //万
+        function wan_f(data) {
+            wan = qz(data / 10000);
+            data = data - (wan * wan_s);
+            let data_json = {
+                data1: data_if(wan, '万'),
+                data2: data,
+            }
+            return data_json;
+        }
+
+        yi = yi_f(number_data);
+        number_data = yi.data2;
+        wan = wan_f(number_data);
+        number_data = wan.data2;
+        let result = yi.data1 + wan.data1;
+        if (result == 0) {
+            return ''
+        }
+        return result
+    }
+</script>

+ 225 - 0
admin/templates/default/refill.company.add.php

@@ -0,0 +1,225 @@
+<?php defined('InShopNC') or exit('Access Invalid!'); ?>
+<style>
+.page .fixed-bar .item-title h3 {
+    margin-top: 18px !important;
+    margin-bottom: 10px !important;
+    font-weight: 700 !important;
+}
+.tab-base li span {
+    font-size: 12px !important;
+}
+</style>
+<div class="page">
+    <div class="fixed-bar">
+        <div class="item-title">
+            <h3>公司信息管理</h3>
+            <ul class="tab-base">
+                <li><a href="index.php?act=refill_company&op=index"><span>公司信息管理</span></a></li>
+                <li><a href="JavaScript:void(0);" class="current"><span>新增</span></a>
+                <li><a href="index.php?act=refill_company&op=remit_cfg"><span>打款配置</span></a></li>
+                <li><a href="index.php?act=refill_company&op=remit_record"><span>公司打款记录</span></a></li>
+            </ul>
+        </div>
+    </div>
+    <div class="fixed-empty"></div>
+    <form id="user_form" enctype="multipart/form-data" method="post"  class="layui-form">
+        <input type="hidden" name="form_submit" value="ok"/>
+        <input type="hidden" name="cid" value=""/>
+        <table class="table tb-type2">
+            <tbody>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="co_type">公司类型:</label></td>
+            </tr>
+            <tr class="">
+                <td class="">
+                    <label for="co_type"></label>
+                    <select name="co_type" id="co_type">
+                        <option value="">请选择...</option>
+                        <option value="<?php echo refill_companyModel::co_type_merchant;?>" <?php if($_GET['co_type'] == refill_companyModel::co_type_merchant){ echo 'selected';}?>>机构</option>
+                        <option value="<?php echo refill_companyModel::co_type_provider;?>" <?php if($_GET['co_type'] == refill_companyModel::co_type_provider){ echo 'selected';}?>>通道</option>
+                    </select>
+                </td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="co_type">通道(机构)选择:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td>
+                    <div id="select_nc"></div>
+                </td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="co_name">公司名称:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" value="" name="co_name" id="co_name" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="bank_name">开户银行名称:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" value="" name="bank_name" id="bank_name" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="bank_username">开户人名称:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" value="" name="bank_username" id="bank_username" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr>
+                <td colspan="2" class="required"><label class="validation" for="bank_card_no">银行卡号:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" id="bank_card_no" name="bank_card_no" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+
+
+            <tr>
+                <td colspan="2" class="required"><label for="max_debt">最大欠款额度:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" id="max_debt" name="max_debt" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr>
+                <td colspan="2" class="required"><label for="province">开户行省份:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" id="province" name="province" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr>
+                <td colspan="2" class="required"><label for="city">开户行城市:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" id="city" name="city" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr>
+                <td colspan="2" class="required"><label for="bank_code">第三方银行编码:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" id="bank_code" name="bank_code" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr>
+                <td colspan="2" class="required"><label>备注:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><textarea name="remark" rows="6" class="tarea"></textarea></td>
+            </tr>
+            </tbody>
+            <tfoot>
+            <tr class="tfoot">
+                <td colspan="15"><a href="JavaScript:void(0);" class="btn" id="submitBtn"><span><?php echo $lang['nc_submit']; ?></span></a></td>
+            </tr>
+            </tfoot>
+        </table>
+    </form>
+</div>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/dialog/dialog.js" id="dialog_js"
+        charset="utf-8"></script>
+<script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL;?>/js/xm-select.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/jquery.ui.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/ajaxfileupload/ajaxfileupload.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery.Jcrop/jquery.Jcrop.js"></script>
+<link href="<?php echo RESOURCE_SITE_URL; ?>/js/jquery.Jcrop/jquery.Jcrop.min.css" rel="stylesheet" type="text/css"
+      id="cssfile2"/>
+<script type="text/javascript">
+    $(function () {
+        //按钮先执行验证再提交表单
+        $("#submitBtn").click(function () {
+            if ($("#user_form").valid()) {
+                select_set();
+                $("#user_form").submit();
+            }
+        });
+        $('#user_form').validate({
+            errorPlacement: function (error, element) {
+                error.appendTo(element.parent().parent().prev().find('td:first'));
+            },
+            rules: {
+                co_type: {
+                    required: true,
+                },
+                co_name: {
+                    required: true,
+                },
+                bank_name: {
+                    required: true,
+                },
+                bank_username: {
+                    required: true,
+                },
+                bank_card_no: {
+                    required: true,
+                },
+            },
+            messages: {
+                co_type: {
+                    required: '必须选择公司类型',
+                },
+                co_name: {
+                    required: '公司名称不能为空',
+                },
+                bank_name: {
+                    required: '收款银行名称不能为空',
+                },
+                bank_username: {
+                    required: '开户人名称不能为空',
+                },
+                bank_card_no: {
+                    required: '收款卡号不能为空',
+                },
+            }
+        });
+        function select_set(){
+            let selectArr = select_nc.getValue();
+            let selectStr = ''
+            for (let i = 0; i < selectArr.length; i++) {
+                selectStr += selectArr[i].value+','
+            }
+            selectStr = selectStr.substr(0, selectStr.length-1)
+            $('input[name="cid"]').val(selectStr);
+        }
+
+        let select_nc
+        let url = '';
+        $('#co_type').on('change', function() {
+            console.log('querySelect', $(this).val());
+            $('#select_nc').children().remove();
+            const co_type = $(this).val();
+            _select(co_type)
+        })
+        function _select (co_type)
+        {
+            if(co_type === 'merchant') {
+                url = 'index.php?act=refill_order&op=merchant_data'
+            }else{
+                url = 'index.php?act=refill_order&op=provider_data'
+            }
+            $.get(url, function (data) {
+                data = JSON.parse(data)
+                select_nc = xmSelect.render({
+                    el: '#select_nc',
+                    size: 'mini',
+                    filterable: true,
+                    style: {
+                        minHeight: '27px',
+                        lineHeight: '27px',
+                        marginLeft: '4px',
+                        width: '250px'
+                    },
+                    language: 'zn',
+                    data: data
+                })
+            })
+        }
+    });
+</script>

+ 255 - 0
admin/templates/default/refill.company.edit.php

@@ -0,0 +1,255 @@
+<?php defined('InShopNC') or exit('Access Invalid!'); ?>
+<style>
+      .layui-form-select .layui-input {
+    padding: 13px 5px;
+}
+.layui-form-select dl {
+    top: 29px !important;
+}
+.layui-form-select {
+    width: 85%;
+}
+.layui-select-title {
+    width: 100%;
+}
+.page .fixed-bar .item-title h3 {
+    margin-top: 18px !important;
+    margin-bottom: 10px !important;
+    font-weight: 700 !important;
+}
+.tab-base li span {
+    font-size: 12px !important;
+}
+</style>
+<div class="page">
+    <div class="fixed-bar">
+        <div class="item-title">
+            <h3>公司信息管理</h3>
+            <ul class="tab-base">
+                <li><a href="index.php?act=refill_company&op=index"><span>公司信息管理</span></a></li>
+                <li><a href="JavaScript:void(0);" class="current"><span>编辑</span></a></li>
+                <li><a href="index.php?act=refill_company&op=remit_cfg"><span>打款配置</span></a></li>
+                <li><a href="index.php?act=refill_company&op=remit_record"><span>公司打款记录</span></a></li>
+            </ul>
+        </div>
+    </div>
+    <div class="fixed-empty"></div>
+    <form id="user_form" enctype="multipart/form-data" method="post"  class="layui-form">
+        <input type="hidden" name="form_submit" value="ok"/>
+        <input type="hidden" name="co_id" value="<?php echo $output['company_info']['co_id'];?>"/>
+        <input type="hidden" name="default_no_mch" value="<?php echo $output['cid']; ?>"/>
+        <input type="hidden" name="cid" value=""/>
+        <table class="table tb-type2">
+            <tbody>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="co_type">公司类型:</label></td>
+            </tr>
+            <tr class="">
+                <td class="">
+                    <label for="co_type"></label>
+                    <select name="co_type" id="co_type">
+                        <option value="">请选择...</option>
+                        <option value="<?php echo refill_companyModel::co_type_merchant;?>" <?php if($output['company_info']['co_type'] == refill_companyModel::co_type_merchant){ echo 'selected';}?>>机构</option>
+                        <option value="<?php echo refill_companyModel::co_type_provider;?>" <?php if($output['company_info']['co_type'] == refill_companyModel::co_type_provider){ echo 'selected';}?>>通道</option>
+                    </select>
+                </td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="co_type">通道(机构)选择:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td>
+                    <div id="select_nc"></div>
+                </td>
+                <td class="vatop tips"></td>
+            </tr>
+
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="co_name">公司名称:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" value="<?php echo $output['company_info']['co_name']; ?>" name="co_name" id="co_name" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="bank_name">开户银行名称:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" value="<?php echo $output['company_info']['bank_name']; ?>" name="bank_name" id="bank_name" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="bank_username">开户人名称:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" value="<?php echo $output['company_info']['bank_username']; ?>" name="bank_username" id="bank_username" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr>
+                <td colspan="2" class="required"><label class="validation" for="bank_card_no">银行卡号:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" value="<?php echo $output['company_info']['bank_card_no']; ?>" id="bank_card_no" name="bank_card_no" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+
+            <tr>
+                <td colspan="2" class="required"><label for="max_debt">最大欠款额度:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" id="max_debt" name="max_debt" value="<?php echo $output['company_info']['max_debt']; ?>" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr>
+                <td colspan="2" class="required"><label for="province">开户行省份:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" value="<?php echo $output['company_info']['province']; ?>" id="province" name="province" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr>
+                <td colspan="2" class="required"><label for="city">开户行城市:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" value="<?php echo $output['company_info']['city']; ?>" id="city" name="city" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr>
+                <td colspan="2" class="required"><label for="bank_code">第三方银行编码:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" value="<?php echo $output['company_info']['bank_code']; ?>" id="bank_code" name="bank_code" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            <tr>
+                <td colspan="2" class="required"><label>备注:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><textarea name="remark" rows="6" class="tarea"><?php echo $output['company_info']['remark']; ?></textarea></td>
+            </tr>
+            </tbody>
+            <tfoot>
+            <tr class="tfoot">
+                <td colspan="15"><a href="JavaScript:void(0);" class="btn" id="submitBtn"><span><?php echo $lang['nc_submit']; ?></span></a></td>
+            </tr>
+            </tfoot>
+        </table>
+    </form>
+</div>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/dialog/dialog.js" id="dialog_js"
+        charset="utf-8"></script>
+<script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL;?>/js/xm-select.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/jquery.ui.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/ajaxfileupload/ajaxfileupload.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery.Jcrop/jquery.Jcrop.js"></script>
+<script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL;?>/layui/layui.js"></script>
+<link rel="stylesheet" type="text/css" href="<?php echo ADMIN_TEMPLATES_URL; ?>/layui/css/layui.css"/>
+<link href="<?php echo RESOURCE_SITE_URL; ?>/js/jquery.Jcrop/jquery.Jcrop.min.css" rel="stylesheet" type="text/css"
+      id="cssfile2"/>
+<script type="text/javascript">
+    $(function () {
+        //按钮先执行验证再提交表单
+        $("#submitBtn").click(function () {
+            if ($("#user_form").valid()) {
+                select_set();
+                $("#user_form").submit();
+            }
+        });
+        $('#user_form').validate({
+            errorPlacement: function (error, element) {
+                error.appendTo(element.parent().parent().prev().find('td:first'));
+            },
+            rules: {
+                co_type: {
+                    required: true,
+                },
+                co_name: {
+                    required: true,
+                },
+                bank_name: {
+                    required: true,
+                },
+                bank_username: {
+                    required: true,
+                },
+                bank_card_no: {
+                    required: true,
+                },
+            },
+            messages: {
+                co_type: {
+                    required: '必须选择公司类型',
+                },
+                co_name: {
+                    required: '公司名称不能为空',
+                },
+                bank_name: {
+                    required: '收款银行名称不能为空',
+                },
+                bank_username: {
+                    required: '开户人名称不能为空',
+                },
+                bank_card_no: {
+                    required: '收款卡号不能为空',
+                },
+            }
+        });
+        function select_set(){
+            let selectArr = select_nc.getValue();
+            let selectStr = ''
+            for (let i = 0; i < selectArr.length; i++) {
+                selectStr += selectArr[i].value+','
+            }
+            selectStr = selectStr.substr(0, selectStr.length-1)
+            $('input[name="cid"]').val(selectStr);
+        }
+
+        let select_nc
+        let url = '';
+        let co_type = $('#co_type').val();
+        let default_no_mch = $('input[name="default_no_mch"]').val().split(',');
+        _select(co_type);
+
+        $('#co_type').on('change', function() {
+            console.log('querySelect', $(this).val());
+            $('#select_nc').children().remove();
+            const co_type = $(this).val();
+            _select(co_type)
+        })
+
+        function _select (co_type)
+        {
+            if(co_type === 'merchant') {
+                url = 'index.php?act=refill_order&op=merchant_data'
+            }else{
+                url = 'index.php?act=refill_order&op=provider_data'
+            }
+            $.get(url, function (data) {
+                data = JSON.parse(data)
+                if (default_no_mch) {
+                    for (let index = 0; index < default_no_mch.length; index++) {
+                        for (let j = 0; j < data.length; j++) {
+                            if (default_no_mch[index] === data[j].value) {
+                                data[j].selected = true
+                            }
+                        }
+                    }
+                }
+                select_nc = xmSelect.render({
+                    el: '#select_nc',
+                    size: 'mini',
+                    filterable: true,
+                    style: {
+                        minHeight: '27px',
+                        lineHeight: '27px',
+                        marginLeft: '4px',
+                        width: '250px'
+                    },
+                    language: 'zn',
+                    data: data
+                })
+            })
+        }
+    });
+</script>

+ 153 - 0
admin/templates/default/refill.company.php

@@ -0,0 +1,153 @@
+<?php defined('InShopNC') or exit('Access Invalid!'); ?>
+<style>
+    .page .fixed-bar .item-title h3 {
+        margin-top:18px !important;
+        margin-bottom:10px !important;
+        font-weight:700 !important;
+    }
+    .tab-base li span {
+        font-size:12px !important;
+    }
+    .layui-form-select .layui-input {
+        height:26px;
+    }
+    input::placeholder{ 
+        color:#333; 
+    }
+</style>
+<div class="page">
+    <div class="fixed-bar">
+        <div class="item-title">
+            <h3>公司信息管理</h3>
+            <ul class="tab-base">
+                <li><a href="JavaScript:void(0);" class="current"><span>公司信息管理</span></a></li>
+                <li><a href="index.php?act=refill_company&op=add"><span>新增</span></a></li>
+                <li><a href="index.php?act=refill_company&op=remit_cfg"><span>打款配置</span></a></li>
+                <li><a href="index.php?act=refill_company&op=remit_record"><span>公司打款记录</span></a></li>
+            </ul>
+        </div>
+    </div>
+    <div class="fixed-empty"></div>
+    <form method="get" name="formSearch" id="formSearch" class="layui-form">
+        <input type="hidden" value="refill_company" name="act">
+        <input type="hidden" value="index" name="op">
+        <table class="tb-type1 noborder search">
+            <tbody>
+            <tr>
+                <th><label>公司名称</label></th>
+                <td><input class="txt2" type="text" name="co_name" value="<?php echo $_GET['co_name']; ?>"/></td>
+
+                <th><label for="co_type">公司类型</label></th>
+                <td>
+                    <select name="co_type" id="co_type">
+                        <option value="">请选择...</option>
+                        <option value="<?php echo refill_companyModel::co_type_merchant;?>" <?php if($_GET['co_type'] == refill_companyModel::co_type_merchant){ echo 'selected';}?>>机构</option>
+                        <option value="<?php echo refill_companyModel::co_type_provider;?>" <?php if($_GET['co_type'] == refill_companyModel::co_type_provider){ echo 'selected';}?>>通道</option>
+                    </select>
+                </td>
+                <th><label for="opened">启用状态</label></th>
+                <td>
+                    <select name="opened" id="opened">
+                        <option value="">请选择...</option>
+                        <option value="<?php echo refill_companyModel::opened_start;?>" <?php if($_GET['opened'] == refill_companyModel::opened_start){ echo 'selected';}?>>启用</option>
+                        <option value="<?php echo refill_companyModel::opened_close;?>" <?php if($_GET['opened'] == refill_companyModel::opened_close){ echo 'selected';}?>>关闭</option>
+                    </select>
+                </td>
+                <td><a href="javascript:void(0);" id="ncsubmit" class="btn-search "
+                       title="<?php echo $lang['nc_query']; ?>">&nbsp;</a>
+            </tr>
+            </tbody>
+        </table>
+    </form>
+    <form method="post" id="refill_company">
+        <input type="hidden" name="form_submit" value="ok"/>
+        <table class="table tb-type2">
+            <thead>
+            <tr class="thead">
+                <th>记录ID</th>
+                <th>公司名称</th>
+                <th>公司类型</th>
+                <th>最大欠款额度</th>
+                <th class="align-left">收款银行名称</th>
+                <th class="align-left">开户人名称</th>
+                <th class="align-left">收款卡号</th>
+                <th class="align-left">开户行省份</th>
+                <th class="align-left">开户行城市</th>
+                <th class="align-left">银行编码</th>
+                <th class="align-left">备注</th>
+                <th class="align-left">启用状态</th>
+                <th class="align-left">更新日期</th>
+                <th class="align-center">操作</th>
+            </tr>
+            </thead>
+            <tbody>
+            <?php if (!empty($output['list']) && is_array($output['list'])) { ?>
+                <?php foreach ($output['list'] as $k => $v) { ?>
+                    <tr class="trFlex">
+                        <td><?php echo $v['co_id']; ?></td>
+                        <td><?php echo $v['co_name']; ?></td>
+                        <td><?php echo $v['co_type']; ?></td>
+                        <td><?php echo $v['max_debt'] ?? '0'; ?></td>
+                        <td class="align-left"><?php echo $v['bank_name']; ?></td>
+                        <td class="align-left"><?php echo $v['bank_username']; ?></td>
+                        <td class="align-left"><?php echo $v['bank_card_no']; ?></td>
+                        <td class="align-left"><?php echo $v['province']; ?></td>
+                        <td class="align-left"><?php echo $v['city']; ?></td>
+                        <td class="align-left"><?php echo $v['bank_code']; ?></td>
+                        <td class="align-left"><?php echo $v['remark']; ?></td>
+                        <td class="align-left">
+                            <?php if ($v['opened'] == refill_companyModel::opened_start) { ?>
+                                <span style="color: #48975A">启用</span>
+                            <?php } ?><?php if ($v['opened'] == refill_companyModel::opened_close) { ?>
+                                <span style="color: #E53737">禁用</span>
+                            <?php } ?>
+                        </td>
+                        <td class="align-left"><?php echo date("Y-m-d H:i:s", $v['oper_time']); ?></td>
+                        <td class="align-center w200">
+                            <a href="index.php?act=refill_company&op=edit&co_id=<?php echo $v['co_id'];?>">编辑</a>
+                            |
+                            <?php if ($v['opened'] == refill_companyModel::opened_start) { ?>
+                                <a href="index.php?act=refill_company&op=changeState&opened=<?php echo refill_companyModel::opened_close;?>&co_id=<?php echo $v['co_id'] ?>">禁用公司</a>
+                            <?php } ?>
+                            <?php if ($v['opened'] == refill_companyModel::opened_close) { ?>
+                                <a href="index.php?act=refill_company&op=changeState&opened=<?php echo refill_companyModel::opened_start;?>&co_id=<?php echo $v['co_id'] ?>">启用公司</a>
+                            <?php } ?>
+                        </td>
+                    </tr>
+                <?php } ?>
+            <?php } else { ?>
+                <tr class="no_data">
+                    <td colspan="13"><?php echo $lang['nc_no_record']; ?></td>
+                </tr>
+            <?php } ?>
+            </tbody>
+            <tfoot>
+            <tr class="tfoot">
+                <td></td>
+                <td colspan="13">
+                    <div class="pagination"><?php echo $output['page']; ?></div>
+                </td>
+            </tr>
+            </tfoot>
+        </table>
+    </form>
+</div>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery.edit.js" charset="utf-8"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/laydate/laydate.js"></script>
+<script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL;?>/layui/layui.js"></script>
+<link rel="stylesheet" type="text/css" href="<?php echo ADMIN_TEMPLATES_URL; ?>/layui/css/layui.css"/>
+<script>
+    $(function () {
+        $('#ncsubmit').click(function () {
+            $('#formSearch').submit();
+        });
+        // 表格hover时背景
+        $('.trFlex').each(function () {
+            $(this).hover(function () {
+                $(this)[0].style.backgroundColor = '#cbe9f3'
+            },function() {
+                $(this)[0].style.backgroundColor = '#fff'
+            })
+        })
+    });
+</script>

+ 173 - 0
admin/templates/default/refill.company.remit.php

@@ -0,0 +1,173 @@
+<?php defined('InShopNC') or exit('Access Invalid!'); ?>
+<style>
+    .page .fixed-bar .item-title h3 {
+        margin-top:18px !important;
+        margin-bottom:10px !important;
+        font-weight:700 !important;
+    }
+    .tab-base li span {
+        font-size:12px !important;
+    }
+    .layui-form-select .layui-input {
+        height:26px;
+    }
+    input::placeholder{ 
+        color:#333; 
+    }
+    .layui-input {
+        width: 160px!important;
+    }
+    .layui-edge {
+        right: 202px!important;
+    }
+    .layui-form-select dl {
+        left: 3px!important;
+        top: 26px!important;
+        min-width: 45%!important;
+    }
+</style>
+<div class="page">
+    <div class="fixed-bar">
+        <div class="item-title">
+            <h3>公司信息管理</h3>
+            <ul class="tab-base">
+                <li><a href="index.php?act=refill_company&op=index"><span>公司信息管理</span></a></li>
+                <li><a href="index.php?act=refill_company&op=add"><span>新增</span></a></li>
+                <li><a href="index.php?act=refill_company&op=remit_cfg"><span>打款配置</span></a></li>
+                <li><a href="JavaScript:void(0);" class="current"><span>公司打款记录</span></a></li>
+            </ul>
+        </div>
+    </div>
+    <div class="fixed-empty"></div>
+    <form method="get" name="formSearch" id="formSearch" class="layui-form">
+        <input type="hidden" value="refill_company" name="act">
+        <input type="hidden" value="remit_record" name="op">
+        <input type="hidden" name="export" value=""/>
+        <table class="tb-type1 noborder search">
+            <tbody>
+            <tr>
+                <th><label for="query_start_time">记录时间</label></th>
+                <td>
+                    <input class="txt date" type="text" value="<?php echo $_GET['query_start_time']; ?>"
+                           id="startTime" name="query_start_time" autocomplete="off" style="width:130px" />
+                    <label for="query_start_time">~</label>
+                    <input class="txt date" type="text" value="<?php echo $_GET['query_end_time']; ?>"
+                           id="endTime" name="query_end_time" autocomplete="off" style="width:130px" />
+                </td>
+                <td>
+                    <a href="javascript:void(0);" id="ncsubmit" class="btn-search"
+                       title="<?php echo $lang['nc_query']; ?>">&nbsp;</a>
+                </td>
+            </tr>
+            </tbody>
+        </table>
+    </form>
+    <table class="table tb-type2" id="prompt">
+        <tbody>
+        </tbody>
+    </table>
+    <form method="post" id="merchant_name_form">
+        <input type="hidden" name="form_submit" value="ok"/>
+        <table class="table tb-type2">
+            <thead>
+            <tr class="thead">
+                <th>序号</th>
+                <th>标题</th>
+                <th class="align-right">打款金额</th>
+                <th class="align-left">打款状态</th>
+                <th class="align-left">操作人</th>
+                <th class="align-left">生成日期</th>
+                <th class="align-left">更新日期</th>
+                <th class="align-center">操作</th>
+            </tr>
+            </thead>
+            <tbody>
+            <?php if (!empty($output['list']) && is_array($output['list'])) { ?>
+                <?php foreach ($output['list'] as $k => $v) { ?>
+                    <tr class="trFlex">
+                        <td><?php echo $k+1;?></td>
+                        <td><?php echo $v['title']; ?></td>
+                        <td class="align-right"><?php echo $v['amount']; ?></td>
+                        <td class="align-left">
+                            <?php if ($v['remit_state'] == refill_company_remitModel::remit_have) { ?>
+                                <span style="color: #48975A">已打款</span>
+                            <?php } ?><?php if ($v['remit_state'] == refill_company_remitModel::remit_init) { ?>
+                                <span style="color: #E53737">未打款</span>
+                            <?php } ?>
+                        </td>
+                        <td class="align-left"><?php echo $v['operation'];?></td>
+                        <td class="align-left"><?php echo $v['add_time'] ? date('Y-m-d H:i', $v['add_time']) : $lang['no_limit']; ?></td>
+                        <td class="align-left"><?php echo $v['oper_time'] ? date('Y-m-d H:i', $v['oper_time']) : $lang['no_limit']; ?></td>
+                        <td class="align-center">
+                            <?php if ($v['remit_state'] == refill_company_remitModel::remit_init) { ?>
+                                <a href="index.php?act=refill_company&op=remit_commit&remit_id=<?php echo $v['remit_id'] ?>">确认提交</a>
+                                |
+                                <a href="index.php?act=refill_company&op=remit_del&remit_id=<?php echo $v['remit_id'] ?>">删除</a>
+                                |
+                                <a href="index.php?act=refill_company&op=remit_edit&remit_id=<?php echo $v['remit_id'] ?>">编辑</a>
+                                |
+                            <?php }?>
+                            <a href="index.php?act=refill_company&op=remit_export&remit_id=<?php echo $v['remit_id'] ?>">下载表格</a>
+                        </td>
+                    </tr>
+                <?php } ?>
+            <?php } else { ?>
+                <tr class="no_data">
+                    <td colspan="8"><?php echo $lang['nc_no_record']; ?></td>
+                </tr>
+            <?php } ?>
+            </tbody>
+            <tfoot>
+            <tr class="tfoot">
+
+                <td></td>
+                <td colspan="8">
+                    <div class="pagination"><?php echo $output['show_page']; ?></div>
+                </td>
+            </tr>
+            </tfoot>
+        </table>
+    </form>
+</div>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery.edit.js" charset="utf-8"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/laydate/laydate.js"></script>
+<script type="text/javascript" src="<?php echo ADMIN_TEMPLATES_URL;?>/layui/layui.js"></script>
+<link rel="stylesheet" type="text/css" href="<?php echo ADMIN_TEMPLATES_URL; ?>/layui/css/layui.css"/>
+<script>
+    $(function () {
+        // 日期选择器
+        laydate.render({
+            elem: '#startTime',
+            type: 'datetime',
+            trigger: 'click'
+        });
+        laydate.render({
+            elem: '#endTime',
+            type: 'datetime',
+            trigger: 'click'
+        });
+        $('#ncsubmit').click(function () {
+            $('#formSearch').submit();
+        });
+        // 表格hover时背景
+        $('.trFlex').each(function () {
+            $(this).hover(function () {
+                $(this)[0].style.backgroundColor = '#cbe9f3'
+            },function() {
+                $(this)[0].style.backgroundColor = '#fff'
+            })
+        })
+
+        // 导出
+        $('#ncexport').click(function () {
+            $('input[name="export"]').val('1');
+            $('#formSearch').submit();
+            $('input[name="export"]').val('');
+            let ii = layer.load();
+            setTimeout(function(){
+                layer.close(ii);
+            }, 800);
+        })
+
+    });
+</script>

+ 58 - 0
admin/templates/default/remit.config.php

@@ -0,0 +1,58 @@
+<?php defined('InShopNC') or exit('Access Invalid!'); ?>
+
+<div class="page">
+    <div class="fixed-bar">
+        <div class="item-title">
+            <h3>公司信息管理</h3>
+            <ul class="tab-base">
+                <li><a href="index.php?act=refill_company&op=index"><span>公司信息管理</span></a></li>
+                <li><a href="index.php?act=refill_company&op=add"><span>新增</span></a></li>
+                <li><a href="JavaScript:void(0);" class="current"><span>打款配置</span></a></li>
+                <li><a href="index.php?act=refill_company&op=remit_record"><span>公司打款记录</span></a></li>
+            </ul>
+        </div>
+    </div>
+    <div class="fixed-empty"></div>
+    <form id="user_form" enctype="multipart/form-data" method="post">
+        <input type="hidden" name="form_submit" value="ok" />
+        <table class="table tb-type2">
+            <tbody>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="remit_money">回款金额限制:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform">小于<input type="text" value="<?php echo $output['config']['remit_money'] ?? 0;?>" name="remit_money" id="remit_money" class="txt">可回款</td>
+                <td class="vatop tips">(余额低于-5w打款,填写-50000)</td>
+            </tr>
+            <tr class="noborder">
+                <td colspan="2" class="required"><label class="validation" for="remit_max">单条记录最大金额:</label></td>
+            </tr>
+            <tr class="noborder">
+                <td class="vatop rowform"><input type="text" value="<?php echo $output['config']['remit_max'] ?? 0;?>" name="remit_max" class="txt"></td>
+                <td class="vatop tips"></td>
+            </tr>
+            </tbody>
+            <tfoot>
+            <tr class="tfoot">
+                <td colspan="15"><a href="JavaScript:void(0);" class="btn"
+                                    id="submitBtn"><span><?php echo $lang['nc_submit']; ?></span></a></td>
+            </tr>
+            </tfoot>
+        </table>
+    </form>
+</div>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/dialog/dialog.js" id="dialog_js"
+        charset="utf-8"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery-ui/jquery.ui.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/ajaxfileupload/ajaxfileupload.js"></script>
+<script type="text/javascript" src="<?php echo RESOURCE_SITE_URL; ?>/js/jquery.Jcrop/jquery.Jcrop.js"></script>
+<link href="<?php echo RESOURCE_SITE_URL; ?>/js/jquery.Jcrop/jquery.Jcrop.min.css" rel="stylesheet" type="text/css"
+      id="cssfile2"/>
+<script type="text/javascript">
+    $(function () {
+        //按钮先执行验证再提交表单
+        $("#submitBtn").click(function () {
+            $("#user_form").submit();
+        });
+    });
+</script>

+ 43 - 11
crontab/control/minutes.php

@@ -435,6 +435,37 @@ class minutesControl extends BaseCronControl
         }
     }
 
+    //更新统计业务数据
+    public function stat_utilOp()
+    {
+        Log::short_name('stat_util');
+
+        while (true)
+        {
+            try {
+                $this->stat_util();
+            } catch (Exception $ex) {
+                Log::record($ex->getMessage(), Log::ERR);
+            }
+            sleep(1);
+        }
+    }
+
+    private function stat_util()
+    {
+        $update_earlist_sendtime = function () {
+            $mod = Model('refill_detail');
+            $time = $mod->getLatestSendTime();
+            wcache('latest_sending', ['order_time' => $time], 'refill-stat-');
+
+            Log::record("latest_send_time={$time}",Log::DEBUG);
+        };
+
+
+        $update_earlist_sendtime();
+
+    }
+
     /**
      * 执行通用任务
      */
@@ -478,19 +509,18 @@ class minutesControl extends BaseCronControl
             $method = '_cron_'.$k;
             Log::record("crontab minutest:{$method}",Log::DEBUG);
 
-            $result = call_user_func_array([$this,'_cron_'.$k], [$v]);
-            if (is_array($result)){
-                $cronid = array_merge($cronid,$result);
-            }
-            else {
-                $method = '_cron_'.$k;
-                Log::record("crontab minutest err:{$method}",Log::ERR);
+            $result = call_user_func_array([$this, '_cron_' . $k], [$v]);
+            if (is_array($result)) {
+                $cronid = array_merge($cronid, $result);
+            } else {
+                $method = '_cron_' . $k;
+                Log::record("crontab minutest err:{$method}", Log::ERR);
             }
         }
 
         //删除执行完成的cron信息
-        if (!empty($cronid) && is_array($cronid)){
-            $model_cron->delCron(['id'=> ['in',$cronid]]);
+        if (!empty($cronid) && is_array($cronid)) {
+            $model_cron->delCron(['id' => ['in', $cronid]]);
         }
 
         return true;
@@ -503,13 +533,15 @@ class minutesControl extends BaseCronControl
     {
         $condition = ['goods_commonid' => ['in',array_keys($cron)]];
         $update = Model('goods')->editProducesOnline($condition);
-        if ($update){
+        if ($update)
+        {
             //返回执行成功的cronid
             $cronid = [];
             foreach ($cron as $v) {
                 $cronid[] = $v['id'];
             }
-        } else {
+        }
+        else {
             return false;
         }
         return $cronid;

+ 84 - 40
data/config/xyz/refill.ini.php

@@ -1649,24 +1649,24 @@ $yunchonggong_phone = ['name' => 'yunchonggong', 'store_id' => 87,'qualitys' =>
 //            ['goods_id' => 6798, 'price' => 18.94, 'quality' => 1, 'card_type' => 'chinaunicom,chinatelecom']
 //        ],
         30 => [
-            ['goods_id' => 6799, 'price' => 28.74, 'quality' => 1, 'card_type' => 'chinamobile'],
-            ['goods_id' => 6799, 'price' => 28.53, 'quality' => 1, 'card_type' => 'chinaunicom'],
-            ['goods_id' => 6799, 'price' => 28.35, 'quality' => 1, 'card_type' => 'chinatelecom']
+            ['goods_id' => 6799, 'price' => 28.8, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 6799, 'price' => 28.35, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 6799, 'price' => 28.5, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         50 => [
-            ['goods_id' => 6800, 'price' => 47.9, 'quality' => 1, 'card_type' => 'chinamobile'],
-            ['goods_id' => 6800, 'price' => 47.55, 'quality' => 1, 'card_type' => 'chinaunicom'],
-            ['goods_id' => 6800, 'price' => 47.25, 'quality' => 1, 'card_type' => 'chinatelecom']
+            ['goods_id' => 6800, 'price' => 48, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 6800, 'price' => 47.25, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 6800, 'price' => 47.5, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         100 => [
-            ['goods_id' => 6801, 'price' => 95.8, 'quality' => 1, 'card_type' => 'chinamobile'],
-            ['goods_id' => 6801, 'price' => 95.1, 'quality' => 1, 'card_type' => 'chinaunicom'],
-            ['goods_id' => 6801, 'price' => 94.5, 'quality' => 1, 'card_type' => 'chinatelecom']
+            ['goods_id' => 6801, 'price' => 96, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 6801, 'price' => 94.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 6801, 'price' => 95, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         200 => [
-            ['goods_id' => 6802, 'price' => 191.6, 'quality' => 1, 'card_type' => 'chinamobile'],
-            ['goods_id' => 6802, 'price' => 190.2, 'quality' => 1, 'card_type' => 'chinaunicom'],
-            ['goods_id' => 6802, 'price' => 189, 'quality' => 1, 'card_type' => 'chinatelecom']
+            ['goods_id' => 6802, 'price' => 192, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 6802, 'price' => 189, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 6802, 'price' => 190, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
 //        300 => [
 //            ['goods_id' => 6803, 'price' => 288, 'quality' => 1, 'card_type' => 'chinamobile'],
@@ -2892,22 +2892,22 @@ $chizeng_phone = ['name' => 'chizeng', 'store_id' => 133, 'qualitys' => '1',
 //            ['goods_id' => 7148, 'price' => 19, 'quality' => 1, 'card_type' => 'chinatelecom']
 //        ],
         30 => [
-            ['goods_id' => 7149, 'price' => 28.8, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7149, 'price' => 28.8, 'quality' => 1, 'card_type' => 'chinamobile'],
             ['goods_id' => 7149, 'price' => 28.8, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7149, 'price' => 28.8, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         50 => [
-            ['goods_id' => 7150, 'price' => 48, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7150, 'price' => 48.25, 'quality' => 1, 'card_type' => 'chinamobile'],
             ['goods_id' => 7150, 'price' => 48, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7150, 'price' => 48, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         100 => [
-            ['goods_id' => 7151, 'price' => 96, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7151, 'price' => 96.5, 'quality' => 1, 'card_type' => 'chinamobile'],
             ['goods_id' => 7151, 'price' => 96, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7151, 'price' => 96, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         200 => [
-            ['goods_id' => 7152, 'price' => 192, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7152, 'price' => 193, 'quality' => 1, 'card_type' => 'chinamobile'],
             ['goods_id' => 7152, 'price' => 192, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7152, 'price' => 192, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
@@ -3265,14 +3265,14 @@ $dashang_normal_phone = ['name' => 'dashang_normal', 'store_id' => 148, 'quality
 
 $yunchonggongfs_phone = ['name' => 'yunchonggongfs', 'store_id' => 149,'qualitys' => '1',
     'amount' => [
-        10 => [['goods_id' => 7275, 'price' => 9.41, 'quality' => 1, 'card_type' => 'chinamobile']],
-        20 => [['goods_id' => 7276, 'price' => 18.82, 'quality' => 1, 'card_type' => 'chinamobile']],
+//        10 => [['goods_id' => 7275, 'price' => 9.41, 'quality' => 1, 'card_type' => 'chinamobile']],
+//        20 => [['goods_id' => 7276, 'price' => 18.82, 'quality' => 1, 'card_type' => 'chinamobile']],
         30 => [['goods_id' => 7277, 'price' => 28.23, 'quality' => 1, 'card_type' => 'chinamobile']],
         50 => [['goods_id' => 7278, 'price' => 47.05, 'quality' => 1, 'card_type' => 'chinamobile']],
         100 => [['goods_id' => 7279, 'price' => 94.1, 'quality' => 1, 'card_type' => 'chinamobile']],
         200 => [['goods_id' => 7280, 'price' => 188.2, 'quality' => 1, 'card_type' => 'chinamobile']],
-        300 => [['goods_id' => 7281, 'price' => 282.3, 'quality' => 1, 'card_type' => 'chinamobile']],
-        500 => [['goods_id' => 7282, 'price' => 470.5, 'quality' => 1, 'card_type' => 'chinamobile']]
+//        300 => [['goods_id' => 7281, 'price' => 282.3, 'quality' => 1, 'card_type' => 'chinamobile']],
+//        500 => [['goods_id' => 7282, 'price' => 470.5, 'quality' => 1, 'card_type' => 'chinamobile']]
     ],
     'official_sn' => true, 'refill_type' => 'api'];
 
@@ -3403,13 +3403,13 @@ $guantu_phone = ['name' => 'guantu', 'store_id' => 157, 'qualitys' => '1',
 $yiqian_phone = ['name' => 'yiqian', 'store_id' => 158,'qualitys' => '2',
     'amount' => [
         10 => [
-//            ['goods_id' => 7333, 'price' => 10.38, 'quality' => 2, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7333, 'price' => 10.335, 'quality' => 2, 'card_type' => 'chinamobile'],
             ['goods_id' => 7333, 'price' => 10.07, 'quality' => 2, 'card_type' => 'chinaunicom'],
 //            ['goods_id' => 7333, 'price' => 9.985, 'quality' => 2, 'card_type' => 'chinatelecom']
         ],
 
         20 => [
-//            ['goods_id' => 7334, 'price' => 20.76, 'quality' => 2, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7334, 'price' => 20.67, 'quality' => 2, 'card_type' => 'chinamobile'],
             ['goods_id' => 7334, 'price' => 20.1, 'quality' => 2, 'card_type' => 'chinaunicom'],
 //            ['goods_id' => 7334, 'price' => 19.97, 'quality' => 2, 'card_type' => 'chinatelecom']
         ],
@@ -3999,8 +3999,8 @@ $yamiao_high_phone = ['name' => 'yamiao_high', 'store_id' => 171, 'qualitys' =>
             ['goods_id' => 7460, 'price' => 193, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7460, 'price' => 193, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
-        300 => [['goods_id' => 7461, 'price' => 289.5, 'quality' => 1, 'card_type' => 'chinamobile,chinaunicom,chinatelecom']],
-        500 => [['goods_id' => 7462, 'price' => 482.5, 'quality' => 1, 'card_type' => 'chinamobile,chinaunicom,chinatelecom']]
+//        300 => [['goods_id' => 7461, 'price' => 289.5, 'quality' => 1, 'card_type' => 'chinamobile,chinaunicom,chinatelecom']],
+//        500 => [['goods_id' => 7462, 'price' => 482.5, 'quality' => 1, 'card_type' => 'chinamobile,chinaunicom,chinatelecom']]
     ],
     'official_sn' => true, 'refill_type' => 'api'];
 
@@ -4009,37 +4009,35 @@ $yamiao_normal_phone = ['name' => 'yamiao_normal', 'store_id' => 172, 'qualitys'
 //        10 => [['goods_id' => 7463, 'price' => 9.55, 'quality' => 1, 'card_type' => 'chinamobile,chinaunicom,chinatelecom']],
 //        20 => [['goods_id' => 7464, 'price' => 19.1, 'quality' => 1, 'card_type' => 'chinamobile,chinaunicom,chinatelecom']],
         30 => [
-            ['goods_id' => 7465, 'price' => 28.71, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7465, 'price' => 28.8, 'quality' => 1, 'card_type' => 'chinamobile'],
             ['goods_id' => 7465, 'price' => 28.65, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7465, 'price' => 28.38, 'quality' => 1, 'card_type' => 'chinatelecom'],
         ],
         50 => [
-            ['goods_id' => 7466, 'price' => 47.85, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7466, 'price' => 48, 'quality' => 1, 'card_type' => 'chinamobile'],
             ['goods_id' => 7466, 'price' => 47.75, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7466, 'price' => 47.3, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         100 => [
-            ['goods_id' => 7467, 'price' => 95.7, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7467, 'price' => 96, 'quality' => 1, 'card_type' => 'chinamobile'],
             ['goods_id' => 7467, 'price' => 95.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7467, 'price' => 94.6, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         200 => [
-            ['goods_id' => 7468, 'price' => 191.4, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7468, 'price' => 192, 'quality' => 1, 'card_type' => 'chinamobile'],
             ['goods_id' => 7468, 'price' => 191, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7468, 'price' => 189.2, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
-        300 => [
-            ['goods_id' => 7469, 'price' => 287.7, 'quality' => 1, 'card_type' => 'chinamobile'],
-            ['goods_id' => 7469, 'price' => 286.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
-            ['goods_id' => 7469, 'price' => 285, 'quality' => 1, 'card_type' => 'chinatelecom']
-
-        ],
-        500 => [
-            ['goods_id' => 7470, 'price' => 479.5, 'quality' => 1, 'card_type' => 'chinamobile'],
-            ['goods_id' => 7470, 'price' => 477.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
-            ['goods_id' => 7470, 'price' => 475, 'quality' => 1, 'card_type' => 'chinatelecom']
-
-        ]
+//        300 => [
+//            ['goods_id' => 7469, 'price' => 287.7, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7469, 'price' => 286.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
+//            ['goods_id' => 7469, 'price' => 285, 'quality' => 1, 'card_type' => 'chinatelecom']
+//        ],
+//        500 => [
+//            ['goods_id' => 7470, 'price' => 479.5, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7470, 'price' => 477.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
+//            ['goods_id' => 7470, 'price' => 475, 'quality' => 1, 'card_type' => 'chinatelecom']
+//        ]
     ],
     'official_sn' => true, 'refill_type' => 'api'];
 
@@ -6274,6 +6272,51 @@ $dezhi_phone = ['name' => 'dezhi', 'store_id' => 236, 'qualitys' => '1',
     ],
     'official_sn' => true, 'refill_type' => 'api'];
 
+$huoshenguo_fs_phone = ['name' => 'huoshenguo_fs', 'store_id' => 237, 'qualitys' => '1',
+    'amount' => [
+//        10 => [
+//            ['goods_id' => 7959, 'price' => 9.67, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7959, 'price' => 9.53, 'quality' => 1, 'card_type' => 'chinaunicom'],
+//            ['goods_id' => 7959, 'price' => 9.55, 'quality' => 1, 'card_type' => 'chinatelecom']
+//        ],
+//        20 => [
+//            ['goods_id' => 7960, 'price' => 19.34, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7960, 'price' => 19.06, 'quality' => 1, 'card_type' => 'chinaunicom'],
+//            ['goods_id' => 7960, 'price' => 19.1, 'quality' => 1, 'card_type' => 'chinatelecom']
+//        ],
+        30 => [
+            ['goods_id' => 7961, 'price' => 28.2, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7961, 'price' => 28.59, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 7961, 'price' => 28.05, 'quality' => 1, 'card_type' => 'chinatelecom']
+        ],
+        50 => [
+            ['goods_id' => 7962, 'price' => 47, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7962, 'price' => 47.65, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 7962, 'price' => 46.75, 'quality' => 1, 'card_type' => 'chinatelecom']
+        ],
+        100 => [
+            ['goods_id' => 7963, 'price' => 94, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7963, 'price' => 95.3, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 7963, 'price' => 93.5, 'quality' => 1, 'card_type' => 'chinatelecom']
+        ],
+        200 => [
+            ['goods_id' => 7964, 'price' => 188, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7964, 'price' => 190.6, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 7964, 'price' => 187, 'quality' => 1, 'card_type' => 'chinatelecom']
+        ],
+//        300 => [
+//            ['goods_id' => 7965, 'price' => 290.1, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7965, 'price' => 285.9, 'quality' => 1, 'card_type' => 'chinaunicom'],
+//            ['goods_id' => 7965, 'price' => 286.5, 'quality' => 1, 'card_type' => 'chinatelecom']
+//        ],
+//        500 => [
+//            ['goods_id' => 7966, 'price' => 483.5, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7966, 'price' => 476.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
+//            ['goods_id' => 7966, 'price' => 477.5, 'quality' => 1, 'card_type' => 'chinatelecom']
+//        ]
+    ],
+    'official_sn' => true, 'refill_type' => 'api'];
+
 $phone_providers = [
 //    ['name' => 'beixt', 'cfg' => $beixt_phone],
 //    ['name' => 'bxtwt', 'cfg' => $bxtwt_phone],
@@ -6467,6 +6510,7 @@ $phone_providers = [
     ['name' => 'huoshenguo_yd', 'cfg' => $huoshenguo_yd_phone],
     ['name' => 'xinruiheng', 'cfg' => $xinruiheng_phone],
     ['name' => 'dezhi', 'cfg' => $dezhi_phone],
+    ['name' => 'huoshenguo_fs', 'cfg' => $huoshenguo_fs_phone],
 
 ];
 $config['phone_providers'] = $phone_providers;

+ 76 - 32
data/config/yl/refill.ini.php

@@ -1657,23 +1657,23 @@ $yunchonggong_phone = ['name' => 'yunchonggong', 'store_id' => 87,'qualitys' =>
 //            ['goods_id' => 6798, 'price' => 18.94, 'quality' => 1, 'card_type' => 'chinaunicom,chinatelecom']
 //        ],
         30 => [
-            ['goods_id' => 6799, 'price' => 28.74, 'quality' => 1, 'card_type' => 'chinamobile'],
-            ['goods_id' => 6799, 'price' => 28.53, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 6799, 'price' => 28.8, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 6799, 'price' => 28.35, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 6799, 'price' => 28.5, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         50 => [
-            ['goods_id' => 6800, 'price' => 47.9, 'quality' => 1, 'card_type' => 'chinamobile'],
-            ['goods_id' => 6800, 'price' => 47.55, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 6800, 'price' => 48, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 6800, 'price' => 47.25, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 6800, 'price' => 47.5, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         100 => [
-            ['goods_id' => 6801, 'price' => 95.8, 'quality' => 1, 'card_type' => 'chinamobile'],
-            ['goods_id' => 6801, 'price' => 95.1, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 6801, 'price' => 96, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 6801, 'price' => 94.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 6801, 'price' => 95, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         200 => [
-            ['goods_id' => 6802, 'price' => 191.6, 'quality' => 1, 'card_type' => 'chinamobile'],
-            ['goods_id' => 6802, 'price' => 190.2, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 6802, 'price' => 192, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 6802, 'price' => 189, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 6802, 'price' => 190, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
 //        300 => [
@@ -2900,22 +2900,22 @@ $chizeng_phone = ['name' => 'chizeng', 'store_id' => 133, 'qualitys' => '1',
 //            ['goods_id' => 7148, 'price' => 19, 'quality' => 1, 'card_type' => 'chinatelecom']
 //        ],
         30 => [
-            ['goods_id' => 7149, 'price' => 28.8, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7149, 'price' => 28.8, 'quality' => 1, 'card_type' => 'chinamobile'],
             ['goods_id' => 7149, 'price' => 28.8, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7149, 'price' => 28.8, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         50 => [
-            ['goods_id' => 7150, 'price' => 48, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7150, 'price' => 48.25, 'quality' => 1, 'card_type' => 'chinamobile'],
             ['goods_id' => 7150, 'price' => 48, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7150, 'price' => 48, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         100 => [
-            ['goods_id' => 7151, 'price' => 96, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7151, 'price' => 96.5, 'quality' => 1, 'card_type' => 'chinamobile'],
             ['goods_id' => 7151, 'price' => 96, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7151, 'price' => 96, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
         200 => [
-            ['goods_id' => 7152, 'price' => 192, 'quality' => 1, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7152, 'price' => 193, 'quality' => 1, 'card_type' => 'chinamobile'],
             ['goods_id' => 7152, 'price' => 192, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7152, 'price' => 192, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
@@ -3275,14 +3275,14 @@ $dashang_normal_phone = ['name' => 'dashang_normal', 'store_id' => 148, 'quality
 
 $yunchonggongfs_phone = ['name' => 'yunchonggongfs', 'store_id' => 149,'qualitys' => '1',
     'amount' => [
-        10 => [['goods_id' => 7275, 'price' => 9.41, 'quality' => 1, 'card_type' => 'chinamobile']],
-        20 => [['goods_id' => 7276, 'price' => 18.82, 'quality' => 1, 'card_type' => 'chinamobile']],
+//        10 => [['goods_id' => 7275, 'price' => 9.41, 'quality' => 1, 'card_type' => 'chinamobile']],
+//        20 => [['goods_id' => 7276, 'price' => 18.82, 'quality' => 1, 'card_type' => 'chinamobile']],
         30 => [['goods_id' => 7277, 'price' => 28.23, 'quality' => 1, 'card_type' => 'chinamobile']],
         50 => [['goods_id' => 7278, 'price' => 47.05, 'quality' => 1, 'card_type' => 'chinamobile']],
         100 => [['goods_id' => 7279, 'price' => 94.1, 'quality' => 1, 'card_type' => 'chinamobile']],
         200 => [['goods_id' => 7280, 'price' => 188.2, 'quality' => 1, 'card_type' => 'chinamobile']],
-        300 => [['goods_id' => 7281, 'price' => 282.3, 'quality' => 1, 'card_type' => 'chinamobile']],
-        500 => [['goods_id' => 7282, 'price' => 470.5, 'quality' => 1, 'card_type' => 'chinamobile']]
+//        300 => [['goods_id' => 7281, 'price' => 282.3, 'quality' => 1, 'card_type' => 'chinamobile']],
+//        500 => [['goods_id' => 7282, 'price' => 470.5, 'quality' => 1, 'card_type' => 'chinamobile']]
     ],
     'official_sn' => true, 'refill_type' => 'api'];
 
@@ -3413,13 +3413,13 @@ $guantu_phone = ['name' => 'guantu', 'store_id' => 157, 'qualitys' => '1',
 $yiqian_phone = ['name' => 'yiqian', 'store_id' => 158,'qualitys' => '2',
     'amount' => [
         10 => [
-//            ['goods_id' => 7333, 'price' => 10.38, 'quality' => 2, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7333, 'price' => 10.335, 'quality' => 2, 'card_type' => 'chinamobile'],
             ['goods_id' => 7333, 'price' => 10.07, 'quality' => 2, 'card_type' => 'chinaunicom'],
 //            ['goods_id' => 7333, 'price' => 9.985, 'quality' => 2, 'card_type' => 'chinatelecom']
         ],
 
         20 => [
-//            ['goods_id' => 7334, 'price' => 20.76, 'quality' => 2, 'card_type' => 'chinamobile'],
+            ['goods_id' => 7334, 'price' => 20.67, 'quality' => 2, 'card_type' => 'chinamobile'],
             ['goods_id' => 7334, 'price' => 20.1, 'quality' => 2, 'card_type' => 'chinaunicom'],
 //            ['goods_id' => 7334, 'price' => 19.97, 'quality' => 2, 'card_type' => 'chinatelecom']
         ],
@@ -4009,8 +4009,8 @@ $yamiao_high_phone = ['name' => 'yamiao_high', 'store_id' => 171, 'qualitys' =>
             ['goods_id' => 7460, 'price' => 193, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7460, 'price' => 193, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
-        300 => [['goods_id' => 7461, 'price' => 289.5, 'quality' => 1, 'card_type' => 'chinamobile,chinaunicom,chinatelecom']],
-        500 => [['goods_id' => 7462, 'price' => 482.5, 'quality' => 1, 'card_type' => 'chinamobile,chinaunicom,chinatelecom']]
+//        300 => [['goods_id' => 7461, 'price' => 289.5, 'quality' => 1, 'card_type' => 'chinamobile,chinaunicom,chinatelecom']],
+//        500 => [['goods_id' => 7462, 'price' => 482.5, 'quality' => 1, 'card_type' => 'chinamobile,chinaunicom,chinatelecom']]
     ],
     'official_sn' => true, 'refill_type' => 'api'];
 
@@ -4038,18 +4038,16 @@ $yamiao_normal_phone = ['name' => 'yamiao_normal', 'store_id' => 172, 'qualitys'
             ['goods_id' => 7468, 'price' => 191, 'quality' => 1, 'card_type' => 'chinaunicom'],
             ['goods_id' => 7468, 'price' => 189.2, 'quality' => 1, 'card_type' => 'chinatelecom']
         ],
-        300 => [
-            ['goods_id' => 7469, 'price' => 287.7, 'quality' => 1, 'card_type' => 'chinamobile'],
-            ['goods_id' => 7469, 'price' => 286.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
-            ['goods_id' => 7469, 'price' => 285, 'quality' => 1, 'card_type' => 'chinatelecom']
-
-        ],
-        500 => [
-            ['goods_id' => 7470, 'price' => 479.5, 'quality' => 1, 'card_type' => 'chinamobile'],
-            ['goods_id' => 7470, 'price' => 477.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
-            ['goods_id' => 7470, 'price' => 475, 'quality' => 1, 'card_type' => 'chinatelecom']
-
-        ]
+//        300 => [
+//            ['goods_id' => 7469, 'price' => 287.7, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7469, 'price' => 286.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
+//            ['goods_id' => 7469, 'price' => 285, 'quality' => 1, 'card_type' => 'chinatelecom']
+//        ],
+//        500 => [
+//            ['goods_id' => 7470, 'price' => 479.5, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7470, 'price' => 477.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
+//            ['goods_id' => 7470, 'price' => 475, 'quality' => 1, 'card_type' => 'chinatelecom']
+//        ]
     ],
     'official_sn' => true, 'refill_type' => 'api'];
 
@@ -6105,6 +6103,51 @@ $dezhi_phone = ['name' => 'dezhi', 'store_id' => 227, 'qualitys' => '1',
     ],
     'official_sn' => true, 'refill_type' => 'api'];
 
+$huoshenguo_fs_phone = ['name' => 'huoshenguo_fs', 'store_id' => 229, 'qualitys' => '1',
+    'amount' => [
+//        10 => [
+//            ['goods_id' => 7915, 'price' => 9.67, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7915, 'price' => 9.53, 'quality' => 1, 'card_type' => 'chinaunicom'],
+//            ['goods_id' => 7915, 'price' => 9.55, 'quality' => 1, 'card_type' => 'chinatelecom']
+//        ],
+//        20 => [
+//            ['goods_id' => 7916, 'price' => 19.34, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7916, 'price' => 19.06, 'quality' => 1, 'card_type' => 'chinaunicom'],
+//            ['goods_id' => 7916, 'price' => 19.1, 'quality' => 1, 'card_type' => 'chinatelecom']
+//        ],
+        30 => [
+            ['goods_id' => 7917, 'price' => 28.2, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7917, 'price' => 28.59, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 7917, 'price' => 28.05, 'quality' => 1, 'card_type' => 'chinatelecom']
+        ],
+        50 => [
+            ['goods_id' => 7918, 'price' => 47, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7918, 'price' => 47.65, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 7918, 'price' => 46.75, 'quality' => 1, 'card_type' => 'chinatelecom']
+        ],
+        100 => [
+            ['goods_id' => 7919, 'price' => 94, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7919, 'price' => 95.3, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 7919, 'price' => 93.5, 'quality' => 1, 'card_type' => 'chinatelecom']
+        ],
+        200 => [
+            ['goods_id' => 7920, 'price' => 188, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7920, 'price' => 190.6, 'quality' => 1, 'card_type' => 'chinaunicom'],
+            ['goods_id' => 7920, 'price' => 187, 'quality' => 1, 'card_type' => 'chinatelecom']
+        ],
+//        300 => [
+//            ['goods_id' => 7921, 'price' => 290.1, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7921, 'price' => 285.9, 'quality' => 1, 'card_type' => 'chinaunicom'],
+//            ['goods_id' => 7921, 'price' => 286.5, 'quality' => 1, 'card_type' => 'chinatelecom']
+//        ],
+//        500 => [
+//            ['goods_id' => 7922, 'price' => 483.5, 'quality' => 1, 'card_type' => 'chinamobile'],
+//            ['goods_id' => 7922, 'price' => 476.5, 'quality' => 1, 'card_type' => 'chinaunicom'],
+//            ['goods_id' => 7922, 'price' => 477.5, 'quality' => 1, 'card_type' => 'chinatelecom']
+//        ]
+    ],
+    'official_sn' => true, 'refill_type' => 'api'];
+
 $phone_providers = [
 //    ['name' => 'beixt', 'cfg' => $beixt_phone],
 //    ['name' => 'bxtwt', 'cfg' => $bxtwt_phone],
@@ -6294,6 +6337,7 @@ $phone_providers = [
     ['name' => 'huoshenguo_yd', 'cfg' => $huoshenguo_yd_phone],
     ['name' => 'xinruiheng', 'cfg' => $xinruiheng_phone],
     ['name' => 'dezhi', 'cfg' => $dezhi_phone],
+    ['name' => 'huoshenguo_fs', 'cfg' => $huoshenguo_fs_phone],
 
 ];
 $config['phone_providers'] = $phone_providers;

+ 41 - 0
data/model/refill_company.model.php

@@ -0,0 +1,41 @@
+<?php
+
+defined('InShopNC') or exit('Access Invalid!');
+
+class refill_companyModel extends Model
+{
+    const co_type_merchant = 'merchant';
+    const co_type_provider = 'provider';
+
+    const opened_start = 1;
+    const opened_close = 2;
+
+    public function __construct()
+    {
+        parent::__construct('refill_company');
+    }
+
+    public function getCompanyList($condition, $pagesize = '',$total = 0, $field = '*', $order = 'co_id asc', $limit = '', $master = false)
+    {
+        $list = $this->field($field)->where($condition)->page($pagesize,$total)->order($order)->limit($limit)->master($master)->select();
+        if (empty($list)) return [];
+        return $list;
+    }
+
+    public function addCompany($insert)
+    {
+        return $this->insert($insert);
+    }
+
+    public function getCompanyInfo($condition = [], $fields = '*', $master = false,$lock=false)
+    {
+        $info = $this->field($fields)->where($condition)->master($master)->lock($lock)->find();
+        if (empty($info)) return [];
+        return $info;
+    }
+
+    public function editCompany($update,$condition)
+    {
+        return $this->where($condition)->update($update);
+    }
+}

+ 41 - 0
data/model/refill_company_remit.model.php

@@ -0,0 +1,41 @@
+<?php
+
+defined('InShopNC') or exit('Access Invalid!');
+
+class refill_company_remitModel extends Model
+{
+    const remit_init = 0;
+    const remit_have = 1;
+
+    public function __construct()
+    {
+        parent::__construct('refill_company_remit');
+    }
+
+    public function getRemitList($condition, $pagesize = '',$total = 0, $field = '*', $order = 'add_time desc', $limit = '', $master = false)
+    {
+        $list = $this->field($field)->where($condition)->page($pagesize,$total)->order($order)->limit($limit)->master($master)->select();
+        if (empty($list)) return [];
+        return $list;
+    }
+
+    public function addRemit($insert)
+    {
+        return $this->insert($insert);
+    }
+
+    public function getRemit($remit_id)
+    {
+        return $this->where(['remit_id' => $remit_id])->find();
+    }
+
+    public function editRemit($update,$condition)
+    {
+        return $this->where($condition)->update($update);
+    }
+
+    public function DelRemit($remit_id)
+    {
+        return $this->where(['remit_id' => $remit_id])->delete();
+    }
+}

+ 10 - 0
data/model/refill_detail.model.php

@@ -20,4 +20,14 @@ class refill_detailModel extends Model
     {
         return $this->where($condition)->find();
     }
+
+    public function getLatestSendTime()
+    {
+        $item = $this->field('min(order_time) as send_time')->where(['order_state' => ORDER_STATE_SEND])->find();
+        if(empty($item)) {
+            return time() - 86400;
+        } else {
+            return intval($item['send_time']);
+        }
+    }
 }

+ 1 - 1
docker/compose/homecuda/cli/docker-compose.yml

@@ -40,7 +40,7 @@ services:
     command: ['vender-init']
 
   pythoncli:
-    image: pycpu:3.7.10
+    image: pyhdf:3.7.10
     ports:
       - 5000:5000
     volumes:

+ 5 - 1
docker/compose/homecuda/statsec/docker-compose.yml

@@ -11,4 +11,8 @@ services:
       - /mnt/stdata:/var/www/html/data/stdata
     container_name: "panda-qreader"
 #    command: [ 'mpiexec', '-n','4','python','qreader.py','-h', '192.168.3.104', '-p', '6379' ]
-    command: [ 'python','qreader.py','-h', '192.168.3.104', '-p', '6379' ]
+    command: [ 'python','qreader.py','-h', '192.168.3.104', '-p', '6379' ]
+    deploy:
+      resources:
+        limits:
+          cpus: '8'

+ 5 - 1
docker/compose/homecuda/storage/docker-compose.yml

@@ -10,4 +10,8 @@ services:
       - ../conf/redis/6379.conf:/etc/redis/redis.conf
       - /mnt/redisdata:/data
     container_name: "panda-redis"
-    command: [redis-server,"/etc/redis/redis.conf"]
+    command: [redis-server,"/etc/redis/redis.conf"]
+    deploy:
+      resources:
+        limits:
+          cpus: '8'

+ 13 - 0
docker/compose/workcuda/sdatacalc/docker-compose.yml

@@ -0,0 +1,13 @@
+version: "3.7"
+
+services:
+  mamount:
+    image: pycpu:3.7.10
+    volumes:
+      - ../../../../:/var/www/html
+      - ../conf/etc/localtime:/etc/localtime:ro
+      - /mnt/upload:/var/www/html/data/upload
+      - /mnt/shoplog:/var/www/html/data/log
+      - /mnt/stdata:/var/www/html/data/stdata
+    container_name: "panda-mamount"
+    command: ['python','mamount.py']

+ 0 - 12
docker/compose/workcuda/statsec/docker-compose.yml

@@ -1,18 +1,6 @@
 version: "3.7"
 
 services:
-  flasksrv:
-    image: pycpu:3.7.10
-    volumes:
-      - ../../../../:/var/www/html
-      - ../conf/etc/localtime:/etc/localtime:ro
-      - /mnt/shoplog:/var/www/html/data/log
-      - /mnt/stdata:/var/www/html/data/stdata
-    ports:
-      - 5000:5000
-    container_name: "panda-flask"
-    command: ['python','plot_control.py']
-
   qreader:
     image: pycpu:3.7.10
     volumes:

+ 12 - 1
docker/compose/workcuda/slave-crond/docker-compose.yml

@@ -47,4 +47,15 @@ services:
     deploy:
       resources:
         limits:
-          cpus: '8'
+          cpus: '8'
+
+  statutil:
+    image: php-zts-debug:7.3.18
+    volumes:
+      - ../../../../:/var/www/html
+      - ../conf/etc/localtime:/etc/localtime:ro
+      - ../conf/php/php.ini:/usr/local/etc/php/php.ini
+      - /mnt/upload:/var/www/html/data/upload
+      - /mnt/shoplog:/var/www/html/data/log
+    container_name: "panda-statutil"
+    command: [php,"/var/www/html/crontab/index.php",'minutes','stat_util']

+ 6 - 2
docker/compose/xyz/statsec/docker-compose.yml

@@ -8,6 +8,10 @@ services:
       - ../conf/etc/localtime:/etc/localtime:ro
       - /mnt/upload:/var/www/html/data/upload
       - /mnt/shoplog:/var/www/html/data/log
-      - /mnt/stdatasec:/var/www/html/data/stdata
+      - /mnt/stdata:/var/www/html/data/stdata
     container_name: "panda-qreader"
-    command: ['python','qreader.py','-h', '172.26.105.125', '-p', '6379']
+    command: ['python','qreader.py','-h', '172.26.105.125', '-p', '6379']
+    deploy:
+      resources:
+        limits:
+          cpus: "4.0"

+ 16 - 0
docker/compose/yl/ylslave-crond/docker-compose.yml

@@ -47,4 +47,20 @@ services:
     deploy:
       resources:
         limits:
+          cpus: '8'
+
+  taskc:
+    image: php-zts-debug:7.3.18
+    volumes:
+      - ../../../../:/var/www/html
+      - ../conf/etc/localtime:/etc/localtime:ro
+      - ../conf/php/php.ini:/usr/local/etc/php/php.ini
+      - ../conf/crontab/slave_root:/var/spool/cron/crontabs/root
+      - /nfs/ylupload:/var/www/html/data/upload
+      - /mnt/yllog:/var/www/html/data/log
+    container_name: "yl-taskc"
+    command: [php,"/var/www/html/crontab/index.php",'minutes','task']
+    deploy:
+      resources:
+        limits:
           cpus: '8'

+ 1 - 1
docker/compose/yl/ylstatsec/docker-compose.yml

@@ -14,4 +14,4 @@ services:
     deploy:
       resources:
         limits:
-          cpus: '8'
+          cpus: "4.0"

+ 10 - 8
helper/refill/RefillBase.php

@@ -163,6 +163,7 @@ class RefillBase
             $spec = intval($refill_info['refill_amount']);
             $mchid = intval($refill_info['mchid']);
             $mch_order = $refill_info['mch_order'];
+            $order_time = intval($refill_info['order_time']);
 
             if($success && $this->risksn_check($refill_info)) {
                 $tran->commit();
@@ -173,9 +174,9 @@ class RefillBase
                 QueueClient::async_push("OnRiskSN", $params, 1);
                 return false;
             }
-
-            $period = time() - intval($refill_info['commit_time']);
-            util::monitor_notify($chname,$spec,$card_type,$refill_info['channel_amount'],$period,$success);
+            $commit_time = intval($refill_info['commit_time']);
+            $period = time() - $commit_time;
+            util::monitor_notify($chname,$spec,$card_type,$refill_info['channel_amount'],$period,$success,$commit_time);
 
             if ($success) {
                 $logic_vr_order->changeOrderStateSuccess($order_id,true);
@@ -184,7 +185,7 @@ class RefillBase
                 util::incr_notify($chname, $card_type, $spec, $quality, true);
                 util::incr_user_success($mchid,$card_type, $spec,$quality);
                 util::onOrderSuccess($refill_info,$order_info);
-                util::monitor_callback($mchid, $spec,$card_type,$refill_info['mch_amount'], $refill_info['channel_amount'], true);
+                util::monitor_callback($mchid, $spec,$card_type,$refill_info['mch_amount'], $refill_info['channel_amount'], true,$order_time);
             }
             elseif ($can_try)
             {
@@ -204,7 +205,7 @@ class RefillBase
                     }
                 }
                 util::incr_user_fail($mchid,$card_type, $spec,$quality);
-                util::monitor_callback($mchid, $spec, $card_type, $refill_info['mch_amount'], 0, false);
+                util::monitor_callback($mchid, $spec, $card_type, $refill_info['mch_amount'], 0, false, $order_time);
             }
             else {
                 $logic_vr_order->changeOrderStateCancel($order_info, '', "{$chname}接口回调通知失败,不可重试.",true,true);
@@ -213,7 +214,7 @@ class RefillBase
                 util::incr_notify($chname, $card_type, $spec, $quality, false);
                 util::incr_amount_lock($mchid,$card_type,$spec);
                 util::incr_user_fail($mchid,$card_type, $spec,$quality);
-                util::monitor_callback($mchid, $spec, $card_type, $refill_info['mch_amount'], 0, false);
+                util::monitor_callback($mchid, $spec, $card_type, $refill_info['mch_amount'], 0, false, $order_time);
             }
 
             $mod_refill->edit($order_id, ['notify_time' => time(), 'is_retrying' => 0,'notify_state' => 1]);
@@ -456,9 +457,10 @@ class RefillBase
 
             if ($state)
             {
+                $commit_time = time();
                 $chfilters->add_channel($channel_name,true);
                 util::incr_commit($channel_name,$card_type,$spec,$quality,true);
-                util::monitor_commit($channel_name, $spec, $card_type, $channel_amount);
+                util::monitor_commit($channel_name, $spec, $card_type, $channel_amount,$commit_time);
                 $trade_no = $errmsg;
 
                 $refill_type = $provider->refill_type();
@@ -480,7 +482,7 @@ class RefillBase
                     Log::record("Err refill_type = {$refill_type}",Log::ERR);
                 }
 
-                $data = ['commit_time' => time(), 'ch_trade_no' => $trade_no];
+                $data = ['commit_time' => $commit_time, 'ch_trade_no' => $trade_no];
                 $mod_refill->edit($order_id, $data);
                 $refill_state = true;
 

二進制
helper/refill/api/xyz/guochuang/20220630广东移动调价函.png


二進制
helper/refill/api/xyz/guochuang/20220630辽宁移动调价函.jpg


二進制
helper/refill/api/xyz/guochuang/20220701广东调价函.png


二進制
helper/refill/api/xyz/guochuang/20220701辽宁移动调价函.png


二進制
helper/refill/api/xyz/guochuang/20220702陕西电信调价函.png


二進制
helper/refill/api/xyz/guochuang/20220704辽宁移动调价函.png


二進制
helper/refill/api/xyz/guochuang/20220705广东移动调价函.png


二進制
helper/refill/api/xyz/guochuang/20220706辽宁移动调价函.png


二進制
helper/refill/api/xyz/guochuang/20220708辽宁 青海 贵州调价函.png


二進制
helper/refill/api/xyz/guochuang/20220710河南移动调价函.png


二進制
helper/refill/api/xyz/guochuang/20220710辽宁移动调价函.png


二進制
helper/refill/api/xyz/guochuang/20220711吉林移动调价函.png


二進制
helper/refill/api/xyz/guochuang/20220713辽宁移动调价函.png


二進制
helper/refill/api/xyz/guochuang/20220714辽宁移动调价函.png


二進制
helper/refill/api/xyz/guochuang/20220715广东移动调价函.png


+ 7 - 7
helper/refill/api/xyz/guochuang/config.php

@@ -64,25 +64,25 @@ class config
     const Price = [
         //移动
         "4-10-2" => 10.15, "4-20-2" => 19.92, "4-30-2" => 29.94, "4-50-2" => 49.9, "4-100-2" => 99.8, "4-200-2" => 199.6, "4-300-2" => 299.4, "4-500-2" => 499,//天津 2
-        "4-10-6" => 9.75, "4-20-6" => 19.5, "4-30-6" => 29.25, "4-50-6" => 48.75, "4-100-6" => 97.5, "4-200-6" => 195, "4-300-6" => 292.5, "4-500-6" => 487.5,//辽宁 6
+        "4-10-6" => 9.8, "4-20-6" => 19.6, "4-30-6" => 29.4, "4-50-6" => 49, "4-100-6" => 98, "4-200-6" => 196, "4-300-6" => 294, "4-500-6" => 490,//辽宁 6
         "4-10-9" => 9.94, "4-20-9" => 19.88, "4-30-9" => 29.82, "4-50-9" => 49.7, "4-100-9" => 99.4,//上海 9
         "4-10-8" => 10.015, "4-20-8" => 20.03, "4-30-8" => 30.045, "4-50-8" => 50.075, "4-100-8" => 100.15, "4-200-8" => 200.3, "4-300-8" => 300.9, "4-500-8" => 501.5,//黑龙江 8
-        "4-10-29" => 9.755, "4-20-29" => 19.51, "4-30-29" => 29.265, "4-50-29" => 48.775, "4-100-29" => 97.55, "4-200-29" => 195.1, "4-300-29" => 292.65, "4-500-29" => 487.75,//青海 29
+        "4-10-29" => 9.765, "4-20-29" => 19.53, "4-30-29" => 29.295, "4-50-29" => 48.825, "4-100-29" => 97.65, "4-200-29" => 195.3, "4-300-29" => 292.95, "4-500-29" => 488.25,//青海 29
         "4-10-28" => 9.985, "4-20-28" => 19.97, "4-30-28" => 29.955, "4-50-28" => 49.925, "4-100-28" => 99.85, "4-200-28" => 199.7, "4-300-28" => 299.55, "4-500-28" => 499.25,//甘肃 28
         "4-10-13" => 10.22, "4-20-13" => 19.94, "4-30-13" => 29.91, "4-50-13" => 49.85, "4-100-13" => 99.7, "4-200-13" => 199.4, "4-300-13" => 300.9, "4-500-13" => 501.5,//福建 13
         "4-10-5" => 10.035, "4-20-5" => 20.07, "4-30-5" => 30.09, "4-50-5" => 50.15, "4-100-5" => 100.3, "4-200-5" => 200.4, "4-300-5" => 300.6, "4-500-5" => 501,//内蒙古 5
         "4-30-18" => 29.835, "4-50-18" => 49.725, "4-100-18" => 99.45, "4-200-18" => 198.3,//湖南 18
-        "4-10-19" => 9.975, "4-20-19" => 19.95, "4-30-19" => 29.865, "4-50-19" => 49.775, "4-100-19" => 99.55, "4-200-19" => 199.1, "4-300-19" => 298.65, "4-500-19" => 497.75,//广东 19
-        "4-10-7" => 9.82, "4-20-7" => 19.64, "4-30-7" => 29.46, "4-50-7" => 49.1, "4-100-7" => 98.2, "4-200-7" => 196.4, "4-300-7" => 294.6, "4-500-7" => 491,//吉林 7
+        "4-10-19" => 9.975, "4-20-19" => 19.95, "4-30-19" => 29.94, "4-50-19" => 49.9, "4-100-19" => 99.8, "4-200-19" => 199.6, "4-300-19" => 299.4, "4-500-19" => 499,//广东 19
+        "4-10-7" => 9.93, "4-20-7" => 19.86, "4-30-7" => 29.52, "4-50-7" => 49.2, "4-100-7" => 98.4, "4-200-7" => 196.8, "4-300-7" => 295.2, "4-500-7" => 492,//吉林 7
         "4-10-1" => 10.31, "4-20-1" => 20.32, "4-30-1" => 30.33, "4-50-1" => 50.35, "4-100-1" => 100.4, "4-200-1" => 200.3, "4-300-1" => 300.45, "4-500-1" => 500.75,//北京 1
         "4-10-22" => 10.015, "4-20-22" => 20.03, "4-30-22" => 30.045, "4-50-22" => 50.075, "4-100-22" => 100.15, "4-200-22" => 200.3, "4-300-22" => 300.45, "4-500-22" => 500.75,//重庆 22
         "4-10-15" => 9.945, "4-20-15" => 19.89, "4-30-15" => 29.835, "4-50-15" => 49.725, "4-100-15" => 99.45, "4-200-15" => 198.9, "4-300-15" => 298.35, "4-500-15" => 497.25,//山东 15
         "4-10-10" => 9.945, "4-20-10" => 19.89, "4-30-10" => 29.835, "4-50-10" => 49.725, "4-100-10" => 99.45, "4-200-10" => 198.9, "4-300-10" => 298.35, "4-500-10" => 497.25,//江苏 10
         "4-10-11" => 9.945, "4-20-11" => 19.89, "4-30-11" => 29.835, "4-50-11" => 49.725, "4-100-11" => 99.45, "4-200-11" => 198.9, "4-300-11" => 298.35, "4-500-11" => 497.25,//浙江 11
         "4-10-17" => 9.945, "4-20-17" => 19.89, "4-30-17" => 29.835, "4-50-17" => 49.725, "4-100-17" => 99.45, "4-200-17" => 198.9, "4-300-17" => 298.35, "4-500-17" => 497.25,//湖北 17
-        "4-10-16" => 10.14, "4-20-16" => 20.28, "4-30-16" => 30.21, "4-50-16" => 50.15, "4-100-16" => 100.3, "4-200-16" => 200.6, "4-300-16" => 300.9, "4-500-16" => 501.5,//河南 16
+        "4-10-16" => 10.19, "4-20-16" => 20.28, "4-30-16" => 30.21, "4-50-16" => 50.15, "4-100-16" => 100.3, "4-200-16" => 200.6, "4-300-16" => 300.9, "4-500-16" => 501.5,//河南 16
         "4-50-4" => 49.75, "4-100-4" => 99.5, "4-200-4" => 199,//山西 4
-        "4-10-24" => 10.21, "4-20-24" => 20.22, "4-30-24" => 30.24, "4-50-24" => 50.25, "4-100-24" => 100.3, "4-200-24" => 200.4, "4-300-24" => 300.6, "4-500-24" => 501,//贵州 24
+        "4-10-24" => 10.22, "4-20-24" => 20.44, "4-30-24" => 30.24, "4-50-24" => 50.25, "4-100-24" => 100.3, "4-200-24" => 200.4, "4-300-24" => 300.6, "4-500-24" => 501,//贵州 24
         "4-10-30" => 10.12, "4-20-30" => 20.24, "4-30-30" => 30.129, "4-50-30" => 50.15, "4-100-30" => 100.2, "4-200-30" => 200.4, "4-300-30" => 300.3, "4-500-30" => 500.5,//宁夏 30
         //联通
         "5-10-19" => 10.04, "5-20-19" => 20.08, "5-30-19" => 30.06, "5-50-19" => 50.1, "5-100-19" => 100.2, "5-200-19" => 200.4, "5-300-19" => 300.6, "5-500-19" => 501,//广东 19
@@ -91,7 +91,7 @@ class config
         "5-10-14" => 10.04, "5-20-14" => 20.08, "5-30-14" => 30.06, "5-50-14" => 50.1, "5-100-14" => 100.1, "5-200-14" => 200.2, "5-300-14" => 300.3, "5-500-14" => 500.5,//江西 14
         "5-20-23" => 20.08, "5-30-23" => 30.12, "5-50-23" => 50.2, "5-100-23" => 100.4, "5-200-23" => 200.8, "5-300-23" => 301.2, "5-500-23" => 502,//四川 23
         //电信
-        "6-10-27" => 9.955, "6-20-27" => 19.91, "6-30-27" => 29.865, "6-50-27" => 49.775, "6-100-27" => 99.55, "6-200-27" => 199.1, "6-300-27" => 298.5, "6-500-27" => 497.5,//陕西 27
+        "6-10-27" => 10.025, "6-20-27" => 20.05, "6-30-27" => 30.075, "6-50-27" => 50.125, "6-100-27" => 100.25, "6-200-27" => 200.5, "6-300-27" => 298.5, "6-500-27" => 497.5,//陕西 27
         "6-10-4" => 9.935, "6-20-4" => 19.87, "6-30-4" => 29.805, "6-50-4" => 49.675, "6-100-4" => 99.35, "6-200-4" => 198.7, "6-300-4" => 298.05, "6-500-4" => 496.75,//山西 4
         "6-10-18" => 10.04, "6-20-18" => 20.08, "6-30-18" => 30.12, "6-50-18" => 50.15, "6-100-18" => 100.3, "6-200-18" => 200.6, "6-300-18" => 300.9, "6-500-18" => 501.5,//湖南 18
         "6-10-15" => 10.21, "6-20-15" => 20.22, "6-30-15" => 30.231, "6-50-15" => 50.25, "6-100-15" => 100.3, "6-200-15" => 200.3, "6-300-15" => 300.45, "6-500-15" => 500.75,//山东 15

+ 67 - 0
helper/refill/api/xyz/huoshenguo_fs/RefillCallBack.php

@@ -0,0 +1,67 @@
+<?php
+namespace refill\huoshenguo_fs;
+
+require_once(BASE_HELPER_RAPI_PATH . '/huoshenguo_fs/config.php');
+
+use refill;
+class RefillCallBack implements refill\IRefillCallBack
+{
+    public function verify($params): bool
+    {
+        $input = $params;
+        unset($input['sign']);
+        $sign = $this->sign($input);
+        if ($params['sign'] == $sign) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private function sign($params)
+    {
+        $params['appSecret'] = config::APP_SECRET;
+        ksort($params);
+        $content = '';
+        foreach ($params as $key => $value) {
+            if($this->check_empty($value) === false) {
+                $content .= "{$key}={$value}&";
+            }
+        }
+        $content = rtrim($content, '&');
+        return md5($content);
+    }
+
+    private function check_empty($value)
+    {
+        if (!isset($value))
+            return true;
+        if ($value === null)
+            return true;
+        if (trim($value) === "")
+            return true;
+
+        return false;
+    }
+
+    public function notify($params)
+    {
+        $status = intval($params['orderStatus']);
+        $order_sn = $params['outOrderId'];
+        $order_info = Model('vr_order')->getOrderInfo(['order_sn' => $order_sn]);
+        if (empty($order_info)) {
+            return [false, false, false,false];
+        }
+
+        $order_id = $order_info['order_id'];
+        if ($status === 2) {
+            $data['official_sn'] = strtolower($params['ext1']) == 'null' ? '' : $params['ext1'];
+            Model('refill_order')->edit($order_id, $data);
+            return [$order_id, true, false, true];
+        } elseif ($status === 3) {
+            return [$order_id, false, true, true];
+        } else {
+            return [$order_id, false, false, false];
+        }
+    }
+}

+ 155 - 0
helper/refill/api/xyz/huoshenguo_fs/RefillPhone.php

@@ -0,0 +1,155 @@
+<?php
+
+namespace refill\huoshenguo_fs;
+
+require_once(BASE_HELPER_RAPI_PATH . '/huoshenguo_fs/config.php');
+
+use refill;
+use Log;
+
+class RefillPhone extends refill\IRefillPhone
+{
+    public function __construct($cfgs)
+    {
+        parent::__construct($cfgs);
+    }
+
+    private function req_params(int $phone, int $amount, int $card_type, string $order_sn)
+    {
+        $params['appId'] = config::APP_ID;
+        $params['outOrderId'] = $order_sn;
+        $params['uuid'] = $phone;
+        $params['itemId'] = config::PRODUCT[$card_type][$amount];
+        $params['itemFace'] = $amount;
+        $params['callbackUrl'] = config::NOTIFY_URL;
+        $params['timestamp'] = date("YmdHis").$this->get_millisecond();
+        return $params;
+    }
+
+    public function add($card_no, $card_type, $amount, $params,&$net_errno = 0)
+    {
+        $order_sn = $params['order_sn'];
+        $params = $this->req_params($card_no, $amount, $card_type, $order_sn);
+        if(empty($params['itemId'])) {
+            return [false, '商品编号错误', false];
+        }
+        $sign = $this->sign($params);
+        $params['sign'] = $sign;
+
+        $resp = http_request(config::ORDER_URL, $params, 'POST', false, config::ExtHeaders, $net_errno);
+
+        if (empty($resp)) {
+            return [false, '网络错误', true];
+        }
+        else
+        {
+            Log::record($resp, Log::DEBUG);
+            $resp = json_decode($resp, true);
+            if (empty($resp)) {
+                return [false, '网络错误', true];
+            } elseif ($resp['code'] === '00') {
+                return [true, $resp['orderId'], false];
+            } elseif (in_array($resp['code'], config::ERRCODES, true)) {
+                return [false, $resp['msg'], false];
+            } elseif (in_array($resp['code'], ['-22', '-23', '-99'], true)) {
+                $net_errno = "HTTP-{$resp['code']}";
+                return [false, $resp['msg'], true];
+            } else {
+                $net_errno = "HTTP-998";
+                return [false, $resp['msg'], true];
+            }
+        }
+    }
+
+    public function query($refill_info)
+    {
+        $params['appId'] = config::APP_ID;
+        $params['outOrderId'] = $refill_info['order_sn'];
+        $params['timestamp'] = date("YmdHis").$this->get_millisecond();
+        $params['sign'] = $this->sign($params);
+
+        $resp = http_request(config::QUERY_URL, $params, 'POST', false, config::ExtHeaders);
+
+        if (empty($resp)) {
+            return [false, '网络错误'];
+        }
+        else
+        {
+            Log::record($resp, Log::DEBUG);
+            $resp = json_decode($resp, true);
+            if (empty($resp)) {
+                return [false, '网络错误'];
+            }
+            elseif ($resp['code'] === '00')
+            {
+                $status = $resp['orderStatus'];
+                if ($status === '2') {
+                    $updata['official_sn'] = $resp['ext1'];
+                    Model('refill_order')->edit($refill_info['order_id'], $updata);
+                    $order_state = ORDER_STATE_SUCCESS;
+                } elseif ($status === '3') {
+                    $order_state = ORDER_STATE_CANCEL;
+                } elseif ($status === '1') {
+                    $order_state = ORDER_STATE_SEND;
+                } elseif ($status === '4' && (time() - $refill_info['commit_time'] >= 600)) {
+                    $order_state = ORDER_STATE_NOEXIST;
+                } else {
+                    return [false, $resp['msg']];
+                }
+                return [true, $order_state];
+            }
+            else
+            {
+                return [false, $resp['msg']];
+            }
+        }
+    }
+
+    public function balance()
+    {
+        $params['appId'] = config::APP_ID;
+        $params['timestamp'] = date("YmdHis").$this->get_millisecond();
+        $params['sign'] = $this->sign($params);
+
+        $resp = http_request(config::BALANCE_URL, $params, 'POST', false, config::ExtHeaders);
+
+        if (empty($resp)) {
+            return [false, '网络错误'];
+        }
+        else
+        {
+            Log::record($resp, Log::DEBUG);
+            $resp = json_decode($resp, true);
+            if (empty($resp)) {
+                return [false, '网络错误'];
+            } elseif ($resp['code'] === '00') {
+                return [true, $resp['balance']];
+            } else {
+                return [false, $resp['msg']];
+            }
+        }
+    }
+
+    /**
+     * 获取毫秒级别的时间戳
+     */
+    private function get_millisecond()
+    {
+        list($usec, $sec) = explode(" ", microtime());
+        return round($usec*1000);
+    }
+
+    private function sign($params)
+    {
+        $params['appSecret'] = config::APP_SECRET;
+        ksort($params);
+        $content = '';
+        foreach ($params as $key => $value) {
+            if($this->check_empty($value) === false) {
+                $content .= "{$key}={$value}&";
+            }
+        }
+        $content = rtrim($content, '&');
+        return md5($content);
+    }
+}

+ 36 - 0
helper/refill/api/xyz/huoshenguo_fs/config.php

@@ -0,0 +1,36 @@
+<?php
+
+
+namespace refill\huoshenguo_fs;
+
+use mtopcard;
+class config
+{
+    const ORDER_URL = 'http://120.26.89.236:8911/api/hf/order/submit';
+    const QUERY_URL = 'http://120.26.89.236:8911/api/order/query';
+    const BALANCE_URL = 'http://120.26.89.236:8911/api/account/balance';
+
+    const APP_ID = '0AQYfAzSyy';
+    const APP_SECRET = 'WkCUpvfrqhvrwinQ';
+    const NOTIFY_URL = BASE_SITE_URL . "/mobile/callback/refill_huoshenguo_fs.php";
+
+    const PRODUCT = [
+        mtopcard\ChinaMobileCard => [
+            30  => 100135,
+            50  => 100136,
+            100 => 100137,
+            200 => 100138,
+        ],
+        mtopcard\ChinaUnicomCard => [
+
+        ],
+        mtopcard\ChinaTelecomCard => [
+            30  => 100147,
+            50  => 100148,
+            100 => 100149,
+            200 => 100150,
+        ],
+    ];
+    const ExtHeaders = ['Content-Type:application/x-www-form-urlencoded;charset=utf-8'];
+    const ERRCODES = ['-10', '-12', '-13', '-14', '-15', '-16', '-18', '-21'];
+}

+ 28 - 0
helper/refill/api/xyz/huoshenguo_fs/开户信息.txt

@@ -0,0 +1,28 @@
+后台地址:http://120.26.89.236:8888
+帐号:YZFS
+密码:351046
+二级密码:RvdJ6903
+appId:0AQYfAzSyy
+appSecret:WkCUpvfrqhvrwinQ
+后台-商品列表,可查看已配置商品信息
+后台-安全中心,可配置IP白名单
+接口文档:https://www.showdoc.com.cn/1686453783298366/7925312871840290
+话费直充接口:http://120.26.89.236:8911/api/hf/order/submit
+通用直充接口:http://120.26.89.236:8911/api/order/submit
+卡密提取接口:http://120.26.89.236:8911/api/card/get
+查询接口接口:http://120.26.89.236:8911/api/order/query
+余额查询接口:http://120.26.89.236:8911/api/account/balance
+
+
+100135 移动分省30
+100136 移动分省50
+100137 移动分省100
+100138 移动分省200
+移动分省 云南 贵州
+
+
+100147 电信分省30
+100148 电信分省50
+100149 电信分省100
+100150 电信分省200
+电信分省  天津 上海   湖南

+ 17 - 23
helper/refill/api/xyz/yamiao_high/config.php

@@ -6,37 +6,31 @@ namespace refill\yamiao_high;
 use mtopcard;
 class config
 {
-    const ORDER_URL = 'http://120.55.90.36:8911/api/hf/order/submit';
-    const QUERY_URL = 'http://120.55.90.36:8911/api/order/query';
-    const BALANCE_URL = 'http://120.55.90.36:8911/api/account/balance';
+    const ORDER_URL = 'http://121.196.43.130:8911/api/hf/order/submit';
+    const QUERY_URL = 'http://121.196.43.130:8911/api/order/query';
+    const BALANCE_URL = 'http://121.196.43.130:8911/api/account/balance';
 
-    const APP_ID = 'HHngfxQs6M';
-    const APP_SECRET = 'jToNycSIbofVwPSn';
+    const APP_ID = 'pNu4tRKL3B';
+    const APP_SECRET = 'CJGgKafirDZjPduS';
     const NOTIFY_URL = BASE_SITE_URL . "/mobile/callback/refill_yamiao_high.php";
     const PRODUCT = [
         mtopcard\ChinaMobileCard => [
-            30  => 100007,
-            50  => 100008,
-            100 => 100009,
-            200 => 100010,
-            300 => 100011,
-            500 => 100012
+            30  => 100000,
+            50  => 100001,
+            100 => 100002,
+            200 => 100003,
         ],
         mtopcard\ChinaUnicomCard => [
-            30  => 100013,
-            50  => 100014,
-            100 => 100015,
-            200 => 100016,
-            300 => 100017,
-            500 => 100018
+            30  => 100004,
+            50  => 100005,
+            100 => 100006,
+            200 => 100007,
         ],
         mtopcard\ChinaTelecomCard => [
-            30  => 100019,
-            50  => 100020,
-            100 => 100021,
-            200 => 100022,
-            300 => 100023,
-            500 => 100024
+            30  => 100008,
+            50  => 100009,
+            100 => 100010,
+            200 => 100011,
         ],
     ];
     const ExtHeaders = ['Content-Type:application/x-www-form-urlencoded;charset=utf-8'];

+ 23 - 30
helper/refill/api/xyz/yamiao_high/开户信息.txt

@@ -1,36 +1,29 @@
-后台地址:http://120.55.90.36:8888
-帐号:椰子
-密码:545795
-二级密码:eJMW5323
-appId:HHngfxQs6M
-appSecret:jToNycSIbofVwPSn
+后台地址:http://121.196.43.130:8888
+帐号:北京椰子高价
+密码:217032
+二级密码:Ujgb9100
+appId:pNu4tRKL3B
+appSecret:CJGgKafirDZjPduS
 后台-商品列表,可查看已配置商品信息
 后台-安全中心,可配置IP白名单
 接口文档:https://www.showdoc.com.cn/1686453783298366/7925312871840290
-话费直充接口:http://120.55.90.36:8911/api/hf/order/submit
-通用直充接口:http://120.55.90.36:8911/api/order/submit
-卡密提取接口:http://120.55.90.36:8911/api/card/get
-查单接口接口:http://120.55.90.36:8911/api/order/query
-余额接口接口:http://120.55.90.36:8911/api/account/balance
+话费直充接口:http://121.196.43.130:8911/api/hf/order/submit
+通用直充接口:http://121.196.43.130:8911/api/order/submit
+卡密提取接口:http://121.196.43.130:8911/api/card/get
+查询接口接口:http://121.196.43.130:8911/api/order/query
+余额查询接口:http://121.196.43.130:8911/api/account/balance
 
+100000  移动30
+100001  移动50
+100002  移动100
+100003  移动200
 
-100007   移动30
-100008   移动50
-100009   移动100
-100010   移动200
-100011   移动300
-100012   移动500
+100004	联通30
+100005	联通50
+100006	联通100
+100007	联通200
 
-100013   联通30
-100014   联通50
-100015   联通100
-100016   联通200
-100017   联通300
-100018	 联通500
-
-100019   电信30
-100020   电信50
-100021   电信100
-100022   电信200
-100023 	 电信300
-100024   电信500
+100008	电信30
+100009	电信50
+100010	电信100
+100011	电信200

+ 17 - 23
helper/refill/api/xyz/yamiao_normal/config.php

@@ -6,37 +6,31 @@ namespace refill\yamiao_normal;
 use mtopcard;
 class config
 {
-    const ORDER_URL = 'http://120.55.90.36:8911/api/hf/order/submit';
-    const QUERY_URL = 'http://120.55.90.36:8911/api/order/query';
-    const BALANCE_URL = 'http://120.55.90.36:8911/api/account/balance';
+    const ORDER_URL = 'http://121.196.43.130:8911/api/hf/order/submit';
+    const QUERY_URL = 'http://121.196.43.130:8911/api/order/query';
+    const BALANCE_URL = 'http://121.196.43.130:8911/api/account/balance';
 
-    const APP_ID = 'RvQe0E9q3S';
-    const APP_SECRET = 'OfVpRCIUBQGYSQUL';
+    const APP_ID = 'QhzfNgAIAn';
+    const APP_SECRET = 'mDewCnLyXBvdTFQs';
     const NOTIFY_URL = BASE_SITE_URL . "/mobile/callback/refill_yamiao_normal.php";
     const PRODUCT = [
         mtopcard\ChinaMobileCard => [
-            30  => 100007,
-            50  => 100008,
-            100 => 100009,
-            200 => 100010,
-            300 => 100011,
-            500 => 100012
+            30  => 100000,
+            50  => 100001,
+            100 => 100002,
+            200 => 100003,
         ],
         mtopcard\ChinaUnicomCard => [
-            30  => 100013,
-            50  => 100014,
-            100 => 100015,
-            200 => 100016,
-            300 => 100017,
-            500 => 100018
+            30  => 100004,
+            50  => 100005,
+            100 => 100006,
+            200 => 100007,
         ],
         mtopcard\ChinaTelecomCard => [
-            30  => 100019,
-            50  => 100020,
-            100 => 100021,
-            200 => 100022,
-            300 => 100023,
-            500 => 100024
+            30  => 100008,
+            50  => 100009,
+            100 => 100010,
+            200 => 100011,
         ],
     ];
     const ExtHeaders = ['Content-Type:application/x-www-form-urlencoded;charset=utf-8'];

+ 23 - 29
helper/refill/api/xyz/yamiao_normal/开户信息.txt

@@ -1,35 +1,29 @@
-后台地址:http://120.55.90.36:8888
-帐号:yezi
-密码:304641
-二级密码:tKDZ6725
-appId:RvQe0E9q3S
-appSecret:OfVpRCIUBQGYSQUL
+后台地址:http://121.196.43.130:8888
+帐号:北京椰子低价
+密码:067443
+二级密码:YeXD1760
+appId:QhzfNgAIAn
+appSecret:mDewCnLyXBvdTFQs
 后台-商品列表,可查看已配置商品信息
 后台-安全中心,可配置IP白名单
 接口文档:https://www.showdoc.com.cn/1686453783298366/7925312871840290
-话费直充接口:http://120.55.90.36:8911/api/hf/order/submit
-通用直充接口:http://120.55.90.36:8911/api/order/submit
-卡密提取接口:http://120.55.90.36:8911/api/card/get
-查单接口接口:http://120.55.90.36:8911/api/order/query
-余额接口接口:http://120.55.90.36:8911/api/account/balance
+话费直充接口:http://121.196.43.130:8911/api/hf/order/submit
+通用直充接口:http://121.196.43.130:8911/api/order/submit
+卡密提取接口:http://121.196.43.130:8911/api/card/get
+查询接口接口:http://121.196.43.130:8911/api/order/query
+余额查询接口:http://121.196.43.130:8911/api/account/balance
 
-100007   移动30
-100008   移动50
-100009   移动100
-100010   移动200
-100011   移动300
-100012   移动500
+100000  移动30
+100001  移动50
+100002  移动100
+100003  移动200
 
-100013   联通30
-100014   联通50
-100015   联通100
-100016   联通200
-100017   联通300
-100018	 联通500
+100004	联通30
+100005	联通50
+100006	联通100
+100007	联通200
 
-100019   电信30
-100020   电信50
-100021   电信100
-100022   电信200
-100023 	 电信300
-100024   电信500
+100008	电信30
+100009	电信50
+100010	电信100
+100011	电信200

+ 17 - 19
helper/refill/api/xyz/yunchonggong/config.php

@@ -6,33 +6,31 @@ namespace refill\yunchonggong;
 use mtopcard;
 class config
 {
-    const ORDER_URL = 'http://119.23.54.206:8911/api/order/submit';
-    const QUERY_URL = 'http://119.23.54.206:8911/api/order/query';
-    const BALANCE_URL = 'http://119.23.54.206:8911/api/account/balance';
+    const ORDER_URL = 'http://39.108.50.235:8911/api/order/submit';
+    const QUERY_URL = 'http://39.108.50.235:8911/api/order/query';
+    const BALANCE_URL = 'http://39.108.50.235:8911/api/account/balance';
 
-    const APP_ID = 'c4vuuOV43q';
-    const APP_SECRET = 'eyxARMYmpqkavQsS';
+    const APP_ID = 'ihAIbQsfqg';
+    const APP_SECRET = 'ydbSZsvAjHtxRGXu';
     const NOTIFY_URL = BASE_SITE_URL . "/mobile/callback/refill_yunchonggong.php";
     const PRODUCT = [
         mtopcard\ChinaMobileCard => [
-            30  => 100032,
-            50  => 100033,
-            100 => 100034,
-            200 => 100035
+            30  => 100000,
+            50  => 100001,
+            100 => 100002,
+            200 => 100003
         ],
         mtopcard\ChinaUnicomCard => [
-            30  => 100036,
-            50  => 100037,
-            100 => 100038,
-            200 => 100039,
-            300 => 100040
+            30  => 100004,
+            50  => 100005,
+            100 => 100006,
+            200 => 100007
         ],
         mtopcard\ChinaTelecomCard => [
-            30  => 100041,
-            50  => 100042,
-            100 => 100043,
-            200 => 100044,
-            300 => 100045
+            30  => 100008,
+            50  => 100009,
+            100 => 100010,
+            200 => 100011
         ],
     ];
     const ExtHeaders = ['Content-Type:application/x-www-form-urlencoded;charset=utf-8'];

+ 26 - 9
helper/refill/api/xyz/yunchonggong/开户信息.txt

@@ -1,12 +1,29 @@
-后台地址:http://119.23.54.206:8888
+后台地址:http://39.108.50.235:8888
 帐号:yezi
-密码:839926
-二级密码:yHNd0040
-appId:c4vuuOV43q
-appSecret:eyxARMYmpqkavQsS
-接口服务器:119.23.54.206
-http端口:8911,https端口:8443
-后台-接口文档,可查看及下载接口文档
+密码:033951
+二级密码:RADk5073
+appId:ihAIbQsfqg
+appSecret:ydbSZsvAjHtxRGXu
 后台-商品列表,可查看已配置商品信息
 后台-安全中心,可配置IP白名单
-接口地址:https://www.showdoc.com.cn/900133176881927/4798108582458838
+接口文档:https://www.showdoc.com.cn/1686453783298366/7925312871840290
+话费直充接口:http://39.108.50.235:8911/api/hf/order/submit
+通用直充接口:http://39.108.50.235:8911/api/order/submit
+卡密提取接口:http://39.108.50.235:8911/api/card/get
+查询接口接口:http://39.108.50.235:8911/api/order/query
+余额查询接口:http://39.108.50.235:8911/api/account/balance
+
+100000	全国移动30
+100001	全国移动50
+100002	全国移动100
+100003	全国移动200
+
+100004	全国联通30
+100005	全国联通50
+100006	全国联通100
+100007	全国联通200
+
+100008	全国电信30
+100009	全国电信50
+100010	全国电信100
+100011	全国电信200

+ 15 - 57
helper/refill/api/xyz/yunchonggongfs/config.php

@@ -5,75 +5,33 @@ namespace refill\yunchonggongfs;
 
 class config
 {
-    const ORDER_URL = 'http://119.23.54.206:8911/api/order/submit';
-    const QUERY_URL = 'http://119.23.54.206:8911/api/order/query';
-    const BALANCE_URL = 'http://119.23.54.206:8911/api/account/balance';
+    const ORDER_URL = 'http://39.108.50.235:8911/api/order/submit';
+    const QUERY_URL = 'http://39.108.50.235:8911/api/order/query';
+    const BALANCE_URL = 'http://39.108.50.235:8911/api/account/balance';
 
-    const APP_ID = 'Z1sU5unYK7';
-    const APP_SECRET = 'jaFAMZtZAiQFWYnL';
+    const APP_ID = 'dyipx0WORM';
+    const APP_SECRET = 'LSBNkvMPKoAMfDrt';
     const NOTIFY_URL = BASE_SITE_URL . "/mobile/callback/refill_yunchonggongfs.php";
 
     const ProvinceItemId = [
-        15	=> [
-                    30  => 100050,
-                    50  => 100051,
-                    100 => 100052,
-                    200 => 100053
-                ], //'山东',
         25	=> [
-                    30  => 100054,
-                    50  => 100055,
-                    100 => 100056,
-                    200 => 100057
+                    30  => 100012,
+                    50  => 100013,
+                    100 => 100014,
+                    200 => 100015
                 ], //'云南',
-        28	=> [
-                    30  => 100066,
-                    50  => 100067,
-                    100 => 100068,
-                    200 => 100069
-                ], //'甘肃',
         24	=> [
-                    30  => 100070,
-                    50  => 100071,
-                    100 => 100072,
-                    200 => 100073
+                    30  => 100016,
+                    50  => 100017,
+                    100 => 100018,
+                    200 => 100019
                 ], //'贵州',
-        4	=> [
-                    30  => 100074,
-                    50  => 100075,
-                    100 => 100076,
-                    200 => 100077
-                ], //'山西',
-        10	=> [
-                    30  => 100078,
-                    50  => 100079,
-                    100 => 100080,
-                    200 => 100081
-                ], //'江苏',
-        11	=> [
-                    30  => 100082,
-                    50  => 100083,
-                    100 => 100084,
-                    200 => 100085
-                ], //'浙江'
-        13	=> [
-                    30  => 100086,
-                    50  => 100087,
-                    100 => 100088,
-                    200 => 100089
-                ] //'福建'
     ];
     const ExtHeaders = ['Content-Type:application/x-www-form-urlencoded;charset=utf-8'];
     const ERRCODES = ['-10', '-12', '-13', '-14', '-15', '-16', '-18', '-21'];
     //key格式 卡类型-面值-regin_no
     const Price = [
-        "4-10-24" => 9.41, "4-20-24" => 18.82, "4-30-24" => 28.23, "4-50-24" => 47.05, "4-100-24" => 94.1, "4-200-24" => 188.2, "4-300-24" => 282.3, "4-500-24" => 470.5,//贵州 24
-        "4-10-15" => 9.47, "4-20-15" => 18.94, "4-30-15" => 28.41, "4-50-15" => 47.35, "4-100-15" => 94.7, "4-200-15" => 189.4, "4-300-15" => 284.1, "4-500-15" => 473.5,//山东 15
-        "4-10-25" => 9.47, "4-20-25" => 18.94, "4-30-25" => 28.41, "4-50-25" => 47.35, "4-100-25" => 94.7, "4-200-25" => 189.4, "4-300-25" => 284.1, "4-500-25" => 473.5,//云南 25
-        "4-10-28" => 9.47, "4-20-28" => 18.94, "4-30-28" => 28.41, "4-50-28" => 47.35, "4-100-28" => 94.7, "4-200-28" => 189.4, "4-300-28" => 284.1, "4-500-28" => 473.5,//甘肃 28
-        "4-10-4" => 9.47, "4-20-4" => 18.94, "4-30-4" => 28.41, "4-50-4" => 47.35, "4-100-4" => 94.7, "4-200-4" => 189.4, "4-300-4" => 284.1, "4-500-4" => 473.5,//山西 4
-        "4-10-10" => 9.47, "4-20-10" => 18.94, "4-30-10" => 28.41, "4-50-10" => 47.35, "4-100-10" => 94.7, "4-200-10" => 189.4, "4-300-10" => 284.1, "4-500-10" => 473.5,//江苏 10
-        "4-10-11" => 9.47, "4-20-11" => 18.94, "4-30-11" => 28.41, "4-50-11" => 47.35, "4-100-11" => 94.7, "4-200-11" => 189.4, "4-300-11" => 284.1, "4-500-11" => 473.5,//浙江 11
-        "4-10-13" => 9.47, "4-20-13" => 18.94, "4-30-13" => 28.41, "4-50-13" => 47.35, "4-100-13" => 94.7, "4-200-13" => 189.4, "4-300-13" => 284.1, "4-500-13" => 473.5,//福建 13
+        "4-30-24" => 28.23, "4-50-24" => 47.05, "4-100-24" => 94.1, "4-200-24" => 188.2,//贵州 24
+        "4-30-25" => 28.23, "4-50-25" => 47.05, "4-100-25" => 94.1, "4-200-25" => 188.2,//云南 25
     ];
 }

+ 22 - 11
helper/refill/api/xyz/yunchonggongfs/开户信息.txt

@@ -1,13 +1,24 @@
-后台地址:http://119.23.54.206:8888
-帐号:fenyezi
-密码:716081
-二级密码:UaVI4513
-appId:Z1sU5unYK7
-appSecret:jaFAMZtZAiQFWYnL
+后台地址:http://39.108.50.235:8888
+帐号:yezi11
+密码:494749
+二级密码:TpKM4298
+appId:dyipx0WORM
+appSecret:LSBNkvMPKoAMfDrt
 后台-商品列表,可查看已配置商品信息
 后台-安全中心,可配置IP白名单
-接口文档:https://www.showdoc.com.cn/900133176881927?page_id=4798465261069610
-下单接口地址:http://119.23.54.206:8911/api/order/submit
-查单接口地址:http://119.23.54.206:8911/api/order/query
-余额接口地址:http://119.23.54.206:8911/api/account/balance
-提卡接口地址:http://119.23.54.206:8911/api/card/get
+接口文档:https://www.showdoc.com.cn/1686453783298366/7925312871840290
+话费直充接口:http://39.108.50.235:8911/api/hf/order/submit
+通用直充接口:http://39.108.50.235:8911/api/order/submit
+卡密提取接口:http://39.108.50.235:8911/api/card/get
+查询接口接口:http://39.108.50.235:8911/api/order/query
+余额查询接口:http://39.108.50.235:8911/api/account/balance
+
+100012	云南移动30
+100013	云南移动50
+100014	云南移动100
+100015	云南移动200
+
+100016	贵州移动30
+100017	贵州移动50
+100018	贵州移动100
+100019	贵州移动200

+ 7 - 7
helper/refill/api/yl/guochuang/config.php

@@ -64,25 +64,25 @@ class config
     const Price = [
         //移动
         "4-10-2" => 10.15, "4-20-2" => 19.92, "4-30-2" => 29.94, "4-50-2" => 49.9, "4-100-2" => 99.8, "4-200-2" => 199.6, "4-300-2" => 299.4, "4-500-2" => 499,//天津 2
-        "4-10-6" => 9.75, "4-20-6" => 19.5, "4-30-6" => 29.25, "4-50-6" => 48.75, "4-100-6" => 97.5, "4-200-6" => 195, "4-300-6" => 292.5, "4-500-6" => 487.5,//辽宁 6
+        "4-10-6" => 9.8, "4-20-6" => 19.6, "4-30-6" => 29.4, "4-50-6" => 49, "4-100-6" => 98, "4-200-6" => 196, "4-300-6" => 294, "4-500-6" => 490,//辽宁 6
         "4-10-9" => 9.94, "4-20-9" => 19.88, "4-30-9" => 29.82, "4-50-9" => 49.7, "4-100-9" => 99.4,//上海 9
         "4-10-8" => 10.015, "4-20-8" => 20.03, "4-30-8" => 30.045, "4-50-8" => 50.075, "4-100-8" => 100.15, "4-200-8" => 200.3, "4-300-8" => 300.9, "4-500-8" => 501.5,//黑龙江 8
-        "4-10-29" => 9.755, "4-20-29" => 19.51, "4-30-29" => 29.265, "4-50-29" => 48.775, "4-100-29" => 97.55, "4-200-29" => 195.1, "4-300-29" => 292.65, "4-500-29" => 487.75,//青海 29
+        "4-10-29" => 9.765, "4-20-29" => 19.53, "4-30-29" => 29.295, "4-50-29" => 48.825, "4-100-29" => 97.65, "4-200-29" => 195.3, "4-300-29" => 292.95, "4-500-29" => 488.25,//青海 29
         "4-10-28" => 9.985, "4-20-28" => 19.97, "4-30-28" => 29.955, "4-50-28" => 49.925, "4-100-28" => 99.85, "4-200-28" => 199.7, "4-300-28" => 299.55, "4-500-28" => 499.25,//甘肃 28
         "4-10-13" => 10.22, "4-20-13" => 19.94, "4-30-13" => 29.91, "4-50-13" => 49.85, "4-100-13" => 99.7, "4-200-13" => 199.4, "4-300-13" => 300.9, "4-500-13" => 501.5,//福建 13
         "4-10-5" => 10.035, "4-20-5" => 20.07, "4-30-5" => 30.09, "4-50-5" => 50.15, "4-100-5" => 100.3, "4-200-5" => 200.4, "4-300-5" => 300.6, "4-500-5" => 501,//内蒙古 5
         "4-30-18" => 29.835, "4-50-18" => 49.725, "4-100-18" => 99.45, "4-200-18" => 198.3,//湖南 18
-        "4-10-19" => 9.975, "4-20-19" => 19.95, "4-30-19" => 29.865, "4-50-19" => 49.775, "4-100-19" => 99.55, "4-200-19" => 199.1, "4-300-19" => 298.65, "4-500-19" => 497.75,//广东 19
-        "4-10-7" => 9.82, "4-20-7" => 19.64, "4-30-7" => 29.46, "4-50-7" => 49.1, "4-100-7" => 98.2, "4-200-7" => 196.4, "4-300-7" => 294.6, "4-500-7" => 491,//吉林 7
+        "4-10-19" => 9.975, "4-20-19" => 19.95, "4-30-19" => 29.94, "4-50-19" => 49.9, "4-100-19" => 99.8, "4-200-19" => 199.6, "4-300-19" => 299.4, "4-500-19" => 499,//广东 19
+        "4-10-7" => 9.93, "4-20-7" => 19.86, "4-30-7" => 29.52, "4-50-7" => 49.2, "4-100-7" => 98.4, "4-200-7" => 196.8, "4-300-7" => 295.2, "4-500-7" => 492,//吉林 7
         "4-10-1" => 10.31, "4-20-1" => 20.32, "4-30-1" => 30.33, "4-50-1" => 50.35, "4-100-1" => 100.4, "4-200-1" => 200.3, "4-300-1" => 300.45, "4-500-1" => 500.75,//北京 1
         "4-10-22" => 10.015, "4-20-22" => 20.03, "4-30-22" => 30.045, "4-50-22" => 50.075, "4-100-22" => 100.15, "4-200-22" => 200.3, "4-300-22" => 300.45, "4-500-22" => 500.75,//重庆 22
         "4-10-15" => 9.945, "4-20-15" => 19.89, "4-30-15" => 29.835, "4-50-15" => 49.725, "4-100-15" => 99.45, "4-200-15" => 198.9, "4-300-15" => 298.35, "4-500-15" => 497.25,//山东 15
         "4-10-10" => 9.945, "4-20-10" => 19.89, "4-30-10" => 29.835, "4-50-10" => 49.725, "4-100-10" => 99.45, "4-200-10" => 198.9, "4-300-10" => 298.35, "4-500-10" => 497.25,//江苏 10
         "4-10-11" => 9.945, "4-20-11" => 19.89, "4-30-11" => 29.835, "4-50-11" => 49.725, "4-100-11" => 99.45, "4-200-11" => 198.9, "4-300-11" => 298.35, "4-500-11" => 497.25,//浙江 11
         "4-10-17" => 9.945, "4-20-17" => 19.89, "4-30-17" => 29.835, "4-50-17" => 49.725, "4-100-17" => 99.45, "4-200-17" => 198.9, "4-300-17" => 298.35, "4-500-17" => 497.25,//湖北 17
-        "4-10-16" => 10.14, "4-20-16" => 20.28, "4-30-16" => 30.21, "4-50-16" => 50.15, "4-100-16" => 100.3, "4-200-16" => 200.6, "4-300-16" => 300.9, "4-500-16" => 501.5,//河南 16
+        "4-10-16" => 10.19, "4-20-16" => 20.28, "4-30-16" => 30.21, "4-50-16" => 50.15, "4-100-16" => 100.3, "4-200-16" => 200.6, "4-300-16" => 300.9, "4-500-16" => 501.5,//河南 16
         "4-50-4" => 49.75, "4-100-4" => 99.5, "4-200-4" => 199,//山西 4
-        "4-10-24" => 10.21, "4-20-24" => 20.22, "4-30-24" => 30.24, "4-50-24" => 50.25, "4-100-24" => 100.3, "4-200-24" => 200.4, "4-300-24" => 300.6, "4-500-24" => 501,//贵州 24
+        "4-10-24" => 10.22, "4-20-24" => 20.44, "4-30-24" => 30.24, "4-50-24" => 50.25, "4-100-24" => 100.3, "4-200-24" => 200.4, "4-300-24" => 300.6, "4-500-24" => 501,//贵州 24
         "4-10-30" => 10.12, "4-20-30" => 20.24, "4-30-30" => 30.129, "4-50-30" => 50.15, "4-100-30" => 100.2, "4-200-30" => 200.4, "4-300-30" => 300.3, "4-500-30" => 500.5,//宁夏 30
         //联通
         "5-10-19" => 10.04, "5-20-19" => 20.08, "5-30-19" => 30.06, "5-50-19" => 50.1, "5-100-19" => 100.2, "5-200-19" => 200.4, "5-300-19" => 300.6, "5-500-19" => 501,//广东 19
@@ -91,7 +91,7 @@ class config
         "5-10-14" => 10.04, "5-20-14" => 20.08, "5-30-14" => 30.06, "5-50-14" => 50.1, "5-100-14" => 100.1, "5-200-14" => 200.2, "5-300-14" => 300.3, "5-500-14" => 500.5,//江西 14
         "5-20-23" => 20.08, "5-30-23" => 30.12, "5-50-23" => 50.2, "5-100-23" => 100.4, "5-200-23" => 200.8, "5-300-23" => 301.2, "5-500-23" => 502,//四川 23
         //电信
-        "6-10-27" => 9.955, "6-20-27" => 19.91, "6-30-27" => 29.865, "6-50-27" => 49.775, "6-100-27" => 99.55, "6-200-27" => 199.1, "6-300-27" => 298.5, "6-500-27" => 497.5,//陕西 27
+        "6-10-27" => 10.025, "6-20-27" => 20.05, "6-30-27" => 30.075, "6-50-27" => 50.125, "6-100-27" => 100.25, "6-200-27" => 200.5, "6-300-27" => 298.5, "6-500-27" => 497.5,//陕西 27
         "6-10-4" => 9.935, "6-20-4" => 19.87, "6-30-4" => 29.805, "6-50-4" => 49.675, "6-100-4" => 99.35, "6-200-4" => 198.7, "6-300-4" => 298.05, "6-500-4" => 496.75,//山西 4
         "6-10-18" => 10.04, "6-20-18" => 20.08, "6-30-18" => 30.12, "6-50-18" => 50.15, "6-100-18" => 100.3, "6-200-18" => 200.6, "6-300-18" => 300.9, "6-500-18" => 501.5,//湖南 18
         "6-10-15" => 10.21, "6-20-15" => 20.22, "6-30-15" => 30.231, "6-50-15" => 50.25, "6-100-15" => 100.3, "6-200-15" => 200.3, "6-300-15" => 300.45, "6-500-15" => 500.75,//山东 15

+ 67 - 0
helper/refill/api/yl/huoshenguo_fs/RefillCallBack.php

@@ -0,0 +1,67 @@
+<?php
+namespace refill\huoshenguo_fs;
+
+require_once(BASE_HELPER_RAPI_PATH . '/huoshenguo_fs/config.php');
+
+use refill;
+class RefillCallBack implements refill\IRefillCallBack
+{
+    public function verify($params): bool
+    {
+        $input = $params;
+        unset($input['sign']);
+        $sign = $this->sign($input);
+        if ($params['sign'] == $sign) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private function sign($params)
+    {
+        $params['appSecret'] = config::APP_SECRET;
+        ksort($params);
+        $content = '';
+        foreach ($params as $key => $value) {
+            if($this->check_empty($value) === false) {
+                $content .= "{$key}={$value}&";
+            }
+        }
+        $content = rtrim($content, '&');
+        return md5($content);
+    }
+
+    private function check_empty($value)
+    {
+        if (!isset($value))
+            return true;
+        if ($value === null)
+            return true;
+        if (trim($value) === "")
+            return true;
+
+        return false;
+    }
+
+    public function notify($params)
+    {
+        $status = intval($params['orderStatus']);
+        $order_sn = $params['outOrderId'];
+        $order_info = Model('vr_order')->getOrderInfo(['order_sn' => $order_sn]);
+        if (empty($order_info)) {
+            return [false, false, false,false];
+        }
+
+        $order_id = $order_info['order_id'];
+        if ($status === 2) {
+            $data['official_sn'] = strtolower($params['ext1']) == 'null' ? '' : $params['ext1'];
+            Model('refill_order')->edit($order_id, $data);
+            return [$order_id, true, false, true];
+        } elseif ($status === 3) {
+            return [$order_id, false, true, true];
+        } else {
+            return [$order_id, false, false, false];
+        }
+    }
+}

+ 155 - 0
helper/refill/api/yl/huoshenguo_fs/RefillPhone.php

@@ -0,0 +1,155 @@
+<?php
+
+namespace refill\huoshenguo_fs;
+
+require_once(BASE_HELPER_RAPI_PATH . '/huoshenguo_fs/config.php');
+
+use refill;
+use Log;
+
+class RefillPhone extends refill\IRefillPhone
+{
+    public function __construct($cfgs)
+    {
+        parent::__construct($cfgs);
+    }
+
+    private function req_params(int $phone, int $amount, int $card_type, string $order_sn)
+    {
+        $params['appId'] = config::APP_ID;
+        $params['outOrderId'] = $order_sn;
+        $params['uuid'] = $phone;
+        $params['itemId'] = config::PRODUCT[$card_type][$amount];
+        $params['itemFace'] = $amount;
+        $params['callbackUrl'] = config::NOTIFY_URL;
+        $params['timestamp'] = date("YmdHis").$this->get_millisecond();
+        return $params;
+    }
+
+    public function add($card_no, $card_type, $amount, $params,&$net_errno = 0)
+    {
+        $order_sn = $params['order_sn'];
+        $params = $this->req_params($card_no, $amount, $card_type, $order_sn);
+        if(empty($params['itemId'])) {
+            return [false, '商品编号错误', false];
+        }
+        $sign = $this->sign($params);
+        $params['sign'] = $sign;
+
+        $resp = http_request(config::ORDER_URL, $params, 'POST', false, config::ExtHeaders, $net_errno);
+
+        if (empty($resp)) {
+            return [false, '网络错误', true];
+        }
+        else
+        {
+            Log::record($resp, Log::DEBUG);
+            $resp = json_decode($resp, true);
+            if (empty($resp)) {
+                return [false, '网络错误', true];
+            } elseif ($resp['code'] === '00') {
+                return [true, $resp['orderId'], false];
+            } elseif (in_array($resp['code'], config::ERRCODES, true)) {
+                return [false, $resp['msg'], false];
+            } elseif (in_array($resp['code'], ['-22', '-23', '-99'], true)) {
+                $net_errno = "HTTP-{$resp['code']}";
+                return [false, $resp['msg'], true];
+            } else {
+                $net_errno = "HTTP-998";
+                return [false, $resp['msg'], true];
+            }
+        }
+    }
+
+    public function query($refill_info)
+    {
+        $params['appId'] = config::APP_ID;
+        $params['outOrderId'] = $refill_info['order_sn'];
+        $params['timestamp'] = date("YmdHis").$this->get_millisecond();
+        $params['sign'] = $this->sign($params);
+
+        $resp = http_request(config::QUERY_URL, $params, 'POST', false, config::ExtHeaders);
+
+        if (empty($resp)) {
+            return [false, '网络错误'];
+        }
+        else
+        {
+            Log::record($resp, Log::DEBUG);
+            $resp = json_decode($resp, true);
+            if (empty($resp)) {
+                return [false, '网络错误'];
+            }
+            elseif ($resp['code'] === '00')
+            {
+                $status = $resp['orderStatus'];
+                if ($status === '2') {
+                    $updata['official_sn'] = $resp['ext1'];
+                    Model('refill_order')->edit($refill_info['order_id'], $updata);
+                    $order_state = ORDER_STATE_SUCCESS;
+                } elseif ($status === '3') {
+                    $order_state = ORDER_STATE_CANCEL;
+                } elseif ($status === '1') {
+                    $order_state = ORDER_STATE_SEND;
+                } elseif ($status === '4' && (time() - $refill_info['commit_time'] >= 600)) {
+                    $order_state = ORDER_STATE_NOEXIST;
+                } else {
+                    return [false, $resp['msg']];
+                }
+                return [true, $order_state];
+            }
+            else
+            {
+                return [false, $resp['msg']];
+            }
+        }
+    }
+
+    public function balance()
+    {
+        $params['appId'] = config::APP_ID;
+        $params['timestamp'] = date("YmdHis").$this->get_millisecond();
+        $params['sign'] = $this->sign($params);
+
+        $resp = http_request(config::BALANCE_URL, $params, 'POST', false, config::ExtHeaders);
+
+        if (empty($resp)) {
+            return [false, '网络错误'];
+        }
+        else
+        {
+            Log::record($resp, Log::DEBUG);
+            $resp = json_decode($resp, true);
+            if (empty($resp)) {
+                return [false, '网络错误'];
+            } elseif ($resp['code'] === '00') {
+                return [true, $resp['balance']];
+            } else {
+                return [false, $resp['msg']];
+            }
+        }
+    }
+
+    /**
+     * 获取毫秒级别的时间戳
+     */
+    private function get_millisecond()
+    {
+        list($usec, $sec) = explode(" ", microtime());
+        return round($usec*1000);
+    }
+
+    private function sign($params)
+    {
+        $params['appSecret'] = config::APP_SECRET;
+        ksort($params);
+        $content = '';
+        foreach ($params as $key => $value) {
+            if($this->check_empty($value) === false) {
+                $content .= "{$key}={$value}&";
+            }
+        }
+        $content = rtrim($content, '&');
+        return md5($content);
+    }
+}

+ 36 - 0
helper/refill/api/yl/huoshenguo_fs/config.php

@@ -0,0 +1,36 @@
+<?php
+
+
+namespace refill\huoshenguo_fs;
+
+use mtopcard;
+class config
+{
+    const ORDER_URL = 'http://120.26.89.236:8911/api/hf/order/submit';
+    const QUERY_URL = 'http://120.26.89.236:8911/api/order/query';
+    const BALANCE_URL = 'http://120.26.89.236:8911/api/account/balance';
+
+    const APP_ID = 'Hcvitg0Y1U';
+    const APP_SECRET = 'WuWtsYIdxiSKucgk';
+    const NOTIFY_URL = BASE_SITE_URL . "/mobile/callback/refill_huoshenguo_fs.php";
+
+    const PRODUCT = [
+        mtopcard\ChinaMobileCard => [
+            30  => 100135,
+            50  => 100136,
+            100 => 100137,
+            200 => 100138,
+        ],
+        mtopcard\ChinaUnicomCard => [
+
+        ],
+        mtopcard\ChinaTelecomCard => [
+            30  => 100147,
+            50  => 100148,
+            100 => 100149,
+            200 => 100150,
+        ],
+    ];
+    const ExtHeaders = ['Content-Type:application/x-www-form-urlencoded;charset=utf-8'];
+    const ERRCODES = ['-10', '-12', '-13', '-14', '-15', '-16', '-18', '-21'];
+}

+ 28 - 0
helper/refill/api/yl/huoshenguo_fs/开户信息.txt

@@ -0,0 +1,28 @@
+后台地址:http://120.26.89.236:8888
+帐号:YLFS
+密码:108502
+二级密码:WLLT7061
+appId:Hcvitg0Y1U
+appSecret:WuWtsYIdxiSKucgk
+后台-商品列表,可查看已配置商品信息
+后台-安全中心,可配置IP白名单
+接口文档:https://www.showdoc.com.cn/1686453783298366/7925312871840290
+话费直充接口:http://120.26.89.236:8911/api/hf/order/submit
+通用直充接口:http://120.26.89.236:8911/api/order/submit
+卡密提取接口:http://120.26.89.236:8911/api/card/get
+查询接口接口:http://120.26.89.236:8911/api/order/query
+余额查询接口:http://120.26.89.236:8911/api/account/balance
+
+
+100135 移动分省30
+100136 移动分省50
+100137 移动分省100
+100138 移动分省200
+移动分省 云南 贵州
+
+
+100147 电信分省30
+100148 电信分省50
+100149 电信分省100
+100150 电信分省200
+电信分省  天津 上海   湖南

+ 17 - 23
helper/refill/api/yl/yamiao_high/config.php

@@ -6,37 +6,31 @@ namespace refill\yamiao_high;
 use mtopcard;
 class config
 {
-    const ORDER_URL = 'http://120.55.90.36:8911/api/hf/order/submit';
-    const QUERY_URL = 'http://120.55.90.36:8911/api/order/query';
-    const BALANCE_URL = 'http://120.55.90.36:8911/api/account/balance';
+    const ORDER_URL = 'http://121.196.43.130:8911/api/hf/order/submit';
+    const QUERY_URL = 'http://121.196.43.130:8911/api/order/query';
+    const BALANCE_URL = 'http://121.196.43.130:8911/api/account/balance';
 
-    const APP_ID = 'ILo9IfHYg0';
-    const APP_SECRET = 'xjHkCgnJwxDgFbpK';
+    const APP_ID = 'LueEQKVnaR';
+    const APP_SECRET = 'GvmuGceMwWpPOTCe';
     const NOTIFY_URL = BASE_SITE_URL . "/mobile/callback/refill_yamiao_high.php";
     const PRODUCT = [
         mtopcard\ChinaMobileCard => [
-            30  => 100007,
-            50  => 100008,
-            100 => 100009,
-            200 => 100010,
-            300 => 100011,
-            500 => 100012
+            30  => 100000,
+            50  => 100001,
+            100 => 100002,
+            200 => 100003,
         ],
         mtopcard\ChinaUnicomCard => [
-            30  => 100013,
-            50  => 100014,
-            100 => 100015,
-            200 => 100016,
-            300 => 100017,
-            500 => 100018
+            30  => 100004,
+            50  => 100005,
+            100 => 100006,
+            200 => 100007,
         ],
         mtopcard\ChinaTelecomCard => [
-            30  => 100019,
-            50  => 100020,
-            100 => 100021,
-            200 => 100022,
-            300 => 100023,
-            500 => 100024
+            30  => 100008,
+            50  => 100009,
+            100 => 100010,
+            200 => 100011,
         ],
     ];
     const ExtHeaders = ['Content-Type:application/x-www-form-urlencoded;charset=utf-8'];

+ 23 - 30
helper/refill/api/yl/yamiao_high/开户信息.txt

@@ -1,36 +1,29 @@
-后台地址:http://120.55.90.36:8888
-帐号:椰林高价
-密码:168884
-二级密码:nuxc3785
-appId:ILo9IfHYg0
-appSecret:xjHkCgnJwxDgFbpK
+后台地址:http://121.196.43.130:8888
+帐号:北京椰林高价
+密码:797922
+二级密码:kBhZ9057
+appId:LueEQKVnaR
+appSecret:GvmuGceMwWpPOTCe
 后台-商品列表,可查看已配置商品信息
 后台-安全中心,可配置IP白名单
 接口文档:https://www.showdoc.com.cn/1686453783298366/7925312871840290
-话费直充接口:http://120.55.90.36:8911/api/hf/order/submit
-通用直充接口:http://120.55.90.36:8911/api/order/submit
-卡密提取接口:http://120.55.90.36:8911/api/card/get
-查单接口接口:http://120.55.90.36:8911/api/order/query
-余额接口接口:http://120.55.90.36:8911/api/account/balance
+话费直充接口:http://121.196.43.130:8911/api/hf/order/submit
+通用直充接口:http://121.196.43.130:8911/api/order/submit
+卡密提取接口:http://121.196.43.130:8911/api/card/get
+查询接口接口:http://121.196.43.130:8911/api/order/query
+余额查询接口:http://121.196.43.130:8911/api/account/balance
 
+100000  移动30
+100001  移动50
+100002  移动100
+100003  移动200
 
-100007   移动30
-100008   移动50
-100009   移动100
-100010   移动200
-100011   移动300
-100012   移动500
+100004	联通30
+100005	联通50
+100006	联通100
+100007	联通200
 
-100013   联通30
-100014   联通50
-100015   联通100
-100016   联通200
-100017   联通300
-100018	 联通500
-
-100019   电信30
-100020   电信50
-100021   电信100
-100022   电信200
-100023 	 电信300
-100024   电信500
+100008	电信30
+100009	电信50
+100010	电信100
+100011	电信200

+ 17 - 23
helper/refill/api/yl/yamiao_normal/config.php

@@ -6,37 +6,31 @@ namespace refill\yamiao_normal;
 use mtopcard;
 class config
 {
-    const ORDER_URL = 'http://120.55.90.36:8911/api/hf/order/submit';
-    const QUERY_URL = 'http://120.55.90.36:8911/api/order/query';
-    const BALANCE_URL = 'http://120.55.90.36:8911/api/account/balance';
+    const ORDER_URL = 'http://121.196.43.130:8911/api/hf/order/submit';
+    const QUERY_URL = 'http://121.196.43.130:8911/api/order/query';
+    const BALANCE_URL = 'http://121.196.43.130:8911/api/account/balance';
 
-    const APP_ID = 'Mxh2JUZocr';
-    const APP_SECRET = 'fKWyNeYlRZAimWXO';
+    const APP_ID = 'OSfxbC60NQ';
+    const APP_SECRET = 'yniMZxXwZAkAqkSp';
     const NOTIFY_URL = BASE_SITE_URL . "/mobile/callback/refill_yamiao_normal.php";
     const PRODUCT = [
         mtopcard\ChinaMobileCard => [
-            30  => 100007,
-            50  => 100008,
-            100 => 100009,
-            200 => 100010,
-            300 => 100011,
-            500 => 100012
+            30  => 100000,
+            50  => 100001,
+            100 => 100002,
+            200 => 100003,
         ],
         mtopcard\ChinaUnicomCard => [
-            30  => 100013,
-            50  => 100014,
-            100 => 100015,
-            200 => 100016,
-            300 => 100017,
-            500 => 100018
+            30  => 100004,
+            50  => 100005,
+            100 => 100006,
+            200 => 100007,
         ],
         mtopcard\ChinaTelecomCard => [
-            30  => 100019,
-            50  => 100020,
-            100 => 100021,
-            200 => 100022,
-            300 => 100023,
-            500 => 100024
+            30  => 100008,
+            50  => 100009,
+            100 => 100010,
+            200 => 100011,
         ],
     ];
     const ExtHeaders = ['Content-Type:application/x-www-form-urlencoded;charset=utf-8'];

+ 23 - 29
helper/refill/api/yl/yamiao_normal/开户信息.txt

@@ -1,35 +1,29 @@
-后台地址:http://120.55.90.36:8888
-帐号:椰林低价
-密码:260379
-二级密码:LFBU6725
-appId:Mxh2JUZocr
-appSecret:fKWyNeYlRZAimWXO
+后台地址:http://121.196.43.130:8888
+帐号:北京椰林低价
+密码:113610
+二级密码:BKWf3390
+appId:OSfxbC60NQ
+appSecret:yniMZxXwZAkAqkSp
 后台-商品列表,可查看已配置商品信息
 后台-安全中心,可配置IP白名单
 接口文档:https://www.showdoc.com.cn/1686453783298366/7925312871840290
-话费直充接口:http://120.55.90.36:8911/api/hf/order/submit
-通用直充接口:http://120.55.90.36:8911/api/order/submit
-卡密提取接口:http://120.55.90.36:8911/api/card/get
-查单接口接口:http://120.55.90.36:8911/api/order/query
-余额接口接口:http://120.55.90.36:8911/api/account/balance
+话费直充接口:http://121.196.43.130:8911/api/hf/order/submit
+通用直充接口:http://121.196.43.130:8911/api/order/submit
+卡密提取接口:http://121.196.43.130:8911/api/card/get
+查询接口接口:http://121.196.43.130:8911/api/order/query
+余额查询接口:http://121.196.43.130:8911/api/account/balance
 
-100007   移动30
-100008   移动50
-100009   移动100
-100010   移动200
-100011   移动300
-100012   移动500
+100000  移动30
+100001  移动50
+100002  移动100
+100003  移动200
 
-100013   联通30
-100014   联通50
-100015   联通100
-100016   联通200
-100017   联通300
-100018	 联通500
+100004	联通30
+100005	联通50
+100006	联通100
+100007	联通200
 
-100019   电信30
-100020   电信50
-100021   电信100
-100022   电信200
-100023 	 电信300
-100024   电信500
+100008	电信30
+100009	电信50
+100010	电信100
+100011	电信200

+ 17 - 17
helper/refill/api/yl/yunchonggong/config.php

@@ -6,31 +6,31 @@ namespace refill\yunchonggong;
 use mtopcard;
 class config
 {
-    const ORDER_URL = 'http://119.23.54.206:8911/api/order/submit';
-    const QUERY_URL = 'http://119.23.54.206:8911/api/order/query';
-    const BALANCE_URL = 'http://119.23.54.206:8911/api/account/balance';
+    const ORDER_URL = 'http://39.108.50.235:8911/api/order/submit';
+    const QUERY_URL = 'http://39.108.50.235:8911/api/order/query';
+    const BALANCE_URL = 'http://39.108.50.235:8911/api/account/balance';
 
-    const APP_ID = 'NCyHHJx9xf';
-    const APP_SECRET = 'vEqnmPrCcnazAzqK';
+    const APP_ID = 'lUdKnPz5cv';
+    const APP_SECRET = 'dIsQfAeVdvXRJLHO';
     const NOTIFY_URL = BASE_SITE_URL . "/mobile/callback/refill_yunchonggong.php";
     const PRODUCT = [
         mtopcard\ChinaMobileCard => [
-            30  => 100032,
-            50  => 100033,
-            100 => 100034,
-            200 => 100035
+            30  => 100000,
+            50  => 100001,
+            100 => 100002,
+            200 => 100003
         ],
         mtopcard\ChinaUnicomCard => [
-            30  => 100036,
-            50  => 100037,
-            100 => 100038,
-            200 => 100039
+            30  => 100004,
+            50  => 100005,
+            100 => 100006,
+            200 => 100007
         ],
         mtopcard\ChinaTelecomCard => [
-            30  => 100041,
-            50  => 100042,
-            100 => 100043,
-            200 => 100044
+            30  => 100008,
+            50  => 100009,
+            100 => 100010,
+            200 => 100011
         ],
     ];
     const ExtHeaders = ['Content-Type:application/x-www-form-urlencoded;charset=utf-8'];

+ 12 - 10
helper/refill/api/yl/yunchonggong/开户信息.txt

@@ -1,12 +1,14 @@
-后台地址:http://119.23.54.206:8888
-帐号:yelin
-密码:180394
-二级密码:Iaml0074
-appId:NCyHHJx9xf
-appSecret:vEqnmPrCcnazAzqK
-接口服务器:119.23.54.206
-http端口:8911,https端口:8443
-后台-接口文档,可查看及下载接口文档
+后台地址:http://39.108.50.235:8888
+帐号:yl11
+密码:934552
+二级密码:aqyy7481
+appId:lUdKnPz5cv
+appSecret:dIsQfAeVdvXRJLHO
 后台-商品列表,可查看已配置商品信息
 后台-安全中心,可配置IP白名单
-接口地址:https://www.showdoc.com.cn/900133176881927/4798108582458838
+接口文档:https://www.showdoc.com.cn/1686453783298366/7925312871840290
+话费直充接口:http://39.108.50.235:8911/api/hf/order/submit
+通用直充接口:http://39.108.50.235:8911/api/order/submit
+卡密提取接口:http://39.108.50.235:8911/api/card/get
+查询接口接口:http://39.108.50.235:8911/api/order/query
+余额查询接口:http://39.108.50.235:8911/api/account/balance

+ 17 - 59
helper/refill/api/yl/yunchonggongfs/config.php

@@ -5,75 +5,33 @@ namespace refill\yunchonggongfs;
 
 class config
 {
-    const ORDER_URL = 'http://119.23.54.206:8911/api/order/submit';
-    const QUERY_URL = 'http://119.23.54.206:8911/api/order/query';
-    const BALANCE_URL = 'http://119.23.54.206:8911/api/account/balance';
+    const ORDER_URL = 'http://39.108.50.235:8911/api/order/submit';
+    const QUERY_URL = 'http://39.108.50.235:8911/api/order/query';
+    const BALANCE_URL = 'http://39.108.50.235:8911/api/account/balance';
 
-    const APP_ID = 'rUKN5DzuzQ';
-    const APP_SECRET = 'uFDmKKqPFxEEZLLs';
+    const APP_ID = 'MEEJnMSL9H';
+    const APP_SECRET = 'cpWFarCEUDnCcMWQ';
     const NOTIFY_URL = BASE_SITE_URL . "/mobile/callback/refill_yunchonggongfs.php";
 
     const ProvinceItemId = [
-        15	=> [
-                    30  => 100050,
-                    50  => 100051,
-                    100 => 100052,
-                    200 => 100053
-                ], //'山东',
         25	=> [
-                    30  => 100054,
-                    50  => 100055,
-                    100 => 100056,
-                    200 => 100057
-                ], //'云南',
-        28	=> [
-                    30  => 100066,
-                    50  => 100067,
-                    100 => 100068,
-                    200 => 100069
-                ], //'甘肃',
+            30  => 100012,
+            50  => 100013,
+            100 => 100014,
+            200 => 100015
+        ], //'云南',
         24	=> [
-                    30  => 100070,
-                    50  => 100071,
-                    100 => 100072,
-                    200 => 100073
-                ], //'贵州',
-        4	=> [
-                    30  => 100074,
-                    50  => 100075,
-                    100 => 100076,
-                    200 => 100077
-                ], //'山西',
-        10	=> [
-                    30  => 100078,
-                    50  => 100079,
-                    100 => 100080,
-                    200 => 100081
-                ], //'江苏',
-        11	=> [
-                    30  => 100082,
-                    50  => 100083,
-                    100 => 100084,
-                    200 => 100085
-                ], //'浙江'
-        13	=> [
-                    30  => 100086,
-                    50  => 100087,
-                    100 => 100088,
-                    200 => 100089
-                ] //'福建'
+            30  => 100016,
+            50  => 100017,
+            100 => 100018,
+            200 => 100019
+        ], //'贵州',
     ];
     const ExtHeaders = ['Content-Type:application/x-www-form-urlencoded;charset=utf-8'];
     const ERRCODES = ['-10', '-12', '-13', '-14', '-15', '-16', '-18', '-21'];
     //key格式 卡类型-面值-regin_no
     const Price = [
-        "4-10-24" => 9.41, "4-20-24" => 18.82, "4-30-24" => 28.23, "4-50-24" => 47.05, "4-100-24" => 94.1, "4-200-24" => 188.2, "4-300-24" => 282.3, "4-500-24" => 470.5,//贵州 24
-        "4-10-15" => 9.47, "4-20-15" => 18.94, "4-30-15" => 28.41, "4-50-15" => 47.35, "4-100-15" => 94.7, "4-200-15" => 189.4, "4-300-15" => 284.1, "4-500-15" => 473.5,//山东 15
-        "4-10-25" => 9.47, "4-20-25" => 18.94, "4-30-25" => 28.41, "4-50-25" => 47.35, "4-100-25" => 94.7, "4-200-25" => 189.4, "4-300-25" => 284.1, "4-500-25" => 473.5,//云南 25
-        "4-10-28" => 9.47, "4-20-28" => 18.94, "4-30-28" => 28.41, "4-50-28" => 47.35, "4-100-28" => 94.7, "4-200-28" => 189.4, "4-300-28" => 284.1, "4-500-28" => 473.5,//甘肃 28
-        "4-10-4" => 9.47, "4-20-4" => 18.94, "4-30-4" => 28.41, "4-50-4" => 47.35, "4-100-4" => 94.7, "4-200-4" => 189.4, "4-300-4" => 284.1, "4-500-4" => 473.5,//山西 4
-        "4-10-10" => 9.47, "4-20-10" => 18.94, "4-30-10" => 28.41, "4-50-10" => 47.35, "4-100-10" => 94.7, "4-200-10" => 189.4, "4-300-10" => 284.1, "4-500-10" => 473.5,//江苏 10
-        "4-10-11" => 9.47, "4-20-11" => 18.94, "4-30-11" => 28.41, "4-50-11" => 47.35, "4-100-11" => 94.7, "4-200-11" => 189.4, "4-300-11" => 284.1, "4-500-11" => 473.5,//浙江 11
-        "4-10-13" => 9.47, "4-20-13" => 18.94, "4-30-13" => 28.41, "4-50-13" => 47.35, "4-100-13" => 94.7, "4-200-13" => 189.4, "4-300-13" => 284.1, "4-500-13" => 473.5,//福建 13
+        "4-30-24" => 28.23, "4-50-24" => 47.05, "4-100-24" => 94.1, "4-200-24" => 188.2,//贵州 24
+        "4-30-25" => 28.23, "4-50-25" => 47.05, "4-100-25" => 94.1, "4-200-25" => 188.2,//云南 25
     ];
 }

+ 12 - 11
helper/refill/api/yl/yunchonggongfs/开户信息.txt

@@ -1,13 +1,14 @@
-后台地址:http://119.23.54.206:8888
-帐号:linfen
-密码:449997
-二级密码:uxXx3131
-appId:rUKN5DzuzQ
-appSecret:uFDmKKqPFxEEZLLs
+后台地址:http://39.108.50.235:8888
+帐号:yf11
+密码:407453
+二级密码:yiMu5052
+appId:MEEJnMSL9H
+appSecret:cpWFarCEUDnCcMWQ
 后台-商品列表,可查看已配置商品信息
 后台-安全中心,可配置IP白名单
-接口文档:https://www.showdoc.com.cn/900133176881927?page_id=4798465261069610
-下单接口地址:http://119.23.54.206:8911/api/order/submit
-查单接口地址:http://119.23.54.206:8911/api/order/query
-余额接口地址:http://119.23.54.206:8911/api/account/balance
-提卡接口地址:http://119.23.54.206:8911/api/card/get
+接口文档:https://www.showdoc.com.cn/1686453783298366/7925312871840290
+话费直充接口:http://39.108.50.235:8911/api/hf/order/submit
+通用直充接口:http://39.108.50.235:8911/api/order/submit
+卡密提取接口:http://39.108.50.235:8911/api/card/get
+查询接口接口:http://39.108.50.235:8911/api/order/query
+余额查询接口:http://39.108.50.235:8911/api/account/balance

+ 9 - 8
helper/refill/util.php

@@ -516,14 +516,15 @@ class util
     }
 
     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-    public static function monitor_submit($mchid,$spec,$card_type,$mch_amount)
+    public static function monitor_submit($mchid, $spec, $card_type, $mch_amount, $time)
     {
-        queue\MonitorClient::instance()->onSubmit($mchid,time(),$spec,$card_type,$mch_amount);
+        $time = intval($time);
+        queue\MonitorClient::instance()->onSubmit($mchid,$time,$spec,$card_type,$mch_amount);
     }
 
-    public static function monitor_callback($mchid,$spec,$card_type,$mch_amount,$channel_amount,$succ)
+    public static function monitor_callback($mchid,$spec,$card_type,$mch_amount,$channel_amount,$succ,$time)
     {
-        queue\MonitorClient::instance()->onCallback($mchid,time(),$spec,$card_type,floatval($mch_amount),floatval($channel_amount),$succ);
+        queue\MonitorClient::instance()->onCallback($mchid,$time,$spec,$card_type,floatval($mch_amount),floatval($channel_amount),$succ);
     }
 
     public static function monitor_netchk($chname,$succ)
@@ -531,14 +532,14 @@ class util
         queue\MonitorClient::instance()->onNetCheck($chname, time(),$succ);
     }
 
-    public static function monitor_commit($chname, $spec, $card_type, $channel_amount)
+    public static function monitor_commit($chname, $spec, $card_type, $channel_amount,$commit_time)
     {
-        queue\MonitorClient::instance()->onCommit($chname, time(), $spec, $card_type, $channel_amount);
+        queue\MonitorClient::instance()->onCommit($chname, $commit_time, $spec, $card_type, $channel_amount);
     }
 
-    public static function monitor_notify($chname, $spec, $card_type, $channel_amount, $period, $succ)
+    public static function monitor_notify($chname, $spec, $card_type, $channel_amount, $period, $succ,$commit_time)
     {
-        queue\MonitorClient::instance()->onNotify($chname, time(), $spec, $card_type, floatval($channel_amount), $period, $succ);
+        queue\MonitorClient::instance()->onNotify($chname, $commit_time, $spec, $card_type, floatval($channel_amount), $period, $succ);
     }
     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     public static function set_order_channels($mchid,$mchorder,$datas)

+ 4 - 0
mobile/callback/refill_huoshenguo_fs.php

@@ -0,0 +1,4 @@
+<?php
+
+refill\util::push_notify('huoshenguo_fs',$_POST);
+echo ('ok');

+ 88 - 29
plot/app.py

@@ -1,7 +1,3 @@
-from gevent import monkey
-from gevent.pywsgi import WSGIServer
-from gevent import signal as geventsig
-import gevent
 from flask import Flask
 import base64
 from io import BytesIO
@@ -28,42 +24,104 @@ logging.basicConfig(filename='/var/www/html/data/log/flask.log',
                     level=logging.DEBUG)
 logger = logging.getLogger('plot')
 
+from refill import ChannelPainter, MerchantPainter
+from refill import filter_chname, filter_cardtype, filter_mchids, get_channels, get_mchids
+
+
+def parse_parmeter():
+    end_time = request.args.get('end_time')
+    end_time = None if end_time is None else int(end_time.strip())
+
+    start_time = request.args.get('start_time')
+    start_time = None if start_time is None else int(start_time.strip())
+
+    card_types = request.args.get('card_types')
+    card_types = filter_cardtype(card_types)
+
+    spec = request.args.get('spec')
+    if spec is not None:
+        spec = int(spec.strip())
+
+    filter_wave = request.args.get('filter_wave')
+    if filter_wave is not None:
+        filter_wave = int(filter_wave.strip())
+
+    return start_time, end_time, card_types, spec, filter_wave
+
+
+def onError(ex):
+    logger.error(ex)
+    return jsonify({'state': 'fail'})
+
+
 @app.route('/plot/ch_ratio')
 def ch_ratio():
-    from refill import ChannelPainter
-    from refill import filter_chname,filter_cardtype
-
     try:
         logger.debug('start chratio')
-        cur_time = int(time.time())
+        start_time, end_time, card_types, spec, filter_wave = parse_parmeter()
+        chnames = request.args.get('chnames')
+        chnames = filter_chname(chnames)
 
-        start_time = request.args.get('start_time')
-        start_time = cur_time - 7200 if start_time is None else int(start_time.strip())
+        painter = ChannelPainter(start_time=start_time, end_time=end_time, chnames=chnames, card_types=card_types, spec=spec, filter_wave=filter_wave)
+        buf, ratios = painter.paint()
+        data = base64.b64encode(buf.getbuffer()).decode("ascii")
 
-        end_time = request.args.get('end_time')
-        end_time = cur_time if end_time is None else int(end_time.strip())
+        return jsonify({'img': data, 'ratios': ratios, 'state': 'success'})
+    except Exception as ex:
+        return onError(ex)
 
-        stime = lambda t: time.strftime('%d-%H:%M:%S', time.localtime(t))
-        logger.debug("start_time=%s end_time=%s",stime(start_time) ,stime(end_time))
 
-        chnames = request.args.get('chnames')
-        chnames = filter_chname(chnames)
+@app.route('/plot/channels')
+def channels():
+    try:
+        channels = get_channels()
+        return jsonify(channels)
+    except Exception as ex:
+        logger.error(ex)
+        return jsonify([])
 
-        card_types = request.args.get('card_types')
-        card_types = filter_cardtype(card_types)
 
-        spec = request.args.get('spec')
-        if spec is not None:
-            spec = int(spec.strip())
+@app.route('/plot/mchids')
+def mchids():
+    try:
+        mchids = get_mchids()
+        return jsonify(mchids)
+    except Exception as ex:
+        logger.error(ex)
+        return jsonify([])
+
 
-        painter = ChannelPainter(start_time=start_time, end_time=end_time, chnames=chnames, card_types=card_types, spec=spec)
-        buf = painter.paint()
+@app.route('/plot/mch_ratio')
+def mch_ratio():
+    try:
+        logger.debug('start mchratio')
+        start_time, end_time, card_types, spec, filter_wave = parse_parmeter()
+        mchids = request.args.get('mchids')
+        mchids = filter_mchids(mchids)
 
+        painter = MerchantPainter(start_time=start_time, end_time=end_time, mchids=mchids, card_types=card_types, spec=spec, filter_wave=filter_wave)
+        buf, ratios = painter.paint_ratios()
         data = base64.b64encode(buf.getbuffer()).decode("ascii")
-        return f"<img src='data:image/png;base64,{data}'/>"
+
+        return jsonify({'img': data, 'ratios': ratios, 'state': 'success'})
     except Exception as ex:
-        logger.error(ex)
-        return f"<img src='data:image/png;base64,{[]}'/>"
+        return onError(ex)
+
+
+@app.route('/plot/mch_order_send')
+def mch_order_send():
+    try:
+        logger.debug('start mch_order_send')
+        start_time, end_time, card_types, spec, filter_wave = parse_parmeter()
+        mchids = request.args.get('mchids')
+        mchids = filter_mchids(mchids)
+
+        painter = MerchantPainter(start_time=start_time, end_time=end_time, mchids=mchids, card_types=card_types, spec=spec, filter_wave=filter_wave)
+        buf, mchids = painter.paint_refilling()
+        data = base64.b64encode(buf.getbuffer()).decode("ascii")
+        return jsonify({'img': data, 'mchids': mchids, 'state': 'success'})
+    except Exception as ex:
+        return onError(ex)
 
 
 @app.route('/plot/index')
@@ -89,7 +147,7 @@ def index():
     else:
         interval = int(interval)
 
-    buf = dataCenter.draw_plot(time_stamp, 
+    buf = dataCenter.draw_plot(time_stamp,
                                interval=interval,
                                chname=chname,
                                quality=quality,
@@ -109,6 +167,7 @@ def days():
     dates = dates[0:30]
     return jsonify(dates)
 
+
 @app.route('/plot/paths')
 def paths():
     time_stamp = request.args.get('time_stamp')
@@ -162,7 +221,7 @@ def mchplot():
 
 
 if __name__ == "__main__":
-    debug_mode = False
+    debug_mode = True
     if debug_mode:
         app.run(debug=True, host='0.0.0.0', port=5000)
     else:
@@ -174,4 +233,4 @@ if __name__ == "__main__":
         http_server = WSGIServer(('0.0.0.0', 5000), app)
         geventsig.signal(sig.SIGTERM, lambda: http_server.stop())
         geventsig.signal(sig.SIGINT, lambda: http_server.stop())
-        http_server.serve_forever()
+        http_server.serve_forever()

+ 78 - 20
plot/plot_control.py

@@ -11,47 +11,105 @@ import time
 import signal as sig
 import sys, getopt
 
-from refill import ChannelPainter
-from refill import filter_chname,filter_cardtype
+from refill import ChannelPainter,MerchantPainter
+from refill import filter_chname, filter_cardtype, filter_mchids, get_channels, get_mchids
 
 logging.basicConfig(filename='/var/www/html/data/log/flask.log',
                     format='%(levelname)10s  %(asctime)s  %(name)10s %(thread)d %(message)s',
                     level=logging.DEBUG)
 logger = logging.getLogger('plot')
 
+def parse_parmeter():
+    end_time = request.args.get('end_time')
+    end_time = None if end_time is None else int(end_time.strip())
+
+    start_time = request.args.get('start_time')
+    start_time = None if start_time is None else int(start_time.strip())
+
+    card_types = request.args.get('card_types')
+    card_types = filter_cardtype(card_types)
+
+    spec = request.args.get('spec')
+    if spec is not None:
+        spec = int(spec.strip())
+
+    filter_wave = request.args.get('filter_wave')
+    if filter_wave is not None:
+        filter_wave = int(filter_wave.strip())
+
+    return start_time,end_time,card_types,spec,filter_wave
+
+def onError(ex):
+    logger.error(ex)
+    data = base64.b64encode(b'').decode("ascii")
+    return f"<img src='data:image/png;base64,{data}'/>"
+
+
 @app.route('/plot/ch_ratio')
 def ch_ratio():
     try:
         logger.debug('start chratio')
-        cur_time = int(time.time())
+        start_time, end_time, card_types, spec, filter_wave = parse_parmeter()
+        chnames = request.args.get('chnames')
+        chnames = filter_chname(chnames)
 
-        start_time = request.args.get('start_time')
-        start_time = cur_time - 7200 if start_time is None else int(start_time.strip())
+        painter = ChannelPainter(start_time=start_time, end_time=end_time, chnames=chnames, card_types=card_types, spec=spec, filter_wave=filter_wave)
+        buf = painter.paint()
+        data = base64.b64encode(buf.getbuffer()).decode("ascii")
 
-        end_time = request.args.get('end_time')
-        end_time = cur_time if end_time is None else int(end_time.strip())
+        return f"<img src='data:image/png;base64,{data}'/>"
+    except Exception as ex:
+        return onError(ex)
 
-        stime = lambda t: time.strftime('%d-%H:%M:%S', time.localtime(t))
-        logger.debug("start_time=%s end_time=%s",stime(start_time) ,stime(end_time))
+@app.route('/plot/channels')
+def channels():
+    try:
+        channels = get_channels()
+        return jsonify(channels)
+    except Exception as ex:
+        logger.error(ex)
+        return jsonify([])
 
-        chnames = request.args.get('chnames')
-        chnames = filter_chname(chnames)
+@app.route('/plot/mchids')
+def mchids():
+    try:
+        mchids = get_mchids()
+        return jsonify(mchids)
+    except Exception as ex:
+        logger.error(ex)
+        return jsonify([])
 
-        card_types = request.args.get('card_types')
-        card_types = filter_cardtype(card_types)
+@app.route('/plot/mch_ratio')
+def mch_ratio():
+    try:
+        logger.debug('start mchratio')
+        start_time, end_time, card_types, spec, filter_wave = parse_parmeter()
+        mchids = request.args.get('mchids')
+        mchids = filter_mchids(mchids)
 
-        spec = request.args.get('spec')
-        if spec is not None:
-                spec = int(spec.strip())
+        painter = MerchantPainter(start_time=start_time, end_time=end_time, mchids=mchids, card_types=card_types, spec=spec, filter_wave=filter_wave)
+        buf = painter.paint_ratios()
+        data = base64.b64encode(buf.getbuffer()).decode("ascii")
 
-        painter = ChannelPainter(start_time=start_time, end_time=end_time, chnames=chnames, card_types=card_types, spec=spec)
-        buf = painter.paint()
+        return f"<img src='data:image/png;base64,{data}'/>"
+    except Exception as ex:
+        return onError(ex)
 
+@app.route('/plot/mch_order_send')
+def mch_order_send():
+    try:
+        logger.debug('start mch_order_send')
+        start_time, end_time, card_types, spec, filter_wave = parse_parmeter()
+        mchids = request.args.get('mchids')
+        mchids = filter_mchids(mchids)
+
+        painter = MerchantPainter(start_time=start_time, end_time=end_time, mchids=mchids, card_types=card_types, spec=spec, filter_wave=filter_wave)
+        buf = painter.paint_refilling()
         data = base64.b64encode(buf.getbuffer()).decode("ascii")
+
         return f"<img src='data:image/png;base64,{data}'/>"
     except Exception as ex:
-        logger.error(ex)
-        return f"<img src='data:image/png;base64,{[]}'/>"
+        return onError(ex)
 
 
 if __name__ == "__main__":

+ 1 - 1
plot/qreader.py

@@ -14,7 +14,7 @@ def handle_sigterm(*args):
 
 if __name__ == '__main__':
     try:
-        opts, args = getopt.getopt(sys.argv[1:],"h:p:",["host=",'port='])
+        opts, args = getopt.getopt(sys.argv[1:], "h:p:", ["host=", 'port='])
     except Exception as ex:
         log.error(ex)
         sys.exit(2)

+ 49 - 17
plot/refill/ChannelPainter.py

@@ -11,7 +11,15 @@ import time as time
 import logging
 logger = logging.getLogger('painter')
 
-def allpathes(reader: ChannelReader, tuple_pathes: dict, days: list, spec=None):
+_all_channels = set()
+def add_channel(channel):
+    if channel not in _all_channels:
+        _all_channels.add(channel)
+
+def get_channels():
+    return list(_all_channels)
+
+def ratio_pathes(reader: ChannelReader, tuple_pathes: dict, days: list, spec=None):
     count = len(days)
     show_detail = True if len(list(tuple_pathes.keys())) == 1 else False
     if show_detail == False:
@@ -20,7 +28,8 @@ def allpathes(reader: ChannelReader, tuple_pathes: dict, days: list, spec=None):
         all_datas = None
 
     for name, tup in tuple_pathes.items():
-        ch_datas = reader.init_data(count)
+        add_channel(name)
+        mch_datas = reader.init_data(count)
         for _card_type, _spec in tup:
             if spec is not None and _spec != spec:
                 continue
@@ -34,7 +43,7 @@ def allpathes(reader: ChannelReader, tuple_pathes: dict, days: list, spec=None):
                 data = reader.read(day, name, _card_type, _spec)
                 if data is not None:
                     column_pos = i * 86400
-                    view = ch_datas[:, column_pos:column_pos + 86400]
+                    view = mch_datas[:, column_pos:column_pos + 86400]
                     view += data
 
                     if show_detail:
@@ -43,20 +52,30 @@ def allpathes(reader: ChannelReader, tuple_pathes: dict, days: list, spec=None):
             if show_detail:
                 yield name, _card_type, _spec, detail_datas
         if all_datas is not None:
-            all_datas += ch_datas
-        yield name, None, None, ch_datas
+            all_datas += mch_datas
+        yield name, None, None, mch_datas
 
     if show_detail == False:
         yield 'all', None, None, all_datas
 
 
 class ChannelPainter(object):
-    def __init__(self, start_time: int, end_time: int, chnames: set = None, card_types: set = None, spec: int = None):
+    def __init__(self, start_time: int, end_time: int, chnames: set = None, card_types: set = None, spec: int = None, filter_wave: int = None):
         self._reader = ChannelReader()
-        _start_time, _end_time, self._chnames, self._card_types, self._spec = start_time, end_time, chnames, card_types, spec
+        _start_time, _end_time, self._chnames, self._card_types, self._spec, self._filter_wave = start_time, end_time, chnames, card_types, spec, filter_wave
+
+        if _end_time is None:
+            _end_time = int(time.time())
+        end_time = self._reader.near_stamp(_end_time, False)
+        if end_time is None:
+            raise Exception('data is empty')
+
+        if _start_time is None or start_time > end_time:
+            _start_time = end_time - 7200
 
-        start_time = self._reader.near_stamp(_start_time,True)
-        end_time = self._reader.near_stamp(_end_time,False)
+        start_time = self._reader.near_stamp(_start_time, True)
+        if start_time is None:
+            raise Exception('data is empty')
 
         stime = lambda t: time.strftime('%d-%H:%M:%S', time.localtime(t))
         logger.debug("start_time=%s end_time=%s",stime(start_time) ,stime(end_time))
@@ -96,26 +115,39 @@ class ChannelPainter(object):
     def paint(self):
         reader = ChannelReader()
         tuple_pathes = reader.many_tuple_path(self._days, self._chnames, self._card_types, self._spec)
-        gen = allpathes(self._reader, tuple_pathes, self._days, self._spec)
+        gen = ratio_pathes(self._reader, tuple_pathes, self._days, self._spec)
         if len(self._days) == 0:
-            return []
+            return BytesIO()
 
         day_stamp = self._days[0]
         fig_create, fig_flush = self._fig_funs()
         ax, fig = fig_create()
         x = np.array([d - self._start_time for d in range(self._start_time, self._end_time)])
 
-        window = np.ones(600) / 600
+        if self._filter_wave is not None and self._filter_wave > 1:
+            window = np.ones(self._filter_wave) / self._filter_wave
+        else:
+            window = None
+
+        chname_ratios = []
         for _chname, _card_type, _spec, _data in gen:
             succ, count, y = calc_chratios(_data, pos_map, self._start_time - day_stamp, self._end_time - day_stamp)
-            print(_chname)
-            y = np.convolve(y, window, 'same')
-            ax.plot(x, y, ls='-', label=self._label(chname=_chname, succ=succ, count=count, card_type=_card_type, spec=_spec))
+            y = np.convolve(y, window, 'same') if window is not None else y
+            label, ratio = self._label(chname=_chname, succ=succ, count=count, card_type=_card_type, spec=_spec)
+            ax.plot(x, y, ls='-', label=label)
+            if _card_type is None and _spec is None and _chname != 'all':
+                chname_ratios.append((_chname, ratio))
 
         ticks = [d - self._start_time for d in range(self._start_time, self._end_time + 1, self._interval)]
         xlables = [time.strftime('%d-%H:%M:%S', time.localtime(d + self._start_time)) for d in ticks]
+        buf = fig_flush(ax, fig, ticks, xlables)
+
+        chname_ratios = sorted(chname_ratios, key=lambda x: (x[1], x[0]), reverse=True)
+        result = []
+        for name, ratio in chname_ratios:
+            result.append(f'{name}:{ratio}')
 
-        return fig_flush(ax, fig, ticks, xlables)
+        return buf, result
 
     def _label(self, chname, succ, count, card_type=None, spec=None):
         _card_type = None
@@ -145,4 +177,4 @@ class ChannelPainter(object):
             ratio = 0.00
         lable += f":{succ}/{count}={ratio}%"
 
-        return lable
+        return lable, ratio

+ 2 - 3
plot/refill/ChannelReader.py

@@ -5,7 +5,7 @@ import numpy as np
 import re
 from collections import defaultdict
 
-__all__ = ['MerchantReader']
+__all__ = ['ChannelReader']
 
 import logging
 
@@ -89,5 +89,4 @@ class ChannelReader(DataReadStream):
             return hfive[path]
         else:
             return None
-
-    pass
+    pass

+ 33 - 11
plot/refill/ChannelWriter.py

@@ -11,12 +11,19 @@ log = logging.getLogger('writer')
 class ChannelWriter(DataWriteStream):
     def write(self, method, params):
         self._lock.acquire()
+        flush = True
         if method == 'ch_commit':
             self._onCommit(params)
         elif method == 'ch_succ':
             self._onSucc(params)
         elif method == 'ch_fail':
             self._onFail(params)
+        else:
+            flush = False
+
+        if flush:
+            hfive = self.file
+            hfive.flush()
         self._lock.release()
         pass
 
@@ -27,8 +34,12 @@ class ChannelWriter(DataWriteStream):
         chname, time, spec, card_type, channel_amount = parse(params)
         dset, pos = self.path_pos(chname, time, spec, card_type)
 
-        dset[pos_map.commit_count, pos] += 1
-        dset[pos_map.commit_amounts, pos] += channel_amount
+        rows = [pos_map.commit_count, pos_map.commit_amounts]
+        vals = [1, channel_amount]
+        dset[rows, pos] += vals
+
+        # dset[pos_map.commit_count, pos] += 1
+        # dset[pos_map.commit_amounts, pos] += channel_amount
         pass
 
     def _onSucc(self, params):
@@ -38,9 +49,13 @@ class ChannelWriter(DataWriteStream):
         chname, time, spec, card_type, channel_amount, period = parse(params)
         dset, pos = self.path_pos(chname, time, spec, card_type)
 
-        dset[pos_map.succ_count, pos] += 1
-        dset[pos_map.succ_amounts, pos] += channel_amount
-        dset[pos_map.succ_periods, pos] += period
+        rows = [pos_map.succ_count, pos_map.succ_amounts, pos_map.succ_periods]
+        vals = [1, channel_amount, period]
+        dset[rows, pos] += vals
+
+        # dset[pos_map.succ_count, pos] += 1
+        # dset[pos_map.succ_amounts, pos] += channel_amount
+        # dset[pos_map.succ_periods, pos] += period
         pass
 
     def _onFail(self, params):
@@ -50,19 +65,26 @@ class ChannelWriter(DataWriteStream):
         chname, time, spec, card_type, channel_amount, period = parse(params)
         dset, pos = self.path_pos(chname, time, spec, card_type)
 
-        dset[pos_map.fail_count, pos] += 1
-        dset[pos_map.fail_amounts, pos] += channel_amount
-        dset[pos_map.fail_periods, pos] += period
+        rows = [pos_map.fail_count, pos_map.fail_amounts, pos_map.fail_periods]
+        vals = [1, channel_amount, period]
+        dset[rows, pos] += vals
+
+        # dset[pos_map.fail_count, pos] += 1
+        # dset[pos_map.fail_amounts, pos] += channel_amount
+        # dset[pos_map.fail_periods, pos] += period
         pass
 
     def path_pos(self, chname, time, spec, card_type):
         today = day_stamp(time)
         path = f'/{self._version}/{today}/{chname}/{card_type}/{spec}'
 
-        log.debug("%s,%s",'ChannelWriter',path)
         hfive = self.file
         if path not in hfive:
             dim = pos_map.dim()
-            hfive[path] = np.zeros((dim, 86400))
+            dset = hfive.create_dataset(path, (dim, 86400), chunks=(dim, 3600))
+            dset[:, :] = np.zeros((dim, 86400))
+            hfive.flush()
+        else:
+            dset = hfive[path]
 
-        return hfive[path], time - today
+        return dset, time - today

+ 8 - 3
plot/refill/DataStream.py

@@ -6,7 +6,8 @@ import h5py
 from enum import IntEnum
 import threading
 
-__all__ = ['DataWriteStream', 'DataReadStream', 'day_stamp', 'EMchPosmap', 'EChPosmap', 'ENetPosmap', 'open_hdf5', 'time_border']
+__all__ = ['DataWriteStream', 'DataReadStream', 'day_stamp', 'EMchPosmap', 'EChPosmap', 'ENetPosmap', 'open_hdf5', 'time_border',
+           'calc_interval']
 
 import logging
 
@@ -25,9 +26,9 @@ def day_stamp(stamp):
 
 def open_hdf5(file, is_wirte):
     if is_wirte:
-        return h5py.File(file, 'a')
+        return h5py.File(file, 'a', libver='latest') #, swmr=True
     else:
-        return h5py.File(file, 'r')
+        return h5py.File(file, 'r', libver='latest') #plot/test_h5py.py
 
 
 def time_border(interval, time_stamp, lt):
@@ -108,6 +109,10 @@ class DataReadStream(metaclass=ABCMeta):
     def __init__(self, hfive):
         self._hfive = hfive
         self._days = self._getdays()
+        stime = lambda t: time.strftime('%d-%H:%M:%S', time.localtime(t))
+        sdays = [stime(day) for day in self._days]
+        logger.debug(sdays)
+
         logger.debug(self._days)
 
     def __del__(self):

+ 296 - 0
plot/refill/MerchantPainter.py

@@ -0,0 +1,296 @@
+from .DataStream import EMchPosmap as pos_map, span_days, time_border, calc_interval
+from .MerchantReader import MerchantReader
+from matplotlib.figure import Figure
+from matplotlib import ticker
+from io import BytesIO
+import numpy as np
+from .algorithm import calc_mchratios, calc_morder_send
+import time as time
+
+import logging
+
+logger = logging.getLogger('painter')
+
+_all_mchids = set()
+def add_mchid(mchid):
+    if mchid not in _all_mchids:
+        _all_mchids.add(mchid)
+
+def get_mchids():
+    return list(_all_mchids)
+
+def allpathes(reader: MerchantReader, tuple_pathes: dict, days: list, spec=None):
+    count = len(days)
+    show_detail = True if len(list(tuple_pathes.keys())) == 1 else False
+    if show_detail == False:
+        all_datas = reader.init_data(count)
+    else:
+        all_datas = None
+
+    for mchid, tup in tuple_pathes.items():
+        add_mchid(mchid)
+        ch_datas = reader.init_data(count)
+        for _card_type, _spec in tup:
+            if spec is not None and _spec != spec:
+                continue
+
+            if show_detail:
+                detail_datas = reader.init_data(count)
+            else:
+                detail_datas = None
+
+            for i, day in enumerate(days):
+                data = reader.read(day, mchid, _card_type, _spec)
+                if data is not None:
+                    column_pos = i * 86400
+                    view = ch_datas[:, column_pos:column_pos + 86400]
+                    view += data
+
+                    if show_detail:
+                        view = detail_datas[:, column_pos:column_pos + 86400]
+                        view += data
+            if show_detail:
+                yield mchid, _card_type, _spec, detail_datas
+        if all_datas is not None:
+            all_datas += ch_datas
+        yield mchid, None, None, ch_datas
+
+    if show_detail == False:
+        yield 'all', None, None, all_datas
+
+
+class MerchantPainter(object):
+    def __init__(self, start_time: int, end_time: int, mchids: set = None, card_types: set = None, spec: int = None, filter_wave: int = None):
+        self._reader = MerchantReader()
+        _start_time, _end_time, self._mchids, self._card_types, self._spec, self._filter_wave = start_time, end_time, mchids, card_types, spec, filter_wave
+
+        if _end_time is None:
+            _end_time = int(time.time())
+        end_time = self._reader.near_stamp(_end_time, False)
+        if end_time is None:
+            raise Exception('data is empty')
+
+        if _start_time is None or start_time > end_time:
+            _start_time = end_time - 7200
+
+        start_time = self._reader.near_stamp(_start_time, True)
+        if start_time is None:
+            raise Exception('data is empty')
+
+        stime = lambda t: time.strftime('%d-%H:%M:%S', time.localtime(t))
+        logger.debug("near_stamp start_time %d , %s end_time=%s", start_time, stime(start_time), stime(end_time))
+
+        interval = calc_interval(start_time, end_time)
+        start_time = time_border(interval, start_time, True)
+        end_time = time_border(interval, end_time, False)
+        logger.debug("time_border start_time %d , %s end_time=%s", start_time, stime(start_time), stime(end_time))
+
+        self._days = span_days(start_time, end_time)
+
+        stime = lambda t: time.strftime('%d-%H:%M:%S', time.localtime(t))
+        sdays = [stime(day) for day in self._days]
+        logger.debug(sdays)
+
+        self._start_time = start_time
+        self._end_time = end_time
+        self._interval = interval
+        pass
+
+    def _fig_funs(self):
+        def create():
+            fig = Figure(figsize=(19, 8))
+            ax = fig.subplots()
+            ax.set_title('success ratio')
+            ax.set(xlabel='time', ylabel='ratio')
+            return ax, fig
+
+        def flush(ax, fig, xticks=None, xlables=None, yticks=None, ylables=None):
+            ax.yaxis.set_major_formatter(ticker.PercentFormatter(xmax=1, decimals=4))
+            if xticks is not None:
+                ax.set_xticks(ticks=xticks)
+            if xlables is not None:
+                ax.set_xticklabels(xlables)
+
+            if yticks is not None:
+                ax.set_yticks(ticks=yticks)
+            if ylables is not None:
+                ax.set_yticklabels(ylables)
+
+            fig.autofmt_xdate()
+            ax.grid()
+            fig.subplots_adjust(left=0.1, right=0.8, top=0.95, bottom=0.1)
+            ax.legend(bbox_to_anchor=(1, 1), loc='upper left')
+
+            buf = BytesIO()
+            fig.savefig(buf, format="png")
+            return buf
+
+        return create, flush
+
+    def paint_ratios(self):
+        tuple_pathes = self._reader.many_tuple_path(self._days, self._mchids, self._card_types, self._spec)
+        gen = allpathes(self._reader, tuple_pathes, self._days, self._spec)
+        if len(self._days) == 0:
+            return BytesIO()
+
+        day_stamp = self._days[0]
+        fig_create, fig_flush = self._fig_funs()
+        ax, fig = fig_create()
+        x = np.array([d - self._start_time for d in range(self._start_time, self._end_time)])
+
+        if self._filter_wave is not None and self._filter_wave > 1:
+            window = np.ones(self._filter_wave) / self._filter_wave
+        else:
+            window = None
+
+        mchid_ratios = []
+        for _mchid, _card_type, _spec, _data in gen:
+            succ, count, y = calc_mchratios(_data, pos_map, self._start_time - day_stamp, self._end_time - day_stamp)
+            y = np.convolve(y, window, 'same') if window is not None else y
+            label, ratio = self._label(chname=_mchid, succ=succ, count=count, card_type=_card_type, spec=_spec)
+            ax.plot(x, y, ls='-', label=label)
+            if _card_type is None and _spec is None and type(_mchid) is int:
+                mchid_ratios.append((_mchid, ratio))
+
+        xticks = [d - self._start_time for d in range(self._start_time, self._end_time + 1, self._interval)]
+        xlables = [time.strftime('%d-%H:%M:%S', time.localtime(d + self._start_time)) for d in xticks]
+
+        buf = fig_flush(ax, fig, xticks=xticks, xlables=xlables)
+
+        mchid_ratios = sorted(mchid_ratios, key=lambda x: (x[1], x[0]), reverse=True)
+        result = []
+        for mchid,ratio in mchid_ratios:
+            result.append(f'{mchid}:{ratio}')
+
+        return buf, result
+
+    def _label(self, chname, succ, count, card_type=None, spec=None):
+        _card_type = None
+        if card_type == 1:
+            _card_type = 'SY'
+        elif card_type == 2:
+            _card_type = 'SH'
+        elif card_type == 4:
+            _card_type = 'YD'
+        elif card_type == 5:
+            _card_type = 'LT'
+        elif card_type == 6:
+            _card_type = 'DX'
+        elif card_type == 7:
+            _card_type = 'TH'
+
+        lable = f"{chname}"
+        if _card_type is not None:
+            lable += f"-{_card_type}"
+
+        if spec is not None:
+            lable += f"-{spec}"
+
+        if count > 0:
+            ratio = round(succ * 100 / count, 2)
+        else:
+            ratio = 0.00
+        lable += f":{succ}/{count}={ratio}%"
+
+        return lable,ratio
+
+    ##################################################################################################################################################
+    def _fig_bar_funs(self):
+        def create():
+            fig = Figure(figsize=(19, 16))
+            ax_count, ax_amount = fig.subplots(2, 1)
+            ax_count.set_title('sending order count monitor')
+            ax_count.set(xlabel='merchant id', ylabel='count')
+
+            ax_amount.set_title('sending order amount monitor')
+            ax_amount.set(xlabel='merchant id', ylabel='amount')
+            return ax_count, ax_amount, fig
+
+        def end(ax, xticks=None, xlables=None, yticks=None, ylables=None):
+            if xticks is not None:
+                ax.set_xticks(ticks=xticks)
+            if xlables is not None:
+                ax.set_xticklabels(xlables)
+
+            if yticks is not None:
+                ax.set_yticks(ticks=yticks)
+            if ylables is not None:
+                ax.set_yticklabels(ylables)
+
+            ax.legend()
+            ax.grid()
+
+        def flush(fig):
+            fig.autofmt_xdate()
+            buf = BytesIO()
+            fig.savefig(buf, format="png")
+            return buf
+
+        return create, end,flush
+
+    def paint_refilling(self):
+        tuple_pathes = self._reader.many_tuple_path(self._days, self._mchids, self._card_types, self._spec)
+        gen = allpathes(self._reader, tuple_pathes, self._days, self._spec)
+        if len(self._days) == 0:
+            return BytesIO()
+
+        day_stamp = self._days[0]
+        fig_create, fig_end, fig_flush = self._fig_bar_funs()
+        ax_count, ax_amount, fig = fig_create()
+
+        lables = list()
+        datas = list()
+        mchids = list()
+        for _mchid, _card_type, _spec, _data in gen:
+            lables.append(f"{_mchid}")
+            logger.debug(_mchid)
+            mchids.append(_mchid)
+            ret = calc_morder_send(_data, pos_map, self._start_time - day_stamp, self._end_time - day_stamp)
+            datas.append(ret)
+            send_count, submit_count, succ_count, fail_count, submit_amount, succ_amount, fail_amount, send_amount, lack = ret
+            logger.debug("send=%d submit=%d succ=%d fail=%d",send_count, submit_count, succ_count, fail_count)
+            cratio = succ_count / (succ_count + fail_count + 0.0001)
+            aratio = succ_amount / (succ_amount + fail_amount + 0.0001)
+            logger.debug("cratio=%.2f aratio=%.2f", cratio, aratio)
+
+        send_count, submit_count, succ_count, fail_count, submit_amount, succ_amount, fail_amount, send_amount, lack = zip(*datas)
+        self.draw_count(ax_count, lables, send_count, submit_count, succ_count, fail_count, fig_end)
+        self.draw_amount(ax_amount, lables, submit_amount, succ_amount, fail_amount, send_amount, lack, fig_end)
+
+        return fig_flush(fig), mchids
+
+    def draw_count(self, ax, lables, send_count, submit_count, succ_count, fail_count, fig_end):
+        width = 0.24
+        x_asix = np.arange(len(lables))
+
+        rect_send = ax.bar(x_asix - width * 0.5, list(send_count), width, label='sending', align='center')
+        rect_submit = ax.bar(x_asix - width * 1.5, list(submit_count), width, label='summit',align='center')
+        rect_succ = ax.bar(x_asix + width * 0.5, list(succ_count), width, label='succ',align='center')
+        rect_fail = ax.bar(x_asix + width * 1.5, list(fail_count), width, label='fail', align='center')
+
+        ax.bar_label(rect_send, padding=0, rotation=270, fmt='%d')
+        ax.bar_label(rect_submit, padding=0, rotation=270, fmt='%d')
+        ax.bar_label(rect_succ, padding=0, rotation=270, fmt='%d')
+        ax.bar_label(rect_fail, padding=0, rotation=270, fmt='%d')
+
+        fig_end(ax, xticks=x_asix, xlables=lables)
+        pass
+
+    def draw_amount(self, ax, lables, submit_amount, succ_amount, fail_amount, send_amount, lack, fig_end):
+        width = 0.18
+        x_asix = np.arange(len(lables))
+
+        rect_submit = ax.bar(x_asix - width * 2, list(submit_amount), width, label='summit',align='center')
+        rect_send = ax.bar(x_asix - width, list(send_amount), width, label='sending', align='center')
+        rect_msucc = ax.bar(x_asix, list(lack), width, label='may succ', align='center')
+        rect_succ = ax.bar(x_asix + width, list(succ_amount), width, label='succ',align='center')
+        rect_fail = ax.bar(x_asix + width * 2, list(fail_amount), width, label='fail', align='center')
+
+        ax.bar_label(rect_submit, padding=0, rotation=270, fmt='%.2f')
+        ax.bar_label(rect_send, padding=0, rotation=270, fmt='%.2f')
+        ax.bar_label(rect_msucc, padding=0, rotation=270, fmt='%.2f')
+        ax.bar_label(rect_succ, padding=0, rotation=270, fmt='%.2f')
+        ax.bar_label(rect_fail, padding=0, rotation=270, fmt='%.2f')
+
+        fig_end(ax, xticks=x_asix, xlables=lables)
+        pass

+ 68 - 2
plot/refill/MerchantReader.py

@@ -2,6 +2,8 @@
 from .DataStream import DataReadStream, day_stamp,open_hdf5
 from .DataStream import EMchPosmap as pos_map
 import numpy as np
+import re
+from collections import defaultdict
 
 __all__ = ['MerchantReader']
 
@@ -19,6 +21,70 @@ class MerchantReader(DataReadStream):
         super(MerchantReader, self).__del__()
         pass
 
-    def read(self, path):
-        pass
+    def tuple_path(self, day: int, mchids: set = None, card_types: set = None, spec: int = None):
+        def parse(path):
+            items = re.split(r'/', path)
+            (_prifix, _version, today, mchid, card_type, spec) = items
+            return int(mchid), int(card_type), int(spec)
+
+        tuples = defaultdict(list)
+        pathes = self.datasets(day)
+        for path in pathes:
+            _mchid, _card_type, _spec = parse(path)
+            tuples[_mchid].append((_card_type, _spec))
+
+        def name_filter(tuples, mchids):
+            all = True if mchids is None or len(mchids) == 0 else False
+            if all:
+                return tuples
+            else:
+                result = defaultdict(list)
+                for mchid, tup in tuples.items():
+                    if mchid in mchids:
+                        result[mchid] = tup
+                return result
+
+        tuples = name_filter(tuples, mchids)
+
+        def typespec_filter(tuples, card_types, spec):
+            result = defaultdict(list)
+            for name, ls in tuples.items():
+                for tup in ls:
+                    _card_type, _spec = tup
+                    if _card_type in card_types:
+                        if spec is None or _spec == spec:
+                            result[name].append((_card_type, _spec))
+
+            return result
+        tuples = typespec_filter(tuples,card_types,spec)
+        return tuples
+
+    def many_tuple_path(self, days: list, mchids: set = None, card_types: set = None, spec: int = None):
+        def merge(l,r):
+            for mchid,ls in l.items():
+                if mchid in r:
+                    r[mchid].union(set(ls))
+                else:
+                    r[mchid] = set(ls)
+            return r
+
+        all = defaultdict(set)
+        for day in days:
+            tuples = self.tuple_path(day, mchids, card_types, spec)
+            all = merge(tuples,all)
+
+        return all
+
+    def init_data(self, days):
+        dim = pos_map.dim()
+        return np.zeros((dim, 86400 * days))
+
+    def read(self, day_stamp, mchid, card_type, spec):
+        path = f'/{self._version}/{day_stamp}/{mchid}/{card_type}/{spec}'
+
+        hfive = self.file
+        if path in hfive:
+            return hfive[path]
+        else:
+            return None
     pass

+ 32 - 9
plot/refill/MerchantWriter.py

@@ -11,12 +11,19 @@ log = logging.getLogger('writer')
 class MerchantWriter(DataWriteStream):
     def write(self, method, params):
         self._lock.acquire()
+        flush = True
         if method == 'mch_submit':
             self._onSubmit(params)
         elif method == 'mch_succ':
             self._onSucc(params)
         elif method == 'mch_fail':
             self._onFail(params)
+        else:
+            flush = False
+
+        if flush:
+            hfive = self.file
+            hfive.flush()
         self._lock.release()
 
     def _onSubmit(self, params):
@@ -26,8 +33,12 @@ class MerchantWriter(DataWriteStream):
         mchid, time, spec, card_type, mch_amount = parse(params)
         dset, pos = self.path_pos(mchid, time, spec, card_type)
 
-        dset[pos_map.submit_count, pos] += 1
-        dset[pos_map.submit_amounts, pos] += mch_amount
+        rows = [pos_map.submit_count, pos_map.submit_amounts]
+        vals = [1, mch_amount]
+        dset[rows, pos] += vals
+
+        # dset[pos_map.submit_count, pos] += 1
+        # dset[pos_map.submit_amounts, pos] += mch_amount
         pass
 
     def _onSucc(self, params):
@@ -37,9 +48,13 @@ class MerchantWriter(DataWriteStream):
         mchid, time, spec, card_type, mch_amount, channel_amount = parse(params)
         dset, pos = self.path_pos(mchid, time, spec, card_type)
 
-        dset[pos_map.succ_count, pos] += 1
-        dset[pos_map.succ_mch_amounts, pos] += mch_amount
-        dset[pos_map.succ_ch_amounts, pos] += channel_amount
+        rows = [pos_map.succ_count, pos_map.succ_mch_amounts, pos_map.succ_ch_amounts]
+        vals = [1, mch_amount, channel_amount]
+        dset[rows, pos] += vals
+
+        # dset[pos_map.succ_count, pos] += 1
+        # dset[pos_map.succ_mch_amounts, pos] += mch_amount
+        # dset[pos_map.succ_ch_amounts, pos] += channel_amount
         pass
 
     def _onFail(self, params):
@@ -49,8 +64,12 @@ class MerchantWriter(DataWriteStream):
         mchid, time, spec, card_type, mch_amount = parse(params)
         dset, pos = self.path_pos(mchid, time, spec, card_type)
 
-        dset[pos_map.fail_count, pos] += 1
-        dset[pos_map.fail_mch_amounts, pos] += mch_amount
+        rows = [pos_map.fail_count, pos_map.fail_mch_amounts]
+        vals = [1, mch_amount]
+        dset[rows, pos] += vals
+
+        # dset[pos_map.fail_count, pos] += 1
+        # dset[pos_map.fail_mch_amounts, pos] += mch_amount
         pass
 
     def path_pos(self, mchid, time, spec, card_type):
@@ -61,6 +80,10 @@ class MerchantWriter(DataWriteStream):
         hfive = self.file
         if path not in hfive:
             dim = pos_map.dim()
-            hfive[path] = np.zeros((dim, 86400))
+            dset = hfive.create_dataset(path, (dim, 86400), chunks=(dim, 3600))
+            dset[:, :] = np.zeros((dim, 86400))
+            hfive.flush()
+        else:
+            dset = hfive[path]
 
-        return hfive[path], time - today
+        return dset, time - today

+ 14 - 5
plot/refill/NetchkWriter.py

@@ -13,10 +13,17 @@ log = logging.getLogger('writer')
 class NetchkWriter(DataWriteStream):
     def write(self, method, params):
         self._lock.acquire()
+        flush = True
         if method == 'net_succ':
             self._onSucc(params)
         elif method == 'net_fail':
             self._onFail(params)
+        else:
+            flush = False
+
+        if flush:
+            hfive = self.file
+            hfive.flush()
         self._lock.release()
 
     def _onSucc(self, params):
@@ -42,14 +49,16 @@ class NetchkWriter(DataWriteStream):
     def path_pos(self, chname, time):
         today = day_stamp(time)
         path = f'/{self._version}/{today}/{chname}'
-
         log.debug("%s,%s", 'NetchkWriter', path)
 
         hfive = self.file
         if path not in hfive:
             dim = pos_map.dim()
-            hfive[path] = np.zeros((dim, 86400))
-
-        return hfive[path], time - today
-
+            dset = hfive.create_dataset(path, (dim, 86400), chunks=(dim, 3600))
+            dset[:, :] = np.zeros((dim, 86400))
+            hfive.flush()
+        else:
+            dset = hfive[path]
+            
+        return dset, time - today
     pass

+ 17 - 2
plot/refill/QueueListener.py

@@ -1,4 +1,5 @@
 import json
+import time
 import time as stime
 import redis
 from threading import Thread
@@ -49,7 +50,7 @@ class QueueListener(object):
     def prepare_data(self):
             try:
                 for _key, val in self._mHandlers.items():
-                    hfive = open_hdf5(val['name'],True)
+                    hfive = open_hdf5(val['name'], True)
                     if _key == 'merchant':
                         val['handler'] = MerchantWriter(hfive)
                     elif _key == 'channel':
@@ -107,7 +108,7 @@ class QueueListener(object):
                 log.info(handler)
 
 
-def read_queue(listener: QueueListener, redis,queue):
+def bread_queue(listener: QueueListener, redis,queue):
     while listener.has_stop() == False:
         item = redis.brpop(queue, 1)
         if item is None:
@@ -122,5 +123,19 @@ def read_queue(listener: QueueListener, redis,queue):
                 log.error(ex)
     pass
 
+def read_queue(listener: QueueListener, redis,queue):
+    while listener.has_stop() == False:
+        item = redis.rpop(queue) #测试每秒性能在三万多.
+        if item is None:
+            time.sleep(1)
+        else:
+            try:
+                val = json.loads(item)
+                method = val['method']
+                params = val['params']
+                listener.write(method, params)
+            except Exception as ex:
+                log.error(ex)
+    pass
 
 queueListener = QueueListener()

+ 0 - 0
plot/refill/__init__.py


部分文件因文件數量過多而無法顯示