544782275@qq.com 3 jaren geleden
bovenliggende
commit
83a0986e54
100 gewijzigde bestanden met toevoegingen van 21773 en 3 verwijderingen
  1. 0 3
      .gitignore
  2. 1 0
      addons/.htaccess
  3. 0 0
      addons/shopro/.addonrc
  4. 134 0
      addons/shopro/Shopro.php
  5. 67 0
      addons/shopro/bootstrap.js
  6. 79 0
      addons/shopro/command/Chat.php
  7. 7 0
      addons/shopro/config/cache.php
  8. 5977 0
      addons/shopro/config/menu.php
  9. 38 0
      addons/shopro/controller/ActivityGroupon.php
  10. 63 0
      addons/shopro/controller/Address.php
  11. 32 0
      addons/shopro/controller/Base.php
  12. 40 0
      addons/shopro/controller/Cart.php
  13. 64 0
      addons/shopro/controller/Category.php
  14. 52 0
      addons/shopro/controller/Coupons.php
  15. 64 0
      addons/shopro/controller/Express.php
  16. 26 0
      addons/shopro/controller/Faq.php
  17. 28 0
      addons/shopro/controller/Feedback.php
  18. 115 0
      addons/shopro/controller/Goods.php
  19. 40 0
      addons/shopro/controller/GoodsComment.php
  20. 293 0
      addons/shopro/controller/Index.php
  21. 60 0
      addons/shopro/controller/Kefu.php
  22. 53 0
      addons/shopro/controller/Live.php
  23. 38 0
      addons/shopro/controller/Notification.php
  24. 129 0
      addons/shopro/controller/Order.php
  25. 69 0
      addons/shopro/controller/OrderAftersale.php
  26. 27 0
      addons/shopro/controller/OrderExpress.php
  27. 382 0
      addons/shopro/controller/Pay.php
  28. 27 0
      addons/shopro/controller/ScoreGoodsSkuPrice.php
  29. 51 0
      addons/shopro/controller/Share.php
  30. 101 0
      addons/shopro/controller/Sms.php
  31. 31 0
      addons/shopro/controller/Store.php
  32. 727 0
      addons/shopro/controller/User.php
  33. 38 0
      addons/shopro/controller/UserBank.php
  34. 28 0
      addons/shopro/controller/UserSign.php
  35. 56 0
      addons/shopro/controller/UserWalletApply.php
  36. 26 0
      addons/shopro/controller/UserWalletLog.php
  37. 197 0
      addons/shopro/controller/Wechat.php
  38. 39 0
      addons/shopro/controller/chat/Index.php
  39. 34 0
      addons/shopro/controller/store/Apply.php
  40. 48 0
      addons/shopro/controller/store/Base.php
  41. 39 0
      addons/shopro/controller/store/Order.php
  42. 26 0
      addons/shopro/controller/store/Store.php
  43. 30 0
      addons/shopro/exception/Exception.php
  44. 133 0
      addons/shopro/helper.php
  45. 122 0
      addons/shopro/hooks.php
  46. 11 0
      addons/shopro/info.ini
  47. 5290 0
      addons/shopro/install.sql
  48. 57 0
      addons/shopro/job/ActivityAutoOper.php
  49. 57 0
      addons/shopro/job/ActivityGrouponAutoOper.php
  50. 25 0
      addons/shopro/job/BaseJob.php
  51. 40 0
      addons/shopro/job/Notification.php
  52. 135 0
      addons/shopro/job/OrderAutoOper.php
  53. 66 0
      addons/shopro/job/OrderPayed.php
  54. 74 0
      addons/shopro/job/Wechat.php
  55. 84 0
      addons/shopro/lang/zh-cn.php
  56. 8 0
      addons/shopro/lang/zh-cn/common.php
  57. 39 0
      addons/shopro/lang/zh-cn/user.php
  58. 116 0
      addons/shopro/library/Export.php
  59. 230 0
      addons/shopro/library/Express.php
  60. 25 0
      addons/shopro/library/Hook.php
  61. 0 0
      addons/shopro/library/Oauth.php
  62. 71 0
      addons/shopro/library/Oper.php
  63. 291 0
      addons/shopro/library/PayService.php
  64. 68 0
      addons/shopro/library/Redis.php
  65. 327 0
      addons/shopro/library/Wechat.php
  66. 138 0
      addons/shopro/library/apple-signin/ASDecoder.php
  67. 7 0
      addons/shopro/library/apple-signin/LICENSE
  68. 8 0
      addons/shopro/library/apple-signin/Vendor/BeforeValidException.php
  69. 8 0
      addons/shopro/library/apple-signin/Vendor/ExpiredException.php
  70. 158 0
      addons/shopro/library/apple-signin/Vendor/JWK.php
  71. 380 0
      addons/shopro/library/apple-signin/Vendor/JWT.php
  72. 30 0
      addons/shopro/library/apple-signin/Vendor/LICENSE
  73. 8 0
      addons/shopro/library/apple-signin/Vendor/SignatureInvalidException.php
  74. 169 0
      addons/shopro/library/chat/Events.php
  75. 49 0
      addons/shopro/library/chat/FileMonitor/start.php
  76. 39 0
      addons/shopro/library/chat/Linker.php
  77. 1085 0
      addons/shopro/library/chat/Online.php
  78. 269 0
      addons/shopro/library/chat/Sender.php
  79. 98 0
      addons/shopro/library/chat/Start.php
  80. 23 0
      addons/shopro/library/chat/config.php
  81. 290 0
      addons/shopro/library/chat/linker/CustomerService.php
  82. 257 0
      addons/shopro/library/chat/linker/User.php
  83. 2 0
      addons/shopro/library/chat/log/.gitignore
  84. 2 0
      addons/shopro/library/chat/start_for_win/shopro_chat_start_for_win.bat
  85. 6 0
      addons/shopro/library/chat/start_for_win/start_businessworker.php
  86. 6 0
      addons/shopro/library/chat/start_for_win/start_gateway.php
  87. 6 0
      addons/shopro/library/chat/start_for_win/start_register.php
  88. 267 0
      addons/shopro/library/chat/traits/GetLinkerTrait.php
  89. 136 0
      addons/shopro/library/chat/traits/SenderTrait.php
  90. 17 0
      addons/shopro/library/notify/Notifiable.php
  91. 68 0
      addons/shopro/library/notify/Notify.php
  92. 41 0
      addons/shopro/library/notify/channel/Database.php
  93. 55 0
      addons/shopro/library/notify/channel/Email.php
  94. 57 0
      addons/shopro/library/notify/channel/Sms.php
  95. 53 0
      addons/shopro/library/notify/channel/WxMiniProgram.php
  96. 53 0
      addons/shopro/library/notify/channel/WxOfficeAccount.php
  97. 53 0
      addons/shopro/library/notify/channel/WxOfficeAccountBizsend.php
  98. 660 0
      addons/shopro/library/traits/ActivityCache.php
  99. 418 0
      addons/shopro/library/traits/Groupon.php
  100. 212 0
      addons/shopro/library/traits/StockSale.php

+ 0 - 3
.gitignore

@@ -1,8 +1,5 @@
 /nbproject/
-/thinkphp/
-/vendor/
 /runtime/*
-/addons/*
 /application/admin/command/Install/*.lock
 /public/assets/libs/
 /public/assets/addons/*

+ 1 - 0
addons/.htaccess

@@ -0,0 +1 @@
+deny from all

File diff suppressed because it is too large
+ 0 - 0
addons/shopro/.addonrc


+ 134 - 0
addons/shopro/Shopro.php

@@ -0,0 +1,134 @@
+<?php
+
+namespace addons\shopro;
+
+use think\Addons;
+use app\common\library\Menu;
+use app\admin\model\AuthRule;
+use addons\shopro\library\Hook;
+use think\Exception;
+use think\exception\PDOException;
+
+/**
+ * Shopro插件 v1.0.7
+ */
+class Shopro extends Addons
+{
+
+    /**
+     * 插件安装方法
+     * @return bool
+     */
+    public function install()
+    { 
+        $menu = self::getMenu();
+        Menu::create($menu['new']);
+        return true;
+    }
+
+    /**
+     * 插件卸载方法
+     * @return bool
+     */
+    public function uninstall()
+    {
+        Menu::delete('shopro');
+        return true;
+    }
+
+    /**
+     * 插件启用方法
+     */
+    public function enable()
+    {
+        Menu::enable('shopro');
+        return true;
+    }
+
+    /**
+     * 插件更新方法
+     */
+    public function upgrade()
+    {
+        $menu = self::getMenu();
+        if(method_exists(Menu::class, 'upgrade')){
+            Menu::upgrade('shopro', $menu['new']);
+        }else {
+            //使用Shopro自带的更新操作
+            self::menuCreateOrUpdate($menu['new'], $menu['old']);
+        }
+
+        return true;
+    }
+
+    /**
+     * 插件禁用方法
+     */
+    public function disable()
+    {
+        Menu::disable('shopro');
+         return true;
+    }
+
+
+    /**
+     * 应用初始化
+     */
+    public function appInit()
+    {
+        // 公共方法
+        require_once __DIR__ . '/helper.php';
+
+        // 全局注册行为事件
+        Hook::register();
+
+        if (request()->isCli()) {
+            \think\Console::addDefaultCommands([
+                'addons\shopro\command\Chat'
+            ]);
+        }
+    }
+
+    private static function getMenu()
+    {
+        $newMenu = [];
+        $config_file = ADDON_PATH . "shopro" . DS . 'config' . DS . "menu.php";
+        if (is_file($config_file)) {
+            $newMenu = include $config_file;
+        }
+        $oldMenu = AuthRule::where('name','like',"shopro%")->select();
+        $oldMenu = array_column($oldMenu, null, 'name');
+        return ['new' => $newMenu, 'old' => $oldMenu];
+    }
+
+    private static function menuCreateOrUpdate($newMenu, $oldMenu, $parent = 0)
+    {
+        if (!is_numeric($parent)) {
+            $parentRule = AuthRule::getByName($parent);
+            $pid = $parentRule ? $parentRule['id'] : 0;
+        } else {
+            $pid = $parent;
+        }
+        $allow = array_flip(['file', 'name', 'title', 'icon', 'condition', 'remark', 'ismenu', 'weigh']);
+        foreach ($newMenu as $k => $v) {
+            $hasChild = isset($v['sublist']) && $v['sublist'] ? true : false;
+            $data = array_intersect_key($v, $allow);
+            $data['ismenu'] = isset($data['ismenu']) ? $data['ismenu'] : ($hasChild ? 1 : 0);
+            $data['icon'] = isset($data['icon']) ? $data['icon'] : ($hasChild ? 'fa fa-list' : 'fa fa-circle-o');
+            $data['pid'] = $pid;
+            $data['status'] = 'normal';
+            try {
+                if (!isset($oldMenu[$data['name']])) {
+                    $menu = AuthRule::create($data);
+                }else{
+                    $menu = $oldMenu[$data['name']];
+                }
+                if ($hasChild) {
+                    self::menuCreateOrUpdate($v['sublist'], $oldMenu, $menu['id']);
+                }
+            } catch (PDOException $e) {
+                new Exception($e->getMessage());
+            }
+        }
+    }
+}

+ 67 - 0
addons/shopro/bootstrap.js

@@ -0,0 +1,67 @@
+if (Config.modulename == 'admin' && Config.controllername == 'index' && Config.actionname == 'index') {
+    require.config({
+        paths: {
+            'vue': "../addons/shopro/libs/vue",
+            'moment': "../addons/shopro/libs/moment",
+            'text': "../addons/shopro/libs/require-text",
+            'chat': '../addons/shopro/libs/chat',
+            'ELEMENT': '../addons/shopro/libs/element/element',
+        },
+        shim: {
+            'ELEMENT': {
+                deps: ['css!../addons/shopro/libs/element/element.css']
+            },
+        },
+    });
+    require(['vue', 'jquery', 'chat', 'text!../addons/shopro/chat.html', 'ELEMENT', 'moment'], function (Vue, $, Chat, ChatTemp, ELEMENT, Moment) {
+
+        Vue.use(ELEMENT);
+
+        var wsUri;
+        Fast.api.ajax({
+            url: 'shopro/chat/index/init',
+            loading: false,
+            type: 'GET'
+        }, function (ret, res) {
+            if (res.data.config.type == 'shopro') {
+
+                let wg = 'ws';
+                if (res.data.config.system.is_ssl == 1) {
+                    wg = 'wss';
+                }
+                wsUri = wg + '://' + window.location.hostname + ':' + res.data.config.system.gateway_port;
+                // 反向代理
+                if (res.data.config.system.is_ssl == 1 && res.data.config.system.ssl_type == 'reverse_proxy') {
+                    wsUri = wg + '://' + window.location.hostname + '/websocket/';
+                }
+                $("body").append(`<div id="chatTemplateContainer" style="display:none"></div>
+                    <div id="chatService"><Chat :passvalue="obj"></Chat></div>`);
+
+                $("#chatTemplateContainer").append(ChatTemp);
+
+                new Vue({
+                    el: "#chatService",
+                    data() {
+                        return {
+                            obj: {
+                                commonWordsList: res.data.fast_reply,
+                                token: res.data.token,
+                                wsUri: wsUri,
+                                expire_time: res.data.expire_time,
+                                customer_service_id: res.data.customer_service.id,
+                                adminData: res.data,
+                                emoji_list: res.data.emoji
+                            }
+                        }
+                    }
+                });
+
+            }
+            return false;
+        }, function (ret, res) {
+            if (res.msg == '') {
+                return false;
+            }
+        })
+    });
+}

+ 79 - 0
addons/shopro/command/Chat.php

@@ -0,0 +1,79 @@
+<?php
+/**
+ * run with command
+ * php start.php start
+ */
+
+namespace addons\shopro\command;
+
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Argument;
+use think\console\Output;
+use Workerman\Worker;
+use addons\shopro\library\chat\Start;
+
+/**
+ *
+ */
+class Chat extends Command
+{
+
+    protected function configure()
+    {
+        $this->setName('shopro:chat')
+            ->addArgument('action', Argument::OPTIONAL, "action start [d]|stop|restart|status")
+            ->addArgument('type', Argument::OPTIONAL, "d -d")
+            ->setHelp('此命令是用来启动 shopro 商城的客服服务端进程')
+            ->setDescription('shopro 客服');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        global $argv;
+        $action = trim($input->getArgument('action'));
+        $type   = trim($input->getArgument('type')) ? '-d' : '';
+
+        $argv[0] = 'shopro:chat';
+        $argv[1] = $action;
+        $argv[2] = $type ? '-d' : '';
+        $this->start($input, $output);
+    }
+
+    private function start($input, $output)
+    {
+        if (strpos(strtolower(PHP_OS), 'win') === 0) {
+            $output->writeln("<error>GatewayWorker Not Support On Windows.</error>");
+            exit(1);
+        }
+
+        // 检查扩展
+        if (!extension_loaded('pcntl')) {
+            $output->writeln("<error>Please install pcntl extension.</error>");
+            exit(1);
+        }
+
+        if (!extension_loaded('posix')) {
+            $output->writeln("<error>Please install posix extension.</error>");
+            exit(1);
+        }
+
+        // 实例化启动类
+        $startServer = new Start();
+
+        // 启动 register
+        $startServer->register();
+
+        // 启动 businessWorker
+        $startServer->businessWorker();
+
+        // 启动 gateway
+        $startServer->gateway();
+
+        // 设置日志
+        $startServer->setLog(__DIR__ . '/../');
+
+        // 运行所有服务
+        Worker::runAll();
+    }
+}

+ 7 - 0
addons/shopro/config/cache.php

@@ -0,0 +1,7 @@
+<?php 
+ return array (
+  'table_name' => '',
+  'self_path' => '
+application/admin/lang/zh-cn/shopro',
+  'update_data' => '',
+);

+ 5977 - 0
addons/shopro/config/menu.php

@@ -0,0 +1,5977 @@
+<?php
+/**
+ * 菜单配置文件
+ */
+
+return array (
+  0 => 
+  array (
+    'type' => 'file',
+    'name' => 'shopro',
+    'title' => 'Shopro商城',
+    'icon' => 'fa fa-home',
+    'url' => '',
+    'condition' => '',
+    'remark' => '',
+    'ismenu' => 1,
+    'menutype' => NULL,
+    'extend' => '',
+    'weigh' => 0,
+    'sublist' => 
+    array (
+      0 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/config',
+        'title' => '商城配置',
+        'icon' => 'fa fa-sliders',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/config/index',
+            'title' => '查看',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/config/add',
+            'title' => '添加',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/config/edit',
+            'title' => '编辑',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          3 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/config/del',
+            'title' => '删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          4 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/config/multi',
+            'title' => '批量更新',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          5 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/config/platform',
+            'title' => '平台配置',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+        ),
+      ),
+      1 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/decorate',
+        'title' => '店铺装修',
+        'icon' => 'fa fa-paint-brush',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/lists',
+            'title' => '模版管理',
+            'icon' => 'fa fa-cubes',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/add',
+            'title' => '添加',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/edit',
+            'title' => '编辑',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          3 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/del',
+            'title' => '删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          4 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/multi',
+            'title' => '批量更新',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          5 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/recyclebin',
+            'title' => '回收站',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          6 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/destroy',
+            'title' => '真实删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          7 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/restore',
+            'title' => '还原',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          8 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/dodecorate',
+            'title' => '装修',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          9 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/preview',
+            'title' => '预览页面',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          10 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/designer',
+            'title' => '设计师模板',
+            'icon' => 'fa fa-cube',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/decorate/use_designer_template',
+                'title' => '使用',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          11 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/custom',
+            'title' => '自定义页面',
+            'icon' => 'fa fa-clone',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/decorate/select',
+                'title' => '自定义选择',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          12 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/publish',
+            'title' => '发布',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          13 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/dodecorate_save',
+            'title' => '装修保存',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          14 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/copy',
+            'title' => '复制模板',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          15 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/index',
+            'title' => '查看',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          16 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/decorate/down',
+            'title' => '模板下架',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+        ),
+      ),
+      2 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/coupons',
+        'title' => '优惠券',
+        'icon' => 'fa fa-money',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/coupons/index',
+            'title' => '查看',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/coupons/recyclebin',
+            'title' => '回收站',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/coupons/add',
+            'title' => '添加',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          3 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/coupons/edit',
+            'title' => '编辑',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          4 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/coupons/del',
+            'title' => '删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          5 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/coupons/destroy',
+            'title' => '真实删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          6 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/coupons/restore',
+            'title' => '还原',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          7 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/coupons/multi',
+            'title' => '批量更新',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          8 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/coupons/select',
+            'title' => '选择优惠券',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+        ),
+      ),
+      3 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/dispatch',
+        'title' => '配送设置',
+        'icon' => 'fa fa-gears',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/dispatch/dispatch',
+            'title' => '发货模板',
+            'icon' => 'fa fa-ambulance',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/dispatch/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/dispatch/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/dispatch/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/dispatch/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/dispatch/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/dispatch/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/dispatch/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/dispatch/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              8 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/dispatch/select',
+                'title' => '选择模板',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/dispatch/selfetch',
+            'title' => '到店/自提',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/selfetch/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/selfetch/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/selfetch/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/selfetch/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/selfetch/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/selfetch/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/selfetch/destroy',
+                'title' => '销毁',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/dispatch/express',
+            'title' => '物流快递',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/express/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/express/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/express/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/express/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/express/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/express/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/express/destroy',
+                'title' => '销毁',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          3 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/dispatch/store',
+            'title' => '商家配送',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/store/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/store/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/store/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/store/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/store/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/store/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/store/destroy',
+                'title' => '销毁',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          4 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/dispatch/autosend',
+            'title' => '自动发货',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/autosend/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/autosend/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/autosend/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/autosend/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/autosend/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/autosend/destroy',
+                'title' => '销毁',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/dispatch/autosend/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          5 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/express',
+            'title' => '快递公司',
+            'icon' => 'fa fa-automobile',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/express/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/express/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/express/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/express/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/express/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/express/select',
+                'title' => '选择',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+        ),
+      ),
+      4 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/product',
+        'title' => '商品管理',
+        'icon' => 'fa fa-archive',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/category',
+            'title' => '商品分类',
+            'icon' => 'fa fa-sitemap',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/category/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/category/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/category/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/category/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/category/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/category/select',
+                'title' => '选择商品组',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/category/update',
+                'title' => '保存更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/goods/goods',
+            'title' => '商品管理',
+            'icon' => 'fa fa-shopping-bag',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/goods/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/goods/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/goods/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/goods/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/goods/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/goods/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/goods/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/goods/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              8 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/goods/select',
+                'title' => '选择商品',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              9 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/goods/detail',
+                'title' => '查看详情',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              10 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/goods/setstatus',
+                'title' => '商品状态',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/goods/service',
+            'title' => '服务标签',
+            'icon' => 'fa fa-tags',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/service/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/service/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/service/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/service/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/service/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/service/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/service/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/service/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          3 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/goods/comment',
+            'title' => '商品评价',
+            'icon' => 'fa fa-pencil-square',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/comment/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/comment/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/comment/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/comment/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/comment/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/comment/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/comment/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/comment/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          4 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/goods/stock_warning',
+            'title' => '库存预警',
+            'icon' => 'fa fa-warning',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/stock_warning/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/stock_warning/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/stock_warning/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/stock_warning/destroy',
+                'title' => '销毁',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/goods/stock_warning/addstock',
+                'title' => '补货',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+        ),
+      ),
+      5 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/material',
+        'title' => '资料管理',
+        'icon' => 'fa fa-file-text',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/richtext',
+            'title' => '富文本',
+            'icon' => 'fa fa-language',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/richtext/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/richtext/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/richtext/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/richtext/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/richtext/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/richtext/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/richtext/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/richtext/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              8 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/richtext/select',
+                'title' => '选择富文本',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/link',
+            'title' => '页面链接',
+            'icon' => 'fa fa-unlink',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/link/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/link/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/link/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/link/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/link/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/link/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/link/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/link/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              8 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/link/select',
+                'title' => '选择链接',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/area',
+            'title' => '省市区数据',
+            'icon' => 'fa fa-percent',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/area/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/area/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/area/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/area/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/area/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/area/select',
+                'title' => '选择省市区',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          3 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/faq',
+            'title' => '常见问题',
+            'icon' => 'fa fa-info-circle',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/faq/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/faq/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/faq/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/faq/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/faq/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/faq/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/faq/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/faq/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          4 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_fake',
+            'title' => '虚拟用户',
+            'icon' => 'fa fa-user-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/user_fake/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/user_fake/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/user_fake/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/user_fake/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/user_fake/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/user_fake/random_user',
+                'title' => '添加虚拟用户',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+        ),
+      ),
+      6 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/activity',
+        'title' => '活动中心',
+        'icon' => 'fa fa-font-awesome',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/activity/activity',
+            'title' => '营销活动',
+            'icon' => 'fa fa-star',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              8 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/createorupdatesku',
+                'title' => '编辑活动规格',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              9 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/select',
+                'title' => '选择活动',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              10 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/sku',
+                'title' => '活动规格',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              11 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/detail',
+                'title' => '活动详情',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              12 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/all',
+                'title' => '活动记录',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              13 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity/gettype',
+                'title' => '活动类型',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/activity/activity_sku_price',
+            'title' => '商品规格',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity_sku_price/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity_sku_price/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity_sku_price/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity_sku_price/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity_sku_price/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity_sku_price/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity_sku_price/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/activity_sku_price/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/activity/groupon',
+            'title' => '拼团列表',
+            'icon' => 'fa fa-modx',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/groupon/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/groupon/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/groupon/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/groupon/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/groupon/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/groupon/detail',
+                'title' => '详情',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/activity/groupon/addfictitious',
+                'title' => '确定拼团虚拟人',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+        ),
+      ),
+      7 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/app',
+        'title' => '应用',
+        'icon' => 'fa fa-suitcase',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/app/score_shop',
+            'title' => '积分商城',
+            'icon' => 'fa fa-database',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/score_shop/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/score_shop/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/score_shop/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/score_shop/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/score_shop/select',
+                'title' => '选择积分产品',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/score_shop/createorupdatesku',
+                'title' => '更编辑积分规格',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/score_shop/sku',
+                'title' => '积分规格',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/score_shop/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              8 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/score_shop/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              9 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/score_shop/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              10 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/score_shop/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/app/live',
+            'title' => '小程序直播',
+            'icon' => 'fa fa-video-camera',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/live/select',
+                'title' => '直播间选择',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/live/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/live/detail',
+                'title' => '直播详情',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/live/synclive',
+                'title' => '同步直播间',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/live/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/live/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/live/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/live/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              8 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/live/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              9 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/live/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              10 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/app/live/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+        ),
+      ),
+      8 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/user_wallet_apply',
+        'title' => '用户提现',
+        'icon' => 'fa fa-jpy',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_wallet_apply/index',
+            'title' => '查看',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_wallet_apply/recyclebin',
+            'title' => '回收站',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_wallet_apply/add',
+            'title' => '添加',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          3 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_wallet_apply/edit',
+            'title' => '编辑',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          4 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_wallet_apply/del',
+            'title' => '删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          5 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_wallet_apply/destroy',
+            'title' => '真实删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          6 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_wallet_apply/restore',
+            'title' => '还原',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          7 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_wallet_apply/multi',
+            'title' => '批量更新',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          8 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_wallet_apply/gettype',
+            'title' => '获取type',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          9 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_wallet_apply/handle',
+            'title' => '提现操作',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          10 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_wallet_apply/log',
+            'title' => '操作日志',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          11 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user_wallet_apply/export',
+            'title' => '导出',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+        ),
+      ),
+      9 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/order',
+        'title' => '订单中心',
+        'icon' => 'fa fa-file',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/order/order',
+            'title' => '订单管理',
+            'icon' => 'fa fa-file-text',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              8 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/detail',
+                'title' => '详情',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              9 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/send',
+                'title' => '发货',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              10 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/aftersalefinish',
+                'title' => '售后',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              11 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/refund',
+                'title' => '退款',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              12 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/editmemo',
+                'title' => '备注',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              13 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/gettype',
+                'title' => '订单筛选',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              14 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/refundrefuse',
+                'title' => '拒绝退款',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              15 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/export',
+                'title' => '订单导出',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              16 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/actions',
+                'title' => '操作记录',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              17 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/editconsignee',
+                'title' => '修改收货信息',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              18 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/sendstore',
+                'title' => '备货',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              19 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/deliverbyapi',
+                'title' => 'api发货',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              20 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/deliverbyinput',
+                'title' => '手动发货',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              21 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/deliverbyuploadtemplate',
+                'title' => '模板发货',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              22 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order/exportdelivery',
+                'title' => '导出发货单',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/order/order_item',
+            'title' => '订单商品明细',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order_item/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order_item/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order_item/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order_item/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order_item/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order_item/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order_item/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/order_item/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/order/aftersale',
+            'title' => '售后/退款',
+            'icon' => 'fa fa-handshake-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/destroy',
+                'title' => '真实删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/restore',
+                'title' => '还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              8 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/detail',
+                'title' => '详情',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              9 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/addlog',
+                'title' => '售后反馈',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              10 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/refuse',
+                'title' => '拒绝申请',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              11 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/refund',
+                'title' => '同意退款',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              12 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/order/aftersale/finish',
+                'title' => '售后完成',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+        ),
+      ),
+      10 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/feedback',
+        'title' => '意见反馈',
+        'icon' => 'fa fa-question-circle-o',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/feedback/index',
+            'title' => '查看',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/feedback/recyclebin',
+            'title' => '回收站',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/feedback/add',
+            'title' => '添加',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          3 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/feedback/edit',
+            'title' => '编辑',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          4 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/feedback/del',
+            'title' => '删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          5 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/feedback/destroy',
+            'title' => '真实删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          6 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/feedback/restore',
+            'title' => '还原',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          7 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/feedback/multi',
+            'title' => '批量更新',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          8 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/feedback/detail',
+            'title' => '详情',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+        ),
+      ),
+      11 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/dashboard',
+        'title' => '数据中心',
+        'icon' => 'fa fa-dashboard',
+        'url' => '',
+        'condition' => '',
+        'remark' => '用于展示当前系统中的统计数据、统计报表及重要实时数据',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/dashboard/index',
+            'title' => '查看',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/dashboard/add',
+            'title' => '添加',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/dashboard/edit',
+            'title' => '编辑',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          3 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/dashboard/del',
+            'title' => '删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          4 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/dashboard/multi',
+            'title' => '批量更新',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+        ),
+      ),
+      12 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/wechat',
+        'title' => '微信管理',
+        'icon' => 'fa fa-wechat',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/wechat/fans/index',
+            'title' => '粉丝管理',
+            'icon' => 'fa fa-users',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/fans/user',
+                'title' => '查看用户',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/fans/syncfans',
+                'title' => '同步粉丝',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/wechat/index',
+            'title' => '查看',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/wechat/add',
+            'title' => '添加',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          3 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/wechat/edit',
+            'title' => '编辑',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          4 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/wechat/del',
+            'title' => '删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          5 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/wechat/multi',
+            'title' => '批量更新',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          6 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/wechat/menu/index',
+            'title' => '菜单管理',
+            'icon' => 'fa fa-server',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/menu/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/menu/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/menu/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/menu/publish',
+                'title' => '发布',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/menu/copy',
+                'title' => '复制',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          7 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/wechat/auto_reply/index',
+            'title' => '自动回复',
+            'icon' => 'fa fa-send',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/auto_reply/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/auto_reply/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/auto_reply/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          8 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/wechat/material/index',
+            'title' => '素材管理',
+            'icon' => 'fa fa-folder-open',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/material/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/material/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/material/detail',
+                'title' => '音频播放',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/material/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/wechat/material/select',
+                'title' => '选择',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+        ),
+      ),
+      13 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/notification',
+        'title' => '消息通知',
+        'icon' => 'fa fa-bullhorn',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/notification/index',
+            'title' => '查看列表',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/notification/recyclebin',
+            'title' => '回收站',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/notification/add',
+            'title' => '添加',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          3 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/notification/edit',
+            'title' => '编辑',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          4 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/notification/del',
+            'title' => '删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          5 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/notification/destroy',
+            'title' => '真实删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          6 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/notification/restore',
+            'title' => '还原',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          7 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/notification/config',
+            'title' => '消息配置',
+            'icon' => 'fa fa-cogs',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          8 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/notification/set_template',
+            'title' => '配置模板',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          9 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/notification/set_status',
+            'title' => '切换状态',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+        ),
+      ),
+      14 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/store',
+        'title' => '门店管理',
+        'icon' => 'fa fa-bank',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/store/store',
+            'title' => '门店列表',
+            'icon' => 'fa fa-building',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/store/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/store/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/store/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/store/recyclebin',
+                'title' => '回收站',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/store/setstatus',
+                'title' => '是否禁用',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/store/select',
+                'title' => '选择',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              6 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/store/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              7 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/store/all',
+                'title' => '全部门店',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              8 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/store/restore',
+                'title' => '单个还原',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              9 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/store/destroy',
+                'title' => '单个销毁',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/store/apply',
+            'title' => '门店审核',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/apply/applyoper',
+                'title' => '操作',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/apply/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/apply/detail',
+                'title' => '详情',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/store/dashboard',
+            'title' => '门店统计',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/store/dashboard/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+        ),
+      ),
+      15 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/user/user',
+        'title' => '用户管理',
+        'icon' => 'fa fa-user',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/index',
+            'title' => '用户列表',
+            'icon' => 'fa fa-list-ul',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/user/user/change_parent_user',
+                'title' => '修改用户推荐人',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/select',
+            'title' => '选择',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/profile',
+            'title' => '编辑',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          3 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/del',
+            'title' => '删除',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          4 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/order_log',
+            'title' => '订单记录',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          5 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/login_log',
+            'title' => '登录记录',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          6 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/money_log',
+            'title' => '余额明细',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          7 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/score_log',
+            'title' => '积分明细',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          8 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/share_log',
+            'title' => '分享记录',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          9 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/goods_favorite',
+            'title' => '收藏商品',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          10 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/coupon_log',
+            'title' => '优惠券',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          11 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/goods_view',
+            'title' => '浏览足迹',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          12 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/recyclebin',
+            'title' => '回收站',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          13 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/update',
+            'title' => '更新',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          14 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/money_recharge',
+            'title' => '余额充值',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          15 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/score_recharge',
+            'title' => '积分充值',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+          16 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/group',
+            'title' => '用户分组',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/user/group/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/user/group/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/user/group/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/user/group/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          17 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/user/user/batchrecharge',
+            'title' => '批量充值',
+            'icon' => 'fa fa-circle-o',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 0,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+          ),
+        ),
+      ),
+      16 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/commission',
+        'title' => '分销中心',
+        'icon' => 'fa fa-users',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/commission/config',
+            'title' => '分销设置',
+            'icon' => 'fa fa-cog',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/commission/config/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/commission/config/save',
+                'title' => '保存',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          )
+        ),
+      ),
+      17 => 
+      array (
+        'type' => 'file',
+        'name' => 'shopro/chat',
+        'title' => '客服管理',
+        'icon' => 'fa fa-list',
+        'url' => '',
+        'condition' => '',
+        'remark' => '',
+        'ismenu' => 1,
+        'menutype' => NULL,
+        'extend' => '',
+        'weigh' => 0,
+        'sublist' => 
+        array (
+          0 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/chat/fast_reply',
+            'title' => '快捷回复',
+            'icon' => 'fa fa-commenting',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/fast_reply/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/fast_reply/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/fast_reply/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/fast_reply/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/fast_reply/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          1 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/chat/question',
+            'title' => '常见问题',
+            'icon' => 'fa fa-envelope-open',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/question/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/question/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/question/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/question/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/question/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+          2 => 
+          array (
+            'type' => 'file',
+            'name' => 'shopro/chat/customer_service',
+            'title' => '客服管理',
+            'icon' => 'fa fa-user-circle',
+            'url' => '',
+            'condition' => '',
+            'remark' => '',
+            'ismenu' => 1,
+            'menutype' => NULL,
+            'extend' => '',
+            'weigh' => 0,
+            'sublist' => 
+            array (
+              0 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/customer_service/index',
+                'title' => '查看',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              1 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/customer_service/add',
+                'title' => '添加',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              2 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/customer_service/edit',
+                'title' => '编辑',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              3 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/customer_service/del',
+                'title' => '删除',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              4 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/chat/customer_service/multi',
+                'title' => '批量更新',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+              5 => 
+              array (
+                'type' => 'file',
+                'name' => 'shopro/admin/index',
+                'title' => '管理员列表',
+                'icon' => 'fa fa-circle-o',
+                'url' => '',
+                'condition' => '',
+                'remark' => '',
+                'ismenu' => 0,
+                'menutype' => NULL,
+                'extend' => '',
+                'weigh' => 0,
+              ),
+            ),
+          ),
+        ),
+      ),
+    ),
+  ),
+);

+ 38 - 0
addons/shopro/controller/ActivityGroupon.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace addons\shopro\controller;
+
+/**
+ * 拼团开的团
+ *
+ */
+
+class ActivityGroupon extends Base
+{
+    protected $noNeedLogin = ['index'];
+    protected $noNeedRight = ['*'];
+
+
+    /**
+     * 根据商品 id 获取正在拼的团
+     */
+    public function index() {
+        $params = $this->request->get();
+
+        $this->success('团列表', \addons\shopro\model\ActivityGroupon::getActivityGroupon($params));
+    }
+
+
+    public function detail () {
+        $id = $this->request->get('id');
+
+        $this->success('团详情', \addons\shopro\model\ActivityGroupon::getActivityGrouponDetail($id));
+    }
+
+
+    public function myGroupon () {
+        $type = $this->request->get('type', 'all');
+
+        $this->success('我的拼团', \addons\shopro\model\ActivityGroupon::getMyGroupon($type));
+    }
+}

+ 63 - 0
addons/shopro/controller/Address.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\exception\Exception;
+use addons\shopro\model\UserAddress;
+use addons\shopro\model\Area;
+
+class Address extends Base
+{
+
+    protected $noNeedLogin = ['area'];
+    protected $noNeedRight = ['*'];
+
+    public function index()
+    {
+        $this->success('收货地址', UserAddress::getUserAddress());
+    }
+
+    public function defaults()
+    {
+        $this->success('默认收货地址', UserAddress::getUserDefaultAddress());
+    }
+
+    public function area()
+    {
+        $data['provinceData'] = Area::where('level', 1)->order('id asc')->field('id as value, name as label, pid, level')->select();
+        foreach ($data['provinceData'] as $k => $p) {
+            $data['cityData'][$k] = Area::where(['level' => 2, 'pid' => $p->value])->order('id asc')->field('id as value, name as label, pid, level')->select();
+            foreach ($data['cityData'][$k] as $i => $c) {
+                $data['areaData'][$k][$i] = Area::where(['level' => 3, 'pid' => $c->value])->order('id asc')->field('id as value, name as label, pid, level')->select();
+            }
+        }
+
+        $this->success('省市区', $data);
+
+    }
+
+    public function edit()
+    {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'edit');
+
+        $this->success('编辑地址', UserAddress::edit($params));
+    }
+
+    public function info()
+    {
+        $params = $this->request->get();
+        $this->success('地址详情', UserAddress::info($params));
+    }
+
+    public function del()
+    {
+        $params = $this->request->post();
+        $this->success('地址详情', UserAddress::del($params));
+
+    }
+
+
+}

+ 32 - 0
addons/shopro/controller/Base.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\exception\Exception;
+use app\common\controller\Api;
+use think\Lang;
+
+class Base extends Api
+{
+    public function _initialize()
+    {
+
+        parent::_initialize();
+        $controllername = strtolower($this->request->controller());
+        $this->loadlang($controllername);
+
+    }
+
+    protected function loadlang($name)
+    {
+        Lang::load(ADDON_PATH  . 'shopro/lang/' . $this->request->langset() . '/' . str_replace('.', '/', $name) . '.php');
+    }
+
+
+    protected function shoproValidate($params, $class, $scene, $rules = []) {
+        $validate = validate(str_replace('controller', 'validate', $class));
+        if (!$validate->check($params, $rules, $scene)) {
+            $this->error($validate->getError());
+        }
+    }
+}

+ 40 - 0
addons/shopro/controller/Cart.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\model\Cart as CartModel;
+
+class Cart extends Base
+{
+
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+    public function index()
+    {
+        $data = CartModel::info();
+        $this->success('我的购物车', $data);
+    }
+
+    public function add()
+    {
+        $params = $this->request->post();
+        
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'add');
+
+        $goodsList = $params['goods_list'];
+        $this->success('已添加', CartModel::add($goodsList));
+    }
+
+    public function edit()
+    {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'edit');
+
+        $this->success('', CartModel::edit($params));
+    }
+
+}

+ 64 - 0
addons/shopro/controller/Category.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\model\Category as CategoryModel;
+use addons\shopro\model\Goods;
+
+/**
+ * 分类管理
+ *
+ * @icon   fa fa-list
+ * @remark 用于统一管理网站的所有分类,分类可进行无限级分类,分类类型请在常规管理->系统配置->字典配置中添加
+ */
+
+class Category extends Base
+{
+    protected $noNeedLogin = ['*'];
+    protected $noNeedRight = ['*'];
+
+
+
+    public function detail () {
+        $id = $this->request->get('id');
+
+        $data = CategoryModel::getCategoryDetail($id);
+        $this->success('商城分类', $data);
+    }
+
+    public function index()
+    {
+        $id = $this->request->get('id');
+        $data = CategoryModel::getCategoryList($id);
+        $this->success('商城分类', $data);
+
+    }
+
+
+    public function goods() {
+        $params = $this->request->get();
+        $category_id = $params['category_id'];
+
+        $categories = CategoryModel::where('pid', $category_id)->where('status', 'normal')->select();
+
+        // 获取这个分类下面的所有商品
+        $goodsList = Goods::getGoodsList(array_merge($params, ['no_activity' => false]), false);
+
+        foreach($categories as $key => $category) {
+            $categoryIds = ',' . $category['id'] . ',';
+
+            $currentCategoryGoods = [];
+            foreach ($goodsList as $k => $goods) {
+                $goodsCategoryIds = ',' . $goods['category_ids'] . ',';
+
+                if (strpos($goodsCategoryIds, $categoryIds) !== false) {
+                    $currentCategoryGoods[] = $goods;
+                }
+            }
+
+            $categories[$key]['goods'] = $currentCategoryGoods;
+        }
+
+        $this->success('商城分类商品', $categories);
+    }
+}

+ 52 - 0
addons/shopro/controller/Coupons.php

@@ -0,0 +1,52 @@
+<?php
+
+namespace addons\shopro\controller;
+
+
+class Coupons extends Base
+{
+
+    protected $noNeedLogin = ['lists', 'detail', 'goods'];
+    protected $noNeedRight = ['*'];
+
+    // 领券中心,自己的优惠券
+    public function index()
+    {
+        $type = $this->request->get('type');
+        $this->success('优惠券中心', \addons\shopro\model\Coupons::getCouponsList($type));
+    }
+
+    public function lists()
+    {
+        $ids = $this->request->get('ids');
+        $this->success('优惠券列表', \addons\shopro\model\Coupons::getCouponsListByIds($ids));
+
+    }
+
+    public function get()
+    {
+        $id = $this->request->get('id');
+        $this->success('领取成功', \addons\shopro\model\Coupons::getCoupon($id));
+    }
+
+    public function detail()
+    {
+        $id = $this->request->get('id');
+        $user_coupons_id = $this->request->get('user_coupons_id', 0);
+        $detail = \addons\shopro\model\Coupons::getCouponsDetail($id, $user_coupons_id);
+
+        $this->success('优惠券详情', $detail);
+    }
+
+    public function goods()
+    {
+        $id = $this->request->get('id');
+        $detail = \addons\shopro\model\Coupons::getGoodsByCoupons($id);
+
+        $this->success('优惠券详情', $detail);
+    }
+
+
+
+
+}

+ 64 - 0
addons/shopro/controller/Express.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\exception\Exception;
+use addons\shopro\model\Order;
+use addons\shopro\model\User;
+use think\Db;
+use think\Log;
+
+class Express extends Base
+{
+
+    protected $noNeedLogin = ['callback'];
+    protected $noNeedRight = ['*'];
+
+
+    /**
+     * 物流信息订阅回调接口
+     */
+    public function callback()
+    {
+        $requestData = $this->request->post();
+
+        $expressLib = new \addons\shopro\library\Express();
+
+        // 信息记录日志
+        // \think\Log::write('expresscallback:'. json_encode($requestData));
+
+        $data = json_decode(html_entity_decode($requestData['RequestData']), true);
+        $expressData = $data['Data'];
+
+        foreach ($expressData as $key => $express) {
+            // 查找包裹
+            $orderExpress = \addons\shopro\model\OrderExpress::with('order')->where('express_code', $express['ShipperCode'])
+                ->where('express_no', $express['LogisticCode'])
+                ->find();
+
+            if (!$orderExpress) {
+                // 包裹不存在,记录日志信息,然后继续下一个
+                \think\Log::write('orderExpressNotFound:' . json_encode($express));
+                continue;
+            }
+
+            if (!$express['Success']) {
+                // 失败了
+                if (isset($express['Reason']) && ($express['Reason'] == '三天无轨迹' || $express['Reason'] == '七天无轨迹')) {
+                    // 需要重新订阅
+                    $expressLib->subscribe([
+                        'express_code' => $express['ShipperCode'],
+                        'express_no' => $express['LogisticCode']
+                    ], $orderExpress, $orderExpress->order);
+                }
+
+                \think\Log::write('orderExpressReason:' . json_encode($express));
+                continue;
+            }
+
+            $expressLib->checkAndAddTraces($orderExpress, $express);
+        }
+
+        return $expressLib->setPushResult(true);
+    }
+}

+ 26 - 0
addons/shopro/controller/Faq.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace addons\shopro\controller;
+
+
+class Faq extends Base
+{
+
+    protected $noNeedLogin = ['*'];
+    protected $noNeedRight = ['*'];
+
+
+    // faq 列表
+    public function index()
+    {
+        $this->success('获取成功', \addons\shopro\model\Faq::order('id', 'DESC')->paginate(10));
+    }
+
+
+    public function detail () {
+        $id = $this->request->get('id');
+
+        $this->success('签到成功', \addons\shopro\model\Faq::where('id', $id)->find());
+    }
+
+}

+ 28 - 0
addons/shopro/controller/Feedback.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace addons\shopro\controller;
+
+
+class Feedback extends Base
+{
+
+    protected $noNeedLogin = ['type'];
+    protected $noNeedRight = ['*'];
+
+
+    public function type()
+    {
+        $this->success('反馈类型', array_values(\addons\shopro\model\Feedback::$typeAll));
+    }
+
+
+    public function add() {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'add');
+
+        $this->success('反馈成功', \addons\shopro\model\Feedback::add($params));
+    }
+
+}

+ 115 - 0
addons/shopro/controller/Goods.php

@@ -0,0 +1,115 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\exception\Exception;
+
+class Goods extends Base
+{
+
+    protected $noNeedLogin = ['index', 'detail', 'lists', 'activity', 'seckillList', 'grouponList', 'store'];
+    protected $noNeedRight = ['*'];
+
+    public function index()
+    {
+    }
+
+    public function detail()
+    {
+        $id = $this->request->get('id');
+        $detail = \addons\shopro\model\Goods::getGoodsDetail($id);
+        
+        // 记录足记
+        \addons\shopro\model\UserView::addView($detail);
+
+        $sku_price = $detail['sku_price'];      // 处理过的规格
+        // tp bug json_encode 或者 toArray 的时候 sku_price 会重新查询数据库,导致被处理过的规格又还原回去了
+        $detail = json_decode(json_encode($detail), true);
+        $detail['sku_price'] = $sku_price;
+
+        $this->success('商品详情', $detail);
+    }
+
+    public function lists()
+    {
+        $params = $this->request->get();
+        $data = \addons\shopro\model\Goods::getGoodsList($params);
+
+        $this->success('商品列表', $data);
+
+    }
+
+
+    /**
+     * 获取商品支持的 自提点
+     */
+    public function store()
+    {
+        $params = $this->request->get();
+        $data = \addons\shopro\model\Goods::getGoodsStore($params);
+
+        $this->success('自提列表', $data);
+    }
+
+
+    // 秒杀列表
+    public function seckillList() {
+        $params = $this->request->get();
+
+        $this->success('秒杀商品列表', \addons\shopro\model\Goods::getSeckillGoodsList($params));
+    }
+
+
+    // 拼团列表
+    public function grouponList() {
+        $params = $this->request->get();
+
+        $this->success('拼团商品列表', \addons\shopro\model\Goods::getGrouponGoodsList($params));
+    }
+
+
+    public function activity()
+    {
+        $activity_id = $this->request->get('activity_id');
+        $activity = \addons\shopro\model\Activity::get($activity_id);
+        if (!$activity) {
+            $this->error('活动不存在', null, -1);
+        }
+        
+        $goods = \addons\shopro\model\Goods::getGoodsList(['goods_ids' => $activity->goods_ids]);
+        $activity->goods = $goods;
+        
+        $this->success('活动列表', $activity);
+    }
+
+    public function favorite()
+    {
+        $params = $this->request->post();
+        $result = \addons\shopro\model\UserFavorite::edit($params);
+        $this->success($result ? '收藏成功' : '取消收藏', $result);
+    }
+
+    public function favoriteList()
+    {
+        $data = \addons\shopro\model\UserFavorite::getGoodsList();
+        $this->success('商品收藏列表', $data);
+    }
+
+
+    public function viewDelete()
+    {
+        $params = $this->request->post();
+        $result = \addons\shopro\model\UserView::del($params);
+        $this->success('删除成功', $result);
+    }
+
+
+    public function viewList()
+    {
+        $data = \addons\shopro\model\UserView::getGoodsList();
+        $this->success('商品浏览列表', $data);
+    }
+
+
+
+}

+ 40 - 0
addons/shopro/controller/GoodsComment.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace addons\shopro\controller;
+
+
+class GoodsComment extends Base
+{
+
+    protected $noNeedLogin = ['index', 'type'];
+    protected $noNeedRight = ['*'];
+
+
+    public function index()
+    {
+        $params = $this->request->get();
+        
+        $goodsComments = \addons\shopro\model\GoodsComment::getList($params);
+        
+        $this->success('评价详情', $goodsComments);
+    }
+
+
+    public function type() {
+        $goods_id = $this->request->get('goods_id', 0);
+
+        $type = array_values(\addons\shopro\model\GoodsComment::$typeAll);
+
+        foreach ($type as $key => $val) {
+            // 只查询 count 比查出来所有评论,在判断状态要快
+            $comment = \addons\shopro\model\GoodsComment::where('goods_id', $goods_id);
+            if ($val['code'] != 'all') {
+                $comment = $comment->{$val['code']}();
+            }
+            $comment = $comment->count();
+            $type[$key]['num'] = $comment;
+        }
+
+        $this->success('筛选类型', $type);
+    }
+}

+ 293 - 0
addons/shopro/controller/Index.php

@@ -0,0 +1,293 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\model\Config;
+use think\Db;
+use think\Config as FaConfig;
+use fast\Random;
+use think\exception\HttpResponseException;
+use addons\shopro\library\commission\Agent as AgentLibrary;
+use addons\shopro\library\commission\Commission as CommissionLibrary;
+use addons\shopro\library\commission\Reward as RewardLibrary;
+use addons\shopro\model\Order;
+
+class Index extends Base
+{
+
+    protected $noNeedLogin = ['*'];
+    protected $noNeedRight = ['*'];
+
+    public function index()
+    {
+    }
+
+    // 初始化商城数据 服务器压力大可以把最后的data数据存入cache缓存中来调用,防止多次查sql
+    public function init()
+    {
+        $platform = $this->request->header('platform'); // 获取平台标识
+        if (!in_array($platform, ['H5', 'App', 'wxMiniProgram', 'wxOfficialAccount'])) {
+            $this->error('请使用正确客户端访问');
+        }
+        $data = [];     // 设置信息
+        $configFields = ['shopro', 'share', 'chat', 'store', $platform];    // 定义设置字段
+        $configModel = new \addons\shopro\model\Config;
+        $config = $configModel->where('name', 'in', $configFields)->column('value', 'name');
+
+        // 商城基本设置
+        $shoproConfig = json_decode($config['shopro'], true);
+        $shoproConfig['logo'] = cdnurl($shoproConfig['logo'], true);
+        $data['shop'] = $shoproConfig;
+
+        // 支付设置
+        $payment = $configModel->where('group', 'payment')->select();
+        $paymentConfig = [];
+        foreach ($payment as $key => $v) {
+            $val = json_decode($v->value, true);
+            if ($val && in_array($platform, $val['platform'])) {
+                $paymentConfig[] = $v->name;
+            }
+        }
+        $data['payment'] = $paymentConfig;        // 平台支持的支付方式
+
+        // 平台设置
+        $platformConfig = json_decode($config[$platform], true);
+        if (in_array($platform, ['wxOfficialAccount', 'wxMiniProgram'])) {
+            if (isset($platformConfig['auto_login']) && $platformConfig['auto_login'] == 1) {
+                $autologin = true;
+            } else {
+                $autologin = false;
+            }
+            $data['wechat'] = [
+                'appid' => isset($platformConfig['app_id']) ? $platformConfig['app_id'] : '',
+                'autologin' => $autologin,
+            ];
+        }
+
+        // 分享设置
+        $shareConfig = json_decode($config['share'], true);
+        $data['share'] = [
+            'title' => $shareConfig['title'],
+            'image' => isset($shareConfig['image']) ? cdnurl($shareConfig['image'], true) : '',
+            'goods_poster_bg' => isset($shareConfig['goods_poster_bg']) ? cdnurl($shareConfig['goods_poster_bg'], true) : '',
+            'user_poster_bg' => isset($shareConfig['user_poster_bg']) ? cdnurl($shareConfig['user_poster_bg'], true) : '',
+            'groupon_poster_bg' => isset($shareConfig['groupon_poster_bg']) ? cdnurl($shareConfig['groupon_poster_bg'], true) : '',
+        ];
+
+        // 插件设置
+        $data['addons'] = array_keys(get_addon_list());
+
+        // 客服设置
+        $data['chat'] =  isset($config['chat']) ? json_decode($config['chat'], true) : [];
+        // 门店配置
+        $data['store'] = isset($config['store']) ? json_decode($config['store'], true) : [];
+        $this->success('初始化数据', $data);
+    }
+
+    // 商城模板数据
+    public function template()
+    {
+        $get = $this->request->get();
+        $platform = $this->request->header('platform');
+        if (isset($get['shop_id']) && $get['shop_id'] != 0) {
+            $template = \addons\shopro\model\Decorate::getCurrentPlatformDecorate('preview', $get['shop_id']);
+        } else {
+            $template = \addons\shopro\model\Decorate::getCurrentPlatformDecorate($platform);
+        }
+        $this->success('模板数据', $template);
+    }
+
+    // 自定义页面
+    public function custom()
+    {
+        $get = $this->request->get();
+        $decorate = \addons\shopro\model\Decorate::get($get['custom_id']);
+        if (!$decorate) {
+            $this->error('未找到自定义页面');
+        }
+        $decorate->template = \addons\shopro\model\Decorate::getCustomDecorate($get['custom_id']);
+        $this->success('自定义模板数据', $decorate);
+    }
+
+    // 富文本详情
+    public function richtext()
+    {
+        $id = $this->request->get('id');
+        $data = \addons\shopro\model\Richtext::get(['id' => $id]);
+        $this->success($data->title, $data);
+    }
+
+    // 同步前端所有页面链接
+    public function asyncPages()
+    {
+        $post = $this->request->post();
+        $newLink = $post['data'];
+        $existLink = (array)Db::name('shopro_link')->select();
+        $newLinkPath = array_column($newLink, 'path');
+        $existLinkPath = array_flip(array_column($existLink, 'path'));
+        $insertData = [];
+        $count = 1;
+        foreach ($newLinkPath as $key => $item) {
+            if (!isset($existLinkPath[$item]) && isset($newLink[$key]['meta']['async']) && $newLink[$key]['meta']['async']) {
+                $insertData[] = [
+                    'name' => isset($newLink[$key]['meta']['title']) ? $newLink[$key]['meta']['title'] : '新链接' . $count,
+                    'path' => $item,
+                    'group' => isset($newLink[$key]['meta']['group']) ? $newLink[$key]['meta']['group'] : '其它',
+                    'createtime' => time(),
+                    'updatetime' => time()
+                ];
+                $count++;
+            }
+        }
+        if ($insertData !== []) {
+            Db::name('shopro_link')->insertAll($insertData);
+        }
+    }
+
+
+    /**
+     * 上传文件
+     * @ApiMethod (POST)
+     * @param File $file 文件流
+     */
+    public function upload()
+    {
+        $file = $this->request->file('file');
+        if (empty($file)) {
+            $this->error(__('No file upload or server upload limit exceeded'));
+        }
+
+        //判断是否已经存在附件
+        $sha1 = $file->hash();
+
+        $upload = FaConfig::get('upload');
+
+        preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches);
+        $type = strtolower($matches[2]);
+        $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
+        $size = (int)$upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
+        $fileInfo = $file->getInfo();
+        $suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
+        $suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file';
+
+        $mimetypeArr = explode(',', strtolower($upload['mimetype']));
+        $typeArr = explode('/', $fileInfo['type']);
+
+        //禁止上传PHP和HTML文件
+        if (in_array($fileInfo['type'], ['text/x-php', 'text/html']) || in_array($suffix, ['php', 'html', 'htm'])) {
+            $this->error(__('Uploaded file format is limited'));
+        }
+        //验证文件后缀
+        if (
+            $upload['mimetype'] !== '*' &&
+            (!in_array($suffix, $mimetypeArr)
+                || (stripos($typeArr[0] . '/', $upload['mimetype']) !== false && (!in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr))))
+        ) {
+            $this->error(__('Uploaded file format is limited'));
+        }
+        //验证是否为图片文件
+        $imagewidth = $imageheight = 0;
+        if (in_array($fileInfo['type'], ['image/gif', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/png', 'image/webp']) || in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp'])) {
+            $imgInfo = getimagesize($fileInfo['tmp_name']);
+            if (!$imgInfo || !isset($imgInfo[0]) || !isset($imgInfo[1])) {
+                $this->error(__('Uploaded file is not a valid image'));
+            }
+            $imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
+            $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
+        }
+
+        // 文件 md5
+        $fileMd5 = md5_file($fileInfo['tmp_name']);
+
+        $replaceArr = [
+            '{year}' => date("Y"),
+            '{mon}' => date("m"),
+            '{day}' => date("d"),
+            '{hour}' => date("H"),
+            '{min}' => date("i"),
+            '{sec}' => date("s"),
+            '{random}' => Random::alnum(16),
+            '{random32}' => Random::alnum(32),
+            '{filename}' => $suffix ? substr($fileInfo['name'], 0, strripos($fileInfo['name'], '.')) : $fileInfo['name'],
+            '{suffix}' => $suffix,
+            '{.suffix}' => $suffix ? '.' . $suffix : '',
+            '{filemd5}' => $fileMd5,
+        ];
+        $savekey = $upload['savekey'];
+        $savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey);
+
+        $uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1);
+        $fileName = substr($savekey, strripos($savekey, '/') + 1);
+        //
+
+        if (in_array($upload['storage'], ['cos', 'alioss', 'qiniu'])) {     // upyun:又拍云 ,bos:百度BOS,ucloud: Ucloud, 如果要使用这三种,请自行安装插件配置,并将标示填入前面数组,进行测试
+            $token_name = $upload['storage'] . 'token';     // costoken, aliosstoken, qiniutoken
+            $controller_name = '\\addons\\' . $upload['storage'] . '\\controller\\Index';
+
+            $storageToken[$token_name] = $upload['multipart'] && $upload['multipart'][$token_name] ? $upload['multipart'][$token_name] : '';
+            $domain = request()->domain();
+
+            try {
+                $uploadCreate = \think\Request::create('foo', 'POST', array_merge([
+                    'name' => $fileInfo['name'],
+                    'md5' => $fileMd5,
+                    'chunk' => 0,
+                ], $storageToken));
+
+                // 重新设置跨域允许域名
+                $cors = config('fastadmin.cors_request_domain');
+                config('fastadmin.cors_request_domain', $cors . ',' . $domain);
+
+                $uploadController = new $controller_name($uploadCreate);
+                $uploadController->upload();
+            } catch (HttpResponseException $e) {
+                $result = $e->getResponse()->getData();
+                if (isset($result['code']) && $result['code'] == 0) {
+                    $this->error($result['msg']);
+                }
+
+                $resultData = $result['data'];
+            }
+        } else {
+            $splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
+
+            if ($splInfo) {
+                $resultData = [
+                    'url' => $uploadDir . $splInfo->getSaveName(),
+                    'fullurl' => request()->domain() . $uploadDir . $splInfo->getSaveName()
+                ];
+            } else {
+                // 上传失败获取错误信息
+                $this->error($file->getError());
+            }
+        }
+
+        $params = array(
+            'admin_id' => 0,
+            'user_id' => (int)$this->auth->id,
+            'filename'    => substr(htmlspecialchars(strip_tags($fileInfo['name'])), 0, 100),
+            'filesize' => $fileInfo['size'],
+            'imagewidth' => $imagewidth,
+            'imageheight' => $imageheight,
+            'imagetype' => $suffix,
+            'imageframes' => 0,
+            'mimetype' => $fileInfo['type'] == 'application/octet-stream' && in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp']) ? 'image/' . $suffix : $fileInfo['type'],
+            'url' => $resultData['url'],
+            'uploadtime' => time(),
+            'storage' => $upload['storage'],
+            'sha1' => $sha1,
+        );
+        $attachment = new \app\common\model\Attachment;
+        $attachment->data(array_filter($params));
+        $attachment->save();
+        \think\Hook::listen("upload_after", $attachment);
+        $this->success(__('Upload successful'), $resultData);
+    }
+
+
+    public function debugLog()
+    {
+        $params = $this->request->post();
+        \think\Log::write($params, 'Frontend-Debug');
+    }
+}

+ 60 - 0
addons/shopro/controller/Kefu.php

@@ -0,0 +1,60 @@
+<?php
+
+namespace addons\shopro\controller;
+
+/**
+ * 客服接口
+ */
+class Kefu extends Base
+{
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+    /**
+     * 对接Fastadmin插件市场WorkerMan客服插件
+     */
+    public function historyGoods()
+    {
+        $viewList = \addons\shopro\model\UserView::getGoodsList();
+        if(!empty($viewList)) {
+            foreach($viewList as $k => &$v) {
+                $v->id = $v->goods_id;
+                $v->logo = $v->goods->image;
+                $v->subject = $v->goods->title;
+                $v->note = $v->goods->subtitle;
+                $v->price = $v->goods->price;
+
+                unset($v['goods']);
+                unset($v['goods_id']);
+                unset($v['user_id']);
+            }
+        }
+        $this->success('浏览历史', $viewList);
+    }
+
+    public function historyOrder()
+    {
+        $orderList = \addons\shopro\model\Order::getList(['type' => 'all']);
+        if(!empty($orderList)) {
+            foreach($orderList['data'] as $k => &$v) {
+                $order = [];
+                $order['id'] = $v['id'];
+                $order['subject'] = $v['item'][0]['goods_title'];
+                $order['logo'] = $v['item'][0]['goods_image'];
+                $order['note'] = "订单编号:{$v['order_sn']}";
+                $order['price'] = $v['total_amount'];
+                $order['number'] = 23;
+                $itemNumber = count($v['item']);
+
+                if($itemNumber == 1) {
+                    $order['subject'] = "{$order['subject']}...等{$itemNumber}个产品";
+                }
+            
+                $v = $order;
+            }
+        }
+        $this->success('order', $orderList);
+    }
+
+
+}

+ 53 - 0
addons/shopro/controller/Live.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\library\Wechat;
+use addons\shopro\exception\Exception;
+use think\Cache;
+
+class Live extends Base
+{
+
+    protected $noNeedLogin = ['*'];
+    protected $noNeedRight = ['*'];
+
+
+    public function index()
+    {
+        $params = $this->request->get();
+        
+        $type = $params['type'] ?? 'all';
+        $ids = array_filter(isset($params['ids']) ? explode(',', $params['ids']) : []);
+
+        if (!in_array($type, ['all', 'notice', 'living', 'lived'])) {
+            $this->error('参数错误');
+        }
+
+        // 同步直播
+        \addons\shopro\model\Live::autoSyncLive();
+        
+        if ($type != 'all') {
+            $lives = \addons\shopro\model\Live::{$type}()
+                        ->with('goods')
+                        ->order('id', 'desc')
+                        ->paginate(10);
+        } else {
+            $lives = \addons\shopro\model\Live::order('live_status', 'asc')
+                        ->with('goods')
+                        ->order('id', 'desc');
+
+            if (isset($params['ids'])) {
+                // 首页根据 id 获取
+                $lives = $lives->where('id', 'in', $ids)->select();
+            } else {
+                // 直播列表
+                $lives = $lives->paginate(10);
+            }
+        }
+
+        $this->success('获取成功', $lives);
+    }
+
+
+}

+ 38 - 0
addons/shopro/controller/Notification.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\exception\Exception;
+use addons\shopro\model\NotificationConfig;
+use think\Cache;
+
+
+class Notification extends Base
+{
+
+    protected $noNeedLogin = ['*'];
+    protected $noNeedRight = ['*'];
+
+
+    public function template()
+    {
+        $platform = request()->header('platform');
+
+        $templates = [];
+        if (in_array($platform, ['wxMiniProgram', 'wxOfficialAccount'])) {
+            $platform = $platform == 'wxOfficialAccount' ? 'wxOfficialAccountBizsend' : $platform;
+            // 获取订阅消息模板
+            $notificationConfig = NotificationConfig::cache(300)->where('platform', $platform)->select();
+            
+            foreach ($notificationConfig as $k => $config) {
+                if ($config['status'] && $config['content_arr'] && $config['content_arr']['template_id']) {
+                    $templates[$config['event']] = $config['content_arr']['template_id'];
+                }
+            }
+        }
+
+        $this->success('获取成功', $templates);
+    }
+
+
+}

+ 129 - 0
addons/shopro/controller/Order.php

@@ -0,0 +1,129 @@
+<?php
+
+namespace addons\shopro\controller;
+
+
+class Order extends Base
+{
+
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+
+    public function index()
+    {
+        $params = $this->request->get();
+
+        $this->success('订单列表', \addons\shopro\model\Order::getList($params));
+    }
+
+
+
+    public function detail()
+    {
+        $params = $this->request->get();
+        $this->success('订单详情', \addons\shopro\model\Order::detail($params));
+    }
+
+
+    public function itemDetail()
+    {
+        $params = $this->request->get();
+        $this->success('订单商品', \addons\shopro\model\Order::itemDetail($params));
+    }
+
+
+    // 即将废弃
+    public function statusNum () {
+        $this->success('订单数量', \addons\shopro\model\Order::statusNum());
+    }
+
+
+    // 取消订单
+    public function cancel()
+    {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'cancel');
+
+        $this->success('取消成功', \addons\shopro\model\Order::operCancel($params));
+    }
+
+    // 删除订单
+    public function delete()
+    {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'delete');
+
+        $this->success('删除成功', \addons\shopro\model\Order::operDelete($params));
+    }
+
+    // 确认收货
+    public function confirm()
+    {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'confirm');
+
+        $this->success('收货成功', \addons\shopro\model\Order::operConfirm($params));
+    }
+
+
+    public function comment () 
+    {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'comment');
+
+        $this->success('评价成功', \addons\shopro\model\Order::operComment($params));
+    }
+
+
+    public function pre()
+    {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'pre');
+
+        $result = \addons\shopro\model\Order::pre($params);
+
+        if (isset($result['msg']) && $result['msg']) {
+            $this->error($result['msg'], $result);
+        } else {
+            $this->success('计算成功', $result);
+        }
+    }
+
+
+    public function createOrder() 
+    {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'createOrder');
+
+        $order = \addons\shopro\model\Order::createOrder($params);
+
+        $this->success('订单添加成功', $order);
+    }
+
+
+    // 获取可用优惠券列表
+    public function coupons () {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'coupons');
+
+        $coupons = \addons\shopro\model\Order::coupons($params);
+
+        $this->success('获取成功', $coupons);
+    }
+    
+}

+ 69 - 0
addons/shopro/controller/OrderAftersale.php

@@ -0,0 +1,69 @@
+<?php
+
+namespace addons\shopro\controller;
+
+
+class OrderAftersale extends Base
+{
+
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+
+    public function index()
+    {
+        $params = $this->request->get();
+
+        $this->success('售后列表', \addons\shopro\model\OrderAftersale::getList($params));
+    }
+
+
+    /**
+     * 详情
+     */
+    public function detail()
+    {
+        $params = $this->request->get();
+
+        $this->shoproValidate($params, get_class(), 'detail');
+
+        $this->success('售后详情', \addons\shopro\model\OrderAftersale::detail($params));
+    }
+
+
+
+    // 申请售后
+    public function aftersale()
+    {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'aftersale');
+
+        $this->success('申请成功', \addons\shopro\model\OrderAftersale::aftersale($params));
+    }
+
+
+    // 取消售后单
+    public function cancel()
+    {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'cancel');
+
+        $this->success('取消成功', \addons\shopro\model\OrderAftersale::operCancel($params));
+    }
+
+    // 删除售后单
+    public function delete()
+    {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'delete');
+
+        $this->success('删除成功', \addons\shopro\model\OrderAftersale::operDelete($params));
+    }
+
+}

+ 27 - 0
addons/shopro/controller/OrderExpress.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace addons\shopro\controller;
+
+
+class OrderExpress extends Base
+{
+
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+
+    public function index()
+    {
+        $params = $this->request->get();
+
+        $this->success('包裹列表', \addons\shopro\model\OrderExpress::getList($params));
+    }
+
+
+    public function detail()
+    {
+        $params = $this->request->get();
+
+        $this->success('包裹详情', \addons\shopro\model\OrderExpress::detail($params));
+    }
+}

+ 382 - 0
addons/shopro/controller/Pay.php

@@ -0,0 +1,382 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\epay\library\Service;
+use fast\Random;
+use think\addons\Controller;
+use addons\shopro\exception\Exception;
+use addons\shopro\model\Order;
+use addons\shopro\model\User;
+use think\Db;
+use think\Log;
+
+class Pay extends Base
+{
+
+    protected $noNeedLogin = ['prepay', 'notifyx', 'notifyr', 'alipay'];
+    protected $noNeedRight = ['*'];
+
+
+    /**
+     * 支付宝网页支付
+     */
+    public function alipay()
+    {
+        $order_sn = $this->request->get('order_sn');
+        $order = Order::where('order_sn', $order_sn)->find();
+
+        try {
+            if (!$order) {
+                throw new \Exception("订单不存在");
+            }
+            if ($order->status > 0) {
+                throw new \Exception("订单已支付");
+            }
+            if ($order->status < 0) {
+                throw new \Exception("订单已失效");
+            }
+    
+            $notify_url = $this->request->root(true) . '/addons/shopro/pay/notifyx/payment/alipay/platform/H5';
+            $pay = new \addons\shopro\library\PayService('alipay', 'url', $notify_url);
+    
+            $order_data = [
+                'out_trade_no' => $order->order_sn,
+                'total_fee' => $order->total_fee,
+                'subject' => '商城订单支付',
+            ];
+    
+            $result = $pay->create($order_data);
+
+            $result = $result->getContent();
+            
+	        echo $result;
+        } catch (\Exception $e) {
+            echo $e->getMessage();
+        }
+
+        // $this->assign('result', $result);
+
+        // return $this->view->fetch();
+    }
+
+
+    /**
+     * 拉起支付
+     */
+    public function prepay()
+    {
+        $order_sn = $this->request->post('order_sn');
+        $payment = $this->request->post('payment');
+        $openid = $this->request->post('openid', '');
+        $platform = request()->header('platform');
+        
+        $order = Order::nopay()->where('order_sn', $order_sn)->find();
+
+        if (!$order) {
+            $this->error("订单不存在");
+        }
+
+        if (!$payment || !in_array($payment, ['wechat', 'alipay', 'wallet'])) {
+            $this->error("支付类型不能为空");
+        }
+
+        if ($payment == 'wallet') {
+            // 余额支付
+            $this->walletPay($order, $payment, $platform);
+        }
+
+        $order_data = [
+            'out_trade_no' => $order->order_sn,
+            'total_fee' => $order->total_fee,
+        ];
+
+        // 微信公众号,小程序支付,必须有 openid
+        if ($payment == 'wechat') {
+            if (in_array($platform, ['wxOfficialAccount', 'wxMiniProgram'])) {
+                if (isset($openid) && $openid) {
+                    // 如果传的有 openid
+                    $order_data['openid'] = $openid;
+                } else {
+                    // 没有 openid 默认拿下单人的 openid
+                    $oauth = \addons\shopro\model\UserOauth::where([
+                        'user_id' => $order->user_id,
+                        'provider' => 'Wechat',
+                        'platform' => $platform
+                    ])->find();
+        
+                    $order_data['openid'] = $oauth ? $oauth->openid : '';
+                }
+    
+                if (empty($order_data['openid'])) {
+                    // 缺少 openid
+                    return $this->success('缺少 openid', 'no_openid');
+                }
+            }
+
+            $order_data['body'] = '商城订单支付';
+        } else {
+            $order_data['subject'] = '商城订单支付';
+        }
+
+        $notify_url = $this->request->root(true) . '/addons/shopro/pay/notifyx/payment/' . $payment . '/platform/' . $platform;
+        $pay = new \addons\shopro\library\PayService($payment, $platform, $notify_url);
+
+        $result = $pay->create($order_data);
+        if ($platform == 'App') {
+            $result = $result->getContent();
+        }
+        if ($platform == 'H5' && $payment == 'wechat') {
+            $result = $result->getContent();
+        }
+
+        return $this->success('获取预付款成功', [
+            'pay_data' => $result,
+            'pay_action' => $pay->method,
+        ]);
+    }
+
+
+
+    // 余额支付
+    public function walletPay ($order, $type, $method) {
+        $order = Db::transaction(function () use ($order, $type, $method) {
+            // 重新加锁读,防止连点问题
+            $order = Order::nopay()->where('order_sn', $order->order_sn)->lock(true)->find();
+            if (!$order) {
+                $this->error("订单已支付");
+            }
+            $total_fee = $order->total_fee;
+
+            // 扣除余额
+            $user = User::info();
+
+            if (is_null($user)) {
+                // 没有登录,请登录
+                $this->error(__('Please login first'), null, 401);
+            }
+
+            User::money(-$total_fee, $user->id, 'wallet_pay', $order->id, '',[
+                'order_id' => $order->id,
+                'order_sn' => $order->order_sn,
+            ]);
+
+            // 支付后流程
+            $notify = [
+                'order_sn' => $order['order_sn'],
+                'transaction_id' => '',
+                'notify_time' => date('Y-m-d H:i:s'),
+                'buyer_email' => $user->id,
+                'pay_fee' => $order->total_fee,
+                'pay_type' => 'wallet'             // 支付方式
+            ];
+            $notify['payment_json'] = json_encode($notify);
+            $order->paymentProcess($order, $notify);
+
+            return $order;
+        });
+
+        $this->success('支付成功', $order);
+    }
+
+
+    /**
+     * 支付成功回调
+     */
+    public function notifyx()
+    {
+        Log::write('notifyx-comein:');
+
+        $payment = $this->request->param('payment');
+        $platform = $this->request->param('platform');
+
+        $pay = new \addons\shopro\library\PayService($payment, $platform);
+
+        $result = $pay->notify(function ($data, $pay) use ($payment, $platform) {
+            Log::write('notifyx-result:'. json_encode($data));
+            // {    // 微信回调参数
+            //     "appid":"wx39cd0799d4567dd0",
+            //     "bank_type":"OTHERS",
+            //     "cash_fee":"1",
+            //     "fee_type":"CNY",
+            //     "is_subscribe":"N",
+            //     "mch_id":"1481069012",
+            //     "nonce_str":"dPpcZ6AzCDU8daNC",
+            //     "openid":"oD9ko4x7QMDQPZEuN8V5jtZjie3g",
+            //     "out_trade_no":"202010240834057843002700",
+            //     "result_code":"SUCCESS",
+            //     "return_code":"SUCCESS",
+            //     "sign":"3103B6D06F13D2B3959C5B3F7F1FD61C",
+            //     "time_end":"20200407102424",
+            //     "total_fee":"1",
+            //     "trade_type":"JSAPI",
+            //     "transaction_id":"4200000479202004070804485027"
+            // }
+
+            // {    // 支付宝支付成功回调参数
+            //     "gmt_create":"2020-04-10 19:15:00",
+            //     "charset":"utf-8",
+            //     "seller_email":"xptech@qq.com",
+            //     "subject":"\u5546\u57ce\u8ba2\u5355\u652f\u4ed8",
+            //     "sign":"AOiYZ1a2mEMOuIbHFCi6V6A0LJ97UMiHsCWgNdSU9dlzKFl15Ts8b0mL\/tN+Hhskl+94S3OUiNTBD3dD0Kv923SqaTWxNdj533PCdo2GDKsZIZgKbavnOvaccSKUdmQRE9KtmePPq9V9lFzEQvdUkKq1M8KAWO5K9LTy2iT2y5CUynpiu\/04GVzsTL9PqY+LDwqj6K+w7MgceWm1BWaFWg27AXIRw7wvsFckr3k9GGajgE2fufhoCYGYtGFbhGOp6ExtqS5RXBuPODOyRhBLpD8mwpOX38Oy0X+R4YQIrOi02dhqwPpvw79YjnvgXY3qZEQ66EdUsrT7EBdcPHK0Gw==",
+            //     "buyer_id":"2088902485164146",
+            //     "invoice_amount":"0.01",
+            //     "notify_id":"2020041000222191501064141414240102",
+            //     "fund_bill_list":"[{\"amount\":\"0.01\",\"fundChannel\":\"PCREDIT\"}]",
+            //     "notify_type":"trade_status_sync",
+            //     "trade_status":"TRADE_SUCCESS",
+            //     "receipt_amount":"0.01",
+            //     "buyer_pay_amount":"0.01",
+            //     "app_id":"2021001114666742",
+            //     "sign_type":"RSA2",
+            //     "seller_id":"2088721922277739",
+            //     "gmt_payment":"2020-04-10 19:15:00",
+            //     "notify_time":"2020-04-10 19:15:01",
+            //     "version":"1.0",
+            //     "out_trade_no":"202007144778322770017000",
+            //     "total_amount":"0.01",
+            //     "trade_no":"2020041022001464141443020240",
+            //     "auth_app_id":"2021001114666742",
+            //     "buyer_logon_id":"157***@163.com",
+            //     "point_amount":"0.00"
+            // }
+
+            // {   // 支付宝退款成功(交易关闭)回调参数
+            //     "gmt_create": "2020-08-15 14:48:32",
+            //     "charset": "utf-8",
+            //     "seller_email": "xptech@qq.com",
+            //     "gmt_payment": "2020-08-15 14:48:32",
+            //     "notify_time": "2020-08-15 16:11:45",
+            //     "subject": "商城订单支付",
+            //     "gmt_refund": "2020-08-15 16:11:45.140",
+            //     "sign": "b6ArkgzLIRteRL9FMGC6i\/jf6VwFYQbaGDGRx002W+pdmN5q9+O4edZ3ALF74fYaijSl9ksNr0dKdvanu3uYxBTcd\/GIS4N1CWzmCOv6pzgx5rO\/YvGoHLM3Yop0GKKuMxmnNsZ6jhYKEY7SYD3Y0L6PU9ZMdHV7yIiVj+zZmbKzUgK9MPDCEXs+nzpNAiSM8GTqYRSUvKobAK68hswG2k1QIcqr5z+ZmVYa\/nHHkoC9qXt5zwyGi4P+2eOsr6V2PjA3x8qqe7TN5aI1DeoZD5KqHPYYaYF17J2q6YPlgl3WUl1RhE7H86bivB1fIuYEv\/3+JR74WN\/o7krGw1RPHg==",
+            //     "out_biz_no": "R202004114414846255015300",
+            //     "buyer_id": "2088902485164146",
+            //     "version": "1.0",
+            //     "notify_id": "2020081500222161145064141453349793",
+            //     "notify_type": "trade_status_sync",
+            //     "out_trade_no": "202002460317545607015300",
+            //     "total_amount": "0.01",
+            //     "trade_status": "TRADE_CLOSED",
+            //     "refund_fee": "0.01",
+            //     "trade_no": "2020081522001464141438570535",
+            //     "auth_app_id": "2021001114666742",
+            //     "buyer_logon_id": "157***@163.com",
+            //     "gmt_close": "2020-08-15 16:11:45",
+            //     "app_id": "2021001114666742",
+            //     "sign_type": "RSA2",
+            //     "seller_id": "2088721922277739"
+            // }
+
+            try {
+                $out_trade_no = $data['out_trade_no'];
+                $out_refund_no = $data['out_biz_no'] ?? '';
+
+
+                
+                // 判断是否是支付宝退款(支付宝退款成功会通知该接口)
+                if ($payment == 'alipay'    // 支付宝支付
+                    && $data['notify_type'] == 'trade_status_sync'      // 同步交易状态
+                    && $data['trade_status'] == 'TRADE_CLOSED'          // 交易关闭
+                    && $out_refund_no                                   // 退款单号
+                ) {
+                    // 退款回调
+                    $this->refundFinish($out_trade_no, $out_refund_no);
+
+                    return $pay->success()->send();
+                }
+
+
+                // 判断支付宝微信是否是支付成功状态,如果不是,直接返回响应
+                if ($payment == 'alipay' && $data['trade_status'] != 'TRADE_SUCCESS') {
+                    // 不是交易成功的通知,直接返回成功
+                    return $pay->success()->send();
+                }
+                if ($payment == 'wechat' && ($data['result_code'] != 'SUCCESS' || $data['return_code'] != 'SUCCESS')) {
+                    // 微信交易未成功,返回 false,让微信再次通知
+                    return false;
+                }
+
+                // 支付成功流程
+                $pay_fee = $payment == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100;
+
+                //你可以在此编写订单逻辑
+                $order = Order::where('order_sn', $out_trade_no)->find();
+
+                if (!$order || $order->status > 0) {
+                    // 订单不存在,或者订单已支付
+                    return $pay->success()->send();
+                }
+
+                Db::transaction(function () use ($order, $data, $payment, $platform, $pay_fee) {
+                    $notify = [
+                        'order_sn' => $data['out_trade_no'],
+                        'transaction_id' => $payment == 'alipay' ? $data['trade_no'] : $data['transaction_id'],
+                        'notify_time' => date('Y-m-d H:i:s', strtotime($data['time_end'])),
+                        'buyer_email' => $payment == 'alipay' ? $data['buyer_logon_id'] : $data['openid'],
+                        'payment_json' => json_encode($data->all()),
+                        'pay_fee' => $pay_fee,
+                        'pay_type' => $payment              // 支付方式
+                    ];
+                    $order->paymentProcess($order, $notify);
+                });
+
+                return $pay->success()->send();
+            } catch (\Exception $e) {
+                Log::write('notifyx-error:' . json_encode($e->getMessage()));
+            }
+        });
+
+        return $result;
+    }
+
+
+    /**
+     * 退款成功回调
+     */
+    public function notifyr()
+    {
+        Log::write('notifyreturn-comein:');
+
+        $payment = $this->request->param('payment');
+        $platform = $this->request->param('platform');
+
+        $pay = new \addons\shopro\library\PayService($payment, $platform);
+
+        $result = $pay->notifyRefund(function ($data, $pay) use ($payment, $platform) {
+            Log::write('notifyr-result:' . json_encode($data));
+            try {
+                $out_refund_no = $data['out_refund_no'];
+                $out_trade_no = $data['out_trade_no'];
+
+                // 退款
+                $this->refundFinish($out_trade_no, $out_refund_no);
+                
+                return $pay->success()->send();
+            } catch (\Exception $e) {
+                Log::write('notifyreturn-error:' . json_encode($e->getMessage()));
+            }
+        });
+
+        return $result;
+    }
+
+    
+    private function refundFinish($out_trade_no, $out_refund_no) {
+        $order = Order::where('order_sn', $out_trade_no)->find();
+        $refundLog = \app\admin\model\shopro\order\RefundLog::where('refund_sn', $out_refund_no)->find();
+
+        if (!$order || !$refundLog || $refundLog->status != 0) {
+            // 订单不存在,或者订单已退款
+            return true;
+        }
+
+        $item = \app\admin\model\shopro\order\OrderItem::where('id', $refundLog->order_item_id)->find();
+
+        Db::transaction(function () use ($order, $item, $refundLog) {
+            \app\admin\model\shopro\order\Order::refundFinish($order, $item, $refundLog);
+        });
+
+        return true;
+    }
+}

+ 27 - 0
addons/shopro/controller/ScoreGoodsSkuPrice.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace addons\shopro\controller;
+
+
+class ScoreGoodsSkuPrice extends Base
+{
+
+    protected $noNeedLogin = ['*'];
+    protected $noNeedRight = ['*'];
+
+    public function index()
+    {
+        $params = $this->request->get();
+        $goods = \addons\shopro\model\ScoreGoodsSkuPrice::getGoodsList($params);
+        
+        $this->success('积分商城列表', $goods);
+    }
+
+    public function detail()
+    {
+        $id = $this->request->get('id');
+        $detail = \addons\shopro\model\ScoreGoodsSkuPrice::getGoodsDetail($id);
+
+        $this->success('商品详情', $detail);
+    }
+}

+ 51 - 0
addons/shopro/controller/Share.php

@@ -0,0 +1,51 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\model\Share as ShareModel;
+
+class Share extends Base
+{
+
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+
+    /**
+     * 获取分享记录
+     *
+     * @return void
+     */
+    public function index()
+    {
+        $params = $this->request->get();
+
+        $shares = ShareModel::getList($params);
+        return $this->success('获取成功', $shares);
+    }
+
+
+    public function add()
+    {
+
+        $spm = $this->request->post('spm');
+        $share = false;
+        if (!empty($spm)) {
+            $share = \think\Db::transaction(function () use ($spm) {
+                try {
+                    $shareLog = ShareModel::add($spm);
+                    if ($shareLog) {
+                        \think\Hook::listen('share_after', $shareLog);
+                        return true;
+                    }
+                } catch (\Exception $e) {
+                    $this->error($e->getMessage());
+                }
+                return false;
+            });
+        }
+        if($share) {
+            $this->success('识别成功'); // 使用 success 前端不提示
+        }
+    }
+}

+ 101 - 0
addons/shopro/controller/Sms.php

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

+ 31 - 0
addons/shopro/controller/Store.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\exception\Exception;
+use addons\shopro\model\Store as ModelStore;
+use addons\shopro\model\User;
+use addons\shopro\model\UserStore;
+
+class Store extends Base
+{
+
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+
+    public function index()
+    {
+        $user = User::info();
+        $userStore = UserStore::where('user_id', $user->id)->select();
+        $store_id_arr = array_column($userStore, 'store_id');
+
+        $stores = [];
+        if ($store_id_arr) {
+            $stores = ModelStore::show()->where('id', 'in', $store_id_arr)->select();
+        }
+        
+        $this->success('获取门店列表', $stores);
+    }
+    
+}

+ 727 - 0
addons/shopro/controller/User.php

@@ -0,0 +1,727 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use think\Db;
+use app\common\library\Sms;
+use fast\Random;
+use think\Validate;
+use addons\shopro\library\Wechat;
+use addons\shopro\model\UserOauth;
+use addons\shopro\model\User as UserModel;
+use addons\shopro\model\UserStore;
+
+/**
+ * 会员接口
+ */
+class User extends Base
+{
+    protected $noNeedLogin = ['accountLogin', 'smsLogin', 'register', 'forgotPwd', 'wxMiniProgramOauth', 'getWxMiniProgramSessionKey', 'wxOfficialAccountOauth', 'wxOfficialAccountBaseLogin', 'wxOpenPlatformOauth', 'appleIdOauth', 'logout'];
+    protected $noNeedRight = '*';
+
+    public function _initialize()
+    {
+        return parent::_initialize();
+    }
+
+    /**
+     * 会员中心
+     */
+    public function index()
+    {
+        $auth = \app\common\library\Auth::instance();
+        $auth->setAllowFields(['id', 'username', 'nickname', 'mobile', 'avatar', 'score', 'birthday', 'money', 'group', 'group_id', 'verification', 'child_user_count', 'child_user_count_1', 'child_user_count_2', 'total_consume']);
+        $data = $auth->getUserinfo();
+        $data['avatar'] = $data['avatar'] ? cdnurl($data['avatar'], true) : '';
+        if (!isset($data['group'])) {
+            $data['group'] = \addons\shopro\model\UserGroup::get($data['group_id']);
+        }
+
+        $this->success('用户信息', $data);
+    }
+
+
+    /**
+     * 获取用户数据
+     *
+     * @return void
+     */
+    public function userData()
+    {
+        $user = $this->auth->getUserinfo();
+        // 查询用户优惠券数量
+        $userCoupons = \addons\shopro\model\Coupons::getCouponsList(1);
+        $data['coupons_num'] = count($userCoupons);
+
+        // 查询用户是否是门店管理员
+        $userStores = UserStore::where('user_id', $user['id'])->select();
+        $data['is_store'] = $userStores ? 1 : 0;
+        $data['store_id'] = 0;
+        if (count($userStores) == 1) {
+            // 只有一个店铺 直接进入店铺
+            $data['store_id'] = $userStores[0]['store_id'];
+        }
+
+        // 订单数量
+        $data['order_num'] = \addons\shopro\model\Order::statusNum();
+
+        $this->success('用户数据', $data);
+    }
+
+    /**
+     * 1.账号登录
+     *
+     * @param string $account 账号
+     * @param string $password 密码
+     */
+    public function accountLogin()
+    {
+        $account = $this->request->post('account');
+        $password = $this->request->post('password');
+        if (!$account || !$password) {
+            $this->error(__('Invalid parameters'));
+        }
+        $ret = $this->auth->login($account, $password);
+        if ($ret) {
+            $data = ['token' => $this->auth->getToken()];
+            $this->success(__('Logged in successful'), $data);
+        } else {
+            $this->error($this->auth->getError());
+        }
+    }
+
+    /**
+     * 2.短信登录
+     *
+     * @param string $mobile 手机号
+     * @param string $code 验证码
+     */
+    public function smsLogin()
+    {
+        $mobile = $this->request->post('mobile');
+        $code = $this->request->post('code');
+        if (!$mobile || !$code) {
+            $this->error(__('Invalid parameters'));
+        }
+        if (!Validate::regex($mobile, "^1\d{10}$")) {
+            $this->error(__('Mobile is incorrect'));
+        }
+        if (!Sms::check($mobile, $code, 'mobilelogin')) {
+            $this->error(__('Captcha is incorrect'));
+        }
+        $user = \app\common\model\User::getByMobile($mobile);
+        if ($user) {
+            if ($user->status != 'normal') {
+                $this->error(__('Account is locked'));
+            }
+            //如果已经有账号则直接登录
+            $ret = $this->auth->direct($user->id);
+        }
+        if ($ret) {
+            Sms::flush($mobile, 'mobilelogin');
+            $data = ['token' => $this->auth->getToken()];
+            $this->success(__('Logged in successful'), $data);
+        } else {
+            $this->error($this->auth->getError());
+        }
+    }
+
+    /**
+     * 3.注册会员
+     *
+     * @param string $mobile 手机号
+     * @param string $password 密码
+     * @param string $code 验证码
+     */
+    public function register()
+    {
+        $username = $this->request->post('mobile');
+        $password = $this->request->post('password');
+        $email = $this->request->post('mobile') . '@' . request()->host();
+
+        $mobile = $this->request->post('mobile');
+        $code = $this->request->post('code');
+        if (!$password) {
+            $this->error(__('请填写密码')); //TODO:密码规则校验
+        }
+        if (strlen($password) < 6 || strlen($password) > 16) {
+            $this->error(__('密码长度 6-16 位')); //TODO:密码规则校验
+        }
+        if ($email && !Validate::is($email, "email")) {
+            $this->error(__('邮箱填写错误'));
+        }
+        if ($mobile && !Validate::regex($mobile, "^1\d{10}$")) {
+            $this->error(__('手机号填写错误'));
+        }
+        $ret = Sms::check($mobile, $code, 'register');
+        if (!$ret) {
+            $this->error(__('Captcha is incorrect'));
+        }
+        $extend = $this->getUserDefaultFields();
+        $ret = $this->auth->register($username, $password, $email, $mobile, $extend);
+        if ($ret) {
+            $user = $this->auth->getUser();
+            $user->nickname = $user->nickname . $user->id;
+            $verification = $user->verification;
+            $verification->mobile = 1;
+            $user->verification = $verification;
+            $user->save();
+            $data = ['token' => $this->auth->getToken()];
+            $this->success(__('注册成功'), $data);
+        } else {
+            $this->error($this->auth->getError());
+        }
+    }
+
+    /**
+     * 4.忘记密码
+     *
+     * @param string $mobile 手机号
+     * @param string $password 新密码
+     * @param string $code 验证码
+     */
+    public function forgotPwd()
+    {
+        $mobile = $this->request->post("mobile");
+        $newpassword = $this->request->post("password");
+        $captcha = $this->request->post("code");
+        if (!$newpassword || !$captcha) {
+            $this->error(__('Invalid parameters'));
+        }
+        if (strlen($newpassword) < 6 || strlen($newpassword) > 16) {
+            $this->error(__('密码长度 6-16 位')); //TODO:密码规则校验
+        }
+        if (!Validate::regex($mobile, "^1\d{10}$")) {
+            $this->error(__('Mobile is incorrect'));
+        }
+        $user = \app\common\model\User::getByMobile($mobile);
+        if (!$user) {
+            $this->error(__('User not found'));
+        }
+        $ret = Sms::check($mobile, $captcha, 'resetpwd');
+        if (!$ret) {
+            $this->error(__('Captcha is incorrect'));
+        }
+        Sms::flush($mobile, 'resetpwd');
+        //模拟一次登录
+        $this->auth->direct($user->id);
+        $ret = $this->auth->changepwd($newpassword, '', true);
+        if ($ret) {
+            $this->success(__('Reset password successful'));
+        } else {
+            $this->error($this->auth->getError());
+        }
+    }
+
+    /**
+     * 5.绑定手机号
+     *
+     * @param string $mobile 手机号
+     * @param string $code 验证码
+     */
+    public function bindMobile()
+    {
+        $user = $this->auth->getUser();
+        $mobile = $this->request->post('mobile');
+        $captcha = $this->request->post('code');
+        if (!$mobile || !$captcha) {
+            $this->error(__('Invalid parameters'));
+        }
+        if (!Validate::regex($mobile, "^1\d{10}$")) {
+            $this->error(__('Mobile is incorrect'));
+        }
+        if (\app\common\model\User::where('mobile', $mobile)->where('id', '<>', $user->id)->find()) {
+            $this->error(__('Mobile already exists'));
+        }
+        $result = Sms::check($mobile, $captcha, 'changemobile');
+        if (!$result) {
+            $this->error(__('Captcha is incorrect'));
+        }
+        $verification = $user->verification;
+        $verification->mobile = 1;
+        $user->verification = $verification;
+        $user->mobile = $mobile;
+        $user->save();
+
+        Sms::flush($mobile, 'changemobile');
+        $this->success(__('Mobile is binded'));
+    }
+
+
+    /**
+     * 6.修改密码
+     *
+     * @param string $oldpassword 手机号
+     * @param string $newpassword 验证码
+     */
+    public function changePwd()
+    {
+        $user = $this->auth->getUser();
+
+        $oldpassword = $this->request->post("oldpassword");
+        $newpassword = $this->request->post("newpassword");
+
+        if (!$newpassword || !$oldpassword) {
+            $this->error(__('Invalid parameters'));
+        }
+        if (strlen($newpassword) < 6 || strlen($newpassword) > 16) {
+            $this->error(__('密码长度 6-16 位')); //TODO:密码规则校验
+        }
+
+        $ret = $this->auth->changepwd($newpassword, $oldpassword);
+
+        if ($ret) {
+            $this->auth->direct($user->id);
+            $data = ['userinfo' => $this->auth->getUserinfo()];
+
+            $this->success(__('Change password successful'), $data);
+        } else {
+            $this->error($this->auth->getError());
+        }
+    }
+
+    /**
+     * 获取微信小程序session_key
+     *
+     * @param string  $code       加密code
+     * @param boolean $autoLogin  是否自动登录(需已注册会员)
+     */
+    public function getWxMiniProgramSessionKey()
+    {
+        $post = $this->request->post();
+        $autoLogin = $post['autoLogin'];
+        $wechat = new Wechat('wxMiniProgram');
+        $decryptSession = $wechat->code($post['code']);
+        if (!isset($decryptSession['session_key'])) {
+            $this->error('未获取session_key,请重启应用');
+        }
+        \think\Cache::set($decryptSession['session_key'], $decryptSession, 24 * 3600 * 31); // 强制31天过期
+        $userOauth = UserOauth::get([
+            'provider' => 'Wechat',
+            'platform' => 'wxMiniProgram',
+            'openid' => $decryptSession['openid'],
+            'user_id' => ['neq', 0]
+        ]);
+        if ($userOauth) {
+            $userOauth->save(['session_key' => $decryptSession['session_key']]);
+        }
+        if ($autoLogin && $userOauth) {
+            $ret = $this->auth->direct($userOauth->user_id);
+            if ($ret) {
+                $token = $this->auth->getToken();
+                $this->success(__('Logged in successful'), ['token' => $token, 'session_key' => $decryptSession['session_key'], 'openid' => $decryptSession['openid']]);
+            } else {
+                $this->error($this->auth->getError());
+            }
+        }
+
+        $this->success('', $decryptSession);
+    }
+    /**
+     * 微信小程序登录
+     *
+     * @param string  $session_key      session_key
+     * @param string  $signature        校验签名
+     * @param string  $iv               解密向量
+     * @param string  $encryptedData    需解密完整用户信息
+     * @param boolean $refresh          重新获取或刷新最新的用户信息 (用户头像失效或微信客户端修改昵称等情况)
+     */
+    public function wxMiniProgramOauth()
+    {
+        $post = $this->request->post();
+
+        $token = Db::transaction(function () use ($post) {
+            try {
+                $wechat = new Wechat('wxMiniProgram');
+                $decryptSession = \think\Cache::get($post['session_key']);
+                if (!$decryptSession || !isset($decryptSession['openid'])) {
+                    throw \Exception('未获取到登录态,请重试');
+                }
+                $decryptUserInfo = $wechat->decryptData($post['session_key'], $post['iv'], $post['encryptedData']); // 客户端传值数据都不可信,需服务端解密用户信息
+                $decryptUserInfo = array_merge($decryptUserInfo, $decryptSession);
+                //组装decryptData
+                $decryptData = array_change_key_case($decryptUserInfo, CASE_LOWER);
+                if (empty($decryptData['openid'])) {
+                    throw \Exception('code错误,请重试');
+                }
+                $decryptData['headimgurl'] = $decryptData['avatarurl'];
+                $decryptData['sex'] = $decryptData['gender'];
+                $decryptData['session_key'] = $post['session_key'];
+                return $this->oauthLoginOrRegisterOrBindOrRefresh($post['event'], $decryptData, 'wxMiniProgram', 'Wechat');
+            } catch (\Exception $e) {
+                $this->error($e->getMessage());
+            }
+        });
+
+        if ($token) {
+            $this->success(__('Logged in successful'), ['token' => $token]);
+        } else {
+            $this->error($this->auth->getError());
+        }
+    }
+
+    /**
+     * 微信APP登录
+     *
+     * @param string $authResult 授权信息
+     */
+    public function wxOpenPlatformOauth()
+    {
+        $post = $this->request->post();
+
+        $token = Db::transaction(function () use ($post) {
+            try {
+                //组装decryptData
+                $authResult = $post['authResult'];
+                $res = \fast\Http::get('https://api.weixin.qq.com/sns/userinfo?access_token=' . $authResult['access_token'] . '&openid=' . $authResult['openid']);
+                $userInfo = json_decode($res, true);
+                if (isset($userInfo['errmsg'])) {
+                    throw \Exception($userInfo['errmsg']);
+                }
+                $decryptData = array_merge($userInfo, $authResult);
+                return $this->oauthLoginOrRegisterOrBindOrRefresh($post['event'], $decryptData, 'App', 'Wechat');
+            } catch (\Exception $e) {
+                $this->error($e->getMessage());
+            }
+        });
+
+        if ($token) {
+            $this->success(__('Logged in successful'), ['token' => $token]);
+        } else {
+            $this->error($this->auth->getError());
+        }
+    }
+
+
+    /**
+     * 微信公众号登录、更新信息、绑定(授权页 非api)
+     *
+     * @param string $code 加密code
+     */
+    public function wxOfficialAccountOauth()
+    {
+        $token = '';
+        $params = $this->request->get();
+
+        $payload = json_decode(htmlspecialchars_decode($params['payload']), true);
+        // 解析前端主机
+        if ($payload['event'] !== 'login' && $payload['token'] !== '') {
+            $this->auth->init($payload['token']);
+        }
+
+        $wechat = new Wechat('wxOfficialAccount');
+        $oauth = $wechat->oauth();
+        $decryptData = $oauth->user()->getOriginal();
+        $token = Db::transaction(function () use ($payload, $decryptData) {
+            try {
+                $token = $this->oauthLoginOrRegisterOrBindOrRefresh($payload['event'], $decryptData, 'wxOfficialAccount', 'Wechat');
+                return $token;
+            } catch (\Exception $e) {
+                $this->error($e->getMessage());
+            }
+        });
+        // 跳转回前端
+        if ($token) {
+            header('Location: ' . $payload['host']  . 'pages/public/loading/?token=' . $token);
+        } else {
+            header('Location: ' . $payload['host']);
+        }
+        exit;
+    }
+
+    /**
+     * 苹果ID授权
+     *
+     * @param string $authResult 授权信息
+     * @param string $userInfo 用户信息
+     */
+    public function appleIdOauth()
+    {
+        $post = $this->request->post();
+        $userInfo = $post['userInfo'];
+        $token = '';
+        $platform = request()->header('platform');
+
+        try {
+            \think\Loader::addNamespace('AppleSignIn', ADDON_PATH . 'shopro' . DS . 'library' . DS . 'apple-signin' . DS);
+            $identityToken = $userInfo['identityToken'];
+            $clientUser = $userInfo['openId'];
+            $appleSignInPayload = \AppleSignIn\ASDecoder::getAppleSignInPayload($identityToken);
+            $isValid = $appleSignInPayload->verifyUser($clientUser);
+            if ($isValid) {
+                $nickname = '';
+                $headimgurl = '';
+                if (isset($userInfo['fullName']['familyName'])) {
+                    $nickname = $userInfo['fullName']['familyName'] . ' ' . $userInfo['fullName']['giveName'];
+                } else {
+                    $nickname = '';
+                }
+                $decryptData = [
+                    'openid' => $userInfo['openId'],
+                    'nickname' => $nickname,
+                    'access_token' => $userInfo['authorizationCode'],
+                    'headimgurl' => $headimgurl
+                ];
+                $token = $this->oauthLoginOrRegisterOrBindOrRefresh($post['event'], $decryptData, $platform, 'Apple');
+            }
+        } catch (\Exception $e) {
+            $this->error('登录失败:' . $e->getMessage());
+        }
+
+        if ($token) {
+            $this->success(__('Logged in successful'), ['token' => $token]);
+        } else {
+            $this->error($this->auth->getError());
+        }
+    }
+
+    /**
+     * 微信公众号静默登录
+     *
+     * @param string $code 加密code
+     */
+    public function wxOfficialAccountBaseLogin()
+    {
+        $wechat = new Wechat('wxOfficialAccount');
+        $oauth = $wechat->oauth();
+        $oUrl = input('get.state');
+        $url = explode('/', $oUrl);
+        $decryptData = $oauth->user()->getOriginal();
+        if ($decryptData) {
+            header('Location:' . $oUrl . '&openid=' . $decryptData['openid']);
+        } else {
+            $this->error('未获取到OPENID');
+        }
+    }
+
+    /**
+     * 第三方登录或自动注册或绑定
+     *
+     * @param string  $event        事件:login=登录, refresh=更新账号授权信息, bind=绑定第三方授权
+     * @param array   $decryptData  解密参数
+     * @param string  $platform     平台名称
+     * @param string  $provider     厂商名称
+     * @param int     $keeptime     有效时长
+     * @return string $token        返回用户token
+     */
+    private function oauthLoginOrRegisterOrBindOrRefresh($event, $decryptData, $platform, $provider, $keeptime = 0)
+    {
+        $oauthData = $decryptData;
+        $oauthData = array_merge($oauthData, [
+            'provider' => $provider,
+            'platform' => $platform,
+
+        ]);
+        if ($platform === 'wxMiniProgram' || $platform === 'App') {
+            $oauthData['expire_in'] = 7200;
+            $oauthData['expiretime'] = time() + 7200;
+        }
+        $userOauth = UserOauth::where(['openid' => $decryptData['openid'], 'user_id' => ['neq', 0]])->where('platform', $platform)->where('provider', $provider)->lock(true)->find();
+        switch ($event) {
+            case 'login':               // 登录(自动注册)
+                if (!$userOauth) {      // 没有找到第三方登录信息 创建新用户
+                    //默认创建新用户
+                    $user_id = 0;
+                    $createNewUser = true;
+                    $oauthData['logintime'] = time();
+                    $oauthData['logincount'] = 1;
+                    // 判断是否有unionid 并且已存在oauth数据中
+                    if (isset($oauthData['unionid'])) {
+                        //存在同厂商信息,添加oauthData数据,合并用户
+                        $userUnionOauth = UserOauth::get(['unionid' => $oauthData['unionid'], 'provider' => $provider, 'user_id' => ['neq', 0]]);
+                        if ($userUnionOauth) {
+                            $existUser = $this->auth->direct($userUnionOauth->user_id);
+                            if ($existUser) {
+                                $createNewUser = false;
+                            }
+                        }
+                    }
+
+                    // 创建空用户
+                    if ($createNewUser) {
+                        $username = Random::alnum(20);
+                        $password = '';
+                        $domain = request()->host();
+                        $extend = $this->getUserDefaultFields();
+                        $extend['nickname'] = $oauthData['nickname'] ? $oauthData['nickname'] : $extend['nickname'];
+                        $extend['avatar'] = $oauthData['headimgurl'] ? $oauthData['headimgurl'] : $extend['avatar'];
+                        $this->auth->register($username, $password, $username . '@' . $domain, '', $extend, $keeptime);
+                        if (empty($oauthData['nickname'])) {
+                            $this->auth->getUser()->save(['nickname' => $extend['nickname'] . $this->auth->getUser()->id]);
+                        }
+                    }
+                    $oauthData['user_id'] = $this->auth->getUser()->id;
+                    $oauthData['createtime'] = time();
+                    UserOauth::strict(false)->insert($oauthData);
+                } else {
+                    // 找到第三方登录信息,直接登录
+                    $user_id = $userOauth->user_id;
+                    if ($user_id && $this->auth->direct($user_id) && $this->auth->getUser()) {       // 获取到用户
+                        $oauthData['logincount'] = $userOauth->logincount + 1;
+                        $oauthData['logintime'] = time();
+                        $userOauth->allowField(true)->save($oauthData);
+                    } else {         // 用户已被删除 重新执行登录
+                        // throw \Exception('此用户已删除');
+                        $userOauth->delete();
+                        $this->oauthLoginOrRegisterOrBindOrRefresh($event, $decryptData, $platform, $provider);                    }
+                }
+                break;
+            case 'refresh':
+                if (!$userOauth) {
+                    throw \Exception('未找到第三方授权账户');
+                }
+                if (!empty($oauthData['nickname'])) {
+                    $refreshFields['nickname'] = $oauthData['nickname'];
+                }
+                if (!empty($oauthData['headimgurl'])) {
+                    $refreshFields['avatar'] = $oauthData['headimgurl'];
+                }
+                $this->auth->getUser()->save($refreshFields);
+                $userOauth->allowField(true)->save($oauthData);
+                break;
+            case 'bind':
+                if (!$this->auth->getUser()) {
+                    throw \Exception('请先登录');
+                }
+
+                $oauthData['user_id'] = $this->auth->getUser()->id;
+
+                if ($userOauth) {
+                    if ($userOauth['user_id'] != 0 && $userOauth['user_id'] != $this->auth->getUser()->id && UserModel::get($userOauth['user_id'])) {
+                        throw \Exception('该账号已被其他用户绑定');
+                    }
+                    $oauthData['id'] = $userOauth->id;
+                    $userOauth->strict(false)->update($oauthData);
+                } else {
+                    $oauthData['logincount'] = 1;
+                    $oauthData['logintime'] = time();
+                    $oauthData['createtime'] = time();
+                    UserOauth::strict(false)->insert($oauthData);
+                }
+                break;
+        }
+        if ($this->auth->getUser()) {
+            $this->setUserVerification($this->auth->getUser(), $provider, $platform);
+            return $this->auth->getToken();
+        }
+        return false;
+    }
+
+    /**
+     * 第三方用户授权信息
+     */
+    public function thirdOauthInfo()
+    {
+        $user = $this->auth->getUser();
+        $platform = request()->header('platform');
+        $userOauth = UserOauth::where([
+            'platform' => $platform,
+            'user_id'  => $user->id
+        ])->field('headimgurl, nickname')->find();
+        $this->success('获取成功', $userOauth);
+    }
+
+
+    /**
+     * 解除绑定
+     */
+    public function unbindThirdOauth()
+    {
+        $user = $this->auth->getUser();
+        $platform = $this->request->post('platform');
+        $provider = $this->request->post('provider');
+
+        $verification = $user->verification;
+        if (!$verification->mobile) {
+            $this->error('请先绑定手机号再进行解绑操作');
+        }
+
+        $verifyField = $platform;
+        if ($platform === 'App' && $provider === 'Wechat') {
+            $verifyField = 'wxOpenPlatform';
+        }
+
+        $verification->$verifyField = 0;
+        $user->verification = $verification;
+        $user->save();
+        $userOauth = UserOauth::where([
+            'platform' => $platform,
+            'provider'  => $provider,
+            'user_id' => $user->id
+        ])->delete();
+        if ($userOauth) {
+            $this->success('解绑成功');
+        }
+        $this->error('解绑失败');
+    }
+
+    /**
+     * 注销登录
+     */
+    public function logout()
+    {
+        if ($this->auth->isLogin()) {
+            $this->auth->logout();
+        }
+        $this->success(__('Logout successful'));
+    }
+
+
+    /**
+     * 修改会员个人信息
+     *
+     * @param string $avatar 头像地址
+     * @param string $username 用户名
+     * @param string $nickname 昵称
+     * @param string $birthday 生日
+     * @param string $bio 个人简介
+     */
+    public function profile()
+    {
+        $user = $this->auth->getUser();
+        $username = $this->request->post('username');
+        $nickname = $this->request->post('nickname');
+        $bio = $this->request->post('bio', '');
+        $birthday = $this->request->post('birthday');
+        $avatar = $this->request->post('avatar', '', 'trim,strip_tags,htmlspecialchars');
+        if ($username) {
+            $exists = \app\common\model\User::where('username', $username)->where('id', '<>', $this->auth->id)->find();
+            if ($exists) {
+                $this->error(__('Username already exists'));
+            }
+            $user->username = $username;
+        }
+        $user->nickname = $nickname;
+        $user->bio = $bio;
+        $user->birthday = $birthday;
+        if (!empty($avatar)) {
+            $user->avatar = $avatar;
+        }
+        $user->save();
+        $this->success();
+    }
+
+    private function getUserDefaultFields()
+    {
+        $userConfig = json_decode(\addons\shopro\model\Config::get(['name' => 'user'])->value, true);
+        return $userConfig;
+    }
+
+    private function setUserVerification($user, $provider, $platform)
+    {
+        $verification = $user->verification;
+        if ($platform === 'App') {
+            $platform = '';
+            if ($provider === 'Wechat') {
+                $platform = 'wxOpenPlatform';
+            } elseif ($provider === 'Alipay') {
+                $platform = 'aliOpenPlatform';
+            }
+        }
+        if ($platform !== '') {
+            $verification->$platform = 1;
+            $user->verification = $verification;
+            $user->save();
+        }
+    }
+}

+ 38 - 0
addons/shopro/controller/UserBank.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace addons\shopro\controller;
+
+
+class UserBank extends Base
+{
+
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+
+    // 获取提现账户信息
+    public function info()
+    {
+        $type = $this->request->get('type');
+        try {
+            $bankInfo = \addons\shopro\model\UserBank::info($type);
+        } catch (\Exception $e) {
+            $this->error($e->getMessage());
+        }
+        $this->success('提现账户', $bankInfo);
+    }
+
+
+    public function edit()
+    {
+        $params = $this->request->post();
+        if ($params['type'] === 'alipay') {
+            $params['bank_name'] = '支付宝账户';
+        }
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'edit');
+
+        $this->success('编辑成功', \addons\shopro\model\UserBank::edit($params));
+    }
+}

+ 28 - 0
addons/shopro/controller/UserSign.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace addons\shopro\controller;
+
+
+class UserSign extends Base
+{
+
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+
+    // 按月份获取签到记录
+    public function index()
+    {
+        $params = $this->request->get();
+        
+        $this->success('获取成功', \addons\shopro\model\UserSign::getList($params));
+    }
+
+
+    public function sign () {
+        $params = $this->request->post();
+
+        $this->success('签到成功', \addons\shopro\model\UserSign::sign($params));
+    }
+
+}

+ 56 - 0
addons/shopro/controller/UserWalletApply.php

@@ -0,0 +1,56 @@
+<?php
+
+namespace addons\shopro\controller;
+
+
+class UserWalletApply extends Base
+{
+
+    protected $noNeedLogin = ['rule'];
+    protected $noNeedRight = ['*'];
+
+
+    public function index()
+    {
+        $this->success('提现记录', \addons\shopro\model\UserWalletApply::getList());
+    }
+
+
+    // 申请提现
+    public function apply()
+    {
+        $type = $this->request->post('type');
+        $money = $this->request->post('money');
+        $apply = \think\Db::transaction(function () use ($type, $money) {
+            try {
+                return \addons\shopro\model\UserWalletApply::apply($type, $money);
+            } catch (\Exception $e) {
+                $this->error($e->getMessage());
+            }
+        });
+        if($apply) {
+            $this->success('申请成功');            
+        }
+        $this->error('申请失败');
+    }
+
+
+    public function rule()
+    {
+        // 提现规则
+        $config = \addons\shopro\model\UserWalletApply::getWithdrawConfig();
+        $min = round(floatval($config['min']), 2);
+        $max = round(floatval($config['max']), 2);
+        $service_fee = floatval($config['service_fee']) * 100;
+        $service_fee = round($service_fee, 1);      // 1 位小数
+
+        $rule = [
+            'min' => $min,
+            'max' => $max,
+            'service_fee' => $service_fee,
+            'methods' => $config['methods'] ?? []
+        ];
+
+        $this->success('提现规则', $rule);
+    }
+}

+ 26 - 0
addons/shopro/controller/UserWalletLog.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\exception\Exception;
+
+class UserWalletLog extends Base
+{
+
+    protected $noNeedLogin = ['*'];
+    protected $noNeedRight = ['*'];
+
+
+    public function index()
+    {
+        $params = $this->request->get();
+        $wallet_type = $params['wallet_type'] ?? 'money';
+
+        if (!in_array($wallet_type, ['money', 'score'])) {
+            $this->error('参数错误');
+        }
+
+        $this->success(($wallet_type == 'money' ? '钱包记录' : '积分记录'), \addons\shopro\model\UserWalletLog::getList($params));
+    }
+
+}

+ 197 - 0
addons/shopro/controller/Wechat.php

@@ -0,0 +1,197 @@
+<?php
+
+namespace addons\shopro\controller;
+
+use addons\shopro\library\Wechat as WechatLibrary;
+use addons\shopro\model\Wechat as WechatModel;
+use addons\shopro\model\Config;
+
+/**
+ * 微信接口
+ */
+class Wechat extends Base
+{
+    protected $noNeedLogin = ['*'];
+    protected $noNeedRight = ['*'];
+    protected $app = null;
+    protected $userOpenId = '';
+    /**
+     * 微信公众号服务端API对接、处理消息回复
+     */
+    public function index()
+    {
+        $wechat = new WechatLibrary('wxOfficialAccount');
+        $this->app = $wechat->getApp();
+        $this->app->server->push(function ($message) {
+            //初始化信息
+            $this->userOpenId = $message['FromUserName'];
+            // return json_encode($message, JSON_UNESCAPED_UNICODE); //调试使用
+
+            switch ($message['MsgType']) {
+                case 'event': //收到事件消息
+                    switch ($message['Event']) {
+                        case 'subscribe': //订阅(关注)事件
+                            //获取粉丝信息并保存
+                            $subscribe = WechatModel::get(['type' => 'subscribe']);
+                            if ($subscribe) {
+                                return $this->response($subscribe);
+                            }
+                            break;
+                        case 'unsubscribe': //取消订阅(关注)事件
+                            //获取粉丝信息并保存
+                            break;
+                        case 'CLICK':  //自定义菜单事件
+                            return $this->response($message, 'CLICK');
+                            break;
+                        case 'SCAN': //扫码事件
+                            return '';
+                            break;
+                    }
+                    break;
+                case 'text': //收到文本消息
+                    //检测关键字回复
+                    $content = $message['Content'];
+                    $auto_reply = WechatModel::where('type', 'auto_reply')->where('find_in_set(:keywords,rules)', ['keywords' => $content])->find();
+                    if ($auto_reply) {
+                        return $this->response($auto_reply);
+                    }
+                case 'image': //收到图片消息
+                case 'voice': //收到语音消息
+                case 'video': //收到视频消息
+                case 'location': //收到坐标消息
+                case 'link': //收到链接消息
+                case 'file': //收到文件消息
+                default: // ... 默认回复消息
+                    $default_reply = WechatModel::where('type', 'default_reply')->find();
+                    if ($default_reply) {
+                        return $this->response($default_reply);
+                    }
+            }
+        });
+        $response = $this->app->server->serve();
+        // 将响应输出
+        $response->send();
+    }
+
+    public function jssdk()
+    {
+        $params = $this->request->post();
+        $apis = [
+            'checkJsApi',
+            'updateTimelineShareData',
+            'updateAppMessageShareData',
+            'getLocation', //获取位置
+            'openLocation', //打开位置
+            'scanQRCode', //扫一扫接口
+            'chooseWXPay', //微信支付
+            'chooseImage', //拍照或从手机相册中选图接口
+            'previewImage', //预览图片接口       'uploadImage', //上传图片
+            'openAddress',   // 获取微信地址
+        ];
+        $openTagList = [
+            'wx-open-subscribe'
+        ];
+
+        $uri = urldecode($params['uri']);
+        
+        $wechat = new WechatLibrary('wxOfficialAccount');
+
+        $jssdk = $wechat->getApp()->jssdk->setUrl($uri);
+        // easywechat 版本 < 4.2.33 的 buildConfig 方法 没有 openTagList 参数,手动覆盖底层 buildConfig 方法
+        $res = $wechat->buildConfig($jssdk, $apis, $debug = false, $beta = false, $json = false, $openTagList);
+
+        $this->success('sdk', $res);
+    }
+
+
+
+    /**
+     * 微信公众号服务端API对接
+     */
+    public function wxacode()
+    {
+        $scene = $this->request->get('scene', '');
+        $path = $this->request->get('path', '');
+
+        if (empty($path)) {
+            $path = 'pages/index/index';
+        }
+
+        $wechat = new WechatLibrary('wxMiniProgram');
+        $content = $wechat->getApp()->app_code->getUnlimit($scene, [
+            'page' => $path,
+            'is_hyaline' => true,
+        ]);
+
+        if ($content instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
+            return response($content->getBody(), 200, ['Content-Length' => strlen($content)])->contentType('image/png');
+        } else {
+            // 小程序码获取失败
+            $msg = isset($content['errcode']) ? $content['errcode'] : '-';
+            $msg .= isset($content['errmsg']) ? $content['errmsg'] : '';
+            \think\Log::write('wxacode-error' . $msg);
+
+            $this->error('获取失败', $msg);
+        }
+    }
+
+    /**
+     * 回复消息
+     */
+    private function response($replyInfo, $event = 'text')
+    {
+        switch ($event) {
+            case 'SCAN': //解析扫码事件EventKey
+                break;
+            case 'CLICK': //解析菜单点击事件EventKey
+                $key = explode('|', $replyInfo['EventKey']);
+                if ($key) {
+                    $message['type'] = $key[0];
+                    if ($key[0] === 'text') {
+                        $message['content'] =  json_decode(WechatModel::get($key[1])->content, true);
+                    } elseif($key[0] === 'link') {
+                        $link = WechatModel::get($key[1]);
+                        $message = array_merge($message, json_decode($link->content, true));
+                        $message['title'] = $link->name;
+                        // return json_encode($message);
+                    }else {
+                        $message['media_id'] = $key[1];
+                    }
+                }
+                break;
+            default:
+                $message = json_decode($replyInfo['content'], true);
+                break;
+        }
+
+        switch ($message['type']) {
+            case 'text':  //回复文本
+                $content = new \EasyWeChat\Kernel\Messages\Text($message['content']);
+                break;
+            case 'image': //回复图片
+                $content = new \EasyWeChat\Kernel\Messages\Image($message['media_id']);
+                break;
+            case 'news': //回复图文
+                $message = new \EasyWeChat\Kernel\Messages\Media($message['media_id'], 'mpnews');
+                $this->app->customer_service->message($message)->to($this->userOpenId)->send();  //素材消息使用客服接口回复
+                break;
+            case 'voice': //回复语音
+                $content = new \EasyWeChat\Kernel\Messages\Voice($message['media_id']);
+                break;
+            case 'video': //回复视频
+                $content = new \EasyWeChat\Kernel\Messages\Video($message['media_id']);
+                break;
+            case 'link': //回复链接
+                $items = new  \EasyWeChat\Kernel\Messages\NewsItem([
+                    'title'       => $message['title'],
+                    'description' => $message['description'],
+                    'url'         => $message['url'],
+                    'image'       => cdnurl($message['image'], true),
+                    // ...
+                ]);
+                $content = new \EasyWeChat\Kernel\Messages\News([$items]);
+                break;
+        }
+        return $content;
+    }
+}

+ 39 - 0
addons/shopro/controller/chat/Index.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace addons\shopro\controller\chat;
+
+use addons\shopro\controller\Base as AddonsBase;
+use addons\shopro\model\chat\Question;
+
+/**
+ * Index 
+ */
+class Index extends AddonsBase
+{
+    protected $noNeedLogin = ['init'];
+    protected $noNeedRight = ['*'];
+
+
+    /**
+     * 客服初始化
+     *
+     * @return void
+     */
+    public function init() {
+        $config = json_decode(\addons\shopro\model\Config::where(['name' => 'chat'])->value('value'), true);
+        // 初始化 ssl 类型, 默认 cert
+        $config['system'] = $config['system'] ?? [];
+        $config['system']['ssl_type'] = $config['system']['ssl_type'] ?? 'cert';
+
+        // 常见问题
+        $question = Question::show()->order('weigh', 'desc')->select();
+
+        $result = [
+            'config' => $config,
+            'question' => $question,
+            'emoji' => json_decode(file_get_contents(ROOT_PATH . 'public/assets/addons/shopro/libs/emoji.json'), true)
+        ];
+
+        $this->success('初始化成功', $result);
+    }
+}

+ 34 - 0
addons/shopro/controller/store/Apply.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace addons\shopro\controller\store;
+
+use addons\shopro\exception\Exception;
+use addons\shopro\controller\Base as ShoproBase;
+
+/**
+ * 不继承门店的 base
+ */
+class Apply extends ShoproBase
+{
+
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+
+    public function info() {
+        $this->success('门店申请', \addons\shopro\model\store\Apply::info());
+    }
+
+
+    public function apply() {
+        $params = $this->request->post();
+
+        // 表单验证
+        $this->shoproValidate($params, get_class(), 'apply');
+
+        $order = \addons\shopro\model\store\Apply::apply($params);
+
+        $this->success('门店申请提交成功', $order);
+    }
+
+}

+ 48 - 0
addons/shopro/controller/store/Base.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace addons\shopro\controller\store;
+
+use addons\shopro\exception\Exception;
+use addons\shopro\controller\Base as AddonsBase;
+use addons\shopro\model\Store;
+use addons\shopro\model\User;
+use addons\shopro\model\UserStore;
+
+class Base extends AddonsBase
+{
+    public function _initialize()
+    {
+        parent::_initialize();
+
+        // 验证登录用户是否可以访问门店接口
+        $this->checkUserStore();
+    }
+
+
+    /**
+     * 检测用户管理的是否有门店
+     */
+    private function checkUserStore() {
+        // 获取当前用户的门店
+        $user = User::info();
+        $store_id = $this->request->param('store_id');
+
+        if (!$store_id) {
+            $this->error('请选择门店');
+        }
+
+        $userStore = UserStore::with('store')->where('user_id', $user->id)->where('store_id', $store_id)->find();
+        if (!$userStore || !$userStore->store) {
+            $this->error('权限不足');
+        }
+
+        $store = $userStore->store->toArray();
+
+        if (!$store['status']) {
+            $this->error('门店已被禁用');
+        }
+
+        // 存 session 本次请求有效
+        session('current_oper_store', $store);
+    }
+}

+ 39 - 0
addons/shopro/controller/store/Order.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace addons\shopro\controller\store;
+
+class Order extends Base
+{
+
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+
+    public function index()
+    {
+        $params = $this->request->get();
+
+        $this->success('订单列表', \addons\shopro\model\store\Order::getList($params));
+    }
+
+
+
+    public function detail()
+    {
+        $params = $this->request->get();
+        $this->success('订单详情', \addons\shopro\model\store\Order::detail($params));
+    }
+
+
+    public function send() {
+        $params = $this->request->post();
+        $this->success('发货成功', \addons\shopro\model\store\Order::operSend($params));
+    }
+
+
+    public function confirm()
+    {
+        $params = $this->request->post();
+        $this->success('核销成功', \addons\shopro\model\store\Order::operConfirm($params));
+    }
+}

+ 26 - 0
addons/shopro/controller/store/Store.php

@@ -0,0 +1,26 @@
+<?php
+
+namespace addons\shopro\controller\store;
+
+use addons\shopro\exception\Exception;
+use addons\shopro\model\Store as ModelStore;
+
+class Store extends Base
+{
+
+    protected $noNeedLogin = [];
+    protected $noNeedRight = ['*'];
+
+
+    public function index()
+    {
+        $params = $this->request->get();
+        $store = ModelStore::info();
+        if (!$store) {
+            $this->error('门店不存在');
+        }
+
+        $this->success('获取成功', $store);
+    }
+    
+}

+ 30 - 0
addons/shopro/exception/Exception.php

@@ -0,0 +1,30 @@
+<?php
+namespace addons\shopro\exception;
+
+use think\Response;
+
+class Exception
+{
+    protected $msg = '错误消息';
+    protected $code = 0;  //TOAST自动弹出消息
+    const NOT_LOGIN = 401; //未登录自动弹框提醒
+    const NOT_AUTHORIZE = 403;//
+    const IGNORE = -1;
+    public function __construct($msg, $code = 0, $status_code = 200)
+    {
+        $this->msg = $msg;
+        $this->code = $code;
+        $this->send($status_code);
+    }
+    protected function send($code = 200)
+    {
+        $data = [
+            'code' => $this->code,
+            'msg' => $this->msg,
+            'data' => null,
+            'time' => time()
+        ];
+        $response = Response::create($data, 'json', $code);
+        throw new \think\exception\HttpResponseException($response);
+    }
+}

+ 133 - 0
addons/shopro/helper.php

@@ -0,0 +1,133 @@
+<?php
+
+if (!function_exists('matchLatLng')) {
+    function matchLatLng($latlng) {
+        $match = "/^\d{1,3}\.\d{1,30}$/";
+        return preg_match($match, $latlng) ? $latlng : 0;
+    }
+}
+
+
+if (!function_exists('getDistanceBuilder')) {
+    function getDistanceBuilder($lat, $lng) {
+        return "ROUND(6378.138 * 2 * ASIN(SQRT(POW(SIN((". matchLatLng($lat) . " * PI() / 180 - latitude * PI() / 180) / 2), 2) + COS(". matchLatLng($lat). " * PI() / 180) * COS(latitude * PI() / 180) * POW(SIN((". matchLatLng($lng). " * PI() / 180 - longitude * PI() / 180) / 2), 2))) * 1000) AS distance";
+    }
+}
+
+
+/**
+ * 下划线转驼峰
+ * step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
+ * step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
+ */
+if (!function_exists('camelize')) {
+    function camelize($uncamelized_words, $separator = '_') {
+        $uncamelized_words = $separator . str_replace($separator, " ", strtolower($uncamelized_words));
+        return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator);
+    }
+}
+    
+/**
+ * 驼峰命名转下划线命名
+ * 思路:
+ * 小写和大写紧挨一起的地方,加上分隔符,然后全部转小写
+ */
+if (!function_exists('uncamelize')) {
+    function uncamelize($camelCaps, $separator='_')
+    {
+        return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
+    }
+}
+
+
+/**
+ * 检测系统必要环境
+ */
+if (!function_exists('checkEnv')) {
+    function checkEnv($need = [], $is_throw = true)
+    {
+        $need = is_string($need) ? [$need] : $need;
+
+        // 检测是否安装浮点数运算扩展
+        if (in_array('bcmath', $need)) {
+            if (!extension_loaded('bcmath')) {
+                if ($is_throw) {
+                    new \addons\shopro\exception\Exception('请安装浮点数扩展 bcmath');
+                } else {
+                    return false;
+                }
+            }
+        }
+
+        // 检测是否安装了队列
+        if (in_array('queue', $need)) {
+            if (!class_exists(\think\Queue::class)) {
+                if ($is_throw) {
+                    new \addons\shopro\exception\Exception('请安装 topthink/think-queue:v1.1.6 队列扩展');
+                } else {
+                    return false;
+                }
+            }
+        }
+
+        if (in_array('commission', $need)) {
+            if (!class_exists(\addons\shopro\listener\commission\CommissionHook::class)) {
+                if ($is_throw) {
+                    new \addons\shopro\exception\Exception('请先升级 shopro');
+                } else {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+}
+
+
+/**
+ * 删除 sql mode 指定模式,或者直接关闭 sql mode
+ */
+if (!function_exists('closeStrict')) {
+    function closeStrict($modes = [])
+    {
+        $modes = array_filter(is_array($modes) ? $modes : [$modes]);
+
+        $result = \think\Db::query("SELECT @@session.sql_mode");
+        $newModes = $oldModes = explode(',', ($result[0]['@@session.sql_mode'] ?? ''));
+
+        if ($modes) {
+            foreach ($modes as $mode) {
+                $delkey = array_search($mode, $newModes);
+                if ($delkey !== false) {
+                    unset($newModes[$delkey]);
+                }
+            }
+            $newModes = join(',', array_values(array_filter($newModes)));
+        } else {
+            $newModes = '';
+        }
+
+        \think\Db::execute("set session sql_mode='" . $newModes . "'");
+
+        return $oldModes;
+    }
+}
+
+
+/**
+ * 重新打开被关闭的 sql mode
+ */
+if (!function_exists('recoverStrict')) {
+    function recoverStrict($modes = [], $append = false)
+    {
+        if ($append) {
+            $result = \think\Db::query("SELECT @@session.sql_mode");
+            $oldModes = explode(',', ($result[0]['@@session.sql_mode'] ?? ''));
+
+            $modes = array_values(array_filter(array_unique(array_merge($oldModes, $modes))));
+        }
+
+        \think\Db::execute("set session sql_mode='" . join(',', $modes) . "'");
+    }
+}

+ 122 - 0
addons/shopro/hooks.php

@@ -0,0 +1,122 @@
+<?php
+
+$defaultHooks = [
+  // 订单创建
+  'order_create_before' => [       // 订单创建前
+    'addons\\shopro\\listener\\order\\Create'
+  ],
+  'order_create_after' => [        // 订单创建后
+    'addons\\shopro\\listener\\order\\Create'
+  ],
+  'order_payed_after' => [        // 订单支付成功
+    'addons\\shopro\\listener\\order\\Payed'
+  ],
+
+  // 订单关闭
+  'order_close_before' => [       // 订单关闭前
+  ],
+  'order_close_after' => [        // 订单关闭后
+    'addons\\shopro\\listener\\order\\Invalid'
+  ],
+
+  // 订单取消
+  'order_cancel_before' => [        // 订单取消前
+  ],
+  'order_cancel_after' => [         // 订单取消后
+    'addons\\shopro\\listener\\order\\Invalid'
+  ],
+
+  // 订单发货
+  'order_send_before' => [       // 订单发货前
+  ],
+  'order_send_after' => [        // 订单发货后
+    'addons\\shopro\\listener\\order\\Send'
+  ],
+
+  // 订单确认收货
+  'order_confirm_before' => [       // 订单确认收货前
+  ],
+  'order_confirm_after' => [        // 订单确认收货后
+    'addons\\shopro\\listener\\order\\Confirm'
+  ],
+  'order_confirm_finish' => [       // 订单确认收货完成
+  ],
+
+  // 订单完成事件
+  'order_finish' => [],
+
+  // 订单评价
+  'order_comment_before' => [       // 订单评价前
+  ],
+  'order_comment_after' => [        // 订单评价后
+    'addons\\shopro\\listener\\order\\Comment'
+  ],
+
+  // 订单退款
+  'order_refund_before' => [       // 订单退款前
+    'addons\\shopro\\listener\\order\\Refund'
+  ],
+  'order_refund_after' => [        // 订单退款后
+    'addons\\shopro\\listener\\order\\Refund'
+  ],
+
+  // 售后完成
+  'aftersale_finish_before' => [        // 售后完成前
+  ],
+  'aftersale_finish_after' => [        // 售后完成后
+  ],
+
+  // 售后拒绝
+  'aftersale_refuse_before' => [        // 售后拒绝前
+  ],
+  'aftersale_refuse_after' => [        // 售后拒绝后
+  ],
+
+  // 售后变动,(包含完成,拒绝)
+  'aftersale_change' => [               // 售后变动
+    'addons\\shopro\\listener\\order\\Aftersale'
+  ],
+
+  // 活动更新
+  'activity_update_after' => [        // 活动更新后
+    'addons\\shopro\\listener\\activity\\Update'
+  ],
+  'activity_delete_after' => [        // 活动删除之后
+    'addons\\shopro\\listener\\activity\\Update'
+  ],
+
+  // 拼团
+  'activity_groupon_finish' => [        // 拼团成功
+    'addons\\shopro\\listener\\activity\\Groupon'
+  ],
+  'activity_groupon_fail' => [        // 拼团失败,超时,后台手动解散等
+    'addons\\shopro\\listener\\activity\\Groupon'
+  ]
+];
+
+// 分销相关钩子
+$commissionHooks = [
+  'order_payed_after' => [        // 订单支付成功
+    'addons\\shopro\\listener\\commission\\CommissionHook'
+  ],
+  'share_after' => [            //分享后
+    'addons\\shopro\\listener\\commission\\CommissionHook'
+  ],
+  'order_confirm_after' => [        // 订单确认收货后
+    'addons\\shopro\\listener\\commission\\CommissionHook'
+  ],
+  'order_refund_after' => [        // 订单退款后
+    'addons\\shopro\\listener\\commission\\CommissionHook'
+  ],
+  'order_finish' => [   // 订单完成事件
+    'addons\\shopro\\listener\\commission\\CommissionHook'
+  ],
+  
+
+];
+
+if (file_exists(ROOT_PATH . 'addons/shopro/listener/commission')) {
+  $defaultHooks = array_merge_recursive($defaultHooks, $commissionHooks);
+}
+
+return $defaultHooks;

+ 11 - 0
addons/shopro/info.ini

@@ -0,0 +1,11 @@
+name = shopro
+title = Shopro商城
+intro = 客服系统、分销商城、多发货方式、到店核销、antV数据中心、店铺装修、小程序直播、跨端通用分享、自定义营销活动、Canvas分享海报、消息通知、微信管理、积分商城、拼团、秒杀等多种功能
+author = 星品科技
+website = https://shopro.top
+version = 1.3.2
+state = 1
+url = /addons/shopro
+first_menu = shopro
+license = regular
+licenseto = 46647

+ 5290 - 0
addons/shopro/install.sql

@@ -0,0 +1,5290 @@
+CREATE TABLE IF NOT EXISTS `__PREFIX__jobs` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `queue` varchar(255) CHARACTER SET utf8 NOT NULL,
+  `payload` longtext CHARACTER SET utf8 NOT NULL,
+  `attempts` tinyint(3) UNSIGNED NOT NULL,
+  `reserved` tinyint(3) UNSIGNED NOT NULL,
+  `reserved_at` int(10) UNSIGNED DEFAULT NULL,
+  `available_at` int(10) UNSIGNED NOT NULL,
+  `created_at` int(10) UNSIGNED NOT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_activity` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `title` varchar(50) DEFAULT NULL COMMENT '活动名称',
+  `goods_ids` varchar(1200) DEFAULT NULL COMMENT '商品组',
+  `type` varchar(20) DEFAULT NULL COMMENT '类型',
+  `richtext_id` int(11) DEFAULT 0 COMMENT '活动说明',
+  `richtext_title` varchar(255) DEFAULT NULL COMMENT '说明标题',
+  `starttime` int(11) DEFAULT NULL COMMENT '开始时间',
+  `endtime` int(11) DEFAULT NULL COMMENT '结束时间',
+  `rules` text COMMENT '活动规则',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营销活动';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_activity_goods_sku_price` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `activity_id` int(11) NOT NULL DEFAULT '0' COMMENT '活动 id',
+  `sku_price_id` int(11) NOT NULL DEFAULT '0' COMMENT '规格 id',
+  `goods_id` int(11) NOT NULL COMMENT '所属产品',
+  `stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存',
+  `sales` int(11) NOT NULL DEFAULT '0' COMMENT '已售',
+  `price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '价格',
+  `status` varchar(20) DEFAULT NULL COMMENT '状态',
+  `createtime` int(11) DEFAULT NULL,
+  `updatetime` int(11) DEFAULT NULL,
+  `deletetime` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品规格';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_activity_groupon` (
+  `id` int(10) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL DEFAULT '0' COMMENT '团长',
+  `goods_id` int(11) NOT NULL COMMENT '商品',
+  `activity_id` int(11) NOT NULL COMMENT '活动',
+  `num` int(11) NOT NULL COMMENT '成团人数',
+  `current_num` int(11) NOT NULL COMMENT '当前人数',
+  `status` enum('invalid','ing','finish','finish-fictitious') NOT NULL COMMENT '状态:invalid=已过期,ing=进行中,finish=已成团,finish-fictitious=虚拟成团',
+  `expiretime` int(10) DEFAULT NULL COMMENT '过期时间',
+  `finishtime` int(10) DEFAULT NULL COMMENT '成团时间',
+  `createtime` int(10) DEFAULT NULL COMMENT '添加时间',
+  `updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_activity_groupon_log` (
+  `id` int(10) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户',
+  `user_nickname` varchar(50) DEFAULT NULL COMMENT '用户昵称',
+  `user_avatar` varchar(1500) DEFAULT NULL COMMENT '头像',
+  `groupon_id` int(11) NOT NULL DEFAULT '0' COMMENT '团',
+  `goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品',
+  `goods_sku_price_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品规格',
+  `activity_id` int(11) NOT NULL DEFAULT '0' COMMENT '活动',
+  `is_leader` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否团长',
+  `is_fictitious` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否虚拟用户',
+  `order_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单',
+  `is_refund` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否退款',
+  `createtime` int(10) DEFAULT NULL COMMENT '添加时间',
+  `updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_area` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(50) DEFAULT NULL COMMENT '名称',
+  `pid` int(11) DEFAULT '0' COMMENT '上级',
+  `level` int(11) DEFAULT '1',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='省市区数据';
+
+INSERT INTO `__PREFIX__shopro_area` (`id`, `name`, `pid`, `level`) VALUES
+(110000, '北京市', 0, 1),
+(110100, '北京市', 110000, 2),
+(110101, '东城区', 110100, 3),
+(110102, '西城区', 110100, 3),
+(110105, '朝阳区', 110100, 3),
+(110106, '丰台区', 110100, 3),
+(110107, '石景山区', 110100, 3),
+(110108, '海淀区', 110100, 3),
+(110109, '门头沟区', 110100, 3),
+(110111, '房山区', 110100, 3),
+(110112, '通州区', 110100, 3),
+(110113, '顺义区', 110100, 3),
+(110114, '昌平区', 110100, 3),
+(110115, '大兴区', 110100, 3),
+(110116, '怀柔区', 110100, 3),
+(110117, '平谷区', 110100, 3),
+(110118, '密云区', 110100, 3),
+(110119, '延庆区', 110100, 3),
+(120000, '天津市', 0, 1),
+(120100, '天津市', 120000, 2),
+(120101, '和平区', 120100, 3),
+(120102, '河东区', 120100, 3),
+(120103, '河西区', 120100, 3),
+(120104, '南开区', 120100, 3),
+(120105, '河北区', 120100, 3),
+(120106, '红桥区', 120100, 3),
+(120110, '东丽区', 120100, 3),
+(120111, '西青区', 120100, 3),
+(120112, '津南区', 120100, 3),
+(120113, '北辰区', 120100, 3),
+(120114, '武清区', 120100, 3),
+(120115, '宝坻区', 120100, 3),
+(120116, '滨海新区', 120100, 3),
+(120117, '宁河区', 120100, 3),
+(120118, '静海区', 120100, 3),
+(120119, '蓟州区', 120100, 3),
+(130000, '河北省', 0, 1),
+(130100, '石家庄市', 130000, 2),
+(130102, '长安区', 130100, 3),
+(130104, '桥西区', 130100, 3),
+(130105, '新华区', 130100, 3),
+(130107, '井陉矿区', 130100, 3),
+(130108, '裕华区', 130100, 3),
+(130109, '藁城区', 130100, 3),
+(130110, '鹿泉区', 130100, 3),
+(130111, '栾城区', 130100, 3),
+(130121, '井陉县', 130100, 3),
+(130123, '正定县', 130100, 3),
+(130125, '行唐县', 130100, 3),
+(130126, '灵寿县', 130100, 3),
+(130127, '高邑县', 130100, 3),
+(130128, '深泽县', 130100, 3),
+(130129, '赞皇县', 130100, 3),
+(130130, '无极县', 130100, 3),
+(130131, '平山县', 130100, 3),
+(130132, '元氏县', 130100, 3),
+(130133, '赵县', 130100, 3),
+(130181, '辛集市', 130100, 3),
+(130183, '晋州市', 130100, 3),
+(130184, '新乐市', 130100, 3),
+(130200, '唐山市', 130000, 2),
+(130202, '路南区', 130200, 3),
+(130203, '路北区', 130200, 3),
+(130204, '古冶区', 130200, 3),
+(130205, '开平区', 130200, 3),
+(130207, '丰南区', 130200, 3),
+(130208, '丰润区', 130200, 3),
+(130209, '曹妃甸区', 130200, 3),
+(130223, '滦县', 130200, 3),
+(130224, '滦南县', 130200, 3),
+(130225, '乐亭县', 130200, 3),
+(130227, '迁西县', 130200, 3),
+(130229, '玉田县', 130200, 3),
+(130281, '遵化市', 130200, 3),
+(130283, '迁安市', 130200, 3),
+(130300, '秦皇岛市', 130000, 2),
+(130302, '海港区', 130300, 3),
+(130303, '山海关区', 130300, 3),
+(130304, '北戴河区', 130300, 3),
+(130306, '抚宁区', 130300, 3),
+(130321, '青龙满族自治县', 130300, 3),
+(130322, '昌黎县', 130300, 3),
+(130324, '卢龙县', 130300, 3),
+(130400, '邯郸市', 130000, 2),
+(130402, '邯山区', 130400, 3),
+(130403, '丛台区', 130400, 3),
+(130404, '复兴区', 130400, 3),
+(130406, '峰峰矿区', 130400, 3),
+(130407, '肥乡区', 130400, 3),
+(130408, '永年区', 130400, 3),
+(130423, '临漳县', 130400, 3),
+(130424, '成安县', 130400, 3),
+(130425, '大名县', 130400, 3),
+(130426, '涉县', 130400, 3),
+(130427, '磁县', 130400, 3),
+(130430, '邱县', 130400, 3),
+(130431, '鸡泽县', 130400, 3),
+(130432, '广平县', 130400, 3),
+(130433, '馆陶县', 130400, 3),
+(130434, '魏县', 130400, 3),
+(130435, '曲周县', 130400, 3),
+(130481, '武安市', 130400, 3),
+(130500, '邢台市', 130000, 2),
+(130502, '桥东区', 130500, 3),
+(130503, '桥西区', 130500, 3),
+(130521, '邢台县', 130500, 3),
+(130522, '临城县', 130500, 3),
+(130523, '内丘县', 130500, 3),
+(130524, '柏乡县', 130500, 3),
+(130525, '隆尧县', 130500, 3),
+(130526, '任县', 130500, 3),
+(130527, '南和县', 130500, 3),
+(130528, '宁晋县', 130500, 3),
+(130529, '巨鹿县', 130500, 3),
+(130530, '新河县', 130500, 3),
+(130531, '广宗县', 130500, 3),
+(130532, '平乡县', 130500, 3),
+(130533, '威县', 130500, 3),
+(130534, '清河县', 130500, 3),
+(130535, '临西县', 130500, 3),
+(130581, '南宫市', 130500, 3),
+(130582, '沙河市', 130500, 3),
+(130600, '保定市', 130000, 2),
+(130602, '竞秀区', 130600, 3),
+(130606, '莲池区', 130600, 3),
+(130607, '满城区', 130600, 3),
+(130608, '清苑区', 130600, 3),
+(130609, '徐水区', 130600, 3),
+(130623, '涞水县', 130600, 3),
+(130624, '阜平县', 130600, 3),
+(130626, '定兴县', 130600, 3),
+(130627, '唐县', 130600, 3),
+(130628, '高阳县', 130600, 3),
+(130629, '容城县', 130600, 3),
+(130630, '涞源县', 130600, 3),
+(130631, '望都县', 130600, 3),
+(130632, '安新县', 130600, 3),
+(130633, '易县', 130600, 3),
+(130634, '曲阳县', 130600, 3),
+(130635, '蠡县', 130600, 3),
+(130636, '顺平县', 130600, 3),
+(130637, '博野县', 130600, 3),
+(130638, '雄县', 130600, 3),
+(130681, '涿州市', 130600, 3),
+(130682, '定州市', 130600, 3),
+(130683, '安国市', 130600, 3),
+(130684, '高碑店市', 130600, 3),
+(130700, '张家口市', 130000, 2),
+(130702, '桥东区', 130700, 3),
+(130703, '桥西区', 130700, 3),
+(130705, '宣化区', 130700, 3),
+(130706, '下花园区', 130700, 3),
+(130708, '万全区', 130700, 3),
+(130709, '崇礼区', 130700, 3),
+(130722, '张北县', 130700, 3),
+(130723, '康保县', 130700, 3),
+(130724, '沽源县', 130700, 3),
+(130725, '尚义县', 130700, 3),
+(130726, '蔚县', 130700, 3),
+(130727, '阳原县', 130700, 3),
+(130728, '怀安县', 130700, 3),
+(130730, '怀来县', 130700, 3),
+(130731, '涿鹿县', 130700, 3),
+(130732, '赤城县', 130700, 3),
+(130800, '承德市', 130000, 2),
+(130802, '双桥区', 130800, 3),
+(130803, '双滦区', 130800, 3),
+(130804, '鹰手营子矿区', 130800, 3),
+(130821, '承德县', 130800, 3),
+(130822, '兴隆县', 130800, 3),
+(130824, '滦平县', 130800, 3),
+(130825, '隆化县', 130800, 3),
+(130826, '丰宁满族自治县', 130800, 3),
+(130827, '宽城满族自治县', 130800, 3),
+(130828, '围场满族蒙古族自治县', 130800, 3),
+(130881, '平泉市', 130800, 3),
+(130900, '沧州市', 130000, 2),
+(130902, '新华区', 130900, 3),
+(130903, '运河区', 130900, 3),
+(130921, '沧县', 130900, 3),
+(130922, '青县', 130900, 3),
+(130923, '东光县', 130900, 3),
+(130924, '海兴县', 130900, 3),
+(130925, '盐山县', 130900, 3),
+(130926, '肃宁县', 130900, 3),
+(130927, '南皮县', 130900, 3),
+(130928, '吴桥县', 130900, 3),
+(130929, '献县', 130900, 3),
+(130930, '孟村回族自治县', 130900, 3),
+(130981, '泊头市', 130900, 3),
+(130982, '任丘市', 130900, 3),
+(130983, '黄骅市', 130900, 3),
+(130984, '河间市', 130900, 3),
+(131000, '廊坊市', 130000, 2),
+(131002, '安次区', 131000, 3),
+(131003, '广阳区', 131000, 3),
+(131022, '固安县', 131000, 3),
+(131023, '永清县', 131000, 3),
+(131024, '香河县', 131000, 3),
+(131025, '大城县', 131000, 3),
+(131026, '文安县', 131000, 3),
+(131028, '大厂回族自治县', 131000, 3),
+(131081, '霸州市', 131000, 3),
+(131082, '三河市', 131000, 3),
+(131100, '衡水市', 130000, 2),
+(131102, '桃城区', 131100, 3),
+(131103, '冀州区', 131100, 3),
+(131121, '枣强县', 131100, 3),
+(131122, '武邑县', 131100, 3),
+(131123, '武强县', 131100, 3),
+(131124, '饶阳县', 131100, 3),
+(131125, '安平县', 131100, 3),
+(131126, '故城县', 131100, 3),
+(131127, '景县', 131100, 3),
+(131128, '阜城县', 131100, 3),
+(131182, '深州市', 131100, 3),
+(140000, '山西省', 0, 1),
+(140100, '太原市', 140000, 2),
+(140105, '小店区', 140100, 3),
+(140106, '迎泽区', 140100, 3),
+(140107, '杏花岭区', 140100, 3),
+(140108, '尖草坪区', 140100, 3),
+(140109, '万柏林区', 140100, 3),
+(140110, '晋源区', 140100, 3),
+(140121, '清徐县', 140100, 3),
+(140122, '阳曲县', 140100, 3),
+(140123, '娄烦县', 140100, 3),
+(140181, '古交市', 140100, 3),
+(140200, '大同市', 140000, 2),
+(140202, '城区', 140200, 3),
+(140203, '矿区', 140200, 3),
+(140211, '南郊区', 140200, 3),
+(140212, '新荣区', 140200, 3),
+(140221, '阳高县', 140200, 3),
+(140222, '天镇县', 140200, 3),
+(140223, '广灵县', 140200, 3),
+(140224, '灵丘县', 140200, 3),
+(140225, '浑源县', 140200, 3),
+(140226, '左云县', 140200, 3),
+(140227, '大同县', 140200, 3),
+(140300, '阳泉市', 140000, 2),
+(140302, '城区', 140300, 3),
+(140303, '矿区', 140300, 3),
+(140311, '郊区', 140300, 3),
+(140321, '平定县', 140300, 3),
+(140322, '盂县', 140300, 3),
+(140400, '长治市', 140000, 2),
+(140402, '城区', 140400, 3),
+(140411, '郊区', 140400, 3),
+(140421, '长治县', 140400, 3),
+(140423, '襄垣县', 140400, 3),
+(140424, '屯留县', 140400, 3),
+(140425, '平顺县', 140400, 3),
+(140426, '黎城县', 140400, 3),
+(140427, '壶关县', 140400, 3),
+(140428, '长子县', 140400, 3),
+(140429, '武乡县', 140400, 3),
+(140430, '沁县', 140400, 3),
+(140431, '沁源县', 140400, 3),
+(140481, '潞城市', 140400, 3),
+(140500, '晋城市', 140000, 2),
+(140502, '城区', 140500, 3),
+(140521, '沁水县', 140500, 3),
+(140522, '阳城县', 140500, 3),
+(140524, '陵川县', 140500, 3),
+(140525, '泽州县', 140500, 3),
+(140581, '高平市', 140500, 3),
+(140600, '朔州市', 140000, 2),
+(140602, '朔城区', 140600, 3),
+(140603, '平鲁区', 140600, 3),
+(140621, '山阴县', 140600, 3),
+(140622, '应县', 140600, 3),
+(140623, '右玉县', 140600, 3),
+(140624, '怀仁县', 140600, 3),
+(140700, '晋中市', 140000, 2),
+(140702, '榆次区', 140700, 3),
+(140721, '榆社县', 140700, 3),
+(140722, '左权县', 140700, 3),
+(140723, '和顺县', 140700, 3),
+(140724, '昔阳县', 140700, 3),
+(140725, '寿阳县', 140700, 3),
+(140726, '太谷县', 140700, 3),
+(140727, '祁县', 140700, 3),
+(140728, '平遥县', 140700, 3),
+(140729, '灵石县', 140700, 3),
+(140781, '介休市', 140700, 3),
+(140800, '运城市', 140000, 2),
+(140802, '盐湖区', 140800, 3),
+(140821, '临猗县', 140800, 3),
+(140822, '万荣县', 140800, 3),
+(140823, '闻喜县', 140800, 3),
+(140824, '稷山县', 140800, 3),
+(140825, '新绛县', 140800, 3),
+(140826, '绛县', 140800, 3),
+(140827, '垣曲县', 140800, 3),
+(140828, '夏县', 140800, 3),
+(140829, '平陆县', 140800, 3),
+(140830, '芮城县', 140800, 3),
+(140881, '永济市', 140800, 3),
+(140882, '河津市', 140800, 3),
+(140900, '忻州市', 140000, 2),
+(140902, '忻府区', 140900, 3),
+(140921, '定襄县', 140900, 3),
+(140922, '五台县', 140900, 3),
+(140923, '代县', 140900, 3),
+(140924, '繁峙县', 140900, 3),
+(140925, '宁武县', 140900, 3),
+(140926, '静乐县', 140900, 3),
+(140927, '神池县', 140900, 3),
+(140928, '五寨县', 140900, 3),
+(140929, '岢岚县', 140900, 3),
+(140930, '河曲县', 140900, 3),
+(140931, '保德县', 140900, 3),
+(140932, '偏关县', 140900, 3),
+(140981, '原平市', 140900, 3),
+(141000, '临汾市', 140000, 2),
+(141002, '尧都区', 141000, 3),
+(141021, '曲沃县', 141000, 3),
+(141022, '翼城县', 141000, 3),
+(141023, '襄汾县', 141000, 3),
+(141024, '洪洞县', 141000, 3),
+(141025, '古县', 141000, 3),
+(141026, '安泽县', 141000, 3),
+(141027, '浮山县', 141000, 3),
+(141028, '吉县', 141000, 3),
+(141029, '乡宁县', 141000, 3),
+(141030, '大宁县', 141000, 3),
+(141031, '隰县', 141000, 3),
+(141032, '永和县', 141000, 3),
+(141033, '蒲县', 141000, 3),
+(141034, '汾西县', 141000, 3),
+(141081, '侯马市', 141000, 3),
+(141082, '霍州市', 141000, 3),
+(141100, '吕梁市', 140000, 2),
+(141102, '离石区', 141100, 3),
+(141121, '文水县', 141100, 3),
+(141122, '交城县', 141100, 3),
+(141123, '兴县', 141100, 3),
+(141124, '临县', 141100, 3),
+(141125, '柳林县', 141100, 3),
+(141126, '石楼县', 141100, 3),
+(141127, '岚县', 141100, 3),
+(141128, '方山县', 141100, 3),
+(141129, '中阳县', 141100, 3),
+(141130, '交口县', 141100, 3),
+(141181, '孝义市', 141100, 3),
+(141182, '汾阳市', 141100, 3),
+(150000, '内蒙古自治区', 0, 1),
+(150100, '呼和浩特市', 150000, 2),
+(150102, '新城区', 150100, 3),
+(150103, '回民区', 150100, 3),
+(150104, '玉泉区', 150100, 3),
+(150105, '赛罕区', 150100, 3),
+(150121, '土默特左旗', 150100, 3),
+(150122, '托克托县', 150100, 3),
+(150123, '和林格尔县', 150100, 3),
+(150124, '清水河县', 150100, 3),
+(150125, '武川县', 150100, 3),
+(150200, '包头市', 150000, 2),
+(150202, '东河区', 150200, 3),
+(150203, '昆都仑区', 150200, 3),
+(150204, '青山区', 150200, 3),
+(150205, '石拐区', 150200, 3),
+(150206, '白云鄂博矿区', 150200, 3),
+(150207, '九原区', 150200, 3),
+(150221, '土默特右旗', 150200, 3),
+(150222, '固阳县', 150200, 3),
+(150223, '达尔罕茂明安联合旗', 150200, 3),
+(150300, '乌海市', 150000, 2),
+(150302, '海勃湾区', 150300, 3),
+(150303, '海南区', 150300, 3),
+(150304, '乌达区', 150300, 3),
+(150400, '赤峰市', 150000, 2),
+(150402, '红山区', 150400, 3),
+(150403, '元宝山区', 150400, 3),
+(150404, '松山区', 150400, 3),
+(150421, '阿鲁科尔沁旗', 150400, 3),
+(150422, '巴林左旗', 150400, 3),
+(150423, '巴林右旗', 150400, 3),
+(150424, '林西县', 150400, 3),
+(150425, '克什克腾旗', 150400, 3),
+(150426, '翁牛特旗', 150400, 3),
+(150428, '喀喇沁旗', 150400, 3),
+(150429, '宁城县', 150400, 3),
+(150430, '敖汉旗', 150400, 3),
+(150500, '通辽市', 150000, 2),
+(150502, '科尔沁区', 150500, 3),
+(150521, '科尔沁左翼中旗', 150500, 3),
+(150522, '科尔沁左翼后旗', 150500, 3),
+(150523, '开鲁县', 150500, 3),
+(150524, '库伦旗', 150500, 3),
+(150525, '奈曼旗', 150500, 3),
+(150526, '扎鲁特旗', 150500, 3),
+(150581, '霍林郭勒市', 150500, 3),
+(150600, '鄂尔多斯市', 150000, 2),
+(150602, '东胜区', 150600, 3),
+(150603, '康巴什区', 150600, 3),
+(150621, '达拉特旗', 150600, 3),
+(150622, '准格尔旗', 150600, 3),
+(150623, '鄂托克前旗', 150600, 3),
+(150624, '鄂托克旗', 150600, 3),
+(150625, '杭锦旗', 150600, 3),
+(150626, '乌审旗', 150600, 3),
+(150627, '伊金霍洛旗', 150600, 3),
+(150700, '呼伦贝尔市', 150000, 2),
+(150702, '海拉尔区', 150700, 3),
+(150703, '扎赉诺尔区', 150700, 3),
+(150721, '阿荣旗', 150700, 3),
+(150722, '莫力达瓦达斡尔族自治旗', 150700, 3),
+(150723, '鄂伦春自治旗', 150700, 3),
+(150724, '鄂温克族自治旗', 150700, 3),
+(150725, '陈巴尔虎旗', 150700, 3),
+(150726, '新巴尔虎左旗', 150700, 3),
+(150727, '新巴尔虎右旗', 150700, 3),
+(150781, '满洲里市', 150700, 3),
+(150782, '牙克石市', 150700, 3),
+(150783, '扎兰屯市', 150700, 3),
+(150784, '额尔古纳市', 150700, 3),
+(150785, '根河市', 150700, 3),
+(150800, '巴彦淖尔市', 150000, 2),
+(150802, '临河区', 150800, 3),
+(150821, '五原县', 150800, 3),
+(150822, '磴口县', 150800, 3),
+(150823, '乌拉特前旗', 150800, 3),
+(150824, '乌拉特中旗', 150800, 3),
+(150825, '乌拉特后旗', 150800, 3),
+(150826, '杭锦后旗', 150800, 3),
+(150900, '乌兰察布市', 150000, 2),
+(150902, '集宁区', 150900, 3),
+(150921, '卓资县', 150900, 3),
+(150922, '化德县', 150900, 3),
+(150923, '商都县', 150900, 3),
+(150924, '兴和县', 150900, 3),
+(150925, '凉城县', 150900, 3),
+(150926, '察哈尔右翼前旗', 150900, 3),
+(150927, '察哈尔右翼中旗', 150900, 3),
+(150928, '察哈尔右翼后旗', 150900, 3),
+(150929, '四子王旗', 150900, 3),
+(150981, '丰镇市', 150900, 3),
+(152200, '兴安盟', 150000, 2),
+(152201, '乌兰浩特市', 152200, 3),
+(152202, '阿尔山市', 152200, 3),
+(152221, '科尔沁右翼前旗', 152200, 3),
+(152222, '科尔沁右翼中旗', 152200, 3),
+(152223, '扎赉特旗', 152200, 3),
+(152224, '突泉县', 152200, 3),
+(152500, '锡林郭勒盟', 150000, 2),
+(152501, '二连浩特市', 152500, 3),
+(152502, '锡林浩特市', 152500, 3),
+(152522, '阿巴嘎旗', 152500, 3),
+(152523, '苏尼特左旗', 152500, 3),
+(152524, '苏尼特右旗', 152500, 3),
+(152525, '东乌珠穆沁旗', 152500, 3),
+(152526, '西乌珠穆沁旗', 152500, 3),
+(152527, '太仆寺旗', 152500, 3),
+(152528, '镶黄旗', 152500, 3),
+(152529, '正镶白旗', 152500, 3),
+(152530, '正蓝旗', 152500, 3),
+(152531, '多伦县', 152500, 3),
+(152900, '阿拉善盟', 150000, 2),
+(152921, '阿拉善左旗', 152900, 3),
+(152922, '阿拉善右旗', 152900, 3),
+(152923, '额济纳旗', 152900, 3),
+(210000, '辽宁省', 0, 1),
+(210100, '沈阳市', 210000, 2),
+(210102, '和平区', 210100, 3),
+(210103, '沈河区', 210100, 3),
+(210104, '大东区', 210100, 3),
+(210105, '皇姑区', 210100, 3),
+(210106, '铁西区', 210100, 3),
+(210111, '苏家屯区', 210100, 3),
+(210112, '浑南区', 210100, 3),
+(210113, '沈北新区', 210100, 3),
+(210114, '于洪区', 210100, 3),
+(210115, '辽中区', 210100, 3),
+(210123, '康平县', 210100, 3),
+(210124, '法库县', 210100, 3),
+(210181, '新民市', 210100, 3),
+(210200, '大连市', 210000, 2),
+(210202, '中山区', 210200, 3),
+(210203, '西岗区', 210200, 3),
+(210204, '沙河口区', 210200, 3),
+(210211, '甘井子区', 210200, 3),
+(210212, '旅顺口区', 210200, 3),
+(210213, '金州区', 210200, 3),
+(210214, '普兰店区', 210200, 3),
+(210224, '长海县', 210200, 3),
+(210281, '瓦房店市', 210200, 3),
+(210283, '庄河市', 210200, 3),
+(210300, '鞍山市', 210000, 2),
+(210302, '铁东区', 210300, 3),
+(210303, '铁西区', 210300, 3),
+(210304, '立山区', 210300, 3),
+(210311, '千山区', 210300, 3),
+(210321, '台安县', 210300, 3),
+(210323, '岫岩满族自治县', 210300, 3),
+(210381, '海城市', 210300, 3),
+(210400, '抚顺市', 210000, 2),
+(210402, '新抚区', 210400, 3),
+(210403, '东洲区', 210400, 3),
+(210404, '望花区', 210400, 3),
+(210411, '顺城区', 210400, 3),
+(210421, '抚顺县', 210400, 3),
+(210422, '新宾满族自治县', 210400, 3),
+(210423, '清原满族自治县', 210400, 3),
+(210500, '本溪市', 210000, 2),
+(210502, '平山区', 210500, 3),
+(210503, '溪湖区', 210500, 3),
+(210504, '明山区', 210500, 3),
+(210505, '南芬区', 210500, 3),
+(210521, '本溪满族自治县', 210500, 3),
+(210522, '桓仁满族自治县', 210500, 3),
+(210600, '丹东市', 210000, 2),
+(210602, '元宝区', 210600, 3),
+(210603, '振兴区', 210600, 3),
+(210604, '振安区', 210600, 3),
+(210624, '宽甸满族自治县', 210600, 3),
+(210681, '东港市', 210600, 3),
+(210682, '凤城市', 210600, 3),
+(210700, '锦州市', 210000, 2),
+(210702, '古塔区', 210700, 3),
+(210703, '凌河区', 210700, 3),
+(210711, '太和区', 210700, 3),
+(210726, '黑山县', 210700, 3),
+(210727, '义县', 210700, 3),
+(210781, '凌海市', 210700, 3),
+(210782, '北镇市', 210700, 3),
+(210800, '营口市', 210000, 2),
+(210802, '站前区', 210800, 3),
+(210803, '西市区', 210800, 3),
+(210804, '鲅鱼圈区', 210800, 3),
+(210811, '老边区', 210800, 3),
+(210881, '盖州市', 210800, 3),
+(210882, '大石桥市', 210800, 3),
+(210900, '阜新市', 210000, 2),
+(210902, '海州区', 210900, 3),
+(210903, '新邱区', 210900, 3),
+(210904, '太平区', 210900, 3),
+(210905, '清河门区', 210900, 3),
+(210911, '细河区', 210900, 3),
+(210921, '阜新蒙古族自治县', 210900, 3),
+(210922, '彰武县', 210900, 3),
+(211000, '辽阳市', 210000, 2),
+(211002, '白塔区', 211000, 3),
+(211003, '文圣区', 211000, 3),
+(211004, '宏伟区', 211000, 3),
+(211005, '弓长岭区', 211000, 3),
+(211011, '太子河区', 211000, 3),
+(211021, '辽阳县', 211000, 3),
+(211081, '灯塔市', 211000, 3),
+(211100, '盘锦市', 210000, 2),
+(211102, '双台子区', 211100, 3),
+(211103, '兴隆台区', 211100, 3),
+(211104, '大洼区', 211100, 3),
+(211122, '盘山县', 211100, 3),
+(211200, '铁岭市', 210000, 2),
+(211202, '银州区', 211200, 3),
+(211204, '清河区', 211200, 3),
+(211221, '铁岭县', 211200, 3),
+(211223, '西丰县', 211200, 3),
+(211224, '昌图县', 211200, 3),
+(211281, '调兵山市', 211200, 3),
+(211282, '开原市', 211200, 3),
+(211300, '朝阳市', 210000, 2),
+(211302, '双塔区', 211300, 3),
+(211303, '龙城区', 211300, 3),
+(211321, '朝阳县', 211300, 3),
+(211322, '建平县', 211300, 3),
+(211324, '喀喇沁左翼蒙古族自治县', 211300, 3),
+(211381, '北票市', 211300, 3),
+(211382, '凌源市', 211300, 3),
+(211400, '葫芦岛市', 210000, 2),
+(211402, '连山区', 211400, 3),
+(211403, '龙港区', 211400, 3),
+(211404, '南票区', 211400, 3),
+(211421, '绥中县', 211400, 3),
+(211422, '建昌县', 211400, 3),
+(211481, '兴城市', 211400, 3),
+(220000, '吉林省', 0, 1),
+(220100, '长春市', 220000, 2),
+(220102, '南关区', 220100, 3),
+(220103, '宽城区', 220100, 3),
+(220104, '朝阳区', 220100, 3),
+(220105, '二道区', 220100, 3),
+(220106, '绿园区', 220100, 3),
+(220112, '双阳区', 220100, 3),
+(220113, '九台区', 220100, 3),
+(220122, '农安县', 220100, 3),
+(220182, '榆树市', 220100, 3),
+(220183, '德惠市', 220100, 3),
+(220200, '吉林市', 220000, 2),
+(220202, '昌邑区', 220200, 3),
+(220203, '龙潭区', 220200, 3),
+(220204, '船营区', 220200, 3),
+(220211, '丰满区', 220200, 3),
+(220221, '永吉县', 220200, 3),
+(220281, '蛟河市', 220200, 3),
+(220282, '桦甸市', 220200, 3),
+(220283, '舒兰市', 220200, 3),
+(220284, '磐石市', 220200, 3),
+(220300, '四平市', 220000, 2),
+(220302, '铁西区', 220300, 3),
+(220303, '铁东区', 220300, 3),
+(220322, '梨树县', 220300, 3),
+(220323, '伊通满族自治县', 220300, 3),
+(220381, '公主岭市', 220300, 3),
+(220382, '双辽市', 220300, 3),
+(220400, '辽源市', 220000, 2),
+(220402, '龙山区', 220400, 3),
+(220403, '西安区', 220400, 3),
+(220421, '东丰县', 220400, 3),
+(220422, '东辽县', 220400, 3),
+(220500, '通化市', 220000, 2),
+(220502, '东昌区', 220500, 3),
+(220503, '二道江区', 220500, 3),
+(220521, '通化县', 220500, 3),
+(220523, '辉南县', 220500, 3),
+(220524, '柳河县', 220500, 3),
+(220581, '梅河口市', 220500, 3),
+(220582, '集安市', 220500, 3),
+(220600, '白山市', 220000, 2),
+(220602, '浑江区', 220600, 3),
+(220605, '江源区', 220600, 3),
+(220621, '抚松县', 220600, 3),
+(220622, '靖宇县', 220600, 3),
+(220623, '长白朝鲜族自治县', 220600, 3),
+(220681, '临江市', 220600, 3),
+(220700, '松原市', 220000, 2),
+(220702, '宁江区', 220700, 3),
+(220721, '前郭尔罗斯蒙古族自治县', 220700, 3),
+(220722, '长岭县', 220700, 3),
+(220723, '乾安县', 220700, 3),
+(220781, '扶余市', 220700, 3),
+(220800, '白城市', 220000, 2),
+(220802, '洮北区', 220800, 3),
+(220821, '镇赉县', 220800, 3),
+(220822, '通榆县', 220800, 3),
+(220881, '洮南市', 220800, 3),
+(220882, '大安市', 220800, 3),
+(222400, '延边朝鲜族自治州', 220000, 2),
+(222401, '延吉市', 222400, 3),
+(222402, '图们市', 222400, 3),
+(222403, '敦化市', 222400, 3),
+(222404, '珲春市', 222400, 3),
+(222405, '龙井市', 222400, 3),
+(222406, '和龙市', 222400, 3),
+(222424, '汪清县', 222400, 3),
+(222426, '安图县', 222400, 3),
+(230000, '黑龙江省', 0, 1),
+(230100, '哈尔滨市', 230000, 2),
+(230102, '道里区', 230100, 3),
+(230103, '南岗区', 230100, 3),
+(230104, '道外区', 230100, 3),
+(230108, '平房区', 230100, 3),
+(230109, '松北区', 230100, 3),
+(230110, '香坊区', 230100, 3),
+(230111, '呼兰区', 230100, 3),
+(230112, '阿城区', 230100, 3),
+(230113, '双城区', 230100, 3),
+(230123, '依兰县', 230100, 3),
+(230124, '方正县', 230100, 3),
+(230125, '宾县', 230100, 3),
+(230126, '巴彦县', 230100, 3),
+(230127, '木兰县', 230100, 3),
+(230128, '通河县', 230100, 3),
+(230129, '延寿县', 230100, 3),
+(230183, '尚志市', 230100, 3),
+(230184, '五常市', 230100, 3),
+(230200, '齐齐哈尔市', 230000, 2),
+(230202, '龙沙区', 230200, 3),
+(230203, '建华区', 230200, 3),
+(230204, '铁锋区', 230200, 3),
+(230205, '昂昂溪区', 230200, 3),
+(230206, '富拉尔基区', 230200, 3),
+(230207, '碾子山区', 230200, 3),
+(230208, '梅里斯达斡尔族区', 230200, 3),
+(230221, '龙江县', 230200, 3),
+(230223, '依安县', 230200, 3),
+(230224, '泰来县', 230200, 3),
+(230225, '甘南县', 230200, 3),
+(230227, '富裕县', 230200, 3),
+(230229, '克山县', 230200, 3),
+(230230, '克东县', 230200, 3),
+(230231, '拜泉县', 230200, 3),
+(230281, '讷河市', 230200, 3),
+(230300, '鸡西市', 230000, 2),
+(230302, '鸡冠区', 230300, 3),
+(230303, '恒山区', 230300, 3),
+(230304, '滴道区', 230300, 3),
+(230305, '梨树区', 230300, 3),
+(230306, '城子河区', 230300, 3),
+(230307, '麻山区', 230300, 3),
+(230321, '鸡东县', 230300, 3),
+(230381, '虎林市', 230300, 3),
+(230382, '密山市', 230300, 3),
+(230400, '鹤岗市', 230000, 2),
+(230402, '向阳区', 230400, 3),
+(230403, '工农区', 230400, 3),
+(230404, '南山区', 230400, 3),
+(230405, '兴安区', 230400, 3),
+(230406, '东山区', 230400, 3),
+(230407, '兴山区', 230400, 3),
+(230421, '萝北县', 230400, 3),
+(230422, '绥滨县', 230400, 3),
+(230500, '双鸭山市', 230000, 2),
+(230502, '尖山区', 230500, 3),
+(230503, '岭东区', 230500, 3),
+(230505, '四方台区', 230500, 3),
+(230506, '宝山区', 230500, 3),
+(230521, '集贤县', 230500, 3),
+(230522, '友谊县', 230500, 3),
+(230523, '宝清县', 230500, 3),
+(230524, '饶河县', 230500, 3),
+(230600, '大庆市', 230000, 2),
+(230602, '萨尔图区', 230600, 3),
+(230603, '龙凤区', 230600, 3),
+(230604, '让胡路区', 230600, 3),
+(230605, '红岗区', 230600, 3),
+(230606, '大同区', 230600, 3),
+(230621, '肇州县', 230600, 3),
+(230622, '肇源县', 230600, 3),
+(230623, '林甸县', 230600, 3),
+(230624, '杜尔伯特蒙古族自治县', 230600, 3),
+(230700, '伊春市', 230000, 2),
+(230702, '伊春区', 230700, 3),
+(230703, '南岔区', 230700, 3),
+(230704, '友好区', 230700, 3),
+(230705, '西林区', 230700, 3),
+(230706, '翠峦区', 230700, 3),
+(230707, '新青区', 230700, 3),
+(230708, '美溪区', 230700, 3),
+(230709, '金山屯区', 230700, 3),
+(230710, '五营区', 230700, 3),
+(230711, '乌马河区', 230700, 3),
+(230712, '汤旺河区', 230700, 3),
+(230713, '带岭区', 230700, 3),
+(230714, '乌伊岭区', 230700, 3),
+(230715, '红星区', 230700, 3),
+(230716, '上甘岭区', 230700, 3),
+(230722, '嘉荫县', 230700, 3),
+(230781, '铁力市', 230700, 3),
+(230800, '佳木斯市', 230000, 2),
+(230803, '向阳区', 230800, 3),
+(230804, '前进区', 230800, 3),
+(230805, '东风区', 230800, 3),
+(230811, '郊区', 230800, 3),
+(230822, '桦南县', 230800, 3),
+(230826, '桦川县', 230800, 3),
+(230828, '汤原县', 230800, 3),
+(230881, '同江市', 230800, 3),
+(230882, '富锦市', 230800, 3),
+(230883, '抚远市', 230800, 3),
+(230900, '七台河市', 230000, 2),
+(230902, '新兴区', 230900, 3),
+(230903, '桃山区', 230900, 3),
+(230904, '茄子河区', 230900, 3),
+(230921, '勃利县', 230900, 3),
+(231000, '牡丹江市', 230000, 2),
+(231002, '东安区', 231000, 3),
+(231003, '阳明区', 231000, 3),
+(231004, '爱民区', 231000, 3),
+(231005, '西安区', 231000, 3),
+(231025, '林口县', 231000, 3),
+(231081, '绥芬河市', 231000, 3),
+(231083, '海林市', 231000, 3),
+(231084, '宁安市', 231000, 3),
+(231085, '穆棱市', 231000, 3),
+(231086, '东宁市', 231000, 3),
+(231100, '黑河市', 230000, 2),
+(231102, '爱辉区', 231100, 3),
+(231121, '嫩江县', 231100, 3),
+(231123, '逊克县', 231100, 3),
+(231124, '孙吴县', 231100, 3),
+(231181, '北安市', 231100, 3),
+(231182, '五大连池市', 231100, 3),
+(231200, '绥化市', 230000, 2),
+(231202, '北林区', 231200, 3),
+(231221, '望奎县', 231200, 3),
+(231222, '兰西县', 231200, 3),
+(231223, '青冈县', 231200, 3),
+(231224, '庆安县', 231200, 3),
+(231225, '明水县', 231200, 3),
+(231226, '绥棱县', 231200, 3),
+(231281, '安达市', 231200, 3),
+(231282, '肇东市', 231200, 3),
+(231283, '海伦市', 231200, 3),
+(232700, '大兴安岭地区', 230000, 2),
+(232701, '加格达奇区', 232700, 3),
+(232702, '松岭区', 232700, 3),
+(232703, '新林区', 232700, 3),
+(232704, '呼中区', 232700, 3),
+(232721, '呼玛县', 232700, 3),
+(232722, '塔河县', 232700, 3),
+(232723, '漠河县', 232700, 3),
+(310000, '上海市', 0, 1),
+(310100, '上海市', 310000, 2),
+(310101, '黄浦区', 310100, 3),
+(310104, '徐汇区', 310100, 3),
+(310105, '长宁区', 310100, 3),
+(310106, '静安区', 310100, 3),
+(310107, '普陀区', 310100, 3),
+(310109, '虹口区', 310100, 3),
+(310110, '杨浦区', 310100, 3),
+(310112, '闵行区', 310100, 3),
+(310113, '宝山区', 310100, 3),
+(310114, '嘉定区', 310100, 3),
+(310115, '浦东新区', 310100, 3),
+(310116, '金山区', 310100, 3),
+(310117, '松江区', 310100, 3),
+(310118, '青浦区', 310100, 3),
+(310120, '奉贤区', 310100, 3),
+(310151, '崇明区', 310100, 3),
+(320000, '江苏省', 0, 1),
+(320100, '南京市', 320000, 2),
+(320102, '玄武区', 320100, 3),
+(320104, '秦淮区', 320100, 3),
+(320105, '建邺区', 320100, 3),
+(320106, '鼓楼区', 320100, 3),
+(320111, '浦口区', 320100, 3),
+(320113, '栖霞区', 320100, 3),
+(320114, '雨花台区', 320100, 3),
+(320115, '江宁区', 320100, 3),
+(320116, '六合区', 320100, 3),
+(320117, '溧水区', 320100, 3),
+(320118, '高淳区', 320100, 3),
+(320200, '无锡市', 320000, 2),
+(320205, '锡山区', 320200, 3),
+(320206, '惠山区', 320200, 3),
+(320211, '滨湖区', 320200, 3),
+(320213, '梁溪区', 320200, 3),
+(320214, '新吴区', 320200, 3),
+(320281, '江阴市', 320200, 3),
+(320282, '宜兴市', 320200, 3),
+(320300, '徐州市', 320000, 2),
+(320302, '鼓楼区', 320300, 3),
+(320303, '云龙区', 320300, 3),
+(320305, '贾汪区', 320300, 3),
+(320311, '泉山区', 320300, 3),
+(320312, '铜山区', 320300, 3),
+(320321, '丰县', 320300, 3),
+(320322, '沛县', 320300, 3),
+(320324, '睢宁县', 320300, 3),
+(320381, '新沂市', 320300, 3),
+(320382, '邳州市', 320300, 3),
+(320400, '常州市', 320000, 2),
+(320402, '天宁区', 320400, 3),
+(320404, '钟楼区', 320400, 3),
+(320411, '新北区', 320400, 3),
+(320412, '武进区', 320400, 3),
+(320413, '金坛区', 320400, 3),
+(320481, '溧阳市', 320400, 3),
+(320500, '苏州市', 320000, 2),
+(320505, '虎丘区', 320500, 3),
+(320506, '吴中区', 320500, 3),
+(320507, '相城区', 320500, 3),
+(320508, '姑苏区', 320500, 3),
+(320509, '吴江区', 320500, 3),
+(320581, '常熟市', 320500, 3),
+(320582, '张家港市', 320500, 3),
+(320583, '昆山市', 320500, 3),
+(320585, '太仓市', 320500, 3),
+(320600, '南通市', 320000, 2),
+(320602, '崇川区', 320600, 3),
+(320611, '港闸区', 320600, 3),
+(320612, '通州区', 320600, 3),
+(320621, '海安县', 320600, 3),
+(320623, '如东县', 320600, 3),
+(320681, '启东市', 320600, 3),
+(320682, '如皋市', 320600, 3),
+(320684, '海门市', 320600, 3),
+(320700, '连云港市', 320000, 2),
+(320703, '连云区', 320700, 3),
+(320706, '海州区', 320700, 3),
+(320707, '赣榆区', 320700, 3),
+(320722, '东海县', 320700, 3),
+(320723, '灌云县', 320700, 3),
+(320724, '灌南县', 320700, 3),
+(320800, '淮安市', 320000, 2),
+(320803, '淮安区', 320800, 3),
+(320804, '淮阴区', 320800, 3),
+(320812, '清江浦区', 320800, 3),
+(320813, '洪泽区', 320800, 3),
+(320826, '涟水县', 320800, 3),
+(320830, '盱眙县', 320800, 3),
+(320831, '金湖县', 320800, 3),
+(320900, '盐城市', 320000, 2),
+(320902, '亭湖区', 320900, 3),
+(320903, '盐都区', 320900, 3),
+(320904, '大丰区', 320900, 3),
+(320921, '响水县', 320900, 3),
+(320922, '滨海县', 320900, 3),
+(320923, '阜宁县', 320900, 3),
+(320924, '射阳县', 320900, 3),
+(320925, '建湖县', 320900, 3),
+(320981, '东台市', 320900, 3),
+(321000, '扬州市', 320000, 2),
+(321002, '广陵区', 321000, 3),
+(321003, '邗江区', 321000, 3),
+(321012, '江都区', 321000, 3),
+(321023, '宝应县', 321000, 3),
+(321081, '仪征市', 321000, 3),
+(321084, '高邮市', 321000, 3),
+(321100, '镇江市', 320000, 2),
+(321102, '京口区', 321100, 3),
+(321111, '润州区', 321100, 3),
+(321112, '丹徒区', 321100, 3),
+(321181, '丹阳市', 321100, 3),
+(321182, '扬中市', 321100, 3),
+(321183, '句容市', 321100, 3),
+(321200, '泰州市', 320000, 2),
+(321202, '海陵区', 321200, 3),
+(321203, '高港区', 321200, 3),
+(321204, '姜堰区', 321200, 3),
+(321281, '兴化市', 321200, 3),
+(321282, '靖江市', 321200, 3),
+(321283, '泰兴市', 321200, 3),
+(321300, '宿迁市', 320000, 2),
+(321302, '宿城区', 321300, 3),
+(321311, '宿豫区', 321300, 3),
+(321322, '沭阳县', 321300, 3),
+(321323, '泗阳县', 321300, 3),
+(321324, '泗洪县', 321300, 3),
+(330000, '浙江省', 0, 1),
+(330100, '杭州市', 330000, 2),
+(330102, '上城区', 330100, 3),
+(330103, '下城区', 330100, 3),
+(330104, '江干区', 330100, 3),
+(330105, '拱墅区', 330100, 3),
+(330106, '西湖区', 330100, 3),
+(330108, '滨江区', 330100, 3),
+(330109, '萧山区', 330100, 3),
+(330110, '余杭区', 330100, 3),
+(330111, '富阳区', 330100, 3),
+(330112, '临安区', 330100, 3),
+(330122, '桐庐县', 330100, 3),
+(330127, '淳安县', 330100, 3),
+(330182, '建德市', 330100, 3),
+(330200, '宁波市', 330000, 2),
+(330203, '海曙区', 330200, 3),
+(330205, '江北区', 330200, 3),
+(330206, '北仑区', 330200, 3),
+(330211, '镇海区', 330200, 3),
+(330212, '鄞州区', 330200, 3),
+(330213, '奉化区', 330200, 3),
+(330225, '象山县', 330200, 3),
+(330226, '宁海县', 330200, 3),
+(330281, '余姚市', 330200, 3),
+(330282, '慈溪市', 330200, 3),
+(330300, '温州市', 330000, 2),
+(330302, '鹿城区', 330300, 3),
+(330303, '龙湾区', 330300, 3),
+(330304, '瓯海区', 330300, 3),
+(330305, '洞头区', 330300, 3),
+(330324, '永嘉县', 330300, 3),
+(330326, '平阳县', 330300, 3),
+(330327, '苍南县', 330300, 3),
+(330328, '文成县', 330300, 3),
+(330329, '泰顺县', 330300, 3),
+(330381, '瑞安市', 330300, 3),
+(330382, '乐清市', 330300, 3),
+(330400, '嘉兴市', 330000, 2),
+(330402, '南湖区', 330400, 3),
+(330411, '秀洲区', 330400, 3),
+(330421, '嘉善县', 330400, 3),
+(330424, '海盐县', 330400, 3),
+(330481, '海宁市', 330400, 3),
+(330482, '平湖市', 330400, 3),
+(330483, '桐乡市', 330400, 3),
+(330500, '湖州市', 330000, 2),
+(330502, '吴兴区', 330500, 3),
+(330503, '南浔区', 330500, 3),
+(330521, '德清县', 330500, 3),
+(330522, '长兴县', 330500, 3),
+(330523, '安吉县', 330500, 3),
+(330600, '绍兴市', 330000, 2),
+(330602, '越城区', 330600, 3),
+(330603, '柯桥区', 330600, 3),
+(330604, '上虞区', 330600, 3),
+(330624, '新昌县', 330600, 3),
+(330681, '诸暨市', 330600, 3),
+(330683, '嵊州市', 330600, 3),
+(330700, '金华市', 330000, 2),
+(330702, '婺城区', 330700, 3),
+(330703, '金东区', 330700, 3),
+(330723, '武义县', 330700, 3),
+(330726, '浦江县', 330700, 3),
+(330727, '磐安县', 330700, 3),
+(330781, '兰溪市', 330700, 3),
+(330782, '义乌市', 330700, 3),
+(330783, '东阳市', 330700, 3),
+(330784, '永康市', 330700, 3),
+(330800, '衢州市', 330000, 2),
+(330802, '柯城区', 330800, 3),
+(330803, '衢江区', 330800, 3),
+(330822, '常山县', 330800, 3),
+(330824, '开化县', 330800, 3),
+(330825, '龙游县', 330800, 3),
+(330881, '江山市', 330800, 3),
+(330900, '舟山市', 330000, 2),
+(330902, '定海区', 330900, 3),
+(330903, '普陀区', 330900, 3),
+(330921, '岱山县', 330900, 3),
+(330922, '嵊泗县', 330900, 3),
+(331000, '台州市', 330000, 2),
+(331002, '椒江区', 331000, 3),
+(331003, '黄岩区', 331000, 3),
+(331004, '路桥区', 331000, 3),
+(331022, '三门县', 331000, 3),
+(331023, '天台县', 331000, 3),
+(331024, '仙居县', 331000, 3),
+(331081, '温岭市', 331000, 3),
+(331082, '临海市', 331000, 3),
+(331083, '玉环市', 331000, 3),
+(331100, '丽水市', 330000, 2),
+(331102, '莲都区', 331100, 3),
+(331121, '青田县', 331100, 3),
+(331122, '缙云县', 331100, 3),
+(331123, '遂昌县', 331100, 3),
+(331124, '松阳县', 331100, 3),
+(331125, '云和县', 331100, 3),
+(331126, '庆元县', 331100, 3),
+(331127, '景宁畲族自治县', 331100, 3),
+(331181, '龙泉市', 331100, 3),
+(340000, '安徽省', 0, 1),
+(340100, '合肥市', 340000, 2),
+(340102, '瑶海区', 340100, 3),
+(340103, '庐阳区', 340100, 3),
+(340104, '蜀山区', 340100, 3),
+(340111, '包河区', 340100, 3),
+(340121, '长丰县', 340100, 3),
+(340122, '肥东县', 340100, 3),
+(340123, '肥西县', 340100, 3),
+(340124, '庐江县', 340100, 3),
+(340181, '巢湖市', 340100, 3),
+(340200, '芜湖市', 340000, 2),
+(340202, '镜湖区', 340200, 3),
+(340203, '弋江区', 340200, 3),
+(340207, '鸠江区', 340200, 3),
+(340208, '三山区', 340200, 3),
+(340221, '芜湖县', 340200, 3),
+(340222, '繁昌县', 340200, 3),
+(340223, '南陵县', 340200, 3),
+(340225, '无为县', 340200, 3),
+(340300, '蚌埠市', 340000, 2),
+(340302, '龙子湖区', 340300, 3),
+(340303, '蚌山区', 340300, 3),
+(340304, '禹会区', 340300, 3),
+(340311, '淮上区', 340300, 3),
+(340321, '怀远县', 340300, 3),
+(340322, '五河县', 340300, 3),
+(340323, '固镇县', 340300, 3),
+(340400, '淮南市', 340000, 2),
+(340402, '大通区', 340400, 3),
+(340403, '田家庵区', 340400, 3),
+(340404, '谢家集区', 340400, 3),
+(340405, '八公山区', 340400, 3),
+(340406, '潘集区', 340400, 3),
+(340421, '凤台县', 340400, 3),
+(340422, '寿县', 340400, 3),
+(340500, '马鞍山市', 340000, 2),
+(340503, '花山区', 340500, 3),
+(340504, '雨山区', 340500, 3),
+(340506, '博望区', 340500, 3),
+(340521, '当涂县', 340500, 3),
+(340522, '含山县', 340500, 3),
+(340523, '和县', 340500, 3),
+(340600, '淮北市', 340000, 2),
+(340602, '杜集区', 340600, 3),
+(340603, '相山区', 340600, 3),
+(340604, '烈山区', 340600, 3),
+(340621, '濉溪县', 340600, 3),
+(340700, '铜陵市', 340000, 2),
+(340705, '铜官区', 340700, 3),
+(340706, '义安区', 340700, 3),
+(340711, '郊区', 340700, 3),
+(340722, '枞阳县', 340700, 3),
+(340800, '安庆市', 340000, 2),
+(340802, '迎江区', 340800, 3),
+(340803, '大观区', 340800, 3),
+(340811, '宜秀区', 340800, 3),
+(340822, '怀宁县', 340800, 3),
+(340824, '潜山县', 340800, 3),
+(340825, '太湖县', 340800, 3),
+(340826, '宿松县', 340800, 3),
+(340827, '望江县', 340800, 3),
+(340828, '岳西县', 340800, 3),
+(340881, '桐城市', 340800, 3),
+(341000, '黄山市', 340000, 2),
+(341002, '屯溪区', 341000, 3),
+(341003, '黄山区', 341000, 3),
+(341004, '徽州区', 341000, 3),
+(341021, '歙县', 341000, 3),
+(341022, '休宁县', 341000, 3),
+(341023, '黟县', 341000, 3),
+(341024, '祁门县', 341000, 3),
+(341100, '滁州市', 340000, 2),
+(341102, '琅琊区', 341100, 3),
+(341103, '南谯区', 341100, 3),
+(341122, '来安县', 341100, 3),
+(341124, '全椒县', 341100, 3),
+(341125, '定远县', 341100, 3),
+(341126, '凤阳县', 341100, 3),
+(341181, '天长市', 341100, 3),
+(341182, '明光市', 341100, 3),
+(341200, '阜阳市', 340000, 2),
+(341202, '颍州区', 341200, 3),
+(341203, '颍东区', 341200, 3),
+(341204, '颍泉区', 341200, 3),
+(341221, '临泉县', 341200, 3),
+(341222, '太和县', 341200, 3),
+(341225, '阜南县', 341200, 3),
+(341226, '颍上县', 341200, 3),
+(341282, '界首市', 341200, 3),
+(341300, '宿州市', 340000, 2),
+(341302, '埇桥区', 341300, 3),
+(341321, '砀山县', 341300, 3),
+(341322, '萧县', 341300, 3),
+(341323, '灵璧县', 341300, 3),
+(341324, '泗县', 341300, 3),
+(341500, '六安市', 340000, 2),
+(341502, '金安区', 341500, 3),
+(341503, '裕安区', 341500, 3),
+(341504, '叶集区', 341500, 3),
+(341522, '霍邱县', 341500, 3),
+(341523, '舒城县', 341500, 3),
+(341524, '金寨县', 341500, 3),
+(341525, '霍山县', 341500, 3),
+(341600, '亳州市', 340000, 2),
+(341602, '谯城区', 341600, 3),
+(341621, '涡阳县', 341600, 3),
+(341622, '蒙城县', 341600, 3),
+(341623, '利辛县', 341600, 3),
+(341700, '池州市', 340000, 2),
+(341702, '贵池区', 341700, 3),
+(341721, '东至县', 341700, 3),
+(341722, '石台县', 341700, 3),
+(341723, '青阳县', 341700, 3),
+(341800, '宣城市', 340000, 2),
+(341802, '宣州区', 341800, 3),
+(341821, '郎溪县', 341800, 3),
+(341822, '广德县', 341800, 3),
+(341823, '泾县', 341800, 3),
+(341824, '绩溪县', 341800, 3),
+(341825, '旌德县', 341800, 3),
+(341881, '宁国市', 341800, 3),
+(350000, '福建省', 0, 1),
+(350100, '福州市', 350000, 2),
+(350102, '鼓楼区', 350100, 3),
+(350103, '台江区', 350100, 3),
+(350104, '仓山区', 350100, 3),
+(350105, '马尾区', 350100, 3),
+(350111, '晋安区', 350100, 3),
+(350112, '长乐区', 350100, 3),
+(350121, '闽侯县', 350100, 3),
+(350122, '连江县', 350100, 3),
+(350123, '罗源县', 350100, 3),
+(350124, '闽清县', 350100, 3),
+(350125, '永泰县', 350100, 3),
+(350128, '平潭县', 350100, 3),
+(350181, '福清市', 350100, 3),
+(350200, '厦门市', 350000, 2),
+(350203, '思明区', 350200, 3),
+(350205, '海沧区', 350200, 3),
+(350206, '湖里区', 350200, 3),
+(350211, '集美区', 350200, 3),
+(350212, '同安区', 350200, 3),
+(350213, '翔安区', 350200, 3),
+(350300, '莆田市', 350000, 2),
+(350302, '城厢区', 350300, 3),
+(350303, '涵江区', 350300, 3),
+(350304, '荔城区', 350300, 3),
+(350305, '秀屿区', 350300, 3),
+(350322, '仙游县', 350300, 3),
+(350400, '三明市', 350000, 2),
+(350402, '梅列区', 350400, 3),
+(350403, '三元区', 350400, 3),
+(350421, '明溪县', 350400, 3),
+(350423, '清流县', 350400, 3),
+(350424, '宁化县', 350400, 3),
+(350425, '大田县', 350400, 3),
+(350426, '尤溪县', 350400, 3),
+(350427, '沙县', 350400, 3),
+(350428, '将乐县', 350400, 3),
+(350429, '泰宁县', 350400, 3),
+(350430, '建宁县', 350400, 3),
+(350481, '永安市', 350400, 3),
+(350500, '泉州市', 350000, 2),
+(350502, '鲤城区', 350500, 3),
+(350503, '丰泽区', 350500, 3),
+(350504, '洛江区', 350500, 3),
+(350505, '泉港区', 350500, 3),
+(350521, '惠安县', 350500, 3),
+(350524, '安溪县', 350500, 3),
+(350525, '永春县', 350500, 3),
+(350526, '德化县', 350500, 3),
+(350527, '金门县', 350500, 3),
+(350581, '石狮市', 350500, 3),
+(350582, '晋江市', 350500, 3),
+(350583, '南安市', 350500, 3),
+(350600, '漳州市', 350000, 2),
+(350602, '芗城区', 350600, 3),
+(350603, '龙文区', 350600, 3),
+(350622, '云霄县', 350600, 3),
+(350623, '漳浦县', 350600, 3),
+(350624, '诏安县', 350600, 3),
+(350625, '长泰县', 350600, 3),
+(350626, '东山县', 350600, 3),
+(350627, '南靖县', 350600, 3),
+(350628, '平和县', 350600, 3),
+(350629, '华安县', 350600, 3),
+(350681, '龙海市', 350600, 3),
+(350700, '南平市', 350000, 2),
+(350702, '延平区', 350700, 3),
+(350703, '建阳区', 350700, 3),
+(350721, '顺昌县', 350700, 3),
+(350722, '浦城县', 350700, 3),
+(350723, '光泽县', 350700, 3),
+(350724, '松溪县', 350700, 3),
+(350725, '政和县', 350700, 3),
+(350781, '邵武市', 350700, 3),
+(350782, '武夷山市', 350700, 3),
+(350783, '建瓯市', 350700, 3),
+(350800, '龙岩市', 350000, 2),
+(350802, '新罗区', 350800, 3),
+(350803, '永定区', 350800, 3),
+(350821, '长汀县', 350800, 3),
+(350823, '上杭县', 350800, 3),
+(350824, '武平县', 350800, 3),
+(350825, '连城县', 350800, 3),
+(350881, '漳平市', 350800, 3),
+(350900, '宁德市', 350000, 2),
+(350902, '蕉城区', 350900, 3),
+(350921, '霞浦县', 350900, 3),
+(350922, '古田县', 350900, 3),
+(350923, '屏南县', 350900, 3),
+(350924, '寿宁县', 350900, 3),
+(350925, '周宁县', 350900, 3),
+(350926, '柘荣县', 350900, 3),
+(350981, '福安市', 350900, 3),
+(350982, '福鼎市', 350900, 3),
+(360000, '江西省', 0, 1),
+(360100, '南昌市', 360000, 2),
+(360102, '东湖区', 360100, 3),
+(360103, '西湖区', 360100, 3),
+(360104, '青云谱区', 360100, 3),
+(360105, '湾里区', 360100, 3),
+(360111, '青山湖区', 360100, 3),
+(360112, '新建区', 360100, 3),
+(360121, '南昌县', 360100, 3),
+(360123, '安义县', 360100, 3),
+(360124, '进贤县', 360100, 3),
+(360200, '景德镇市', 360000, 2),
+(360202, '昌江区', 360200, 3),
+(360203, '珠山区', 360200, 3),
+(360222, '浮梁县', 360200, 3),
+(360281, '乐平市', 360200, 3),
+(360300, '萍乡市', 360000, 2),
+(360302, '安源区', 360300, 3),
+(360313, '湘东区', 360300, 3),
+(360321, '莲花县', 360300, 3),
+(360322, '上栗县', 360300, 3),
+(360323, '芦溪县', 360300, 3),
+(360400, '九江市', 360000, 2),
+(360402, '濂溪区', 360400, 3),
+(360403, '浔阳区', 360400, 3),
+(360404, '柴桑区', 360400, 3),
+(360423, '武宁县', 360400, 3),
+(360424, '修水县', 360400, 3),
+(360425, '永修县', 360400, 3),
+(360426, '德安县', 360400, 3),
+(360428, '都昌县', 360400, 3),
+(360429, '湖口县', 360400, 3),
+(360430, '彭泽县', 360400, 3),
+(360481, '瑞昌市', 360400, 3),
+(360482, '共青城市', 360400, 3),
+(360483, '庐山市', 360400, 3),
+(360500, '新余市', 360000, 2),
+(360502, '渝水区', 360500, 3),
+(360521, '分宜县', 360500, 3),
+(360600, '鹰潭市', 360000, 2),
+(360602, '月湖区', 360600, 3),
+(360622, '余江区', 360600, 3),
+(360681, '贵溪市', 360600, 3),
+(360700, '赣州市', 360000, 2),
+(360702, '章贡区', 360700, 3),
+(360703, '南康区', 360700, 3),
+(360704, '赣县区', 360700, 3),
+(360722, '信丰县', 360700, 3),
+(360723, '大余县', 360700, 3),
+(360724, '上犹县', 360700, 3),
+(360725, '崇义县', 360700, 3),
+(360726, '安远县', 360700, 3),
+(360727, '龙南县', 360700, 3),
+(360728, '定南县', 360700, 3),
+(360729, '全南县', 360700, 3),
+(360730, '宁都县', 360700, 3),
+(360731, '于都县', 360700, 3),
+(360732, '兴国县', 360700, 3),
+(360733, '会昌县', 360700, 3),
+(360734, '寻乌县', 360700, 3),
+(360735, '石城县', 360700, 3),
+(360781, '瑞金市', 360700, 3),
+(360800, '吉安市', 360000, 2),
+(360802, '吉州区', 360800, 3),
+(360803, '青原区', 360800, 3),
+(360821, '吉安县', 360800, 3),
+(360822, '吉水县', 360800, 3),
+(360823, '峡江县', 360800, 3),
+(360824, '新干县', 360800, 3),
+(360825, '永丰县', 360800, 3),
+(360826, '泰和县', 360800, 3),
+(360827, '遂川县', 360800, 3),
+(360828, '万安县', 360800, 3),
+(360829, '安福县', 360800, 3),
+(360830, '永新县', 360800, 3),
+(360881, '井冈山市', 360800, 3),
+(360900, '宜春市', 360000, 2),
+(360902, '袁州区', 360900, 3),
+(360921, '奉新县', 360900, 3),
+(360922, '万载县', 360900, 3),
+(360923, '上高县', 360900, 3),
+(360924, '宜丰县', 360900, 3),
+(360925, '靖安县', 360900, 3),
+(360926, '铜鼓县', 360900, 3),
+(360981, '丰城市', 360900, 3),
+(360982, '樟树市', 360900, 3),
+(360983, '高安市', 360900, 3),
+(361000, '抚州市', 360000, 2),
+(361002, '临川区', 361000, 3),
+(361003, '东乡区', 361000, 3),
+(361021, '南城县', 361000, 3),
+(361022, '黎川县', 361000, 3),
+(361023, '南丰县', 361000, 3),
+(361024, '崇仁县', 361000, 3),
+(361025, '乐安县', 361000, 3),
+(361026, '宜黄县', 361000, 3),
+(361027, '金溪县', 361000, 3),
+(361028, '资溪县', 361000, 3),
+(361030, '广昌县', 361000, 3),
+(361100, '上饶市', 360000, 2),
+(361102, '信州区', 361100, 3),
+(361103, '广丰区', 361100, 3),
+(361121, '上饶县', 361100, 3),
+(361123, '玉山县', 361100, 3),
+(361124, '铅山县', 361100, 3),
+(361125, '横峰县', 361100, 3),
+(361126, '弋阳县', 361100, 3),
+(361127, '余干县', 361100, 3),
+(361128, '鄱阳县', 361100, 3),
+(361129, '万年县', 361100, 3),
+(361130, '婺源县', 361100, 3),
+(361181, '德兴市', 361100, 3),
+(370000, '山东省', 0, 1),
+(370100, '济南市', 370000, 2),
+(370102, '历下区', 370100, 3),
+(370103, '市中区', 370100, 3),
+(370104, '槐荫区', 370100, 3),
+(370105, '天桥区', 370100, 3),
+(370112, '历城区', 370100, 3),
+(370113, '长清区', 370100, 3),
+(370114, '章丘区', 370100, 3),
+(370124, '平阴县', 370100, 3),
+(370125, '济阳县', 370100, 3),
+(370126, '商河县', 370100, 3),
+(370200, '青岛市', 370000, 2),
+(370202, '市南区', 370200, 3),
+(370203, '市北区', 370200, 3),
+(370211, '黄岛区', 370200, 3),
+(370212, '崂山区', 370200, 3),
+(370213, '李沧区', 370200, 3),
+(370214, '城阳区', 370200, 3),
+(370215, '即墨区', 370200, 3),
+(370281, '胶州市', 370200, 3),
+(370283, '平度市', 370200, 3),
+(370285, '莱西市', 370200, 3),
+(370300, '淄博市', 370000, 2),
+(370302, '淄川区', 370300, 3),
+(370303, '张店区', 370300, 3),
+(370304, '博山区', 370300, 3),
+(370305, '临淄区', 370300, 3),
+(370306, '周村区', 370300, 3),
+(370321, '桓台县', 370300, 3),
+(370322, '高青县', 370300, 3),
+(370323, '沂源县', 370300, 3),
+(370400, '枣庄市', 370000, 2),
+(370402, '市中区', 370400, 3),
+(370403, '薛城区', 370400, 3),
+(370404, '峄城区', 370400, 3),
+(370405, '台儿庄区', 370400, 3),
+(370406, '山亭区', 370400, 3),
+(370481, '滕州市', 370400, 3),
+(370500, '东营市', 370000, 2),
+(370502, '东营区', 370500, 3),
+(370503, '河口区', 370500, 3),
+(370505, '垦利区', 370500, 3),
+(370522, '利津县', 370500, 3),
+(370523, '广饶县', 370500, 3),
+(370600, '烟台市', 370000, 2),
+(370602, '芝罘区', 370600, 3),
+(370611, '福山区', 370600, 3),
+(370612, '牟平区', 370600, 3),
+(370613, '莱山区', 370600, 3),
+(370634, '长岛县', 370600, 3),
+(370681, '龙口市', 370600, 3),
+(370682, '莱阳市', 370600, 3),
+(370683, '莱州市', 370600, 3),
+(370684, '蓬莱市', 370600, 3),
+(370685, '招远市', 370600, 3),
+(370686, '栖霞市', 370600, 3),
+(370687, '海阳市', 370600, 3),
+(370700, '潍坊市', 370000, 2),
+(370702, '潍城区', 370700, 3),
+(370703, '寒亭区', 370700, 3),
+(370704, '坊子区', 370700, 3),
+(370705, '奎文区', 370700, 3),
+(370724, '临朐县', 370700, 3),
+(370725, '昌乐县', 370700, 3),
+(370781, '青州市', 370700, 3),
+(370782, '诸城市', 370700, 3),
+(370783, '寿光市', 370700, 3),
+(370784, '安丘市', 370700, 3),
+(370785, '高密市', 370700, 3),
+(370786, '昌邑市', 370700, 3),
+(370800, '济宁市', 370000, 2),
+(370811, '任城区', 370800, 3),
+(370812, '兖州区', 370800, 3),
+(370826, '微山县', 370800, 3),
+(370827, '鱼台县', 370800, 3),
+(370828, '金乡县', 370800, 3),
+(370829, '嘉祥县', 370800, 3),
+(370830, '汶上县', 370800, 3),
+(370831, '泗水县', 370800, 3),
+(370832, '梁山县', 370800, 3),
+(370881, '曲阜市', 370800, 3),
+(370883, '邹城市', 370800, 3),
+(370900, '泰安市', 370000, 2),
+(370902, '泰山区', 370900, 3),
+(370911, '岱岳区', 370900, 3),
+(370921, '宁阳县', 370900, 3),
+(370923, '东平县', 370900, 3),
+(370982, '新泰市', 370900, 3),
+(370983, '肥城市', 370900, 3),
+(371000, '威海市', 370000, 2),
+(371002, '环翠区', 371000, 3),
+(371003, '文登区', 371000, 3),
+(371082, '荣成市', 371000, 3),
+(371083, '乳山市', 371000, 3),
+(371100, '日照市', 370000, 2),
+(371102, '东港区', 371100, 3),
+(371103, '岚山区', 371100, 3),
+(371121, '五莲县', 371100, 3),
+(371122, '莒县', 371100, 3),
+(371200, '莱芜市', 370000, 2),
+(371202, '莱城区', 371200, 3),
+(371203, '钢城区', 371200, 3),
+(371300, '临沂市', 370000, 2),
+(371302, '兰山区', 371300, 3),
+(371311, '罗庄区', 371300, 3),
+(371312, '河东区', 371300, 3),
+(371321, '沂南县', 371300, 3),
+(371322, '郯城县', 371300, 3),
+(371323, '沂水县', 371300, 3),
+(371324, '兰陵县', 371300, 3),
+(371325, '费县', 371300, 3),
+(371326, '平邑县', 371300, 3),
+(371327, '莒南县', 371300, 3),
+(371328, '蒙阴县', 371300, 3),
+(371329, '临沭县', 371300, 3),
+(371400, '德州市', 370000, 2),
+(371402, '德城区', 371400, 3),
+(371403, '陵城区', 371400, 3),
+(371422, '宁津县', 371400, 3),
+(371423, '庆云县', 371400, 3),
+(371424, '临邑县', 371400, 3),
+(371425, '齐河县', 371400, 3),
+(371426, '平原县', 371400, 3),
+(371427, '夏津县', 371400, 3),
+(371428, '武城县', 371400, 3),
+(371481, '乐陵市', 371400, 3),
+(371482, '禹城市', 371400, 3),
+(371500, '聊城市', 370000, 2),
+(371502, '东昌府区', 371500, 3),
+(371521, '阳谷县', 371500, 3),
+(371522, '莘县', 371500, 3),
+(371523, '茌平县', 371500, 3),
+(371524, '东阿县', 371500, 3),
+(371525, '冠县', 371500, 3),
+(371526, '高唐县', 371500, 3),
+(371581, '临清市', 371500, 3),
+(371600, '滨州市', 370000, 2),
+(371602, '滨城区', 371600, 3),
+(371603, '沾化区', 371600, 3),
+(371621, '惠民县', 371600, 3),
+(371622, '阳信县', 371600, 3),
+(371623, '无棣县', 371600, 3),
+(371625, '博兴县', 371600, 3),
+(371626, '邹平县', 371600, 3),
+(371700, '菏泽市', 370000, 2),
+(371702, '牡丹区', 371700, 3),
+(371703, '定陶区', 371700, 3),
+(371721, '曹县', 371700, 3),
+(371722, '单县', 371700, 3),
+(371723, '成武县', 371700, 3),
+(371724, '巨野县', 371700, 3),
+(371725, '郓城县', 371700, 3),
+(371726, '鄄城县', 371700, 3),
+(371728, '东明县', 371700, 3),
+(410000, '河南省', 0, 1),
+(410100, '郑州市', 410000, 2),
+(410102, '中原区', 410100, 3),
+(410103, '二七区', 410100, 3),
+(410104, '管城回族区', 410100, 3),
+(410105, '金水区', 410100, 3),
+(410106, '上街区', 410100, 3),
+(410108, '惠济区', 410100, 3),
+(410122, '中牟县', 410100, 3),
+(410181, '巩义市', 410100, 3),
+(410182, '荥阳市', 410100, 3),
+(410183, '新密市', 410100, 3),
+(410184, '新郑市', 410100, 3),
+(410185, '登封市', 410100, 3),
+(410200, '开封市', 410000, 2),
+(410202, '龙亭区', 410200, 3),
+(410203, '顺河回族区', 410200, 3),
+(410204, '鼓楼区', 410200, 3),
+(410205, '禹王台区', 410200, 3),
+(410212, '祥符区', 410200, 3),
+(410221, '杞县', 410200, 3),
+(410222, '通许县', 410200, 3),
+(410223, '尉氏县', 410200, 3),
+(410225, '兰考县', 410200, 3),
+(410300, '洛阳市', 410000, 2),
+(410302, '老城区', 410300, 3),
+(410303, '西工区', 410300, 3),
+(410304, '瀍河回族区', 410300, 3),
+(410305, '涧西区', 410300, 3),
+(410306, '吉利区', 410300, 3),
+(410311, '洛龙区', 410300, 3),
+(410322, '孟津县', 410300, 3),
+(410323, '新安县', 410300, 3),
+(410324, '栾川县', 410300, 3),
+(410325, '嵩县', 410300, 3),
+(410326, '汝阳县', 410300, 3),
+(410327, '宜阳县', 410300, 3),
+(410328, '洛宁县', 410300, 3),
+(410329, '伊川县', 410300, 3),
+(410381, '偃师市', 410300, 3),
+(410400, '平顶山市', 410000, 2),
+(410402, '新华区', 410400, 3),
+(410403, '卫东区', 410400, 3),
+(410404, '石龙区', 410400, 3),
+(410411, '湛河区', 410400, 3),
+(410421, '宝丰县', 410400, 3),
+(410422, '叶县', 410400, 3),
+(410423, '鲁山县', 410400, 3),
+(410425, '郏县', 410400, 3),
+(410481, '舞钢市', 410400, 3),
+(410482, '汝州市', 410400, 3),
+(410500, '安阳市', 410000, 2),
+(410502, '文峰区', 410500, 3),
+(410503, '北关区', 410500, 3),
+(410505, '殷都区', 410500, 3),
+(410506, '龙安区', 410500, 3),
+(410522, '安阳县', 410500, 3),
+(410523, '汤阴县', 410500, 3),
+(410526, '滑县', 410500, 3),
+(410527, '内黄县', 410500, 3),
+(410581, '林州市', 410500, 3),
+(410600, '鹤壁市', 410000, 2),
+(410602, '鹤山区', 410600, 3),
+(410603, '山城区', 410600, 3),
+(410611, '淇滨区', 410600, 3),
+(410621, '浚县', 410600, 3),
+(410622, '淇县', 410600, 3),
+(410700, '新乡市', 410000, 2),
+(410702, '红旗区', 410700, 3),
+(410703, '卫滨区', 410700, 3),
+(410704, '凤泉区', 410700, 3),
+(410711, '牧野区', 410700, 3),
+(410721, '新乡县', 410700, 3),
+(410724, '获嘉县', 410700, 3),
+(410725, '原阳县', 410700, 3),
+(410726, '延津县', 410700, 3),
+(410727, '封丘县', 410700, 3),
+(410728, '长垣县', 410700, 3),
+(410781, '卫辉市', 410700, 3),
+(410782, '辉县市', 410700, 3),
+(410800, '焦作市', 410000, 2),
+(410802, '解放区', 410800, 3),
+(410803, '中站区', 410800, 3),
+(410804, '马村区', 410800, 3),
+(410811, '山阳区', 410800, 3),
+(410821, '修武县', 410800, 3),
+(410822, '博爱县', 410800, 3),
+(410823, '武陟县', 410800, 3),
+(410825, '温县', 410800, 3),
+(410882, '沁阳市', 410800, 3),
+(410883, '孟州市', 410800, 3),
+(410900, '濮阳市', 410000, 2),
+(410902, '华龙区', 410900, 3),
+(410922, '清丰县', 410900, 3),
+(410923, '南乐县', 410900, 3),
+(410926, '范县', 410900, 3),
+(410927, '台前县', 410900, 3),
+(410928, '濮阳县', 410900, 3),
+(411000, '许昌市', 410000, 2),
+(411002, '魏都区', 411000, 3),
+(411003, '建安区', 411000, 3),
+(411024, '鄢陵县', 411000, 3),
+(411025, '襄城县', 411000, 3),
+(411081, '禹州市', 411000, 3),
+(411082, '长葛市', 411000, 3),
+(411100, '漯河市', 410000, 2),
+(411102, '源汇区', 411100, 3),
+(411103, '郾城区', 411100, 3),
+(411104, '召陵区', 411100, 3),
+(411121, '舞阳县', 411100, 3),
+(411122, '临颍县', 411100, 3),
+(411200, '三门峡市', 410000, 2),
+(411202, '湖滨区', 411200, 3),
+(411203, '陕州区', 411200, 3),
+(411221, '渑池县', 411200, 3),
+(411224, '卢氏县', 411200, 3),
+(411281, '义马市', 411200, 3),
+(411282, '灵宝市', 411200, 3),
+(411300, '南阳市', 410000, 2),
+(411302, '宛城区', 411300, 3),
+(411303, '卧龙区', 411300, 3),
+(411321, '南召县', 411300, 3),
+(411322, '方城县', 411300, 3),
+(411323, '西峡县', 411300, 3),
+(411324, '镇平县', 411300, 3),
+(411325, '内乡县', 411300, 3),
+(411326, '淅川县', 411300, 3),
+(411327, '社旗县', 411300, 3),
+(411328, '唐河县', 411300, 3),
+(411329, '新野县', 411300, 3),
+(411330, '桐柏县', 411300, 3),
+(411381, '邓州市', 411300, 3),
+(411400, '商丘市', 410000, 2),
+(411402, '梁园区', 411400, 3),
+(411403, '睢阳区', 411400, 3),
+(411421, '民权县', 411400, 3),
+(411422, '睢县', 411400, 3),
+(411423, '宁陵县', 411400, 3),
+(411424, '柘城县', 411400, 3),
+(411425, '虞城县', 411400, 3),
+(411426, '夏邑县', 411400, 3),
+(411481, '永城市', 411400, 3),
+(411500, '信阳市', 410000, 2),
+(411502, '浉河区', 411500, 3),
+(411503, '平桥区', 411500, 3),
+(411521, '罗山县', 411500, 3),
+(411522, '光山县', 411500, 3),
+(411523, '新县', 411500, 3),
+(411524, '商城县', 411500, 3),
+(411525, '固始县', 411500, 3),
+(411526, '潢川县', 411500, 3),
+(411527, '淮滨县', 411500, 3),
+(411528, '息县', 411500, 3),
+(411600, '周口市', 410000, 2),
+(411602, '川汇区', 411600, 3),
+(411621, '扶沟县', 411600, 3),
+(411622, '西华县', 411600, 3),
+(411623, '商水县', 411600, 3),
+(411624, '沈丘县', 411600, 3),
+(411625, '郸城县', 411600, 3),
+(411626, '淮阳县', 411600, 3),
+(411627, '太康县', 411600, 3),
+(411628, '鹿邑县', 411600, 3),
+(411681, '项城市', 411600, 3),
+(411700, '驻马店市', 410000, 2),
+(411702, '驿城区', 411700, 3),
+(411721, '西平县', 411700, 3),
+(411722, '上蔡县', 411700, 3),
+(411723, '平舆县', 411700, 3),
+(411724, '正阳县', 411700, 3),
+(411725, '确山县', 411700, 3),
+(411726, '泌阳县', 411700, 3),
+(411727, '汝南县', 411700, 3),
+(411728, '遂平县', 411700, 3),
+(411729, '新蔡县', 411700, 3),
+(419000, '省直辖县级行政区划', 410000, 2),
+(419001, '济源市', 419000, 3),
+(420000, '湖北省', 0, 1),
+(420100, '武汉市', 420000, 2),
+(420102, '江岸区', 420100, 3),
+(420103, '江汉区', 420100, 3),
+(420104, '硚口区', 420100, 3),
+(420105, '汉阳区', 420100, 3),
+(420106, '武昌区', 420100, 3),
+(420107, '青山区', 420100, 3),
+(420111, '洪山区', 420100, 3),
+(420112, '东西湖区', 420100, 3),
+(420113, '汉南区', 420100, 3),
+(420114, '蔡甸区', 420100, 3),
+(420115, '江夏区', 420100, 3),
+(420116, '黄陂区', 420100, 3),
+(420117, '新洲区', 420100, 3),
+(420200, '黄石市', 420000, 2),
+(420202, '黄石港区', 420200, 3),
+(420203, '西塞山区', 420200, 3),
+(420204, '下陆区', 420200, 3),
+(420205, '铁山区', 420200, 3),
+(420222, '阳新县', 420200, 3),
+(420281, '大冶市', 420200, 3),
+(420300, '十堰市', 420000, 2),
+(420302, '茅箭区', 420300, 3),
+(420303, '张湾区', 420300, 3),
+(420304, '郧阳区', 420300, 3),
+(420322, '郧西县', 420300, 3),
+(420323, '竹山县', 420300, 3),
+(420324, '竹溪县', 420300, 3),
+(420325, '房县', 420300, 3),
+(420381, '丹江口市', 420300, 3),
+(420500, '宜昌市', 420000, 2),
+(420502, '西陵区', 420500, 3),
+(420503, '伍家岗区', 420500, 3),
+(420504, '点军区', 420500, 3),
+(420505, '猇亭区', 420500, 3),
+(420506, '夷陵区', 420500, 3),
+(420525, '远安县', 420500, 3),
+(420526, '兴山县', 420500, 3),
+(420527, '秭归县', 420500, 3),
+(420528, '长阳土家族自治县', 420500, 3),
+(420529, '五峰土家族自治县', 420500, 3),
+(420581, '宜都市', 420500, 3),
+(420582, '当阳市', 420500, 3),
+(420583, '枝江市', 420500, 3),
+(420600, '襄阳市', 420000, 2),
+(420602, '襄城区', 420600, 3),
+(420606, '樊城区', 420600, 3),
+(420607, '襄州区', 420600, 3),
+(420624, '南漳县', 420600, 3),
+(420625, '谷城县', 420600, 3),
+(420626, '保康县', 420600, 3),
+(420682, '老河口市', 420600, 3),
+(420683, '枣阳市', 420600, 3),
+(420684, '宜城市', 420600, 3),
+(420700, '鄂州市', 420000, 2),
+(420702, '梁子湖区', 420700, 3),
+(420703, '华容区', 420700, 3),
+(420704, '鄂城区', 420700, 3),
+(420800, '荆门市', 420000, 2),
+(420802, '东宝区', 420800, 3),
+(420804, '掇刀区', 420800, 3),
+(420821, '京山县', 420800, 3),
+(420822, '沙洋县', 420800, 3),
+(420881, '钟祥市', 420800, 3),
+(420900, '孝感市', 420000, 2),
+(420902, '孝南区', 420900, 3),
+(420921, '孝昌县', 420900, 3),
+(420922, '大悟县', 420900, 3),
+(420923, '云梦县', 420900, 3),
+(420981, '应城市', 420900, 3),
+(420982, '安陆市', 420900, 3),
+(420984, '汉川市', 420900, 3),
+(421000, '荆州市', 420000, 2),
+(421002, '沙市区', 421000, 3),
+(421003, '荆州区', 421000, 3),
+(421022, '公安县', 421000, 3),
+(421023, '监利县', 421000, 3),
+(421024, '江陵县', 421000, 3),
+(421081, '石首市', 421000, 3),
+(421083, '洪湖市', 421000, 3),
+(421087, '松滋市', 421000, 3),
+(421100, '黄冈市', 420000, 2),
+(421102, '黄州区', 421100, 3),
+(421121, '团风县', 421100, 3),
+(421122, '红安县', 421100, 3),
+(421123, '罗田县', 421100, 3),
+(421124, '英山县', 421100, 3),
+(421125, '浠水县', 421100, 3),
+(421126, '蕲春县', 421100, 3),
+(421127, '黄梅县', 421100, 3),
+(421181, '麻城市', 421100, 3),
+(421182, '武穴市', 421100, 3),
+(421200, '咸宁市', 420000, 2),
+(421202, '咸安区', 421200, 3),
+(421221, '嘉鱼县', 421200, 3),
+(421222, '通城县', 421200, 3),
+(421223, '崇阳县', 421200, 3),
+(421224, '通山县', 421200, 3),
+(421281, '赤壁市', 421200, 3),
+(421300, '随州市', 420000, 2),
+(421303, '曾都区', 421300, 3),
+(421321, '随县', 421300, 3),
+(421381, '广水市', 421300, 3),
+(422800, '恩施土家族苗族自治州', 420000, 2),
+(422801, '恩施市', 422800, 3),
+(422802, '利川市', 422800, 3),
+(422822, '建始县', 422800, 3),
+(422823, '巴东县', 422800, 3),
+(422825, '宣恩县', 422800, 3),
+(422826, '咸丰县', 422800, 3),
+(422827, '来凤县', 422800, 3),
+(422828, '鹤峰县', 422800, 3),
+(429000, '省直辖县级行政区划', 420000, 2),
+(429004, '仙桃市', 429000, 3),
+(429005, '潜江市', 429000, 3),
+(429006, '天门市', 429000, 3),
+(429021, '神农架林区', 429000, 3),
+(430000, '湖南省', 0, 1),
+(430100, '长沙市', 430000, 2),
+(430102, '芙蓉区', 430100, 3),
+(430103, '天心区', 430100, 3),
+(430104, '岳麓区', 430100, 3),
+(430105, '开福区', 430100, 3),
+(430111, '雨花区', 430100, 3),
+(430112, '望城区', 430100, 3),
+(430121, '长沙县', 430100, 3),
+(430181, '浏阳市', 430100, 3),
+(430182, '宁乡市', 430100, 3),
+(430200, '株洲市', 430000, 2),
+(430202, '荷塘区', 430200, 3),
+(430203, '芦淞区', 430200, 3),
+(430204, '石峰区', 430200, 3),
+(430211, '天元区', 430200, 3),
+(430221, '株洲县', 430200, 3),
+(430223, '攸县', 430200, 3),
+(430224, '茶陵县', 430200, 3),
+(430225, '炎陵县', 430200, 3),
+(430281, '醴陵市', 430200, 3),
+(430300, '湘潭市', 430000, 2),
+(430302, '雨湖区', 430300, 3),
+(430304, '岳塘区', 430300, 3),
+(430321, '湘潭县', 430300, 3),
+(430381, '湘乡市', 430300, 3),
+(430382, '韶山市', 430300, 3),
+(430400, '衡阳市', 430000, 2),
+(430405, '珠晖区', 430400, 3),
+(430406, '雁峰区', 430400, 3),
+(430407, '石鼓区', 430400, 3),
+(430408, '蒸湘区', 430400, 3),
+(430412, '南岳区', 430400, 3),
+(430421, '衡阳县', 430400, 3),
+(430422, '衡南县', 430400, 3),
+(430423, '衡山县', 430400, 3),
+(430424, '衡东县', 430400, 3),
+(430426, '祁东县', 430400, 3),
+(430481, '耒阳市', 430400, 3),
+(430482, '常宁市', 430400, 3),
+(430500, '邵阳市', 430000, 2),
+(430502, '双清区', 430500, 3),
+(430503, '大祥区', 430500, 3),
+(430511, '北塔区', 430500, 3),
+(430521, '邵东县', 430500, 3),
+(430522, '新邵县', 430500, 3),
+(430523, '邵阳县', 430500, 3),
+(430524, '隆回县', 430500, 3),
+(430525, '洞口县', 430500, 3),
+(430527, '绥宁县', 430500, 3),
+(430528, '新宁县', 430500, 3),
+(430529, '城步苗族自治县', 430500, 3),
+(430581, '武冈市', 430500, 3),
+(430600, '岳阳市', 430000, 2),
+(430602, '岳阳楼区', 430600, 3),
+(430603, '云溪区', 430600, 3),
+(430611, '君山区', 430600, 3),
+(430621, '岳阳县', 430600, 3),
+(430623, '华容县', 430600, 3),
+(430624, '湘阴县', 430600, 3),
+(430626, '平江县', 430600, 3),
+(430681, '汨罗市', 430600, 3),
+(430682, '临湘市', 430600, 3),
+(430700, '常德市', 430000, 2),
+(430702, '武陵区', 430700, 3),
+(430703, '鼎城区', 430700, 3),
+(430721, '安乡县', 430700, 3),
+(430722, '汉寿县', 430700, 3),
+(430723, '澧县', 430700, 3),
+(430724, '临澧县', 430700, 3),
+(430725, '桃源县', 430700, 3),
+(430726, '石门县', 430700, 3),
+(430781, '津市市', 430700, 3),
+(430800, '张家界市', 430000, 2),
+(430802, '永定区', 430800, 3),
+(430811, '武陵源区', 430800, 3),
+(430821, '慈利县', 430800, 3),
+(430822, '桑植县', 430800, 3),
+(430900, '益阳市', 430000, 2),
+(430902, '资阳区', 430900, 3),
+(430903, '赫山区', 430900, 3),
+(430921, '南县', 430900, 3),
+(430922, '桃江县', 430900, 3),
+(430923, '安化县', 430900, 3),
+(430981, '沅江市', 430900, 3),
+(431000, '郴州市', 430000, 2),
+(431002, '北湖区', 431000, 3),
+(431003, '苏仙区', 431000, 3),
+(431021, '桂阳县', 431000, 3),
+(431022, '宜章县', 431000, 3),
+(431023, '永兴县', 431000, 3),
+(431024, '嘉禾县', 431000, 3),
+(431025, '临武县', 431000, 3),
+(431026, '汝城县', 431000, 3),
+(431027, '桂东县', 431000, 3),
+(431028, '安仁县', 431000, 3),
+(431081, '资兴市', 431000, 3),
+(431100, '永州市', 430000, 2),
+(431102, '零陵区', 431100, 3),
+(431103, '冷水滩区', 431100, 3),
+(431121, '祁阳县', 431100, 3),
+(431122, '东安县', 431100, 3),
+(431123, '双牌县', 431100, 3),
+(431124, '道县', 431100, 3),
+(431125, '江永县', 431100, 3),
+(431126, '宁远县', 431100, 3),
+(431127, '蓝山县', 431100, 3),
+(431128, '新田县', 431100, 3),
+(431129, '江华瑶族自治县', 431100, 3);
+INSERT INTO `__PREFIX__shopro_area` (`id`, `name`, `pid`, `level`) VALUES
+(431200, '怀化市', 430000, 2),
+(431202, '鹤城区', 431200, 3),
+(431221, '中方县', 431200, 3),
+(431222, '沅陵县', 431200, 3),
+(431223, '辰溪县', 431200, 3),
+(431224, '溆浦县', 431200, 3),
+(431225, '会同县', 431200, 3),
+(431226, '麻阳苗族自治县', 431200, 3),
+(431227, '新晃侗族自治县', 431200, 3),
+(431228, '芷江侗族自治县', 431200, 3),
+(431229, '靖州苗族侗族自治县', 431200, 3),
+(431230, '通道侗族自治县', 431200, 3),
+(431281, '洪江市', 431200, 3),
+(431300, '娄底市', 430000, 2),
+(431302, '娄星区', 431300, 3),
+(431321, '双峰县', 431300, 3),
+(431322, '新化县', 431300, 3),
+(431381, '冷水江市', 431300, 3),
+(431382, '涟源市', 431300, 3),
+(433100, '湘西土家族苗族自治州', 430000, 2),
+(433101, '吉首市', 433100, 3),
+(433122, '泸溪县', 433100, 3),
+(433123, '凤凰县', 433100, 3),
+(433124, '花垣县', 433100, 3),
+(433125, '保靖县', 433100, 3),
+(433126, '古丈县', 433100, 3),
+(433127, '永顺县', 433100, 3),
+(433130, '龙山县', 433100, 3),
+(440000, '广东省', 0, 1),
+(440100, '广州市', 440000, 2),
+(440103, '荔湾区', 440100, 3),
+(440104, '越秀区', 440100, 3),
+(440105, '海珠区', 440100, 3),
+(440106, '天河区', 440100, 3),
+(440111, '白云区', 440100, 3),
+(440112, '黄埔区', 440100, 3),
+(440113, '番禺区', 440100, 3),
+(440114, '花都区', 440100, 3),
+(440115, '南沙区', 440100, 3),
+(440117, '从化区', 440100, 3),
+(440118, '增城区', 440100, 3),
+(440200, '韶关市', 440000, 2),
+(440203, '武江区', 440200, 3),
+(440204, '浈江区', 440200, 3),
+(440205, '曲江区', 440200, 3),
+(440222, '始兴县', 440200, 3),
+(440224, '仁化县', 440200, 3),
+(440229, '翁源县', 440200, 3),
+(440232, '乳源瑶族自治县', 440200, 3),
+(440233, '新丰县', 440200, 3),
+(440281, '乐昌市', 440200, 3),
+(440282, '南雄市', 440200, 3),
+(440300, '深圳市', 440000, 2),
+(440303, '罗湖区', 440300, 3),
+(440304, '福田区', 440300, 3),
+(440305, '南山区', 440300, 3),
+(440306, '宝安区', 440300, 3),
+(440307, '龙岗区', 440300, 3),
+(440308, '盐田区', 440300, 3),
+(440309, '龙华区', 440300, 3),
+(440310, '坪山区', 440300, 3),
+(440400, '珠海市', 440000, 2),
+(440402, '香洲区', 440400, 3),
+(440403, '斗门区', 440400, 3),
+(440404, '金湾区', 440400, 3),
+(440500, '汕头市', 440000, 2),
+(440507, '龙湖区', 440500, 3),
+(440511, '金平区', 440500, 3),
+(440512, '濠江区', 440500, 3),
+(440513, '潮阳区', 440500, 3),
+(440514, '潮南区', 440500, 3),
+(440515, '澄海区', 440500, 3),
+(440523, '南澳县', 440500, 3),
+(440600, '佛山市', 440000, 2),
+(440604, '禅城区', 440600, 3),
+(440605, '南海区', 440600, 3),
+(440606, '顺德区', 440600, 3),
+(440607, '三水区', 440600, 3),
+(440608, '高明区', 440600, 3),
+(440700, '江门市', 440000, 2),
+(440703, '蓬江区', 440700, 3),
+(440704, '江海区', 440700, 3),
+(440705, '新会区', 440700, 3),
+(440781, '台山市', 440700, 3),
+(440783, '开平市', 440700, 3),
+(440784, '鹤山市', 440700, 3),
+(440785, '恩平市', 440700, 3),
+(440800, '湛江市', 440000, 2),
+(440802, '赤坎区', 440800, 3),
+(440803, '霞山区', 440800, 3),
+(440804, '坡头区', 440800, 3),
+(440811, '麻章区', 440800, 3),
+(440823, '遂溪县', 440800, 3),
+(440825, '徐闻县', 440800, 3),
+(440881, '廉江市', 440800, 3),
+(440882, '雷州市', 440800, 3),
+(440883, '吴川市', 440800, 3),
+(440900, '茂名市', 440000, 2),
+(440902, '茂南区', 440900, 3),
+(440904, '电白区', 440900, 3),
+(440981, '高州市', 440900, 3),
+(440982, '化州市', 440900, 3),
+(440983, '信宜市', 440900, 3),
+(441200, '肇庆市', 440000, 2),
+(441202, '端州区', 441200, 3),
+(441203, '鼎湖区', 441200, 3),
+(441204, '高要区', 441200, 3),
+(441223, '广宁县', 441200, 3),
+(441224, '怀集县', 441200, 3),
+(441225, '封开县', 441200, 3),
+(441226, '德庆县', 441200, 3),
+(441284, '四会市', 441200, 3),
+(441300, '惠州市', 440000, 2),
+(441302, '惠城区', 441300, 3),
+(441303, '惠阳区', 441300, 3),
+(441322, '博罗县', 441300, 3),
+(441323, '惠东县', 441300, 3),
+(441324, '龙门县', 441300, 3),
+(441400, '梅州市', 440000, 2),
+(441402, '梅江区', 441400, 3),
+(441403, '梅县区', 441400, 3),
+(441422, '大埔县', 441400, 3),
+(441423, '丰顺县', 441400, 3),
+(441424, '五华县', 441400, 3),
+(441426, '平远县', 441400, 3),
+(441427, '蕉岭县', 441400, 3),
+(441481, '兴宁市', 441400, 3),
+(441500, '汕尾市', 440000, 2),
+(441502, '城区', 441500, 3),
+(441521, '海丰县', 441500, 3),
+(441523, '陆河县', 441500, 3),
+(441581, '陆丰市', 441500, 3),
+(441600, '河源市', 440000, 2),
+(441602, '源城区', 441600, 3),
+(441621, '紫金县', 441600, 3),
+(441622, '龙川县', 441600, 3),
+(441623, '连平县', 441600, 3),
+(441624, '和平县', 441600, 3),
+(441625, '东源县', 441600, 3),
+(441700, '阳江市', 440000, 2),
+(441702, '江城区', 441700, 3),
+(441704, '阳东区', 441700, 3),
+(441721, '阳西县', 441700, 3),
+(441781, '阳春市', 441700, 3),
+(441800, '清远市', 440000, 2),
+(441802, '清城区', 441800, 3),
+(441803, '清新区', 441800, 3),
+(441821, '佛冈县', 441800, 3),
+(441823, '阳山县', 441800, 3),
+(441825, '连山壮族瑶族自治县', 441800, 3),
+(441826, '连南瑶族自治县', 441800, 3),
+(441881, '英德市', 441800, 3),
+(441882, '连州市', 441800, 3),
+(441900, '东莞市', 440000, 2),
+(441901, '东城街道', 441900, 3),
+(441902, '南城街道', 441900, 3),
+(441903, '万江街道', 441900, 3),
+(441904, '莞城街道', 441900, 3),
+(441905, '石碣镇', 441900, 3),
+(441906, '石龙镇', 441900, 3),
+(441907, '茶山镇', 441900, 3),
+(441908, '石排镇', 441900, 3),
+(441909, '企石镇', 441900, 3),
+(441910, '横沥镇', 441900, 3),
+(441911, '桥头镇', 441900, 3),
+(441912, '谢岗镇', 441900, 3),
+(441913, '东坑镇', 441900, 3),
+(441914, '常平镇', 441900, 3),
+(441915, '寮步镇', 441900, 3),
+(441916, '樟木头镇', 441900, 3),
+(441917, '大朗镇', 441900, 3),
+(441918, '黄江镇', 441900, 3),
+(441919, '清溪镇', 441900, 3),
+(441920, '塘厦镇', 441900, 3),
+(441921, '凤岗镇', 441900, 3),
+(441922, '大岭山镇', 441900, 3),
+(441923, '长安镇', 441900, 3),
+(441924, '虎门镇', 441900, 3),
+(441925, '厚街镇', 441900, 3),
+(441926, '沙田镇', 441900, 3),
+(441927, '道滘镇', 441900, 3),
+(441928, '洪梅镇', 441900, 3),
+(441929, '麻涌镇', 441900, 3),
+(441930, '望牛墩镇', 441900, 3),
+(441931, '中堂镇', 441900, 3),
+(441932, '高埗镇', 441900, 3),
+(441933, '松山湖管委会', 441900, 3),
+(441934, '虎门港管委会', 441900, 3),
+(441935, '东莞生态园', 441900, 3),
+(442000, '中山市', 440000, 2),
+(442001, '石岐区街道', 442000, 3),
+(442002, '东区街道', 442000, 3),
+(442003, '火炬开发区', 442000, 3),
+(442004, '西区街道', 442000, 3),
+(442005, '南区街道', 442000, 3),
+(442006, '五桂山街道', 442000, 3),
+(442007, '小榄镇', 442000, 3),
+(442008, '黄圃镇', 442000, 3),
+(442009, '民众镇', 442000, 3),
+(442010, '东凤镇', 442000, 3),
+(442011, '东升镇', 442000, 3),
+(442012, '古镇镇', 442000, 3),
+(442013, '沙溪镇', 442000, 3),
+(442014, '坦洲镇', 442000, 3),
+(442015, '港口镇', 442000, 3),
+(442016, '三角镇', 442000, 3),
+(442017, '横栏镇', 442000, 3),
+(442018, '南头镇', 442000, 3),
+(442019, '阜沙镇', 442000, 3),
+(442020, '南朗镇', 442000, 3),
+(442021, '三乡镇', 442000, 3),
+(442022, '板芙镇', 442000, 3),
+(442023, '大涌镇', 442000, 3),
+(442024, '神湾镇', 442000, 3),
+(445100, '潮州市', 440000, 2),
+(445102, '湘桥区', 445100, 3),
+(445103, '潮安区', 445100, 3),
+(445122, '饶平县', 445100, 3),
+(445200, '揭阳市', 440000, 2),
+(445202, '榕城区', 445200, 3),
+(445203, '揭东区', 445200, 3),
+(445222, '揭西县', 445200, 3),
+(445224, '惠来县', 445200, 3),
+(445281, '普宁市', 445200, 3),
+(445300, '云浮市', 440000, 2),
+(445302, '云城区', 445300, 3),
+(445303, '云安区', 445300, 3),
+(445321, '新兴县', 445300, 3),
+(445322, '郁南县', 445300, 3),
+(445381, '罗定市', 445300, 3),
+(450000, '广西壮族自治区', 0, 1),
+(450100, '南宁市', 450000, 2),
+(450102, '兴宁区', 450100, 3),
+(450103, '青秀区', 450100, 3),
+(450105, '江南区', 450100, 3),
+(450107, '西乡塘区', 450100, 3),
+(450108, '良庆区', 450100, 3),
+(450109, '邕宁区', 450100, 3),
+(450110, '武鸣区', 450100, 3),
+(450123, '隆安县', 450100, 3),
+(450124, '马山县', 450100, 3),
+(450125, '上林县', 450100, 3),
+(450126, '宾阳县', 450100, 3),
+(450127, '横县', 450100, 3),
+(450200, '柳州市', 450000, 2),
+(450202, '城中区', 450200, 3),
+(450203, '鱼峰区', 450200, 3),
+(450204, '柳南区', 450200, 3),
+(450205, '柳北区', 450200, 3),
+(450206, '柳江区', 450200, 3),
+(450222, '柳城县', 450200, 3),
+(450223, '鹿寨县', 450200, 3),
+(450224, '融安县', 450200, 3),
+(450225, '融水苗族自治县', 450200, 3),
+(450226, '三江侗族自治县', 450200, 3),
+(450300, '桂林市', 450000, 2),
+(450302, '秀峰区', 450300, 3),
+(450303, '叠彩区', 450300, 3),
+(450304, '象山区', 450300, 3),
+(450305, '七星区', 450300, 3),
+(450311, '雁山区', 450300, 3),
+(450312, '临桂区', 450300, 3),
+(450321, '阳朔县', 450300, 3),
+(450323, '灵川县', 450300, 3),
+(450324, '全州县', 450300, 3),
+(450325, '兴安县', 450300, 3),
+(450326, '永福县', 450300, 3),
+(450327, '灌阳县', 450300, 3),
+(450328, '龙胜各族自治县', 450300, 3),
+(450329, '资源县', 450300, 3),
+(450330, '平乐县', 450300, 3),
+(450331, '荔浦县', 450300, 3),
+(450332, '恭城瑶族自治县', 450300, 3),
+(450400, '梧州市', 450000, 2),
+(450403, '万秀区', 450400, 3),
+(450405, '长洲区', 450400, 3),
+(450406, '龙圩区', 450400, 3),
+(450421, '苍梧县', 450400, 3),
+(450422, '藤县', 450400, 3),
+(450423, '蒙山县', 450400, 3),
+(450481, '岑溪市', 450400, 3),
+(450500, '北海市', 450000, 2),
+(450502, '海城区', 450500, 3),
+(450503, '银海区', 450500, 3),
+(450512, '铁山港区', 450500, 3),
+(450521, '合浦县', 450500, 3),
+(450600, '防城港市', 450000, 2),
+(450602, '港口区', 450600, 3),
+(450603, '防城区', 450600, 3),
+(450621, '上思县', 450600, 3),
+(450681, '东兴市', 450600, 3),
+(450700, '钦州市', 450000, 2),
+(450702, '钦南区', 450700, 3),
+(450703, '钦北区', 450700, 3),
+(450721, '灵山县', 450700, 3),
+(450722, '浦北县', 450700, 3),
+(450800, '贵港市', 450000, 2),
+(450802, '港北区', 450800, 3),
+(450803, '港南区', 450800, 3),
+(450804, '覃塘区', 450800, 3),
+(450821, '平南县', 450800, 3),
+(450881, '桂平市', 450800, 3),
+(450900, '玉林市', 450000, 2),
+(450902, '玉州区', 450900, 3),
+(450903, '福绵区', 450900, 3),
+(450921, '容县', 450900, 3),
+(450922, '陆川县', 450900, 3),
+(450923, '博白县', 450900, 3),
+(450924, '兴业县', 450900, 3),
+(450981, '北流市', 450900, 3),
+(451000, '百色市', 450000, 2),
+(451002, '右江区', 451000, 3),
+(451021, '田阳县', 451000, 3),
+(451022, '田东县', 451000, 3),
+(451023, '平果县', 451000, 3),
+(451024, '德保县', 451000, 3),
+(451026, '那坡县', 451000, 3),
+(451027, '凌云县', 451000, 3),
+(451028, '乐业县', 451000, 3),
+(451029, '田林县', 451000, 3),
+(451030, '西林县', 451000, 3),
+(451031, '隆林各族自治县', 451000, 3),
+(451081, '靖西市', 451000, 3),
+(451100, '贺州市', 450000, 2),
+(451102, '八步区', 451100, 3),
+(451103, '平桂区', 451100, 3),
+(451121, '昭平县', 451100, 3),
+(451122, '钟山县', 451100, 3),
+(451123, '富川瑶族自治县', 451100, 3),
+(451200, '河池市', 450000, 2),
+(451202, '金城江区', 451200, 3),
+(451203, '宜州区', 451200, 3),
+(451221, '南丹县', 451200, 3),
+(451222, '天峨县', 451200, 3),
+(451223, '凤山县', 451200, 3),
+(451224, '东兰县', 451200, 3),
+(451225, '罗城仫佬族自治县', 451200, 3),
+(451226, '环江毛南族自治县', 451200, 3),
+(451227, '巴马瑶族自治县', 451200, 3),
+(451228, '都安瑶族自治县', 451200, 3),
+(451229, '大化瑶族自治县', 451200, 3),
+(451300, '来宾市', 450000, 2),
+(451302, '兴宾区', 451300, 3),
+(451321, '忻城县', 451300, 3),
+(451322, '象州县', 451300, 3),
+(451323, '武宣县', 451300, 3),
+(451324, '金秀瑶族自治县', 451300, 3),
+(451381, '合山市', 451300, 3),
+(451400, '崇左市', 450000, 2),
+(451402, '江州区', 451400, 3),
+(451421, '扶绥县', 451400, 3),
+(451422, '宁明县', 451400, 3),
+(451423, '龙州县', 451400, 3),
+(451424, '大新县', 451400, 3),
+(451425, '天等县', 451400, 3),
+(451481, '凭祥市', 451400, 3),
+(460000, '海南省', 0, 1),
+(460100, '海口市', 460000, 2),
+(460105, '秀英区', 460100, 3),
+(460106, '龙华区', 460100, 3),
+(460107, '琼山区', 460100, 3),
+(460108, '美兰区', 460100, 3),
+(460200, '三亚市', 460000, 2),
+(460202, '海棠区', 460200, 3),
+(460203, '吉阳区', 460200, 3),
+(460204, '天涯区', 460200, 3),
+(460205, '崖州区', 460200, 3),
+(460300, '三沙市', 460000, 2),
+(460321, '西沙群岛', 460300, 3),
+(460322, '南沙群岛', 460300, 3),
+(460323, '中沙群岛的岛礁及其海域', 460300, 3),
+(460400, '儋州市', 460000, 2),
+(460401, '那大镇', 460400, 3),
+(460402, '和庆镇', 460400, 3),
+(460403, '南丰镇', 460400, 3),
+(460404, '大成镇', 460400, 3),
+(460405, '雅星镇', 460400, 3),
+(460406, '兰洋镇', 460400, 3),
+(460407, '光村镇', 460400, 3),
+(460408, '木棠镇', 460400, 3),
+(460409, '海头镇', 460400, 3),
+(460410, '峨蔓镇', 460400, 3),
+(460411, '三都镇', 460400, 3),
+(460412, '王五镇', 460400, 3),
+(460413, '白马井镇', 460400, 3),
+(460414, '中和镇', 460400, 3),
+(460415, '排浦镇', 460400, 3),
+(460416, '东成镇', 460400, 3),
+(460417, '新州镇', 460400, 3),
+(460418, '国营西培农场', 460400, 3),
+(460419, '国营西联农场', 460400, 3),
+(460420, '国营蓝洋农场', 460400, 3),
+(460421, '国营八一农场', 460400, 3),
+(460422, '洋浦经济开发区', 460400, 3),
+(460423, '华南热作学院', 460400, 3),
+(460424, '红岭农场', 460400, 3),
+(469000, '省直辖县级行政区划', 460000, 2),
+(469001, '五指山市', 469000, 3),
+(469002, '琼海市', 469000, 3),
+(469005, '文昌市', 469000, 3),
+(469006, '万宁市', 469000, 3),
+(469007, '东方市', 469000, 3),
+(469021, '定安县', 469000, 3),
+(469022, '屯昌县', 469000, 3),
+(469023, '澄迈县', 469000, 3),
+(469024, '临高县', 469000, 3),
+(469025, '白沙黎族自治县', 469000, 3),
+(469026, '昌江黎族自治县', 469000, 3),
+(469027, '乐东黎族自治县', 469000, 3),
+(469028, '陵水黎族自治县', 469000, 3),
+(469029, '保亭黎族苗族自治县', 469000, 3),
+(469030, '琼中黎族苗族自治县', 469000, 3),
+(500000, '重庆市', 0, 1),
+(500100, '重庆市', 500000, 2),
+(500101, '万州区', 500100, 3),
+(500102, '涪陵区', 500100, 3),
+(500103, '渝中区', 500100, 3),
+(500104, '大渡口区', 500100, 3),
+(500105, '江北区', 500100, 3),
+(500106, '沙坪坝区', 500100, 3),
+(500107, '九龙坡区', 500100, 3),
+(500108, '南岸区', 500100, 3),
+(500109, '北碚区', 500100, 3),
+(500110, '綦江区', 500100, 3),
+(500111, '大足区', 500100, 3),
+(500112, '渝北区', 500100, 3),
+(500113, '巴南区', 500100, 3),
+(500114, '黔江区', 500100, 3),
+(500115, '长寿区', 500100, 3),
+(500116, '江津区', 500100, 3),
+(500117, '合川区', 500100, 3),
+(500118, '永川区', 500100, 3),
+(500119, '南川区', 500100, 3),
+(500120, '璧山区', 500100, 3),
+(500151, '铜梁区', 500100, 3),
+(500152, '潼南区', 500100, 3),
+(500153, '荣昌区', 500100, 3),
+(500154, '开州区', 500100, 3),
+(500155, '梁平区', 500100, 3),
+(500156, '武隆区', 500100, 3),
+(500200, '县', 500000, 2),
+(500229, '城口县', 500200, 3),
+(500230, '丰都县', 500200, 3),
+(500231, '垫江县', 500200, 3),
+(500233, '忠县', 500200, 3),
+(500235, '云阳县', 500200, 3),
+(500236, '奉节县', 500200, 3),
+(500237, '巫山县', 500200, 3),
+(500238, '巫溪县', 500200, 3),
+(500240, '石柱土家族自治县', 500200, 3),
+(500241, '秀山土家族苗族自治县', 500200, 3),
+(500242, '酉阳土家族苗族自治县', 500200, 3),
+(500243, '彭水苗族土家族自治县', 500200, 3),
+(510000, '四川省', 0, 1),
+(510100, '成都市', 510000, 2),
+(510104, '锦江区', 510100, 3),
+(510105, '青羊区', 510100, 3),
+(510106, '金牛区', 510100, 3),
+(510107, '武侯区', 510100, 3),
+(510108, '成华区', 510100, 3),
+(510112, '龙泉驿区', 510100, 3),
+(510113, '青白江区', 510100, 3),
+(510114, '新都区', 510100, 3),
+(510115, '温江区', 510100, 3),
+(510116, '双流区', 510100, 3),
+(510117, '郫都区', 510100, 3),
+(510121, '金堂县', 510100, 3),
+(510129, '大邑县', 510100, 3),
+(510131, '蒲江县', 510100, 3),
+(510132, '新津县', 510100, 3),
+(510181, '都江堰市', 510100, 3),
+(510182, '彭州市', 510100, 3),
+(510183, '邛崃市', 510100, 3),
+(510184, '崇州市', 510100, 3),
+(510185, '简阳市', 510100, 3),
+(510300, '自贡市', 510000, 2),
+(510302, '自流井区', 510300, 3),
+(510303, '贡井区', 510300, 3),
+(510304, '大安区', 510300, 3),
+(510311, '沿滩区', 510300, 3),
+(510321, '荣县', 510300, 3),
+(510322, '富顺县', 510300, 3),
+(510400, '攀枝花市', 510000, 2),
+(510402, '东区', 510400, 3),
+(510403, '西区', 510400, 3),
+(510411, '仁和区', 510400, 3),
+(510421, '米易县', 510400, 3),
+(510422, '盐边县', 510400, 3),
+(510500, '泸州市', 510000, 2),
+(510502, '江阳区', 510500, 3),
+(510503, '纳溪区', 510500, 3),
+(510504, '龙马潭区', 510500, 3),
+(510521, '泸县', 510500, 3),
+(510522, '合江县', 510500, 3),
+(510524, '叙永县', 510500, 3),
+(510525, '古蔺县', 510500, 3),
+(510600, '德阳市', 510000, 2),
+(510603, '旌阳区', 510600, 3),
+(510604, '罗江区', 510600, 3),
+(510623, '中江县', 510600, 3),
+(510681, '广汉市', 510600, 3),
+(510682, '什邡市', 510600, 3),
+(510683, '绵竹市', 510600, 3),
+(510700, '绵阳市', 510000, 2),
+(510703, '涪城区', 510700, 3),
+(510704, '游仙区', 510700, 3),
+(510705, '安州区', 510700, 3),
+(510722, '三台县', 510700, 3),
+(510723, '盐亭县', 510700, 3),
+(510725, '梓潼县', 510700, 3),
+(510726, '北川羌族自治县', 510700, 3),
+(510727, '平武县', 510700, 3),
+(510781, '江油市', 510700, 3),
+(510800, '广元市', 510000, 2),
+(510802, '利州区', 510800, 3),
+(510811, '昭化区', 510800, 3),
+(510812, '朝天区', 510800, 3),
+(510821, '旺苍县', 510800, 3),
+(510822, '青川县', 510800, 3),
+(510823, '剑阁县', 510800, 3),
+(510824, '苍溪县', 510800, 3),
+(510900, '遂宁市', 510000, 2),
+(510903, '船山区', 510900, 3),
+(510904, '安居区', 510900, 3),
+(510921, '蓬溪县', 510900, 3),
+(510922, '射洪县', 510900, 3),
+(510923, '大英县', 510900, 3),
+(511000, '内江市', 510000, 2),
+(511002, '市中区', 511000, 3),
+(511011, '东兴区', 511000, 3),
+(511024, '威远县', 511000, 3),
+(511025, '资中县', 511000, 3),
+(511083, '隆昌市', 511000, 3),
+(511100, '乐山市', 510000, 2),
+(511102, '市中区', 511100, 3),
+(511111, '沙湾区', 511100, 3),
+(511112, '五通桥区', 511100, 3),
+(511113, '金口河区', 511100, 3),
+(511123, '犍为县', 511100, 3),
+(511124, '井研县', 511100, 3),
+(511126, '夹江县', 511100, 3),
+(511129, '沐川县', 511100, 3),
+(511132, '峨边彝族自治县', 511100, 3),
+(511133, '马边彝族自治县', 511100, 3),
+(511181, '峨眉山市', 511100, 3),
+(511300, '南充市', 510000, 2),
+(511302, '顺庆区', 511300, 3),
+(511303, '高坪区', 511300, 3),
+(511304, '嘉陵区', 511300, 3),
+(511321, '南部县', 511300, 3),
+(511322, '营山县', 511300, 3),
+(511323, '蓬安县', 511300, 3),
+(511324, '仪陇县', 511300, 3),
+(511325, '西充县', 511300, 3),
+(511381, '阆中市', 511300, 3),
+(511400, '眉山市', 510000, 2),
+(511402, '东坡区', 511400, 3),
+(511403, '彭山区', 511400, 3),
+(511421, '仁寿县', 511400, 3),
+(511423, '洪雅县', 511400, 3),
+(511424, '丹棱县', 511400, 3),
+(511425, '青神县', 511400, 3),
+(511500, '宜宾市', 510000, 2),
+(511502, '翠屏区', 511500, 3),
+(511503, '南溪区', 511500, 3),
+(511521, '宜宾县', 511500, 3),
+(511523, '江安县', 511500, 3),
+(511524, '长宁县', 511500, 3),
+(511525, '高县', 511500, 3),
+(511526, '珙县', 511500, 3),
+(511527, '筠连县', 511500, 3),
+(511528, '兴文县', 511500, 3),
+(511529, '屏山县', 511500, 3),
+(511600, '广安市', 510000, 2),
+(511602, '广安区', 511600, 3),
+(511603, '前锋区', 511600, 3),
+(511621, '岳池县', 511600, 3),
+(511622, '武胜县', 511600, 3),
+(511623, '邻水县', 511600, 3),
+(511681, '华蓥市', 511600, 3),
+(511700, '达州市', 510000, 2),
+(511702, '通川区', 511700, 3),
+(511703, '达川区', 511700, 3),
+(511722, '宣汉县', 511700, 3),
+(511723, '开江县', 511700, 3),
+(511724, '大竹县', 511700, 3),
+(511725, '渠县', 511700, 3),
+(511781, '万源市', 511700, 3),
+(511800, '雅安市', 510000, 2),
+(511802, '雨城区', 511800, 3),
+(511803, '名山区', 511800, 3),
+(511822, '荥经县', 511800, 3),
+(511823, '汉源县', 511800, 3),
+(511824, '石棉县', 511800, 3),
+(511825, '天全县', 511800, 3),
+(511826, '芦山县', 511800, 3),
+(511827, '宝兴县', 511800, 3),
+(511900, '巴中市', 510000, 2),
+(511902, '巴州区', 511900, 3),
+(511903, '恩阳区', 511900, 3),
+(511921, '通江县', 511900, 3),
+(511922, '南江县', 511900, 3),
+(511923, '平昌县', 511900, 3),
+(512000, '资阳市', 510000, 2),
+(512002, '雁江区', 512000, 3),
+(512021, '安岳县', 512000, 3),
+(512022, '乐至县', 512000, 3),
+(513200, '阿坝藏族羌族自治州', 510000, 2),
+(513201, '马尔康市', 513200, 3),
+(513221, '汶川县', 513200, 3),
+(513222, '理县', 513200, 3),
+(513223, '茂县', 513200, 3),
+(513224, '松潘县', 513200, 3),
+(513225, '九寨沟县', 513200, 3),
+(513226, '金川县', 513200, 3),
+(513227, '小金县', 513200, 3),
+(513228, '黑水县', 513200, 3),
+(513230, '壤塘县', 513200, 3),
+(513231, '阿坝县', 513200, 3),
+(513232, '若尔盖县', 513200, 3),
+(513233, '红原县', 513200, 3),
+(513300, '甘孜藏族自治州', 510000, 2),
+(513301, '康定市', 513300, 3),
+(513322, '泸定县', 513300, 3),
+(513323, '丹巴县', 513300, 3),
+(513324, '九龙县', 513300, 3),
+(513325, '雅江县', 513300, 3),
+(513326, '道孚县', 513300, 3),
+(513327, '炉霍县', 513300, 3),
+(513328, '甘孜县', 513300, 3),
+(513329, '新龙县', 513300, 3),
+(513330, '德格县', 513300, 3),
+(513331, '白玉县', 513300, 3),
+(513332, '石渠县', 513300, 3),
+(513333, '色达县', 513300, 3),
+(513334, '理塘县', 513300, 3),
+(513335, '巴塘县', 513300, 3),
+(513336, '乡城县', 513300, 3),
+(513337, '稻城县', 513300, 3),
+(513338, '得荣县', 513300, 3),
+(513400, '凉山彝族自治州', 510000, 2),
+(513401, '西昌市', 513400, 3),
+(513422, '木里藏族自治县', 513400, 3),
+(513423, '盐源县', 513400, 3),
+(513424, '德昌县', 513400, 3),
+(513425, '会理县', 513400, 3),
+(513426, '会东县', 513400, 3),
+(513427, '宁南县', 513400, 3),
+(513428, '普格县', 513400, 3),
+(513429, '布拖县', 513400, 3),
+(513430, '金阳县', 513400, 3),
+(513431, '昭觉县', 513400, 3),
+(513432, '喜德县', 513400, 3),
+(513433, '冕宁县', 513400, 3),
+(513434, '越西县', 513400, 3),
+(513435, '甘洛县', 513400, 3),
+(513436, '美姑县', 513400, 3),
+(513437, '雷波县', 513400, 3),
+(520000, '贵州省', 0, 1),
+(520100, '贵阳市', 520000, 2),
+(520102, '南明区', 520100, 3),
+(520103, '云岩区', 520100, 3),
+(520111, '花溪区', 520100, 3),
+(520112, '乌当区', 520100, 3),
+(520113, '白云区', 520100, 3),
+(520115, '观山湖区', 520100, 3),
+(520121, '开阳县', 520100, 3),
+(520122, '息烽县', 520100, 3),
+(520123, '修文县', 520100, 3),
+(520181, '清镇市', 520100, 3),
+(520200, '六盘水市', 520000, 2),
+(520201, '钟山区', 520200, 3),
+(520203, '六枝特区', 520200, 3),
+(520221, '水城县', 520200, 3),
+(520281, '盘州市', 520200, 3),
+(520300, '遵义市', 520000, 2),
+(520302, '红花岗区', 520300, 3),
+(520303, '汇川区', 520300, 3),
+(520304, '播州区', 520300, 3),
+(520322, '桐梓县', 520300, 3),
+(520323, '绥阳县', 520300, 3),
+(520324, '正安县', 520300, 3),
+(520325, '道真仡佬族苗族自治县', 520300, 3),
+(520326, '务川仡佬族苗族自治县', 520300, 3),
+(520327, '凤冈县', 520300, 3),
+(520328, '湄潭县', 520300, 3),
+(520329, '余庆县', 520300, 3),
+(520330, '习水县', 520300, 3),
+(520381, '赤水市', 520300, 3),
+(520382, '仁怀市', 520300, 3),
+(520400, '安顺市', 520000, 2),
+(520402, '西秀区', 520400, 3),
+(520403, '平坝区', 520400, 3),
+(520422, '普定县', 520400, 3),
+(520423, '镇宁布依族苗族自治县', 520400, 3),
+(520424, '关岭布依族苗族自治县', 520400, 3),
+(520425, '紫云苗族布依族自治县', 520400, 3),
+(520500, '毕节市', 520000, 2),
+(520502, '七星关区', 520500, 3),
+(520521, '大方县', 520500, 3),
+(520522, '黔西县', 520500, 3),
+(520523, '金沙县', 520500, 3),
+(520524, '织金县', 520500, 3),
+(520525, '纳雍县', 520500, 3),
+(520526, '威宁彝族回族苗族自治县', 520500, 3),
+(520527, '赫章县', 520500, 3),
+(520600, '铜仁市', 520000, 2),
+(520602, '碧江区', 520600, 3),
+(520603, '万山区', 520600, 3),
+(520621, '江口县', 520600, 3),
+(520622, '玉屏侗族自治县', 520600, 3),
+(520623, '石阡县', 520600, 3),
+(520624, '思南县', 520600, 3),
+(520625, '印江土家族苗族自治县', 520600, 3),
+(520626, '德江县', 520600, 3),
+(520627, '沿河土家族自治县', 520600, 3),
+(520628, '松桃苗族自治县', 520600, 3),
+(522300, '黔西南布依族苗族自治州', 520000, 2),
+(522301, '兴义市', 522300, 3),
+(522322, '兴仁县', 522300, 3),
+(522323, '普安县', 522300, 3),
+(522324, '晴隆县', 522300, 3),
+(522325, '贞丰县', 522300, 3),
+(522326, '望谟县', 522300, 3),
+(522327, '册亨县', 522300, 3),
+(522328, '安龙县', 522300, 3),
+(522600, '黔东南苗族侗族自治州', 520000, 2),
+(522601, '凯里市', 522600, 3),
+(522622, '黄平县', 522600, 3),
+(522623, '施秉县', 522600, 3),
+(522624, '三穗县', 522600, 3),
+(522625, '镇远县', 522600, 3),
+(522626, '岑巩县', 522600, 3),
+(522627, '天柱县', 522600, 3),
+(522628, '锦屏县', 522600, 3),
+(522629, '剑河县', 522600, 3),
+(522630, '台江县', 522600, 3),
+(522631, '黎平县', 522600, 3),
+(522632, '榕江县', 522600, 3),
+(522633, '从江县', 522600, 3),
+(522634, '雷山县', 522600, 3),
+(522635, '麻江县', 522600, 3),
+(522636, '丹寨县', 522600, 3),
+(522700, '黔南布依族苗族自治州', 520000, 2),
+(522701, '都匀市', 522700, 3),
+(522702, '福泉市', 522700, 3),
+(522722, '荔波县', 522700, 3),
+(522723, '贵定县', 522700, 3),
+(522725, '瓮安县', 522700, 3),
+(522726, '独山县', 522700, 3),
+(522727, '平塘县', 522700, 3),
+(522728, '罗甸县', 522700, 3),
+(522729, '长顺县', 522700, 3),
+(522730, '龙里县', 522700, 3),
+(522731, '惠水县', 522700, 3),
+(522732, '三都水族自治县', 522700, 3),
+(530000, '云南省', 0, 1),
+(530100, '昆明市', 530000, 2),
+(530102, '五华区', 530100, 3),
+(530103, '盘龙区', 530100, 3),
+(530111, '官渡区', 530100, 3),
+(530112, '西山区', 530100, 3),
+(530113, '东川区', 530100, 3),
+(530114, '呈贡区', 530100, 3),
+(530115, '晋宁区', 530100, 3),
+(530124, '富民县', 530100, 3),
+(530125, '宜良县', 530100, 3),
+(530126, '石林彝族自治县', 530100, 3),
+(530127, '嵩明县', 530100, 3),
+(530128, '禄劝彝族苗族自治县', 530100, 3),
+(530129, '寻甸回族彝族自治县', 530100, 3),
+(530181, '安宁市', 530100, 3),
+(530300, '曲靖市', 530000, 2),
+(530302, '麒麟区', 530300, 3),
+(530303, '沾益区', 530300, 3),
+(530321, '马龙县', 530300, 3),
+(530322, '陆良县', 530300, 3),
+(530323, '师宗县', 530300, 3),
+(530324, '罗平县', 530300, 3),
+(530325, '富源县', 530300, 3),
+(530326, '会泽县', 530300, 3),
+(530381, '宣威市', 530300, 3),
+(530400, '玉溪市', 530000, 2),
+(530402, '红塔区', 530400, 3),
+(530403, '江川区', 530400, 3),
+(530422, '澄江县', 530400, 3),
+(530423, '通海县', 530400, 3),
+(530424, '华宁县', 530400, 3),
+(530425, '易门县', 530400, 3),
+(530426, '峨山彝族自治县', 530400, 3),
+(530427, '新平彝族傣族自治县', 530400, 3),
+(530428, '元江哈尼族彝族傣族自治县', 530400, 3),
+(530500, '保山市', 530000, 2),
+(530502, '隆阳区', 530500, 3),
+(530521, '施甸县', 530500, 3),
+(530523, '龙陵县', 530500, 3),
+(530524, '昌宁县', 530500, 3),
+(530581, '腾冲市', 530500, 3),
+(530600, '昭通市', 530000, 2),
+(530602, '昭阳区', 530600, 3),
+(530621, '鲁甸县', 530600, 3),
+(530622, '巧家县', 530600, 3),
+(530623, '盐津县', 530600, 3),
+(530624, '大关县', 530600, 3),
+(530625, '永善县', 530600, 3),
+(530626, '绥江县', 530600, 3),
+(530627, '镇雄县', 530600, 3),
+(530628, '彝良县', 530600, 3),
+(530629, '威信县', 530600, 3),
+(530630, '水富县', 530600, 3),
+(530700, '丽江市', 530000, 2),
+(530702, '古城区', 530700, 3),
+(530721, '玉龙纳西族自治县', 530700, 3),
+(530722, '永胜县', 530700, 3),
+(530723, '华坪县', 530700, 3),
+(530724, '宁蒗彝族自治县', 530700, 3),
+(530800, '普洱市', 530000, 2),
+(530802, '思茅区', 530800, 3),
+(530821, '宁洱哈尼族彝族自治县', 530800, 3),
+(530822, '墨江哈尼族自治县', 530800, 3),
+(530823, '景东彝族自治县', 530800, 3),
+(530824, '景谷傣族彝族自治县', 530800, 3),
+(530825, '镇沅彝族哈尼族拉祜族自治县', 530800, 3),
+(530826, '江城哈尼族彝族自治县', 530800, 3),
+(530827, '孟连傣族拉祜族佤族自治县', 530800, 3),
+(530828, '澜沧拉祜族自治县', 530800, 3),
+(530829, '西盟佤族自治县', 530800, 3),
+(530900, '临沧市', 530000, 2),
+(530902, '临翔区', 530900, 3),
+(530921, '凤庆县', 530900, 3),
+(530922, '云县', 530900, 3),
+(530923, '永德县', 530900, 3),
+(530924, '镇康县', 530900, 3),
+(530925, '双江拉祜族佤族布朗族傣族自治县', 530900, 3),
+(530926, '耿马傣族佤族自治县', 530900, 3),
+(530927, '沧源佤族自治县', 530900, 3),
+(532300, '楚雄彝族自治州', 530000, 2),
+(532301, '楚雄市', 532300, 3),
+(532322, '双柏县', 532300, 3),
+(532323, '牟定县', 532300, 3),
+(532324, '南华县', 532300, 3),
+(532325, '姚安县', 532300, 3),
+(532326, '大姚县', 532300, 3),
+(532327, '永仁县', 532300, 3),
+(532328, '元谋县', 532300, 3),
+(532329, '武定县', 532300, 3),
+(532331, '禄丰县', 532300, 3),
+(532500, '红河哈尼族彝族自治州', 530000, 2),
+(532501, '个旧市', 532500, 3),
+(532502, '开远市', 532500, 3),
+(532503, '蒙自市', 532500, 3),
+(532504, '弥勒市', 532500, 3),
+(532523, '屏边苗族自治县', 532500, 3),
+(532524, '建水县', 532500, 3),
+(532525, '石屏县', 532500, 3),
+(532527, '泸西县', 532500, 3),
+(532528, '元阳县', 532500, 3),
+(532529, '红河县', 532500, 3),
+(532530, '金平苗族瑶族傣族自治县', 532500, 3),
+(532531, '绿春县', 532500, 3),
+(532532, '河口瑶族自治县', 532500, 3),
+(532600, '文山壮族苗族自治州', 530000, 2),
+(532601, '文山市', 532600, 3),
+(532622, '砚山县', 532600, 3),
+(532623, '西畴县', 532600, 3),
+(532624, '麻栗坡县', 532600, 3),
+(532625, '马关县', 532600, 3),
+(532626, '丘北县', 532600, 3),
+(532627, '广南县', 532600, 3),
+(532628, '富宁县', 532600, 3),
+(532800, '西双版纳傣族自治州', 530000, 2),
+(532801, '景洪市', 532800, 3),
+(532822, '勐海县', 532800, 3),
+(532823, '勐腊县', 532800, 3),
+(532900, '大理白族自治州', 530000, 2),
+(532901, '大理市', 532900, 3),
+(532922, '漾濞彝族自治县', 532900, 3),
+(532923, '祥云县', 532900, 3),
+(532924, '宾川县', 532900, 3),
+(532925, '弥渡县', 532900, 3),
+(532926, '南涧彝族自治县', 532900, 3),
+(532927, '巍山彝族回族自治县', 532900, 3),
+(532928, '永平县', 532900, 3),
+(532929, '云龙县', 532900, 3),
+(532930, '洱源县', 532900, 3),
+(532931, '剑川县', 532900, 3),
+(532932, '鹤庆县', 532900, 3),
+(533100, '德宏傣族景颇族自治州', 530000, 2),
+(533102, '瑞丽市', 533100, 3),
+(533103, '芒市', 533100, 3),
+(533122, '梁河县', 533100, 3),
+(533123, '盈江县', 533100, 3),
+(533124, '陇川县', 533100, 3),
+(533300, '怒江傈僳族自治州', 530000, 2),
+(533301, '泸水市', 533300, 3),
+(533323, '福贡县', 533300, 3),
+(533324, '贡山独龙族怒族自治县', 533300, 3),
+(533325, '兰坪白族普米族自治县', 533300, 3),
+(533400, '迪庆藏族自治州', 530000, 2),
+(533401, '香格里拉市', 533400, 3),
+(533422, '德钦县', 533400, 3),
+(533423, '维西傈僳族自治县', 533400, 3),
+(540000, '西藏自治区', 0, 1),
+(540100, '拉萨市', 540000, 2),
+(540102, '城关区', 540100, 3),
+(540103, '堆龙德庆区', 540100, 3),
+(540104, '达孜区', 540100, 3),
+(540121, '林周县', 540100, 3),
+(540122, '当雄县', 540100, 3),
+(540123, '尼木县', 540100, 3),
+(540124, '曲水县', 540100, 3),
+(540127, '墨竹工卡县', 540100, 3),
+(540200, '日喀则市', 540000, 2),
+(540202, '桑珠孜区', 540200, 3),
+(540221, '南木林县', 540200, 3),
+(540222, '江孜县', 540200, 3),
+(540223, '定日县', 540200, 3),
+(540224, '萨迦县', 540200, 3),
+(540225, '拉孜县', 540200, 3),
+(540226, '昂仁县', 540200, 3),
+(540227, '谢通门县', 540200, 3),
+(540228, '白朗县', 540200, 3),
+(540229, '仁布县', 540200, 3),
+(540230, '康马县', 540200, 3),
+(540231, '定结县', 540200, 3),
+(540232, '仲巴县', 540200, 3),
+(540233, '亚东县', 540200, 3),
+(540234, '吉隆县', 540200, 3),
+(540235, '聂拉木县', 540200, 3),
+(540236, '萨嘎县', 540200, 3),
+(540237, '岗巴县', 540200, 3),
+(540300, '昌都市', 540000, 2),
+(540302, '卡若区', 540300, 3),
+(540321, '江达县', 540300, 3),
+(540322, '贡觉县', 540300, 3),
+(540323, '类乌齐县', 540300, 3),
+(540324, '丁青县', 540300, 3),
+(540325, '察雅县', 540300, 3),
+(540326, '八宿县', 540300, 3),
+(540327, '左贡县', 540300, 3),
+(540328, '芒康县', 540300, 3),
+(540329, '洛隆县', 540300, 3),
+(540330, '边坝县', 540300, 3),
+(540400, '林芝市', 540000, 2),
+(540402, '巴宜区', 540400, 3),
+(540421, '工布江达县', 540400, 3),
+(540422, '米林县', 540400, 3),
+(540423, '墨脱县', 540400, 3),
+(540424, '波密县', 540400, 3),
+(540425, '察隅县', 540400, 3),
+(540426, '朗县', 540400, 3),
+(540500, '山南市', 540000, 2),
+(540502, '乃东区', 540500, 3),
+(540521, '扎囊县', 540500, 3),
+(540522, '贡嘎县', 540500, 3),
+(540523, '桑日县', 540500, 3),
+(540524, '琼结县', 540500, 3),
+(540525, '曲松县', 540500, 3),
+(540526, '措美县', 540500, 3),
+(540527, '洛扎县', 540500, 3),
+(540528, '加查县', 540500, 3),
+(540529, '隆子县', 540500, 3),
+(540530, '错那县', 540500, 3),
+(540531, '浪卡子县', 540500, 3),
+(542400, '那曲地区', 540000, 2),
+(542421, '那曲县', 542400, 3),
+(542422, '嘉黎县', 542400, 3),
+(542423, '比如县', 542400, 3),
+(542424, '聂荣县', 542400, 3),
+(542425, '安多县', 542400, 3),
+(542426, '申扎县', 542400, 3),
+(542427, '索县', 542400, 3),
+(542428, '班戈县', 542400, 3),
+(542429, '巴青县', 542400, 3),
+(542430, '尼玛县', 542400, 3),
+(542431, '双湖县', 542400, 3),
+(542500, '阿里地区', 540000, 2),
+(542521, '普兰县', 542500, 3),
+(542522, '札达县', 542500, 3),
+(542523, '噶尔县', 542500, 3),
+(542524, '日土县', 542500, 3),
+(542525, '革吉县', 542500, 3),
+(542526, '改则县', 542500, 3),
+(542527, '措勤县', 542500, 3),
+(610000, '陕西省', 0, 1),
+(610100, '西安市', 610000, 2),
+(610102, '新城区', 610100, 3),
+(610103, '碑林区', 610100, 3),
+(610104, '莲湖区', 610100, 3),
+(610111, '灞桥区', 610100, 3),
+(610112, '未央区', 610100, 3),
+(610113, '雁塔区', 610100, 3),
+(610114, '阎良区', 610100, 3),
+(610115, '临潼区', 610100, 3),
+(610116, '长安区', 610100, 3),
+(610117, '高陵区', 610100, 3),
+(610118, '鄠邑区', 610100, 3),
+(610122, '蓝田县', 610100, 3),
+(610124, '周至县', 610100, 3),
+(610200, '铜川市', 610000, 2),
+(610202, '王益区', 610200, 3),
+(610203, '印台区', 610200, 3),
+(610204, '耀州区', 610200, 3),
+(610222, '宜君县', 610200, 3),
+(610300, '宝鸡市', 610000, 2),
+(610302, '渭滨区', 610300, 3),
+(610303, '金台区', 610300, 3),
+(610304, '陈仓区', 610300, 3),
+(610322, '凤翔县', 610300, 3),
+(610323, '岐山县', 610300, 3),
+(610324, '扶风县', 610300, 3),
+(610326, '眉县', 610300, 3),
+(610327, '陇县', 610300, 3),
+(610328, '千阳县', 610300, 3),
+(610329, '麟游县', 610300, 3),
+(610330, '凤县', 610300, 3),
+(610331, '太白县', 610300, 3),
+(610400, '咸阳市', 610000, 2),
+(610402, '秦都区', 610400, 3),
+(610403, '杨陵区', 610400, 3),
+(610404, '渭城区', 610400, 3),
+(610422, '三原县', 610400, 3),
+(610423, '泾阳县', 610400, 3),
+(610424, '乾县', 610400, 3),
+(610425, '礼泉县', 610400, 3),
+(610426, '永寿县', 610400, 3),
+(610427, '彬州市', 610400, 3),
+(610428, '长武县', 610400, 3),
+(610429, '旬邑县', 610400, 3),
+(610430, '淳化县', 610400, 3),
+(610431, '武功县', 610400, 3),
+(610481, '兴平市', 610400, 3),
+(610500, '渭南市', 610000, 2),
+(610502, '临渭区', 610500, 3),
+(610503, '华州区', 610500, 3),
+(610522, '潼关县', 610500, 3),
+(610523, '大荔县', 610500, 3),
+(610524, '合阳县', 610500, 3),
+(610525, '澄城县', 610500, 3),
+(610526, '蒲城县', 610500, 3),
+(610527, '白水县', 610500, 3),
+(610528, '富平县', 610500, 3),
+(610581, '韩城市', 610500, 3),
+(610582, '华阴市', 610500, 3),
+(610600, '延安市', 610000, 2),
+(610602, '宝塔区', 610600, 3),
+(610603, '安塞区', 610600, 3),
+(610621, '延长县', 610600, 3),
+(610622, '延川县', 610600, 3),
+(610623, '子长县', 610600, 3),
+(610625, '志丹县', 610600, 3),
+(610626, '吴起县', 610600, 3),
+(610627, '甘泉县', 610600, 3),
+(610628, '富县', 610600, 3),
+(610629, '洛川县', 610600, 3),
+(610630, '宜川县', 610600, 3),
+(610631, '黄龙县', 610600, 3),
+(610632, '黄陵县', 610600, 3),
+(610700, '汉中市', 610000, 2),
+(610702, '汉台区', 610700, 3),
+(610703, '南郑区', 610700, 3),
+(610722, '城固县', 610700, 3),
+(610723, '洋县', 610700, 3),
+(610724, '西乡县', 610700, 3),
+(610725, '勉县', 610700, 3),
+(610726, '宁强县', 610700, 3),
+(610727, '略阳县', 610700, 3),
+(610728, '镇巴县', 610700, 3),
+(610729, '留坝县', 610700, 3),
+(610730, '佛坪县', 610700, 3),
+(610800, '榆林市', 610000, 2),
+(610802, '榆阳区', 610800, 3),
+(610803, '横山区', 610800, 3),
+(610822, '府谷县', 610800, 3),
+(610824, '靖边县', 610800, 3),
+(610825, '定边县', 610800, 3),
+(610826, '绥德县', 610800, 3),
+(610827, '米脂县', 610800, 3),
+(610828, '佳县', 610800, 3),
+(610829, '吴堡县', 610800, 3),
+(610830, '清涧县', 610800, 3),
+(610831, '子洲县', 610800, 3),
+(610881, '神木市', 610800, 3),
+(610900, '安康市', 610000, 2),
+(610902, '汉滨区', 610900, 3),
+(610921, '汉阴县', 610900, 3),
+(610922, '石泉县', 610900, 3),
+(610923, '宁陕县', 610900, 3),
+(610924, '紫阳县', 610900, 3),
+(610925, '岚皋县', 610900, 3),
+(610926, '平利县', 610900, 3),
+(610927, '镇坪县', 610900, 3),
+(610928, '旬阳县', 610900, 3),
+(610929, '白河县', 610900, 3),
+(611000, '商洛市', 610000, 2),
+(611002, '商州区', 611000, 3),
+(611021, '洛南县', 611000, 3),
+(611022, '丹凤县', 611000, 3),
+(611023, '商南县', 611000, 3),
+(611024, '山阳县', 611000, 3),
+(611025, '镇安县', 611000, 3),
+(611026, '柞水县', 611000, 3),
+(620000, '甘肃省', 0, 1),
+(620100, '兰州市', 620000, 2),
+(620102, '城关区', 620100, 3),
+(620103, '七里河区', 620100, 3),
+(620104, '西固区', 620100, 3),
+(620105, '安宁区', 620100, 3),
+(620111, '红古区', 620100, 3),
+(620121, '永登县', 620100, 3),
+(620122, '皋兰县', 620100, 3),
+(620123, '榆中县', 620100, 3),
+(620200, '嘉峪关市', 620000, 2),
+(620201, '雄关区', 620200, 3),
+(620202, '镜铁区', 620200, 3),
+(620203, '长城区', 620200, 3),
+(620300, '金昌市', 620000, 2),
+(620302, '金川区', 620300, 3),
+(620321, '永昌县', 620300, 3),
+(620400, '白银市', 620000, 2),
+(620402, '白银区', 620400, 3),
+(620403, '平川区', 620400, 3),
+(620421, '靖远县', 620400, 3),
+(620422, '会宁县', 620400, 3),
+(620423, '景泰县', 620400, 3),
+(620500, '天水市', 620000, 2),
+(620502, '秦州区', 620500, 3),
+(620503, '麦积区', 620500, 3),
+(620521, '清水县', 620500, 3),
+(620522, '秦安县', 620500, 3),
+(620523, '甘谷县', 620500, 3),
+(620524, '武山县', 620500, 3),
+(620525, '张家川回族自治县', 620500, 3),
+(620600, '武威市', 620000, 2),
+(620602, '凉州区', 620600, 3),
+(620621, '民勤县', 620600, 3),
+(620622, '古浪县', 620600, 3),
+(620623, '天祝藏族自治县', 620600, 3),
+(620700, '张掖市', 620000, 2),
+(620702, '甘州区', 620700, 3),
+(620721, '肃南裕固族自治县', 620700, 3),
+(620722, '民乐县', 620700, 3),
+(620723, '临泽县', 620700, 3),
+(620724, '高台县', 620700, 3),
+(620725, '山丹县', 620700, 3),
+(620800, '平凉市', 620000, 2),
+(620802, '崆峒区', 620800, 3),
+(620821, '泾川县', 620800, 3),
+(620822, '灵台县', 620800, 3),
+(620823, '崇信县', 620800, 3),
+(620824, '华亭县', 620800, 3),
+(620825, '庄浪县', 620800, 3),
+(620826, '静宁县', 620800, 3),
+(620900, '酒泉市', 620000, 2),
+(620902, '肃州区', 620900, 3),
+(620921, '金塔县', 620900, 3),
+(620922, '瓜州县', 620900, 3),
+(620923, '肃北蒙古族自治县', 620900, 3),
+(620924, '阿克塞哈萨克族自治县', 620900, 3),
+(620981, '玉门市', 620900, 3),
+(620982, '敦煌市', 620900, 3),
+(621000, '庆阳市', 620000, 2),
+(621002, '西峰区', 621000, 3),
+(621021, '庆城县', 621000, 3),
+(621022, '环县', 621000, 3),
+(621023, '华池县', 621000, 3),
+(621024, '合水县', 621000, 3),
+(621025, '正宁县', 621000, 3),
+(621026, '宁县', 621000, 3),
+(621027, '镇原县', 621000, 3),
+(621100, '定西市', 620000, 2),
+(621102, '安定区', 621100, 3),
+(621121, '通渭县', 621100, 3),
+(621122, '陇西县', 621100, 3),
+(621123, '渭源县', 621100, 3),
+(621124, '临洮县', 621100, 3),
+(621125, '漳县', 621100, 3),
+(621126, '岷县', 621100, 3),
+(621200, '陇南市', 620000, 2),
+(621202, '武都区', 621200, 3),
+(621221, '成县', 621200, 3),
+(621222, '文县', 621200, 3),
+(621223, '宕昌县', 621200, 3),
+(621224, '康县', 621200, 3),
+(621225, '西和县', 621200, 3),
+(621226, '礼县', 621200, 3),
+(621227, '徽县', 621200, 3),
+(621228, '两当县', 621200, 3),
+(622900, '临夏回族自治州', 620000, 2),
+(622901, '临夏市', 622900, 3),
+(622921, '临夏县', 622900, 3),
+(622922, '康乐县', 622900, 3),
+(622923, '永靖县', 622900, 3),
+(622924, '广河县', 622900, 3),
+(622925, '和政县', 622900, 3),
+(622926, '东乡族自治县', 622900, 3),
+(622927, '积石山保安族东乡族撒拉族自治县', 622900, 3),
+(623000, '甘南藏族自治州', 620000, 2),
+(623001, '合作市', 623000, 3),
+(623021, '临潭县', 623000, 3),
+(623022, '卓尼县', 623000, 3),
+(623023, '舟曲县', 623000, 3),
+(623024, '迭部县', 623000, 3),
+(623025, '玛曲县', 623000, 3),
+(623026, '碌曲县', 623000, 3),
+(623027, '夏河县', 623000, 3),
+(630000, '青海省', 0, 1),
+(630100, '西宁市', 630000, 2),
+(630102, '城东区', 630100, 3),
+(630103, '城中区', 630100, 3),
+(630104, '城西区', 630100, 3),
+(630105, '城北区', 630100, 3),
+(630121, '大通回族土族自治县', 630100, 3),
+(630122, '湟中县', 630100, 3),
+(630123, '湟源县', 630100, 3),
+(630200, '海东市', 630000, 2),
+(630202, '乐都区', 630200, 3),
+(630203, '平安区', 630200, 3),
+(630222, '民和回族土族自治县', 630200, 3),
+(630223, '互助土族自治县', 630200, 3),
+(630224, '化隆回族自治县', 630200, 3),
+(630225, '循化撒拉族自治县', 630200, 3),
+(632200, '海北藏族自治州', 630000, 2),
+(632221, '门源回族自治县', 632200, 3),
+(632222, '祁连县', 632200, 3),
+(632223, '海晏县', 632200, 3),
+(632224, '刚察县', 632200, 3),
+(632300, '黄南藏族自治州', 630000, 2),
+(632321, '同仁县', 632300, 3),
+(632322, '尖扎县', 632300, 3),
+(632323, '泽库县', 632300, 3),
+(632324, '河南蒙古族自治县', 632300, 3),
+(632500, '海南藏族自治州', 630000, 2),
+(632521, '共和县', 632500, 3),
+(632522, '同德县', 632500, 3),
+(632523, '贵德县', 632500, 3),
+(632524, '兴海县', 632500, 3),
+(632525, '贵南县', 632500, 3),
+(632600, '果洛藏族自治州', 630000, 2),
+(632621, '玛沁县', 632600, 3),
+(632622, '班玛县', 632600, 3),
+(632623, '甘德县', 632600, 3),
+(632624, '达日县', 632600, 3),
+(632625, '久治县', 632600, 3),
+(632626, '玛多县', 632600, 3),
+(632700, '玉树藏族自治州', 630000, 2),
+(632701, '玉树市', 632700, 3),
+(632722, '杂多县', 632700, 3),
+(632723, '称多县', 632700, 3),
+(632724, '治多县', 632700, 3),
+(632725, '囊谦县', 632700, 3),
+(632726, '曲麻莱县', 632700, 3),
+(632800, '海西蒙古族藏族自治州', 630000, 2),
+(632801, '格尔木市', 632800, 3),
+(632802, '德令哈市', 632800, 3),
+(632821, '乌兰县', 632800, 3),
+(632822, '都兰县', 632800, 3),
+(632823, '天峻县', 632800, 3),
+(632824, '冷湖行政委员会', 632800, 3),
+(632825, '大柴旦行政委员会', 632800, 3),
+(632826, '茫崖行政委员会', 632800, 3),
+(640000, '宁夏回族自治区', 0, 1),
+(640100, '银川市', 640000, 2),
+(640104, '兴庆区', 640100, 3),
+(640105, '西夏区', 640100, 3),
+(640106, '金凤区', 640100, 3),
+(640121, '永宁县', 640100, 3),
+(640122, '贺兰县', 640100, 3),
+(640181, '灵武市', 640100, 3),
+(640200, '石嘴山市', 640000, 2),
+(640202, '大武口区', 640200, 3),
+(640205, '惠农区', 640200, 3),
+(640221, '平罗县', 640200, 3),
+(640300, '吴忠市', 640000, 2),
+(640302, '利通区', 640300, 3),
+(640303, '红寺堡区', 640300, 3),
+(640323, '盐池县', 640300, 3),
+(640324, '同心县', 640300, 3),
+(640381, '青铜峡市', 640300, 3),
+(640400, '固原市', 640000, 2),
+(640402, '原州区', 640400, 3),
+(640422, '西吉县', 640400, 3),
+(640423, '隆德县', 640400, 3),
+(640424, '泾源县', 640400, 3),
+(640425, '彭阳县', 640400, 3),
+(640500, '中卫市', 640000, 2),
+(640502, '沙坡头区', 640500, 3),
+(640521, '中宁县', 640500, 3),
+(640522, '海原县', 640500, 3),
+(650000, '新疆维吾尔自治区', 0, 1),
+(650100, '乌鲁木齐市', 650000, 2),
+(650102, '天山区', 650100, 3),
+(650103, '沙依巴克区', 650100, 3),
+(650104, '新市区', 650100, 3),
+(650105, '水磨沟区', 650100, 3),
+(650106, '头屯河区', 650100, 3),
+(650107, '达坂城区', 650100, 3),
+(650109, '米东区', 650100, 3),
+(650121, '乌鲁木齐县', 650100, 3),
+(650200, '克拉玛依市', 650000, 2),
+(650202, '独山子区', 650200, 3),
+(650203, '克拉玛依区', 650200, 3),
+(650204, '白碱滩区', 650200, 3),
+(650205, '乌尔禾区', 650200, 3),
+(650400, '吐鲁番市', 650000, 2),
+(650402, '高昌区', 650400, 3),
+(650421, '鄯善县', 650400, 3),
+(650422, '托克逊县', 650400, 3),
+(650500, '哈密市', 650000, 2),
+(650502, '伊州区', 650500, 3),
+(650521, '巴里坤哈萨克自治县', 650500, 3),
+(650522, '伊吾县', 650500, 3),
+(652300, '昌吉回族自治州', 650000, 2),
+(652301, '昌吉市', 652300, 3),
+(652302, '阜康市', 652300, 3),
+(652323, '呼图壁县', 652300, 3),
+(652324, '玛纳斯县', 652300, 3),
+(652325, '奇台县', 652300, 3),
+(652327, '吉木萨尔县', 652300, 3),
+(652328, '木垒哈萨克自治县', 652300, 3),
+(652700, '博尔塔拉蒙古自治州', 650000, 2),
+(652701, '博乐市', 652700, 3),
+(652702, '阿拉山口市', 652700, 3),
+(652722, '精河县', 652700, 3),
+(652723, '温泉县', 652700, 3),
+(652800, '巴音郭楞蒙古自治州', 650000, 2),
+(652801, '库尔勒市', 652800, 3),
+(652822, '轮台县', 652800, 3),
+(652823, '尉犁县', 652800, 3),
+(652824, '若羌县', 652800, 3),
+(652825, '且末县', 652800, 3),
+(652826, '焉耆回族自治县', 652800, 3),
+(652827, '和静县', 652800, 3),
+(652828, '和硕县', 652800, 3),
+(652829, '博湖县', 652800, 3),
+(652900, '阿克苏地区', 650000, 2),
+(652901, '阿克苏市', 652900, 3),
+(652922, '温宿县', 652900, 3),
+(652923, '库车县', 652900, 3),
+(652924, '沙雅县', 652900, 3),
+(652925, '新和县', 652900, 3),
+(652926, '拜城县', 652900, 3),
+(652927, '乌什县', 652900, 3),
+(652928, '阿瓦提县', 652900, 3),
+(652929, '柯坪县', 652900, 3),
+(653000, '克孜勒苏柯尔克孜自治州', 650000, 2),
+(653001, '阿图什市', 653000, 3),
+(653022, '阿克陶县', 653000, 3),
+(653023, '阿合奇县', 653000, 3),
+(653024, '乌恰县', 653000, 3),
+(653100, '喀什地区', 650000, 2),
+(653101, '喀什市', 653100, 3),
+(653121, '疏附县', 653100, 3),
+(653122, '疏勒县', 653100, 3),
+(653123, '英吉沙县', 653100, 3),
+(653124, '泽普县', 653100, 3),
+(653125, '莎车县', 653100, 3),
+(653126, '叶城县', 653100, 3),
+(653127, '麦盖提县', 653100, 3),
+(653128, '岳普湖县', 653100, 3),
+(653129, '伽师县', 653100, 3),
+(653130, '巴楚县', 653100, 3),
+(653131, '塔什库尔干塔吉克自治县', 653100, 3),
+(653200, '和田地区', 650000, 2),
+(653201, '和田市', 653200, 3),
+(653221, '和田县', 653200, 3),
+(653222, '墨玉县', 653200, 3),
+(653223, '皮山县', 653200, 3),
+(653224, '洛浦县', 653200, 3),
+(653225, '策勒县', 653200, 3),
+(653226, '于田县', 653200, 3),
+(653227, '民丰县', 653200, 3),
+(654000, '伊犁哈萨克自治州', 650000, 2),
+(654002, '伊宁市', 654000, 3),
+(654003, '奎屯市', 654000, 3),
+(654004, '霍尔果斯市', 654000, 3),
+(654021, '伊宁县', 654000, 3),
+(654022, '察布查尔锡伯自治县', 654000, 3),
+(654023, '霍城县', 654000, 3),
+(654024, '巩留县', 654000, 3),
+(654025, '新源县', 654000, 3),
+(654026, '昭苏县', 654000, 3),
+(654027, '特克斯县', 654000, 3),
+(654028, '尼勒克县', 654000, 3),
+(654200, '塔城地区', 650000, 2),
+(654201, '塔城市', 654200, 3),
+(654202, '乌苏市', 654200, 3),
+(654221, '额敏县', 654200, 3),
+(654223, '沙湾县', 654200, 3),
+(654224, '托里县', 654200, 3),
+(654225, '裕民县', 654200, 3),
+(654226, '和布克赛尔蒙古自治县', 654200, 3),
+(654300, '阿勒泰地区', 650000, 2),
+(654301, '阿勒泰市', 654300, 3),
+(654321, '布尔津县', 654300, 3),
+(654322, '富蕴县', 654300, 3),
+(654323, '福海县', 654300, 3),
+(654324, '哈巴河县', 654300, 3),
+(654325, '青河县', 654300, 3),
+(654326, '吉木乃县', 654300, 3),
+(659000, '自治区直辖县级行政区划', 650000, 2),
+(659001, '石河子市', 659000, 3),
+(659002, '阿拉尔市', 659000, 3),
+(659003, '图木舒克市', 659000, 3),
+(659004, '五家渠市', 659000, 3),
+(659005, '北屯市', 659000, 3),
+(659006, '铁门关市', 659000, 3),
+(659007, '双河市', 659000, 3),
+(659008, '可克达拉市', 659000, 3),
+(659009, '昆玉市', 659000, 3),
+(710000, '台湾省', 0, 1),
+(710100, '台北市', 710000, 2),
+(710101, '中正区', 710100, 3),
+(710102, '大同区', 710100, 3),
+(710103, '中山区', 710100, 3),
+(710104, '松山区', 710100, 3),
+(710105, '大安区', 710100, 3),
+(710106, '万华区', 710100, 3),
+(710107, '信义区', 710100, 3),
+(710108, '士林区', 710100, 3),
+(710109, '北投区', 710100, 3),
+(710110, '内湖区', 710100, 3),
+(710111, '南港区', 710100, 3),
+(710112, '文山区', 710100, 3),
+(710200, '高雄市', 710000, 2),
+(710201, '新兴区', 710200, 3),
+(710202, '前金区', 710200, 3),
+(710203, '苓雅区', 710200, 3),
+(710204, '盐埕区', 710200, 3),
+(710205, '鼓山区', 710200, 3),
+(710206, '旗津区', 710200, 3),
+(710207, '前镇区', 710200, 3),
+(710208, '三民区', 710200, 3),
+(710209, '左营区', 710200, 3),
+(710210, '楠梓区', 710200, 3),
+(710211, '小港区', 710200, 3),
+(710242, '仁武区', 710200, 3),
+(710243, '大社区', 710200, 3),
+(710244, '冈山区', 710200, 3),
+(710245, '路竹区', 710200, 3),
+(710246, '阿莲区', 710200, 3),
+(710247, '田寮区', 710200, 3),
+(710248, '燕巢区', 710200, 3),
+(710249, '桥头区', 710200, 3),
+(710250, '梓官区', 710200, 3),
+(710251, '弥陀区', 710200, 3),
+(710252, '永安区', 710200, 3),
+(710253, '湖内区', 710200, 3),
+(710254, '凤山区', 710200, 3),
+(710255, '大寮区', 710200, 3),
+(710256, '林园区', 710200, 3),
+(710257, '鸟松区', 710200, 3),
+(710258, '大树区', 710200, 3),
+(710259, '旗山区', 710200, 3),
+(710260, '美浓区', 710200, 3),
+(710261, '六龟区', 710200, 3),
+(710262, '内门区', 710200, 3),
+(710263, '杉林区', 710200, 3),
+(710264, '甲仙区', 710200, 3),
+(710265, '桃源区', 710200, 3),
+(710266, '那玛夏区', 710200, 3),
+(710267, '茂林区', 710200, 3),
+(710268, '茄萣区', 710200, 3),
+(710300, '台南市', 710000, 2),
+(710301, '中西区', 710300, 3),
+(710302, '东区', 710300, 3),
+(710303, '南区', 710300, 3),
+(710304, '北区', 710300, 3),
+(710305, '安平区', 710300, 3),
+(710306, '安南区', 710300, 3),
+(710339, '永康区', 710300, 3),
+(710340, '归仁区', 710300, 3),
+(710341, '新化区', 710300, 3),
+(710342, '左镇区', 710300, 3),
+(710343, '玉井区', 710300, 3),
+(710344, '楠西区', 710300, 3),
+(710345, '南化区', 710300, 3),
+(710346, '仁德区', 710300, 3),
+(710347, '关庙区', 710300, 3),
+(710348, '龙崎区', 710300, 3),
+(710349, '官田区', 710300, 3),
+(710350, '麻豆区', 710300, 3),
+(710351, '佳里区', 710300, 3),
+(710352, '西港区', 710300, 3),
+(710353, '七股区', 710300, 3),
+(710354, '将军区', 710300, 3),
+(710355, '学甲区', 710300, 3),
+(710356, '北门区', 710300, 3),
+(710357, '新营区', 710300, 3),
+(710358, '后壁区', 710300, 3),
+(710359, '白河区', 710300, 3),
+(710360, '东山区', 710300, 3),
+(710361, '六甲区', 710300, 3),
+(710362, '下营区', 710300, 3),
+(710363, '柳营区', 710300, 3),
+(710364, '盐水区', 710300, 3),
+(710365, '善化区', 710300, 3),
+(710366, '大内区', 710300, 3),
+(710367, '山上区', 710300, 3),
+(710368, '新市区', 710300, 3),
+(710369, '安定区', 710300, 3),
+(710400, '台中市', 710000, 2),
+(710401, '中区', 710400, 3),
+(710402, '东区', 710400, 3),
+(710403, '南区', 710400, 3),
+(710404, '西区', 710400, 3),
+(710405, '北区', 710400, 3),
+(710406, '北屯区', 710400, 3),
+(710407, '西屯区', 710400, 3),
+(710408, '南屯区', 710400, 3),
+(710431, '太平区', 710400, 3),
+(710432, '大里区', 710400, 3),
+(710433, '雾峰区', 710400, 3),
+(710434, '乌日区', 710400, 3),
+(710435, '丰原区', 710400, 3),
+(710436, '后里区', 710400, 3),
+(710437, '石冈区', 710400, 3),
+(710438, '东势区', 710400, 3),
+(710439, '和平区', 710400, 3),
+(710440, '新社区', 710400, 3),
+(710441, '潭子区', 710400, 3),
+(710442, '大雅区', 710400, 3),
+(710443, '神冈区', 710400, 3),
+(710444, '大肚区', 710400, 3),
+(710445, '沙鹿区', 710400, 3),
+(710446, '龙井区', 710400, 3),
+(710447, '梧栖区', 710400, 3),
+(710448, '清水区', 710400, 3),
+(710449, '大甲区', 710400, 3),
+(710450, '外埔区', 710400, 3),
+(710451, '大安区', 710400, 3),
+(710600, '南投县', 710000, 2),
+(710614, '南投市', 710600, 3),
+(710615, '中寮乡', 710600, 3),
+(710616, '草屯镇', 710600, 3),
+(710617, '国姓乡', 710600, 3),
+(710618, '埔里镇', 710600, 3),
+(710619, '仁爱乡', 710600, 3),
+(710620, '名间乡', 710600, 3),
+(710621, '集集镇', 710600, 3),
+(710622, '水里乡', 710600, 3),
+(710623, '鱼池乡', 710600, 3),
+(710624, '信义乡', 710600, 3),
+(710625, '竹山镇', 710600, 3),
+(710626, '鹿谷乡', 710600, 3),
+(710700, '基隆市', 710000, 2),
+(710701, '仁爱区', 710700, 3),
+(710702, '信义区', 710700, 3),
+(710703, '中正区', 710700, 3),
+(710704, '中山区', 710700, 3),
+(710705, '安乐区', 710700, 3),
+(710706, '暖暖区', 710700, 3),
+(710707, '七堵区', 710700, 3),
+(710800, '新竹市', 710000, 2),
+(710801, '东区', 710800, 3),
+(710802, '北区', 710800, 3),
+(710803, '香山区', 710800, 3),
+(710900, '嘉义市', 710000, 2),
+(710901, '东区', 710900, 3),
+(710902, '西区', 710900, 3),
+(711100, '新北市', 710000, 2),
+(711130, '万里区', 711100, 3),
+(711131, '金山区', 711100, 3),
+(711132, '板桥区', 711100, 3),
+(711133, '汐止区', 711100, 3),
+(711134, '深坑区', 711100, 3),
+(711135, '石碇区', 711100, 3),
+(711136, '瑞芳区', 711100, 3),
+(711137, '平溪区', 711100, 3),
+(711138, '双溪区', 711100, 3),
+(711139, '贡寮区', 711100, 3),
+(711140, '新店区', 711100, 3),
+(711141, '坪林区', 711100, 3),
+(711142, '乌来区', 711100, 3),
+(711143, '永和区', 711100, 3),
+(711144, '中和区', 711100, 3),
+(711145, '土城区', 711100, 3),
+(711146, '三峡区', 711100, 3),
+(711147, '树林区', 711100, 3),
+(711148, '莺歌区', 711100, 3),
+(711149, '三重区', 711100, 3),
+(711150, '新庄区', 711100, 3),
+(711151, '泰山区', 711100, 3),
+(711152, '林口区', 711100, 3),
+(711153, '芦洲区', 711100, 3),
+(711154, '五股区', 711100, 3),
+(711155, '八里区', 711100, 3),
+(711156, '淡水区', 711100, 3),
+(711157, '三芝区', 711100, 3),
+(711158, '石门区', 711100, 3),
+(711200, '宜兰县', 710000, 2),
+(711214, '宜兰市', 711200, 3),
+(711215, '头城镇', 711200, 3),
+(711216, '礁溪乡', 711200, 3),
+(711217, '壮围乡', 711200, 3),
+(711218, '员山乡', 711200, 3),
+(711219, '罗东镇', 711200, 3),
+(711220, '三星乡', 711200, 3),
+(711221, '大同乡', 711200, 3),
+(711222, '五结乡', 711200, 3),
+(711223, '冬山乡', 711200, 3),
+(711224, '苏澳镇', 711200, 3),
+(711225, '南澳乡', 711200, 3),
+(711300, '新竹县', 710000, 2),
+(711314, '竹北市', 711300, 3),
+(711315, '湖口乡', 711300, 3),
+(711316, '新丰乡', 711300, 3),
+(711317, '新埔镇', 711300, 3),
+(711318, '关西镇', 711300, 3),
+(711319, '芎林乡', 711300, 3),
+(711320, '宝山乡', 711300, 3),
+(711321, '竹东镇', 711300, 3),
+(711322, '五峰乡', 711300, 3),
+(711323, '横山乡', 711300, 3),
+(711324, '尖石乡', 711300, 3),
+(711325, '北埔乡', 711300, 3),
+(711326, '峨眉乡', 711300, 3),
+(711400, '桃园市', 710000, 2),
+(711414, '中坜区', 711400, 3),
+(711415, '平镇区', 711400, 3),
+(711416, '龙潭区', 711400, 3),
+(711417, '杨梅区', 711400, 3),
+(711418, '新屋区', 711400, 3),
+(711419, '观音区', 711400, 3),
+(711420, '桃园区', 711400, 3),
+(711421, '龟山区', 711400, 3),
+(711422, '八德区', 711400, 3),
+(711423, '大溪区', 711400, 3),
+(711424, '复兴区', 711400, 3),
+(711425, '大园区', 711400, 3),
+(711426, '芦竹区', 711400, 3),
+(711500, '苗栗县', 710000, 2),
+(711519, '竹南镇', 711500, 3),
+(711520, '头份市', 711500, 3),
+(711521, '三湾乡', 711500, 3),
+(711522, '南庄乡', 711500, 3),
+(711523, '狮潭乡', 711500, 3),
+(711524, '后龙镇', 711500, 3),
+(711525, '通霄镇', 711500, 3),
+(711526, '苑里镇', 711500, 3),
+(711527, '苗栗市', 711500, 3),
+(711528, '造桥乡', 711500, 3),
+(711529, '头屋乡', 711500, 3),
+(711530, '公馆乡', 711500, 3),
+(711531, '大湖乡', 711500, 3),
+(711532, '泰安乡', 711500, 3),
+(711533, '铜锣乡', 711500, 3),
+(711534, '三义乡', 711500, 3),
+(711535, '西湖乡', 711500, 3),
+(711536, '卓兰镇', 711500, 3),
+(711700, '彰化县', 710000, 2),
+(711727, '彰化市', 711700, 3),
+(711728, '芬园乡', 711700, 3),
+(711729, '花坛乡', 711700, 3),
+(711730, '秀水乡', 711700, 3),
+(711731, '鹿港镇', 711700, 3),
+(711732, '福兴乡', 711700, 3),
+(711733, '线西乡', 711700, 3),
+(711734, '和美镇', 711700, 3),
+(711735, '伸港乡', 711700, 3),
+(711736, '员林市', 711700, 3),
+(711737, '社头乡', 711700, 3),
+(711738, '永靖乡', 711700, 3),
+(711739, '埔心乡', 711700, 3),
+(711740, '溪湖镇', 711700, 3),
+(711741, '大村乡', 711700, 3),
+(711742, '埔盐乡', 711700, 3),
+(711743, '田中镇', 711700, 3),
+(711744, '北斗镇', 711700, 3),
+(711745, '田尾乡', 711700, 3),
+(711746, '埤头乡', 711700, 3),
+(711747, '溪州乡', 711700, 3),
+(711748, '竹塘乡', 711700, 3),
+(711749, '二林镇', 711700, 3),
+(711750, '大城乡', 711700, 3),
+(711751, '芳苑乡', 711700, 3),
+(711752, '二水乡', 711700, 3),
+(711900, '嘉义县', 710000, 2),
+(711919, '番路乡', 711900, 3),
+(711920, '梅山乡', 711900, 3),
+(711921, '竹崎乡', 711900, 3),
+(711922, '阿里山乡', 711900, 3),
+(711923, '中埔乡', 711900, 3),
+(711924, '大埔乡', 711900, 3),
+(711925, '水上乡', 711900, 3),
+(711926, '鹿草乡', 711900, 3),
+(711927, '太保市', 711900, 3),
+(711928, '朴子市', 711900, 3),
+(711929, '东石乡', 711900, 3),
+(711930, '六脚乡', 711900, 3),
+(711931, '新港乡', 711900, 3),
+(711932, '民雄乡', 711900, 3),
+(711933, '大林镇', 711900, 3),
+(711934, '溪口乡', 711900, 3),
+(711935, '义竹乡', 711900, 3),
+(711936, '布袋镇', 711900, 3),
+(712100, '云林县', 710000, 2),
+(712121, '斗南镇', 712100, 3),
+(712122, '大埤乡', 712100, 3),
+(712123, '虎尾镇', 712100, 3),
+(712124, '土库镇', 712100, 3),
+(712125, '褒忠乡', 712100, 3),
+(712126, '东势乡', 712100, 3),
+(712127, '台西乡', 712100, 3),
+(712128, '仑背乡', 712100, 3),
+(712129, '麦寮乡', 712100, 3),
+(712130, '斗六市', 712100, 3),
+(712131, '林内乡', 712100, 3),
+(712132, '古坑乡', 712100, 3),
+(712133, '莿桐乡', 712100, 3),
+(712134, '西螺镇', 712100, 3),
+(712135, '二仑乡', 712100, 3),
+(712136, '北港镇', 712100, 3),
+(712137, '水林乡', 712100, 3),
+(712138, '口湖乡', 712100, 3),
+(712139, '四湖乡', 712100, 3),
+(712140, '元长乡', 712100, 3),
+(712400, '屏东县', 710000, 2),
+(712434, '屏东市', 712400, 3),
+(712435, '三地门乡', 712400, 3),
+(712436, '雾台乡', 712400, 3),
+(712437, '玛家乡', 712400, 3),
+(712438, '九如乡', 712400, 3),
+(712439, '里港乡', 712400, 3),
+(712440, '高树乡', 712400, 3),
+(712441, '盐埔乡', 712400, 3),
+(712442, '长治乡', 712400, 3),
+(712443, '麟洛乡', 712400, 3),
+(712444, '竹田乡', 712400, 3),
+(712445, '内埔乡', 712400, 3),
+(712446, '万丹乡', 712400, 3),
+(712447, '潮州镇', 712400, 3),
+(712448, '泰武乡', 712400, 3),
+(712449, '来义乡', 712400, 3),
+(712450, '万峦乡', 712400, 3),
+(712451, '崁顶乡', 712400, 3),
+(712452, '新埤乡', 712400, 3),
+(712453, '南州乡', 712400, 3),
+(712454, '林边乡', 712400, 3),
+(712455, '东港镇', 712400, 3),
+(712456, '琉球乡', 712400, 3),
+(712457, '佳冬乡', 712400, 3),
+(712458, '新园乡', 712400, 3),
+(712459, '枋寮乡', 712400, 3),
+(712460, '枋山乡', 712400, 3),
+(712461, '春日乡', 712400, 3),
+(712462, '狮子乡', 712400, 3),
+(712463, '车城乡', 712400, 3),
+(712464, '牡丹乡', 712400, 3),
+(712465, '恒春镇', 712400, 3),
+(712466, '满州乡', 712400, 3),
+(712500, '台东县', 710000, 2),
+(712517, '台东市', 712500, 3),
+(712518, '绿岛乡', 712500, 3),
+(712519, '兰屿乡', 712500, 3),
+(712520, '延平乡', 712500, 3),
+(712521, '卑南乡', 712500, 3),
+(712522, '鹿野乡', 712500, 3),
+(712523, '关山镇', 712500, 3),
+(712524, '海端乡', 712500, 3),
+(712525, '池上乡', 712500, 3),
+(712526, '东河乡', 712500, 3),
+(712527, '成功镇', 712500, 3),
+(712528, '长滨乡', 712500, 3),
+(712529, '金峰乡', 712500, 3),
+(712530, '大武乡', 712500, 3),
+(712531, '达仁乡', 712500, 3),
+(712532, '太麻里乡', 712500, 3),
+(712600, '花莲县', 710000, 2),
+(712615, '花莲市', 712600, 3),
+(712616, '新城乡', 712600, 3),
+(712618, '秀林乡', 712600, 3),
+(712619, '吉安乡', 712600, 3),
+(712620, '寿丰乡', 712600, 3),
+(712621, '凤林镇', 712600, 3),
+(712622, '光复乡', 712600, 3),
+(712623, '丰滨乡', 712600, 3),
+(712624, '瑞穗乡', 712600, 3),
+(712625, '万荣乡', 712600, 3),
+(712626, '玉里镇', 712600, 3),
+(712627, '卓溪乡', 712600, 3),
+(712628, '富里乡', 712600, 3),
+(712700, '澎湖县', 710000, 2),
+(712707, '马公市', 712700, 3),
+(712708, '西屿乡', 712700, 3),
+(712709, '望安乡', 712700, 3),
+(712710, '七美乡', 712700, 3),
+(712711, '白沙乡', 712700, 3),
+(712712, '湖西乡', 712700, 3),
+(810000, '香港特别行政区', 0, 1),
+(810100, '香港特别行政区', 810000, 2),
+(810101, '中西区', 810100, 3),
+(810102, '东区', 810100, 3),
+(810103, '九龙城区', 810100, 3),
+(810104, '观塘区', 810100, 3),
+(810105, '南区', 810100, 3),
+(810106, '深水埗区', 810100, 3),
+(810107, '湾仔区', 810100, 3),
+(810108, '黄大仙区', 810100, 3),
+(810109, '油尖旺区', 810100, 3),
+(810110, '离岛区', 810100, 3),
+(810111, '葵青区', 810100, 3),
+(810112, '北区', 810100, 3),
+(810113, '西贡区', 810100, 3),
+(810114, '沙田区', 810100, 3),
+(810115, '屯门区', 810100, 3),
+(810116, '大埔区', 810100, 3),
+(810117, '荃湾区', 810100, 3),
+(810118, '元朗区', 810100, 3),
+(820000, '澳门特别行政区', 0, 1),
+(820100, '澳门特别行政区', 820000, 2),
+(820101, '澳门半岛', 820100, 3),
+(820102, '凼仔', 820100, 3),
+(820103, '路凼城', 820100, 3),
+(820104, '路环', 820100, 3);
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_cart` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) DEFAULT NULL COMMENT '用户',
+  `goods_id` int(11) DEFAULT NULL,
+  `goods_num` int(11) DEFAULT NULL,
+  `sku_price_id` int(11) DEFAULT NULL COMMENT '规格',
+  `createtime` int(11) DEFAULT NULL,
+  `updatetime` int(11) DEFAULT NULL,
+  `deletetime` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='购物车';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_category` (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `name` varchar(30) NOT NULL DEFAULT '',
+  `type` varchar(30) NOT NULL DEFAULT '' COMMENT '栏目类型',
+  `image` varchar(100) NOT NULL DEFAULT '' COMMENT '图片',
+  `pid` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '父ID',
+  `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重',
+  `description` varchar(255) NOT NULL DEFAULT '' COMMENT '描述',
+  `status` varchar(30) NOT NULL DEFAULT '' COMMENT '状态',
+  `createtime` int(10) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `pid` (`pid`) USING BTREE,
+  KEY `weigh_id` (`weigh`,`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商城分类表';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_config` (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `name` varchar(30) NOT NULL DEFAULT '' COMMENT '变量名',
+  `group` varchar(30) NOT NULL DEFAULT '' COMMENT '分组',
+  `title` varchar(100) NOT NULL DEFAULT '' COMMENT '变量标题',
+  `tip` varchar(100) NOT NULL DEFAULT '' COMMENT '变量描述',
+  `type` varchar(30) NOT NULL DEFAULT '' COMMENT '类型:string,text,int,bool,array,datetime,date,file',
+  `value` longtext NOT NULL COMMENT '变量值',
+  `content` longtext DEFAULT NULL COMMENT '变量字典数据',
+  `rule` varchar(100) NOT NULL DEFAULT '' COMMENT '验证规则',
+  `extend` varchar(255) NOT NULL DEFAULT '' COMMENT '扩展属性',
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE KEY `name` (`name`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商城配置';
+
+INSERT INTO `__PREFIX__shopro_config` (`id`, `name`, `group`, `title`, `tip`, `type`, `value`, `content`, `rule`, `extend`) VALUES 
+(1, 'shopro', 'basic', '商城信息', '', 'array', '{\"name\":\"Shopro\",\"domain\":\"https://m.shopro.top/\",\"version\":\"1.3.0\",\"logo\":\"http://file.shopro.top/uploads/20200410/d5b2c163e9a23d78c7205d9ab5d7e47c.png\",\"copyright\":[\"星品科技Shopro版权所有\",\"Copyright 2020-2021\"],\"user_protocol\":1,\"privacy_protocol\":2,\"about_us\":3}', NULL, '', ''),
+(2, 'user', 'basic', '会员配置', '', 'array', '{\"nickname\":\"Shopro-\",\"avatar\":\"http://file.shopro.top/uploads/20200410/default-avatar.png\",\"group_id\":\"1\"}', NULL, '', ''),
+(3, 'share', 'basic', '分享配置', '', 'array', '{\"title\":\"邀请有好礼\",\"image\":\"http://file.shopro.top/uploads/20200410/4be7c944935a0fd6fc890f0214e6c3e0.jpeg\",\"goods_poster_bg\":\"http://file.shopro.top/uploads/20200410/ab863760d809b0d0bfdf5eed24fecb61.png\",\"user_poster_bg\":\"http://file.shopro.top/uploads/20200410/000fada6ece566b12ccfc348861fedf6.png\",\"groupon_poster_bg\":\"http://file.shopro.top/uploads/20200410/c65b86f0ffb7f334fe7ca7528d2bb44a.png\"}', NULL, '', ''),
+(4, 'score', 'basic', '积分配置', '', 'array', '{\"everyday\":\"1\",\"until_day\":\"1\",\"inc_value\":\"7\"}', NULL, '', ''),
+(5, 'withdraw', 'basic', '提现配置', '', 'array', '{\"methods\":[\"wechat\",\"alipay\",\"bank\"],\"wechat_alipay_auto\":\"0\",\"service_fee\":\"0.03\",\"min\":\"100\",\"max\":\"1000\"}', NULL, '', ''),
+(6, 'order', 'basic', '商城配置', '', 'array', '{\"order_auto_close\":\"15\",\"order_auto_confirm\":\"6\",\"order_auto_comment\":\"3\",\"order_comment_content\":\"客户默认好评~\",\"goods\":{\"stock_warning\":\"20\"}}', NULL, '', ''),
+(7, 'services', 'basic', '第三方服务', '', 'array', '{\"amap\":{\"appkey\":\"654b72d9fd8a1*********6156be7f\"},\"express\":{\"ebusiness_id\":\"1655***\",\"type\":\"free\",\"appkey\":\"af70d0-******-3eda4ae78fb2\",\"jd_code\":\"001K1***50\",\"Sender\":{\"Name\":\"\",\"Mobile\":\"\",\"ProvinceName\":\"\",\"CityName\":\"\",\"ExpAreaName\":\"\",\"Address\":\"\"},\"PayType\":1,\"ExpType\":1,\"CustomerName\":\"\",\"CustomerPwd\":\"\",\"ShipperCode\":\"\"}}', NULL, '', ''),
+(8, 'chat', 'basic', '客服配置', '', 'array', '{\"type\":\"shopro\",\"basic\":{\"last_customer_service\":1,\"allocate\":\"busy\",\"notice\":\"显示在用户端头部\"},\"system\":{\"is_ssl\":1,\"ssl_cert\":\"/www/server/panel/vhost/cert/****/fullchain.pem\",\"ssl_key\":\"/www/server/panel/vhost/cert/****/privkey.pem\",\"gateway_port\":1819,\"gateway_num\":2,\"gateway_start_port\":2010,\"business_worker_port\":2238,\"business_worker_num\":4}}', NULL, '', ''),
+(9, 'store', 'basic', '门店配置', '', 'array', '{\"protocol\":\"\",\"selfetch_protocol\":\"\"}', NULL, '', ''),
+(10, 'wxOfficialAccount', 'platform', '微信公众号', '', 'array', '{\"name\":\"\",\"wx_type\":\"4\",\"avatar\":\"\",\"qrcode\":\"\",\"app_id\":\"\",\"secret\":\"\",\"url\":\"http://demo.shopro.top/addons/shopro/wechat\",\"token\":\"\",\"aes_key\":\"\",\"auto_login\":\"1\",\"status\":\"0\"}', NULL, '', ''),
+(11, 'wxMiniProgram', 'platform', '小程序', '', 'array', '{\"name\":\"\",\"avatar\":\"\",\"qrcode\":\"\",\"app_id\":\"\",\"secret\":\"\",\"auto_login\":\"1\"}', NULL, '', ''),
+(12, 'H5', 'platform', 'H5', '', 'array', '{\"app_id\":\"\",\"secret\":\"\"}', NULL, '', ''),
+(13, 'App', 'platform', 'App', '', 'array', '{\"app_id\":\"\",\"secret\":\"\"}', NULL, '', '');
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_coupons` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(50) DEFAULT NULL COMMENT '名称',
+  `type` enum('cash','discount') NOT NULL DEFAULT 'cash' COMMENT '类型:cash=代金券,discount=折扣券',
+  `goods_ids` varchar(1200) DEFAULT NULL COMMENT '适用商品',
+  `amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '券面额',
+  `enough` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '消费门槛',
+  `stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存',
+  `limit` int(11) NOT NULL DEFAULT '1' COMMENT '每人限制',
+  `gettime` varchar(50) DEFAULT NULL COMMENT '领取周期',
+  `usetime` varchar(50) DEFAULT NULL COMMENT '有效期',
+  `description` varchar(255) DEFAULT NULL COMMENT '描述',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  `usetimestart` int(11) DEFAULT NULL,
+  `usetimeend` int(11) DEFAULT NULL,
+  `gettimestart` int(11) DEFAULT NULL,
+  `gettimeend` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='优惠券';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_decorate` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(50) DEFAULT NULL COMMENT '模板名称',
+  `type` enum('shop','custom','preview') NOT NULL DEFAULT 'shop' COMMENT '页面分类:shop=商城,custom=自定义,preview=临时预览',
+  `image` varchar(255) DEFAULT NULL COMMENT '图片',
+  `memo` varchar(255) DEFAULT NULL COMMENT '备注',
+  `status` enum('normal','hidden') DEFAULT 'normal' COMMENT '状态',
+  `platform` set('H5','wxOfficialAccount','wxMiniProgram','App','preview') DEFAULT NULL COMMENT '适用平台:H5=H5,wxOfficialAccount=微信公众号网页,wxMiniProgram=微信小程序,App=App,preview=预览',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='店铺装修';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_decorate_content` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `type` varchar(20) DEFAULT NULL COMMENT '类型',
+  `category` enum('home','user','tabbar','popup','custom','float-button') NOT NULL COMMENT '页面类型:home=首页,user=个人中心,tabbar=底部导航,popup=弹出提醒,float-button=悬浮按钮,custom=自定义',
+  `name` varchar(50) DEFAULT NULL COMMENT '名称',
+  `content` text COMMENT '规则',
+  `decorate_id` int(11) DEFAULT NULL COMMENT '归属模板ID',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='模板内容';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_dispatch` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(50) DEFAULT NULL COMMENT '名称',
+  `type` enum('express','selfetch','store','autosend') NOT NULL COMMENT '发货方式:express=物流快递,selfetch=用户自提,store=商户配送,autosend=自动发货',
+  `type_ids` varchar(255) DEFAULT NULL COMMENT '包含模板',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发货设置';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_dispatch_autosend` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `type` enum('card','text','params') NOT NULL COMMENT '自动发货类型:card=卡密,text=固定内容,params=自定义内容',
+  `content` varchar(1200) NOT NULL COMMENT '发货内容',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='自动发货';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_dispatch_express` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `type` enum('number','weight') DEFAULT NULL COMMENT '计费方式:number=件数,weight=重量',
+  `weigh` int(11) DEFAULT NULL COMMENT '权重',
+  `first_num` int(11) NOT NULL DEFAULT '1' COMMENT '首(重/件)数',
+  `first_price` decimal(10,2) DEFAULT '0.00' COMMENT '首(重/件)',
+  `additional_num` int(11) NOT NULL DEFAULT '0' COMMENT '续(重/件)数',
+  `additional_price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '续(重/件)',
+  `province_ids` varchar(255) DEFAULT NULL COMMENT '省份',
+  `city_ids` varchar(2500) DEFAULT NULL COMMENT '市级',
+  `area_ids` text COMMENT '区域',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运费模板';
+
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_dispatch_selfetch` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `store_ids` varchar(255) NOT NULL COMMENT '包含门店',
+  `expire_type` enum('day','time') NOT NULL DEFAULT 'day' COMMENT '过期类型:day=天数,time=截至日期',
+  `expire_day` int(11) NOT NULL DEFAULT '0' COMMENT 'X天过期',
+  `expire_time` int(11) NOT NULL DEFAULT '0' COMMENT '截至日期',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='自提点';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_dispatch_store` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `store_ids` varchar(255) NOT NULL COMMENT '包含门店',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商家配送';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_failed_job` (
+  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '失败队列',
+  `data` varchar(2048) DEFAULT NULL COMMENT '数据',
+  `createtime` int(10) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_faq` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `title` varchar(255) DEFAULT NULL COMMENT '标题',
+  `content` longtext COMMENT '内容',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='常见问题';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_feedback` (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL COMMENT '反馈用户',
+  `type` varchar(30) DEFAULT NULL COMMENT '反馈类型',
+  `content` varchar(255) DEFAULT NULL COMMENT '反馈内容',
+  `images` varchar(512) DEFAULT NULL COMMENT '图片',
+  `phone` varchar(30) DEFAULT NULL COMMENT '联系电话',
+  `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否处理:0=未处理,1=已处理',
+  `remark` varchar(191) DEFAULT NULL COMMENT '处理备注',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='意见反馈';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_goods` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `type` enum('normal','virtual') NOT NULL DEFAULT 'normal' COMMENT '商品类型:normal=实体商品,virtual=虚拟商品',
+  `title` varchar(100) NOT NULL COMMENT '标题',
+  `subtitle` varchar(255) DEFAULT NULL COMMENT '副标题',
+  `status` enum('up','hidden','down') DEFAULT NULL COMMENT '商品状态:up=上架,hidden=隐藏商品,down=下架',
+  `weigh` int(11) NOT NULL DEFAULT '0' COMMENT '排序(从大到小)',
+  `category_ids` varchar(120) DEFAULT NULL COMMENT '所属分类',
+  `image` varchar(255) DEFAULT NULL COMMENT '商品主图',
+  `images` varchar(2500) DEFAULT NULL COMMENT '轮播图',
+  `params` varchar(2500) DEFAULT NULL COMMENT '参数详情',
+  `content` text COMMENT '图文详情',
+  `price` varchar(20) NOT NULL COMMENT '价格',
+  `original_price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '原价',
+  `is_sku` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否多规格',
+  `likes` int(11) NOT NULL DEFAULT '0' COMMENT '收藏人数',
+  `views` int(11) NOT NULL DEFAULT '0' COMMENT '浏览人数',
+  `sales` int(11) NOT NULL DEFAULT '0' COMMENT '销量',
+  `show_sales` int(11) NOT NULL COMMENT '显示销量',
+  `service_ids` varchar(255) DEFAULT NULL COMMENT '服务标签',
+  `dispatch_type` set('express','selfetch','store','autosend') DEFAULT NULL COMMENT '发货方式:express=物流快递,selfetch=用户自提,store=商家配送,autosend=自动发货',
+  `dispatch_ids` varchar(255) DEFAULT NULL COMMENT '发货模板',
+  `createtime` int(11) DEFAULT NULL COMMENT '添加时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_goods_comment` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '评论 id',
+  `goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品',
+  `order_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单',
+  `order_item_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单商品',
+  `user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户',
+  `level` tinyint(4) NOT NULL DEFAULT '0' COMMENT '评价星级',
+  `content` varchar(255) DEFAULT NULL COMMENT '评价内容',
+  `images` varchar(2500) DEFAULT NULL COMMENT '评价图片',
+  `status` enum('show','hidden') NOT NULL DEFAULT 'show' COMMENT '显示状态',
+  `admin_id` int(11) NOT NULL DEFAULT '0' COMMENT '管理员 id',
+  `reply_content` varchar(255) DEFAULT NULL COMMENT '回复内容',
+  `replytime` int(11) DEFAULT NULL COMMENT '回复时间',
+  `createtime` int(11) DEFAULT NULL COMMENT '评论时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品评价';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_goods_service` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(10) DEFAULT NULL COMMENT '名称',
+  `image` varchar(255) DEFAULT NULL COMMENT '服务标志',
+  `description` varchar(127) DEFAULT NULL COMMENT '描述',
+  `createtime` int(11) DEFAULT NULL,
+  `updatetime` int(11) DEFAULT NULL,
+  `deletetime` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务标签';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_goods_sku` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(50) DEFAULT NULL COMMENT '名称',
+  `pid` int(11) NOT NULL DEFAULT '0' COMMENT '所属规格',
+  `goods_id` int(11) NOT NULL COMMENT '产品',
+  `weigh` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品规格';
+
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_goods_sku_price` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `goods_sku_ids` varchar(255) DEFAULT NULL,
+  `goods_id` int(11) NOT NULL COMMENT '所属产品',
+  `weigh` int(11) NOT NULL DEFAULT '0' COMMENT '排序',
+  `image` varchar(255) DEFAULT NULL COMMENT '缩略图',
+  `stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存',
+  `sales` int(11) NOT NULL DEFAULT '0' COMMENT '已售',
+  `sn` varchar(50) DEFAULT NULL COMMENT '货号',
+  `weight` int(11) DEFAULT NULL COMMENT '重量(kg)',
+  `price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '价格',
+  `goods_sku_text` varchar(255) DEFAULT NULL COMMENT '中文规格',
+  `status` varchar(10) DEFAULT 'up' COMMENT '状态',
+  `createtime` int(11) DEFAULT NULL,
+  `updatetime` int(11) DEFAULT NULL,
+  `deletetime` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品规格';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_link` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(50) DEFAULT NULL COMMENT '名称',
+  `path` varchar(255) DEFAULT NULL COMMENT '路径',
+  `group` varchar(20) DEFAULT NULL COMMENT '所属分组',
+  `createtime` int(11) DEFAULT NULL,
+  `updatetime` int(11) DEFAULT NULL,
+  `deletetime` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='页面链接';
+
+INSERT INTO `__PREFIX__shopro_link` (`id`, `name`, `path`, `group`, `createtime`, `updatetime`, `deletetime`) VALUES 
+(1, '首页', '/pages/index/index', '商城', 1622197045, 1622197045, NULL),
+(2, '分类', '/pages/index/category', '商城', 1622197045, 1622197045, NULL),
+(3, '购物车', '/pages/index/cart', '商城', 1622197045, 1622197045, NULL),
+(4, '我的', '/pages/index/user', '商城', 1622197045, 1622197045, NULL),
+(5, '签到中心', '/pages/activity/sign/index', '应用', 1622197045, 1622197045, NULL),
+(6, '限时秒杀', '/pages/activity/seckill/list', '秒杀', 1622197045, 1622197045, NULL),
+(7, '今日必拼', '/pages/activity/groupon/list', '拼团', 1622197045, 1622197045, NULL),
+(8, '我的拼团', '/pages/activity/groupon/my-groupon', '拼团', 1622197045, 1622197045, NULL),
+(9, '积分商品', '/pages/app/score/list', '积分', 1622197045, 1622197045, NULL),
+(10, '优惠券中心', '/pages/app/coupon/list', '优惠券', 1622197045, 1622197045, NULL),
+(11, '优惠券详情', '/pages/app/coupon/detail', '优惠券', 1622197045, 1622197045, NULL),
+(12, '门店入驻', '/pages/app/merchant/apply', '门店', 1622197045, 1622197045, NULL),
+(13, '我的门店', '/pages/app/merchant/list', '门店', 1622197045, 1622197045, NULL),
+(14, '分销中心', '/pages/app/commission/index', '分销', 1622197045, 1622197045, NULL),
+(15, '我的团队', '/pages/app/commission/team', '分销', 1622197045, 1622197045, NULL),
+(16, '佣金明细', '/pages/app/commission/commission-log', '分销', 1622197045, 1622197045, NULL),
+(17, '分销订单', '/pages/app/commission/order', '分销', 1622197045, 1622197045, NULL),
+(18, '推广商品', '/pages/app/commission/goods', '分销', 1622197045, 1622197045, NULL),
+(19, '申请分销商', '/pages/app/commission/apply', '分销', 1622197045, 1622197045, NULL),
+(20, '分销排行', '/pages/app/commission/rankings', '分销', 1622197045, 1622197045, NULL),
+(21, '商品列表', '/pages/goods/list', '商品', 1622197045, 1622197045, NULL),
+(22, '商品详情', '/pages/goods/detail', '商品', 1622197045, 1622197045, NULL),
+(23, '订单列表', '/pages/order/list', '订单', 1622197045, 1622197045, NULL),
+(24, '售后列表', '/pages/order/after-sale/list', '订单', 1622197045, 1622197045, NULL),
+(25, '常见问题', '/pages/public/faq', '通用', 1622197045, 1622197045, NULL),
+(26, '问题反馈', '/pages/public/feedback', '通用', 1622197045, 1622197045, NULL),
+(27, '客服', '/pages/public/chat/index', '通用', 1622197045, 1622197045, NULL),
+(28, '搜索', '/pages/public/search', '通用', 1622197045, 1622197045, NULL),
+(29, '富文本', '/pages/public/richtext', '通用', 1622197045, 1622197045, NULL),
+(30, '外链', '/pages/public/webview', '通用', 1622197045, 1622197045, NULL),
+(31, '个人信息', '/pages/user/info', '用户', 1622197045, 1622197045, NULL),
+(32, '系统设置', '/pages/user/set', '通用', 1622197045, 1622197045, NULL),
+(33, '浏览足迹', '/pages/user/view-log', '用户', 1622197045, 1622197045, NULL),
+(34, '钱包', '/pages/user/wallet/index', '用户', 1622197045, 1622197045, NULL),
+(35, '提现', '/pages/user/wallet/withdraw', '用户', 1622197045, 1622197045, NULL),
+(36, '提现记录', '/pages/user/wallet/withdraw-log', '用户', 1622197045, 1622197045, NULL),
+(37, '积分余额', '/pages/user/wallet/score-balance', '积分', 1622197045, 1622197045, NULL),
+(38, '收货地址', '/pages/user/address/list', '用户', 1622197045, 1622197045, NULL),
+(39, '我的收藏', '/pages/user/favorite', '用户', 1622197045, 1622197045, NULL);
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_live` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(255) NOT NULL COMMENT '房间名',
+  `room_id` int(11) NOT NULL DEFAULT '0' COMMENT '房间 ID',
+  `cover_img` varchar(255) DEFAULT NULL COMMENT '房间背景',
+  `live_status` enum('101','102','103','104','105','106','107') NOT NULL COMMENT '直播状态:101=直播中,102=未开始,103=已结束,104=禁播,105=暂停中,106=异常,107=已过期',
+  `starttime` int(10) NOT NULL DEFAULT '0' COMMENT '开始时间',
+  `endtime` int(10) NOT NULL DEFAULT '0' COMMENT '结束时间',
+  `anchor_name` varchar(255) NOT NULL COMMENT '主播',
+  `anchor_img` varchar(255) DEFAULT NULL COMMENT '主播头像',
+  `share_img` varchar(255) DEFAULT NULL COMMENT '分享封面',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_live_goods` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `live_id` int(11) NOT NULL COMMENT '直播ID',
+  `name` varchar(255) NOT NULL COMMENT '商品名称',
+  `origin_price` decimal(10,2) NOT NULL COMMENT '原价',
+  `price` decimal(10,2) NOT NULL COMMENT '价格',
+  `max_price` decimal(10,2) NOT NULL COMMENT '最大价格',
+  `url` varchar(255) DEFAULT NULL COMMENT '商品链接',
+  `cover_img` varchar(255) DEFAULT NULL COMMENT '商品图片',
+  `createtime` int(10) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_live_link` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `live_id` int(11) NOT NULL COMMENT '直播ID',
+  `media_url` varchar(255) NOT NULL COMMENT '回放链接',
+  `create_time` datetime DEFAULT NULL COMMENT '回放创建时间',
+  `expire_time` datetime DEFAULT NULL COMMENT '回放过期时间',
+  `createtime` int(10) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_order` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `type` enum('goods','score') NOT NULL DEFAULT 'goods' COMMENT '订单类型:goods=商城订单,score=积分商城订单',
+  `order_sn` varchar(60) NOT NULL COMMENT '订单号',
+  `user_id` int(11) DEFAULT '0' COMMENT '用户',
+  `activity_type` varchar(255) DEFAULT NULL COMMENT '活动类型',
+  `goods_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '商品总价',
+  `dispatch_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '总运费',
+  `phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
+  `consignee` varchar(20) DEFAULT NULL COMMENT '收货人',
+  `province_name` varchar(20) DEFAULT NULL COMMENT '省',
+  `city_name` varchar(20) DEFAULT NULL COMMENT '市',
+  `area_name` varchar(20) DEFAULT NULL COMMENT '区',
+  `address` varchar(255) DEFAULT NULL COMMENT '详细地址',
+  `province_id` int(11) NOT NULL DEFAULT '0',
+  `city_id` int(11) NOT NULL DEFAULT '0',
+  `area_id` int(11) NOT NULL DEFAULT '0',
+  `status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '订单状态:-2=交易关闭,-1=已取消,0=未支付,1=已支付,2=已完成',
+  `memo` varchar(255) DEFAULT NULL COMMENT '商户备注',
+  `remark` varchar(255) DEFAULT NULL COMMENT '用户备注',
+  `total_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单总金额',
+  `score_amount` int(11) NOT NULL DEFAULT '0' COMMENT '积分总数',
+  `total_fee` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '支付金额',
+  `discount_fee` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '折扣总金额',
+  `coupon_fee` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠券抵用金额',
+  `pay_fee` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '实际支付金额',
+  `score_fee` int(11) NOT NULL DEFAULT '0' COMMENT '积分支付数',
+  `goods_original_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '商品原价',
+  `coupons_id` int(11) NOT NULL DEFAULT '0' COMMENT '优惠券 id',
+  `transaction_id` varchar(60) DEFAULT NULL COMMENT '交易单号',
+  `payment_json` varchar(2500) DEFAULT NULL COMMENT '交易原始数据',
+  `pay_type` enum('wechat','alipay','wallet','score') DEFAULT NULL COMMENT '支付方式:wechat=微信支付,alipay=支付宝,wallet=钱包支付,score=积分支付',
+  `paytime` int(11) DEFAULT NULL COMMENT '支付时间',
+  `ext` varchar(255) DEFAULT NULL COMMENT '附加字段',
+  `platform` enum('H5','App','wxOfficialAccount','wxMiniProgram') DEFAULT NULL COMMENT '平台:H5=H5,wxOfficialAccount=微信公众号,wxMiniProgram=微信小程序,App=App',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE KEY `order_sn` (`order_sn`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单管理';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_order_action` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '操作记录 id',
+  `order_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单 id',
+  `order_item_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单商品id',
+  `oper_type` enum('user','store','admin','system') NOT NULL COMMENT '操作人类型',
+  `oper_id` int(11) NOT NULL DEFAULT '0' COMMENT '操作人 id',
+  `order_status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '订单状态',
+  `dispatch_status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '发货状态',
+  `comment_status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '评论状态',
+  `aftersale_status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '售后状态',
+  `refund_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '退款状态',
+  `remark` varchar(255) DEFAULT NULL COMMENT '操作备注',
+  `createtime` int(11) DEFAULT NULL COMMENT '操作时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单操作记录';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_order_item` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) DEFAULT NULL COMMENT '用户',
+  `order_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单',
+  `goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品',
+  `goods_type` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'normal' COMMENT '商品类型:normal=实体商品,virtual=虚拟商品',
+  `goods_sku_price_id` int(11) NOT NULL DEFAULT '0' COMMENT '规格 id',
+  `activity_id` int(11) NOT NULL DEFAULT '0' COMMENT '活动 id',
+  `activity_type` varchar(255) DEFAULT NULL COMMENT '活动类型',
+  `item_goods_sku_price_id` int(11) NOT NULL DEFAULT '0' COMMENT '活动规格|积分商城规格 id',
+  `goods_sku_text` varchar(30) DEFAULT NULL COMMENT '规格名',
+  `goods_title` varchar(255) DEFAULT NULL COMMENT '商品名称',
+  `goods_image` varchar(255) DEFAULT NULL COMMENT '商品图片',
+  `goods_original_price` decimal(10,2) NOT NULL COMMENT '商品原价',
+  `discount_fee` decimal(10,2) DEFAULT NULL COMMENT '优惠费用',
+  `goods_price` decimal(10,2) NOT NULL COMMENT '商品价格',
+  `goods_num` int(11) NOT NULL DEFAULT '0' COMMENT '购买数量',
+  `pay_price` decimal(10, 2) NOT NULL COMMENT '支付金额(不含运费)',
+  `dispatch_status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '发货状态:0=未发货,1=已发货,2=已收货',
+  `dispatch_fee` decimal(10,2) DEFAULT NULL COMMENT '发货费用',
+  `dispatch_type` varchar(20) DEFAULT NULL COMMENT '发货方式',
+  `dispatch_id` int(11) DEFAULT NULL COMMENT '发货模板',
+  `store_id` int(11) NOT NULL DEFAULT 0 COMMENT '门店',
+  `aftersale_status` tinyint(2) NOT NULL COMMENT '售后状态:-1=拒绝,0=未申请,1=申请售后,2=售后完成',
+  `comment_status` tinyint(2) NOT NULL COMMENT '评价状态:0=未评价,1=已评价',
+  `refund_status` tinyint(1) DEFAULT NULL COMMENT '退款状态:-1=拒绝退款,0=无,1=申请中,2=同意',
+  `refund_fee` decimal(10,2) DEFAULT NULL COMMENT '退款金额',
+  `refund_msg` varchar(255) DEFAULT NULL COMMENT '退款原因',
+  `express_name` varchar(60) DEFAULT NULL COMMENT '快递公司',
+  `express_code` varchar(60) DEFAULT NULL COMMENT '快递公司编号',
+  `express_no` varchar(60) DEFAULT NULL COMMENT '快递单号',
+  `ext` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '附加字段',
+  `createtime` int(11) DEFAULT NULL COMMENT '添加时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单商品明细';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_refund_log` (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `order_sn` varchar(45) DEFAULT NULL COMMENT '商户订单号',
+  `refund_sn` varchar(45) DEFAULT NULL COMMENT '商户退款单号',
+  `order_item_id` varchar(45) DEFAULT NULL COMMENT '订单商品',
+  `pay_fee` decimal(10,2) DEFAULT NULL COMMENT '支付金额',
+  `refund_fee` decimal(10,2) DEFAULT NULL COMMENT '退款金额',
+  `pay_type` varchar(20) NOT NULL DEFAULT '' COMMENT '付款方式',
+  `status` tinyint(1) DEFAULT '0' COMMENT '退款状态:0=退款中,1=退款完成,-1=退款失败',
+  `payment_json` varchar(1024) DEFAULT NULL COMMENT '退款原始数据',
+  `createtime` int(10) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='退款日志';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_richtext` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `title` varchar(255) DEFAULT NULL COMMENT '标题',
+  `content` longtext COMMENT '内容',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='富文本';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_score_goods_sku_price` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `sku_price_id` int(11) NOT NULL DEFAULT '0' COMMENT '规格 id',
+  `goods_id` int(11) NOT NULL COMMENT '所属产品',
+  `status` enum('up','hidden','down') NOT NULL COMMENT '上架状态:up=上架,hidden=隐藏,down=下架',
+  `stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存',
+  `sales` int(11) NOT NULL DEFAULT '0' COMMENT '已售',
+  `price` decimal(10,2) DEFAULT NULL COMMENT '价格',
+  `score` int(11) NOT NULL DEFAULT '0' COMMENT '积分',
+  `createtime` int(11) DEFAULT NULL,
+  `updatetime` int(11) DEFAULT NULL,
+  `deletetime` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分商城商品规格';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_share` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL COMMENT '用户',
+  `share_id` int(11) NOT NULL COMMENT '分享人',
+  `type` varchar(20) DEFAULT NULL COMMENT '识别类型',
+  `type_id` varchar(255) DEFAULT NULL COMMENT '识别标识',
+  `platform` varchar(20) DEFAULT NULL COMMENT '平台',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户分享';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_startup` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) DEFAULT '0' COMMENT '用户',
+  `platform` varchar(20) DEFAULT NULL COMMENT '终端',
+  `content` varchar(1200) DEFAULT NULL COMMENT '访问详情',
+  `ip` varchar(20) DEFAULT NULL COMMENT '客户端IP',
+  `createtime` int(11) DEFAULT NULL COMMENT '访问时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户端启动信息';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_user_address` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `is_default` enum('0','1') DEFAULT '0' COMMENT '默认',
+  `user_id` int(11) DEFAULT NULL COMMENT '用户',
+  `consignee` varchar(20) DEFAULT NULL COMMENT '收货人',
+  `phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
+  `province_name` varchar(20) DEFAULT NULL COMMENT '省',
+  `city_name` varchar(20) DEFAULT NULL COMMENT '市',
+  `area_name` varchar(20) DEFAULT NULL COMMENT '区',
+  `address` varchar(255) DEFAULT NULL COMMENT '详细地址',
+  `province_id` int(11) DEFAULT NULL,
+  `city_id` int(11) DEFAULT NULL,
+  `area_id` int(11) DEFAULT NULL,
+  `latitude` decimal(10, 6) NULL DEFAULT NULL COMMENT '纬度',
+  `longitude` decimal(10, 6) NULL DEFAULT NULL COMMENT '经度',
+  `createtime` int(11) DEFAULT NULL,
+  `updatetime` int(11) DEFAULT NULL,
+  `deletetime` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户地址';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_user_bank` (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL COMMENT '用户id',
+  `real_name` varchar(191) DEFAULT NULL COMMENT '真实姓名',
+  `bank_name` varchar(191) DEFAULT NULL COMMENT '银行名',
+  `card_no` varchar(191) DEFAULT NULL COMMENT '卡号',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='提现银行卡';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_user_coupons` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) DEFAULT NULL COMMENT '用户',
+  `coupons_id` int(11) DEFAULT NULL COMMENT '优惠券',
+  `use_order_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单 id',
+  `usetime` int(11) DEFAULT NULL COMMENT '使用时间',
+  `createtime` int(11) DEFAULT NULL COMMENT '领取时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户优惠券';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_user_fake` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `nickname` varchar(20) NOT NULL COMMENT '昵称',
+  `avatar` varchar(255) NOT NULL COMMENT '头像',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='虚拟用户';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_user_favorite` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) DEFAULT NULL COMMENT '用户',
+  `goods_id` int(11) DEFAULT NULL COMMENT '商品',
+  `createtime` int(11) DEFAULT NULL,
+  `updatetime` int(11) DEFAULT NULL,
+  `deletetime` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户收藏';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_user_oauth` (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `user_id` int(10) UNSIGNED DEFAULT '0' COMMENT '用户',
+  `provider` varchar(50) NOT NULL COMMENT '厂商',
+  `platform` varchar(50) NOT NULL COMMENT '平台',
+  `unionid` varchar(50) DEFAULT NULL COMMENT '厂商ID',
+  `openid` varchar(50) NOT NULL COMMENT '平台ID',
+  `nickname` varchar(255) DEFAULT '' COMMENT '昵称',
+  `sex` tinyint(1) DEFAULT '0' COMMENT '性别',
+  `country` varchar(50) DEFAULT NULL COMMENT '国家',
+  `province` varchar(50) DEFAULT '' COMMENT '省',
+  `city` varchar(50) DEFAULT '' COMMENT '市',
+  `headimgurl` varchar(500) DEFAULT '' COMMENT '头像',
+  `logintime` int(11) DEFAULT NULL COMMENT '登录时间',
+  `logincount` int(11) DEFAULT '0' COMMENT '累计登陆',
+  `expire_in` int(11) DEFAULT NULL COMMENT '过期周期(s)',
+  `expiretime` int(11) DEFAULT NULL COMMENT '过期时间',
+  `session_key` varchar(45) DEFAULT '' COMMENT 'session_key',
+  `refresh_token` varchar(110) DEFAULT NULL COMMENT 'refresh_token',
+  `access_token` varchar(110) DEFAULT NULL COMMENT 'access_token',
+  `createtime` int(10) DEFAULT '0' COMMENT '创建时间',
+  `updatetime` int(10) DEFAULT '0' COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='第三方授权';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_user_sign` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户',
+  `date` varchar(30) DEFAULT NULL COMMENT '签到日期',
+  `score` int(11) NOT NULL DEFAULT '0' COMMENT '所得积分',
+  `is_replenish` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否补签:0=正常,1=补签',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `date` (`date`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户签到';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_user_view` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户',
+  `goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品',
+  `createtime` int(11) DEFAULT NULL COMMENT '添加时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户浏览记录';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_user_wallet_apply` (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL COMMENT '提现用户',
+  `money` decimal(10,2) NOT NULL COMMENT '提现金额',
+  `charge_money` decimal(10,2) NOT NULL COMMENT '手续费',
+  `service_fee` decimal(10,3) DEFAULT NULL COMMENT '手续费率',
+  `get_type` enum('bank') DEFAULT NULL COMMENT '收款类型:bank=银行卡',
+  `bank_id` int(11) NOT NULL DEFAULT '0' COMMENT '银行卡',
+  `real_name` varchar(30) DEFAULT NULL COMMENT '真实姓名',
+  `bank_info` varchar(255) DEFAULT NULL COMMENT '打款信息',
+  `status` tinyint(1) DEFAULT '0' COMMENT '提现状态:0=申请中,1=已打款,-1=已拒绝',
+  `status_msg` varchar(255) DEFAULT NULL COMMENT '驳回理由',
+  `createtime` int(11) DEFAULT NULL COMMENT '申请时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '操作时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户提现';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_user_wallet_log` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '日志 id',
+  `user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户',
+  `wallet` decimal(10,2) NOT NULL COMMENT '变动金额',
+  `type` varchar(30) NOT NULL COMMENT '变动类型',
+  `wallet_type` enum('money','score') NOT NULL COMMENT '日志类型:money=余额,score=积分',
+  `item_id` varchar(60) DEFAULT NULL COMMENT '项目 id',
+  `ext` varchar(512) DEFAULT NULL COMMENT '附加字段',
+  `oper_type` enum('user','store','admin','system') CHARACTER SET utf8mb4 NOT NULL DEFAULT 'user' COMMENT '操作人类型',
+  `oper_id` int(11) NOT NULL DEFAULT 0 COMMENT '操作人',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='钱包日志';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_wechat` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `type` varchar(50) NOT NULL COMMENT '配置类型',
+  `name` varchar(50) NOT NULL COMMENT '名称',
+  `rules` varchar(255) CHARACTER SET utf8mb4  NULL DEFAULT NULL COMMENT '规则',
+  `content` text NOT NULL COMMENT '内容',
+  `createtime` int(11) NOT NULL COMMENT '创建时间',
+  `updatetime` int(11) NOT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微信管理';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_wechat_fans` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `nickname` varchar(50) DEFAULT NULL COMMENT '粉丝昵称',
+  `headimgurl` varchar(255) NOT NULL COMMENT '粉丝头像',
+  `openid` varchar(30) NOT NULL COMMENT 'openid',
+  `sex` int(11) NOT NULL DEFAULT '0' COMMENT '性别',
+  `country` varchar(20) NOT NULL COMMENT '国家',
+  `province` varchar(20) NOT NULL COMMENT '省',
+  `city` varchar(20) NOT NULL COMMENT '市',
+  `subscribe` enum('0','1') NOT NULL COMMENT '关注状态:0=取消关注,1=已关注',
+  `subscribe_time` int(11) NOT NULL COMMENT '关注时间',
+  `createtime` int(11) NOT NULL COMMENT '创建时间',
+  `updatetime` int(11) NOT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='粉丝管理';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_notification` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '消息表',
+  `type` varchar(60) NOT NULL COMMENT '消息类型',
+  `notifiable_id` int(10) UNSIGNED NOT NULL COMMENT '接收人',
+  `notifiable_type` varchar(255) NOT NULL COMMENT '接收人类型',
+  `data` text NOT NULL COMMENT '数据',
+  `readtime` int(10) DEFAULT NULL COMMENT '是否已读',
+  `createtime` int(10) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(10) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `notifiable_id_notifiable_type` (`notifiable_id`,`notifiable_type`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='消息管理';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_notification_config` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `platform` varchar(50) NOT NULL COMMENT '发送平台',
+  `name` varchar(50) NOT NULL COMMENT '消息名称',
+  `event` varchar(50) NOT NULL COMMENT '消息事件',
+  `content` text COMMENT '消息内容',
+  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:0=关闭,1=启用',
+  `sendnum` int(11) NOT NULL DEFAULT '0' COMMENT '发送次数',
+  `createtime` int(11) DEFAULT NULL,
+  `updatetime` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通知配置';
+
+ALTER TABLE `__PREFIX__shopro_goods` ADD COLUMN `show_sales` INT(10) NOT NULL DEFAULT 0 COMMENT '虚增销量' AFTER `sales`;
+ALTER TABLE `__PREFIX__shopro_goods` ADD COLUMN `is_sku` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否多规格' AFTER `original_price`;
+ALTER TABLE `__PREFIX__shopro_order` ADD COLUMN `activity_type` VARCHAR(255) DEFAULT NULL COMMENT '活动类型' AFTER `type`;
+ALTER TABLE `__PREFIX__shopro_order_item` ADD COLUMN `refund_msg` VARCHAR(255) DEFAULT NULL COMMENT '退款原因' AFTER `refund_fee`;
+ALTER TABLE `__PREFIX__shopro_activity` ADD COLUMN `richtext_id` INT(11) DEFAULT 0 COMMENT '活动说明' AFTER `type`;
+ALTER TABLE `__PREFIX__shopro_activity` ADD COLUMN `richtext_title` VARCHAR(255) DEFAULT '' COMMENT '说明标题' AFTER `type`;
+ALTER TABLE `__PREFIX__shopro_decorate` ADD COLUMN `type` enum('shop','custom','preview') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'shop' COMMENT '页面分类:shop=商城,custom=自定义,preview=临时预览' AFTER `name`;
+ALTER TABLE `__PREFIX__shopro_decorate` ADD COLUMN `image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '图片' AFTER `type`;
+ALTER TABLE `__PREFIX__shopro_decorate_content` ADD COLUMN `category` enum('home','user','tabbar','popup','custom','float-button') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '页面类型:home=首页,user=个人中心,tabbar=底部导航,popup=弹出提醒,float-button=悬浮按钮,custom=自定义' AFTER `type`;
+
+-- 1.0.7更新 ↓
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_express` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(60) DEFAULT NULL COMMENT '快递公司',
+  `code` varchar(60) DEFAULT NULL COMMENT '编码',
+  `weigh` int(11) NOT NULL DEFAULT '0' COMMENT '权重',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='快递公司';
+INSERT INTO `__PREFIX__shopro_express` (`id`, `name`, `code`, `weigh`) VALUES
+(1, '顺丰速运', 'SF', 0),
+(2, '百世快递', 'HTKY', 0),
+(3, '中通快递', 'ZTO', 0),
+(4, '申通快递', 'STO', 0),
+(5, '圆通速递', 'YTO', 0),
+(6, '韵达速递', 'YD', 0),
+(7, '邮政快递包裹', 'YZPY', 0),
+(8, 'EMS', 'EMS', 0),
+(9, '天天快递', 'HHTT', 0),
+(10, '京东快递', 'JD', 0),
+(11, '优速快递', 'UC', 0),
+(12, '德邦快递', 'DBL', 0),
+(13, '宅急送', 'ZJS', 0),
+(14, '安捷快递', 'AJ', 0),
+(15, '阿里跨境电商物流', 'ALKJWL', 0),
+(16, '安迅物流', 'AX', 0),
+(17, '安邮美国', 'AYUS', 0),
+(18, '亚马逊物流', 'AMAZON', 0),
+(19, '澳门邮政', 'AOMENYZ', 0),
+(20, '安能物流', 'ANE', 0),
+(21, '澳多多', 'ADD', 0),
+(22, '澳邮专线', 'AYCA', 0),
+(23, '安鲜达', 'AXD', 0),
+(24, '安能快运', 'ANEKY', 0),
+(25, '澳邦国际', 'ABGJ', 0),
+(26, '安得物流', 'ANNTO', 0),
+(27, '八达通  ', 'BDT', 0),
+(28, '百腾物流', 'BETWL', 0),
+(29, '北极星快运', 'BJXKY', 0),
+(30, '奔腾物流', 'BNTWL', 0),
+(31, '百福东方', 'BFDF', 0),
+(32, '贝海国际 ', 'BHGJ', 0),
+(33, '八方安运', 'BFAY', 0),
+(34, '百世快运', 'BTWL', 0),
+(35, '帮帮发转运', 'BBFZY', 0),
+(36, '百城通物流', 'BCTWL', 0),
+(37, '春风物流', 'CFWL', 0),
+(38, '诚通物流', 'CHTWL', 0),
+(39, '传喜物流', 'CXHY', 0),
+(40, '城市100', 'CITY100', 0),
+(41, '城际快递', 'CJKD', 0),
+(42, 'CNPEX中邮快递', 'CNPEX', 0),
+(43, 'COE东方快递', 'COE', 0),
+(44, '长沙创一', 'CSCY', 0),
+(45, '成都善途速运', 'CDSTKY', 0),
+(46, '联合运通', 'CTG', 0),
+(47, '疯狂快递', 'CRAZY', 0),
+(48, 'CBO钏博物流', 'CBO', 0),
+(49, '佳吉快运', 'CNEX', 0),
+(50, '承诺达', 'CND', 0),
+(51, '畅顺通达', 'CSTD', 0),
+(52, 'D速物流', 'DSWL', 0),
+(53, '到了港', 'DLG ', 0),
+(54, '大田物流', 'DTWL', 0),
+(55, '东骏快捷物流', 'DJKJWL', 0),
+(56, '德坤', 'DEKUN', 0),
+(57, '德邦快运', 'DBLKY', 0),
+(58, '大马鹿', 'DML', 0),
+(59, '丹鸟物流', 'DNWL', 0),
+(60, '东方汇', 'EST365', 0),
+(61, 'E特快', 'ETK', 0),
+(62, 'EMS国内', 'EMS2', 0),
+(63, 'EWE', 'EWE', 0),
+(64, '飞康达', 'FKD', 0),
+(65, '富腾达  ', 'FTD', 0),
+(66, '凡宇货的', 'FYKD', 0),
+(67, '速派快递', 'FASTGO', 0),
+(68, '飞豹快递', 'FBKD', 0),
+(69, '丰巢', 'FBOX', 0),
+(70, '飞狐快递', 'FHKD', 0),
+(71, '复融供应链', 'FRGYL', 0),
+(72, '飞远配送', 'FYPS', 0),
+(73, '凡宇速递', 'FYSD', 0),
+(74, '丰通快运', 'FT', 0),
+(75, '冠达   ', 'GD', 0),
+(76, '广东邮政', 'GDEMS', 0),
+(77, '共速达', 'GSD', 0),
+(78, '广通       ', 'GTONG', 0),
+(79, '冠达快递', 'GDKD', 0),
+(80, '挂号信', 'GHX', 0),
+(81, '广通速递', 'GTKD', 0),
+(82, '高铁快运', 'GTKY', 0),
+(83, '迦递快递', 'GAI', 0),
+(84, '港快速递', 'GKSD', 0),
+(85, '高铁速递', 'GTSD', 0),
+(86, '黑狗冷链', 'HGLL', 0),
+(87, '恒路物流', 'HLWL', 0),
+(88, '天地华宇', 'HOAU', 0),
+(89, '鸿桥供应链', 'HOTSCM', 0),
+(90, '海派通物流公司', 'HPTEX', 0),
+(91, '华强物流', 'hq568', 0),
+(92, '环球速运  ', 'HQSY', 0),
+(93, '华夏龙物流', 'HXLWL', 0),
+(94, '河北建华', 'HBJH', 0),
+(95, '汇丰物流', 'HF', 0),
+(96, '华航快递', 'HHKD', 0),
+(97, '华翰物流', 'HHWL', 0),
+(98, '黄马甲快递', 'HMJKD', 0),
+(99, '海盟速递', 'HMSD', 0),
+(100, '华企快运', 'HQKY', 0),
+(101, '昊盛物流', 'HSWL', 0),
+(102, '鸿泰物流', 'HTWL', 0),
+(103, '豪翔物流 ', 'HXWL', 0),
+(104, '合肥汇文', 'HFHW', 0),
+(105, '辉隆物流', 'HLONGWL', 0),
+(106, '华企快递', 'HQKD', 0),
+(107, '韩润物流', 'HRWL', 0),
+(108, '青岛恒通快递', 'HTKD', 0),
+(109, '货运皇物流', 'HYH', 0),
+(110, '好来运快递', 'HLYSD', 0),
+(111, '皇家物流', 'HJWL', 0),
+(112, '海信物流', 'HISENSE', 0),
+(113, '捷安达  ', 'JAD', 0),
+(114, '京广速递', 'JGSD', 0),
+(115, '九曳供应链', 'JIUYE', 0),
+(116, '急先达', 'JXD', 0),
+(117, '晋越快递', 'JYKD', 0),
+(118, '佳成国际', 'JCEX', 0),
+(119, '捷特快递', 'JTKD', 0),
+(120, '精英速运', 'JYSY', 0),
+(121, '加运美', 'JYM', 0),
+(122, '景光物流', 'JGWL', 0),
+(123, '佳怡物流', 'JYWL', 0),
+(124, '京东快运', 'JDKY', 0),
+(125, '金大物流', 'JDWL', 0),
+(126, '极兔速递', 'JTSD', 0),
+(127, '跨越速运', 'KYSY', 0),
+(128, '快服务', 'KFW', 0),
+(129, '快速递物流', 'KSDWL', 0),
+(130, '康力物流', 'KLWL', 0),
+(131, '快淘快递', 'KTKD', 0),
+(132, '快优达速递', 'KYDSD', 0),
+(133, '跨越物流', 'KYWL', 0),
+(134, '快8速运', 'KBSY', 0),
+(135, '龙邦快递', 'LB', 0),
+(136, '蓝弧快递', 'LHKD', 0),
+(137, '乐捷递', 'LJD', 0),
+(138, '立即送', 'LJS', 0),
+(139, '联昊通速递', 'LHT', 0),
+(140, '民邦快递', 'MB', 0),
+(141, '民航快递', 'MHKD', 0),
+(142, '美快    ', 'MK', 0),
+(143, '门对门快递', 'MDM', 0),
+(144, '迈达', 'MD', 0),
+(145, '闽盛快递', 'MSKD', 0),
+(146, '迈隆递运', 'MRDY', 0),
+(147, '明亮物流', 'MLWL', 0),
+(148, '南方传媒物流', 'NFCM', 0),
+(149, '南京晟邦物流', 'NJSBWL', 0),
+(150, '能达速递', 'NEDA', 0),
+(151, '平安达腾飞快递', 'PADTF', 0),
+(152, '泛捷快递', 'PANEX', 0),
+(153, '品骏快递', 'PJ', 0),
+(154, '陪行物流', 'PXWL', 0),
+(155, 'PCA Express', 'PCA', 0),
+(156, '全晨快递', 'QCKD', 0),
+(157, '全日通快递', 'QRT', 0),
+(158, '快客快递', 'QUICK', 0),
+(159, '全信通', 'QXT', 0),
+(160, '七曜中邮', 'QYZY', 0),
+(161, '如风达', 'RFD', 0),
+(162, '荣庆物流', 'RQ', 0),
+(163, '日日顺物流', 'RRS', 0),
+(164, '日昱物流', 'RLWL', 0),
+(165, '瑞丰速递', 'RFEX', 0),
+(166, '赛澳递', 'SAD', 0),
+(167, '苏宁物流', 'SNWL', 0),
+(168, '圣安物流', 'SAWL', 0),
+(169, '晟邦物流', 'SBWL', 0),
+(170, '上大物流', 'SDWL', 0),
+(171, '盛丰物流', 'SFWL', 0),
+(172, '速通物流', 'ST', 0),
+(173, '速腾快递', 'STWL', 0),
+(174, '速必达物流', 'SUBIDA', 0),
+(175, '速递e站', 'SDEZ', 0),
+(176, '速呈宅配', 'SCZPDS', 0),
+(177, '速尔快递', 'SURE', 0),
+(178, '山东海红', 'SDHH', 0),
+(179, '顺丰国际', 'SFGJ', 0),
+(180, '盛辉物流', 'SHWL', 0),
+(181, '穗佳物流', 'SJWL', 0),
+(182, '三态速递', 'STSD', 0),
+(183, '山西红马甲', 'SXHMJ', 0),
+(184, '世运快递', 'SYKD', 0),
+(185, '闪送', 'SS', 0),
+(186, '盛通快递', 'STKD', 0),
+(187, '郑州速捷', 'SJ', 0),
+(188, '顺心捷达', 'SX', 0),
+(189, '商桥物流', 'SQWL', 0),
+(190, '佳旺达物流', 'SYJWDX', 0),
+(191, '台湾邮政', 'TAIWANYZ', 0),
+(192, '唐山申通', 'TSSTO', 0),
+(193, '特急送', 'TJS', 0),
+(194, '通用物流', 'TYWL', 0),
+(195, '华宇物流', 'TDHY', 0),
+(196, '通和天下', 'THTX', 0),
+(197, '腾林物流', 'TLWL', 0),
+(198, '全一快递', 'UAPEX', 0),
+(199, 'UBI', 'UBI', 0),
+(200, 'UEQ Express', 'UEQ', 0),
+(201, '万家康  ', 'WJK', 0),
+(202, '万家物流', 'WJWL', 0),
+(203, '武汉同舟行', 'WHTZX', 0),
+(204, '维普恩', 'WPE', 0),
+(205, '中粮我买网', 'WM', 0),
+(206, '万象物流', 'WXWL', 0),
+(207, '微特派', 'WTP', 0),
+(208, '温通物流', 'WTWL', 0),
+(209, '迅驰物流  ', 'XCWL', 0),
+(210, '信丰物流', 'XFEX', 0),
+(211, '希优特', 'XYT', 0),
+(212, '新邦物流', 'XBWL', 0),
+(213, '祥龙运通', 'XLYT', 0),
+(214, '新杰物流', 'XJ', 0),
+(215, '源安达快递', 'YADEX', 0),
+(216, '远成物流', 'YCWL', 0),
+(217, '远成快运', 'YCSY', 0),
+(218, '义达国际物流', 'YDH', 0),
+(219, '易达通  ', 'YDT', 0),
+(220, '原飞航物流', 'YFHEX', 0),
+(221, '亚风快递', 'YFSD', 0),
+(222, '运通快递', 'YTKD', 0),
+(223, '亿翔快递', 'YXKD', 0),
+(224, '运东西网', 'YUNDX', 0),
+(225, '壹米滴答', 'YMDD', 0),
+(226, '邮政国内标快', 'YZBK', 0),
+(227, '一站通速运', 'YZTSY', 0),
+(228, '驭丰速运', 'YFSUYUN', 0),
+(229, '余氏东风', 'YSDF', 0),
+(230, '耀飞快递', 'YF', 0),
+(231, '韵达快运', 'YDKY', 0),
+(232, '云路', 'YL', 0),
+(233, '邮必佳', 'YBJ', 0),
+(234, '越丰物流', 'YFEX', 0),
+(235, '银捷速递', 'YJSD', 0),
+(236, '优联吉运', 'YLJY', 0),
+(237, '亿领速运', 'YLSY', 0),
+(238, '英脉物流', 'YMWL', 0),
+(239, '亿顺航', 'YSH', 0),
+(240, '音素快运', 'YSKY', 0),
+(241, '易通达', 'YTD', 0),
+(242, '一统飞鸿', 'YTFH', 0),
+(243, '圆通国际', 'YTOGJ', 0),
+(244, '宇鑫物流', 'YXWL', 0),
+(245, '包裹/平邮/挂号信', 'YZGN', 0),
+(246, '一智通', 'YZT', 0),
+(247, '优拜物流', 'YBWL', 0),
+(248, '增益快递', 'ZENY', 0),
+(249, '中睿速递', 'ZRSD', 0),
+(250, '中铁快运', 'ZTKY', 0),
+(251, '中天万运', 'ZTWY', 0),
+(252, '中外运速递', 'ZWYSD', 0),
+(253, '澳转运', 'ZY_AZY', 0),
+(254, '八达网', 'ZY_BDA', 0),
+(255, '贝易购', 'ZY_BYECO', 0),
+(256, '赤兔马转运', 'ZY_CTM', 0),
+(257, 'CUL中美速递', 'ZY_CUL', 0),
+(258, 'ETD', 'ZY_ETD', 0),
+(259, '风驰快递', 'ZY_FCKD', 0),
+(260, '风雷速递', 'ZY_FLSD', 0),
+(261, '皓晨优递', 'ZY_HCYD', 0),
+(262, '海带宝', 'ZY_HDB', 0),
+(263, '汇丰美中速递', 'ZY_HFMZ', 0),
+(264, '豪杰速递', 'ZY_HJSD', 0),
+(265, '华美快递', 'ZY_HMKD', 0),
+(266, '360hitao转运', 'ZY_HTAO', 0),
+(267, '海淘村', 'ZY_HTCUN', 0),
+(268, '365海淘客', 'ZY_HTKE', 0),
+(269, '华通快运', 'ZY_HTONG', 0),
+(270, '海星桥快递', 'ZY_HXKD', 0),
+(271, '华兴速运', 'ZY_HXSY', 0),
+(272, 'LogisticsY', 'ZY_IHERB', 0),
+(273, '领跑者快递', 'ZY_LPZ', 0),
+(274, '量子物流', 'ZY_LZWL', 0),
+(275, '明邦转运', 'ZY_MBZY', 0),
+(276, '美嘉快递', 'ZY_MJ', 0),
+(277, '168 美中快递', 'ZY_MZ', 0),
+(278, '欧e捷', 'ZY_OEJ', 0),
+(279, '欧洲疯', 'ZY_OZF', 0),
+(280, '欧洲GO', 'ZY_OZGO', 0),
+(281, '全美通', 'ZY_QMT', 0),
+(282, 'SCS国际物流', 'ZY_SCS', 0),
+(283, 'SOHO苏豪国际', 'ZY_SOHO', 0),
+(284, 'Sonic-Ex速递', 'ZY_SONIC', 0),
+(285, '通诚美中快递', 'ZY_TCM', 0),
+(286, 'TrakPak', 'ZY_TPAK', 0),
+(287, '天天海淘', 'ZY_TTHT', 0),
+(288, '天泽快递', 'ZY_TZKD', 0),
+(289, '迅达快递', 'ZY_XDKD', 0),
+(290, '信达速运', 'ZY_XDSY', 0),
+(291, '新干线快递', 'ZY_XGX', 0),
+(292, '信捷转运', 'ZY_XJ', 0),
+(293, '优购快递', 'ZY_YGKD', 0),
+(294, '友家速递(UCS)', 'ZY_YJSD', 0),
+(295, '云畔网', 'ZY_YPW', 0),
+(296, '易送网', 'ZY_YSW', 0),
+(297, '中运全速', 'ZYQS', 0),
+(298, '中邮物流', 'ZYWL', 0),
+(299, '汇强快递', 'ZHQKD', 0),
+(300, '众通快递', 'ZTE', 0),
+(301, '中通快运', 'ZTOKY', 0),
+(302, '中邮快递', 'ZYKD', 0),
+(303, '芝麻开门', 'ZMKM', 0),
+(304, '中骅物流', 'ZHWL', 0),
+(305, '中铁物流', 'ZTWL', 0),
+(306, '智汇鸟', 'ZHN', 99),
+(307, '众邮快递', 'ZYE', 0);
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_order_aftersale` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `aftersale_sn` varchar(40) NOT NULL COMMENT '售后单号',
+  `user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户',
+  `type` varchar(20) NOT NULL COMMENT '类型:refund=退款,return=退货,other=其他',
+  `phone` varchar(20) DEFAULT NULL COMMENT '联系方式',
+  `activity_id` int(11) DEFAULT NULL COMMENT '活动',
+  `activity_type` varchar(255) DEFAULT NULL COMMENT '活动类型',
+  `order_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单',
+  `order_item_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单商品',
+  `goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品',
+  `goods_sku_price_id` int(11) NOT NULL DEFAULT '0' COMMENT '规格 id',
+  `goods_sku_text` varchar(30) DEFAULT NULL COMMENT '规格名',
+  `goods_title` varchar(255) DEFAULT NULL COMMENT '商品名称',
+  `goods_image` varchar(255) DEFAULT NULL COMMENT '商品图片',
+  `goods_original_price` decimal(10,2) NOT NULL COMMENT '商品原价',
+  `discount_fee` decimal(10,2) DEFAULT NULL COMMENT '优惠费用',
+  `goods_price` decimal(10,2) NOT NULL COMMENT '商品价格',
+  `goods_num` int(11) NOT NULL DEFAULT '0' COMMENT '购买数量',
+  `dispatch_status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '发货状态:0=未发货,1=已发货,2=已收货',
+  `dispatch_fee` decimal(10,2) DEFAULT NULL COMMENT '发货费用',
+  `aftersale_status` tinyint(2) NOT NULL COMMENT '售后状态:-1=拒绝,0=未处理,1=处理中,2=售后完成',
+  `refund_status` tinyint(1) DEFAULT NULL COMMENT '退款状态:-1=拒绝退款,0=未退款,1=同意',
+  `refund_fee` decimal(10,2) DEFAULT NULL COMMENT '退款金额',
+  `createtime` int(11) DEFAULT NULL COMMENT '添加时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE KEY `aftersale_sn` (`aftersale_sn`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='售后单';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_order_aftersale_log` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '操作记录 id',
+  `order_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单',
+  `order_aftersale_id` int(11) NOT NULL DEFAULT '0' COMMENT '售后单',
+  `oper_type` enum('user','store','admin','system') NOT NULL COMMENT '操作人类型',
+  `oper_id` int(11) NOT NULL DEFAULT '0' COMMENT '操作人 id',
+  `dispatch_status` tinyint(2) NOT NULL COMMENT '发货状态',
+  `aftersale_status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '售后状态',
+  `refund_status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '退款状态',
+  `reason` varchar(255) DEFAULT NULL COMMENT '售后原因',
+  `content` varchar(255) DEFAULT NULL COMMENT '内容',
+  `images` varchar(2500) DEFAULT NULL COMMENT '图片',
+  `createtime` int(11) DEFAULT NULL COMMENT '操作时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='售后单记录';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_order_express` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL COMMENT '用户',
+  `order_id` int(11) NOT NULL COMMENT '订单',
+  `express_name` varchar(60) DEFAULT NULL COMMENT '快递公司',
+  `express_code` varchar(60) DEFAULT NULL COMMENT '公司编号',
+  `express_no` varchar(60) DEFAULT NULL COMMENT '快递单号',
+  `createtime` int(11) DEFAULT NULL COMMENT '添加时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='快递包裹';
+
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_order_express_log` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL COMMENT '用户',
+  `order_id` int(11) NOT NULL COMMENT '订单',
+  `order_express_id` int(11) NOT NULL COMMENT '包裹',
+  `status` tinyint(4) DEFAULT '0' COMMENT '物流状态',
+  `location` varchar(255) DEFAULT NULL COMMENT '城市',
+  `content` varchar(512) DEFAULT NULL COMMENT '物流信息',
+  `changedate` datetime DEFAULT NULL COMMENT '变动时间',
+  `createtime` int(11) DEFAULT NULL COMMENT '添加时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物流信息';
+
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_store` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `name` varchar(50) NOT NULL COMMENT '门店名称',
+  `images` varchar(2500) NOT NULL COMMENT '门店图片',
+  `realname` varchar(50) NOT NULL COMMENT '联系人',
+  `phone` varchar(20) NOT NULL COMMENT '联系电话',
+  `province_name` varchar(50) NOT NULL COMMENT '省',
+  `city_name` varchar(50) NOT NULL COMMENT '市',
+  `area_name` varchar(50) NOT NULL COMMENT '区',
+  `province_id` int(11) NOT NULL COMMENT '省ID',
+  `city_id` int(11) NOT NULL COMMENT '市ID',
+  `area_id` int(11) NOT NULL COMMENT '区ID',
+  `address` varchar(255) NOT NULL COMMENT '详细地址',
+  `latitude` decimal(10,6) NULL DEFAULT NULL COMMENT '纬度',
+  `longitude` decimal(10,6) NULL DEFAULT NULL COMMENT '经度',
+  `store` enum('0','1') NOT NULL DEFAULT '0' COMMENT '支持配送:0=否,1=是',
+  `selfetch` enum('0','1') NOT NULL DEFAULT '0' COMMENT '支持自提:0=否,1=是',
+  `service_type` varchar(20) NOT NULL COMMENT '服务范围',
+  `service_radius` int(11) NOT NULL DEFAULT '0' COMMENT '服务半径',
+  `service_province_ids` varchar(1200) DEFAULT NULL COMMENT '服务行政省',
+  `service_city_ids` varchar(1200) DEFAULT NULL COMMENT '服务行政市',
+  `service_area_ids` varchar(1200) DEFAULT NULL COMMENT '服务行政区',
+  `openhours` varchar(20) NOT NULL COMMENT '营业时间',
+  `openweeks` set('1','2','3','4','5','6','7') NOT NULL DEFAULT '1,2,3,4,5,6,7' COMMENT '营业天数',
+  `status` enum('0','1') NOT NULL DEFAULT '1' COMMENT '门店状态:0=禁用,1=启用',
+  `createtime` int(11) NOT NULL COMMENT '创建时间',
+  `updatetime` int(11) NOT NULL COMMENT '更新时间',
+  `deletetime` int(11) DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='门店';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_user_store` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL COMMENT '用户',
+  `store_id` int(11) NOT NULL COMMENT '门店',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='门店管理员';
+
+CREATE TABLE IF NOT EXISTS `__PREFIX__shopro_verify` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL COMMENT '用户',
+  `type` varchar(30) DEFAULT 'verify' COMMENT '类型:verify=核销券',
+  `code` varchar(20) NOT NULL COMMENT '核销码',
+  `order_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单',
+  `order_item_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单商品',
+  `usetime` int(11) DEFAULT NULL COMMENT '使用时间',
+  `expiretime` int(11) DEFAULT NULL COMMENT '过期时间',
+  `oper_type` enum('user','store','admin','system') DEFAULT NULL COMMENT '操作人类型',
+  `oper_id` int(11) NOT NULL DEFAULT '0' COMMENT '操作人',
+  `createtime` int(11) DEFAULT NULL COMMENT '添加时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE KEY `code` (`code`) USING BTREE COMMENT '核销码'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='二维码';
+
+-- 用户地理位置加入经纬度
+ALTER TABLE `__PREFIX__shopro_user_address` ADD COLUMN `latitude` decimal(10, 6) NULL DEFAULT NULL COMMENT '纬度' AFTER `area_id`;
+ALTER TABLE `__PREFIX__shopro_user_address` ADD COLUMN `longitude` decimal(10, 6) NULL DEFAULT NULL COMMENT '经度' AFTER `latitude`;
+
+-- 订单副表加入扩展字段
+ALTER TABLE `__PREFIX__shopro_order_item` ADD COLUMN `goods_type` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'normal' COMMENT '商品类型:normal=实体商品,virtual=虚拟商品' AFTER `goods_id`;
+ALTER TABLE `__PREFIX__shopro_order_item` ADD COLUMN `store_id` int(11) NOT NULL DEFAULT 0 COMMENT '门店' AFTER `dispatch_id`;
+ALTER TABLE `__PREFIX__shopro_order_item` MODIFY COLUMN `aftersale_status` tinyint(2) NOT NULL COMMENT '售后状态:-1=拒绝,0=未申请,1=申请售后,2=售后完成' AFTER `store_id`;
+ALTER TABLE `__PREFIX__shopro_order_item` ADD COLUMN `express_code` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '公司编号' AFTER `express_name`;
+ALTER TABLE `__PREFIX__shopro_order_item` ADD COLUMN `ext` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '附加字段' AFTER `express_no`;
+
+-- 订单操作日志加入操作人类型
+ALTER TABLE `__PREFIX__shopro_order_action` MODIFY COLUMN `oper_type` enum('user','store','admin','system') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '操作人类型' AFTER `order_item_id`;
+
+-- 配送方式 商家配送
+ALTER TABLE `__PREFIX__shopro_dispatch_store` COMMENT = '商家配送';
+ALTER TABLE `__PREFIX__shopro_dispatch_store` ADD COLUMN `store_ids` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '包含门店' AFTER `id`;
+ALTER TABLE `__PREFIX__shopro_dispatch_store` ADD COLUMN `createtime` int(11) DEFAULT NULL COMMENT '创建时间' AFTER `store_ids`;
+ALTER TABLE `__PREFIX__shopro_dispatch_store` ADD COLUMN `updatetime` int(11) DEFAULT NULL COMMENT '更新时间' AFTER `createtime`;
+ALTER TABLE `__PREFIX__shopro_dispatch_store` ADD COLUMN `deletetime` int(11) NULL DEFAULT NULL COMMENT '删除时间' AFTER `updatetime`;
+
+-- 配送方式 自提点
+ALTER TABLE `__PREFIX__shopro_dispatch_selfetch` drop COLUMN `name`;
+ALTER TABLE `__PREFIX__shopro_dispatch_selfetch` drop COLUMN `weigh`;
+ALTER TABLE `__PREFIX__shopro_dispatch_selfetch` drop COLUMN `longitude`;
+ALTER TABLE `__PREFIX__shopro_dispatch_selfetch` drop COLUMN `latitude`;
+ALTER TABLE `__PREFIX__shopro_dispatch_selfetch` drop COLUMN `address`;
+ALTER TABLE `__PREFIX__shopro_dispatch_selfetch` ADD COLUMN `store_ids` varchar(255) CHARACTER SET utf8mb4 NOT NULL COMMENT '包含门店' AFTER `id`;
+ALTER TABLE `__PREFIX__shopro_dispatch_selfetch` ADD COLUMN `expire_type` enum('day','time') CHARACTER SET utf8mb4  NOT NULL DEFAULT 'day' COMMENT '过期类型:day=天数,time=截至日期' AFTER `store_ids`;
+ALTER TABLE `__PREFIX__shopro_dispatch_selfetch` ADD COLUMN `expire_day` int(11) NOT NULL DEFAULT 0 COMMENT 'X天过期' AFTER `expire_type`;
+ALTER TABLE `__PREFIX__shopro_dispatch_selfetch` ADD COLUMN `expire_time` int(11) NOT NULL DEFAULT 0 COMMENT '截至日期' AFTER `expire_day`;
+
+-- 配送方式 快递物流
+ALTER TABLE `__PREFIX__shopro_dispatch_express` DROP COLUMN `name`;
+
+-- 配送方式 自动发货
+ALTER TABLE `__PREFIX__shopro_dispatch_autosend` ADD COLUMN `type` enum('card','text','params') CHARACTER SET utf8mb4 NOT NULL COMMENT '自动发货类型:card=卡密,text=固定内容,params=自定义内容' AFTER `id`;
+ALTER TABLE `__PREFIX__shopro_dispatch_autosend` ADD COLUMN `content` varchar(1200) CHARACTER SET utf8mb4 NOT NULL COMMENT '发货内容' AFTER `type`;
+ALTER TABLE `__PREFIX__shopro_dispatch_autosend` ADD COLUMN `createtime` int(11) DEFAULT NULL COMMENT '创建时间' AFTER `content`;
+ALTER TABLE `__PREFIX__shopro_dispatch_autosend` ADD COLUMN `updatetime` int(11) DEFAULT NULL COMMENT '更新时间' AFTER `createtime`;
+ALTER TABLE `__PREFIX__shopro_dispatch_autosend` ADD COLUMN `deletetime` int(11) NULL DEFAULT NULL COMMENT '删除时间' AFTER `updatetime`;
+
+-- 优惠券 添加多类型
+ALTER TABLE `__PREFIX__shopro_coupons` ADD COLUMN `type` enum('cash','discount') NOT NULL DEFAULT 'cash' COMMENT '类型:cash=代金券,discount=折扣券' AFTER `name`;
+
+-- 用户钱包记录 添加操作人
+ALTER TABLE `__PREFIX__shopro_user_wallet_log` ADD COLUMN `oper_type` enum('user','store','admin','system') CHARACTER SET utf8mb4 NOT NULL DEFAULT 'user' COMMENT '操作人类型' AFTER `ext`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_log` ADD COLUMN `oper_id` int(11) NOT NULL DEFAULT 0 COMMENT '操作人 id' AFTER `oper_type`;
+
+-- 微信管理 添加自定义规则
+ALTER TABLE `__PREFIX__shopro_wechat` ADD COLUMN `rules` varchar(255) CHARACTER SET utf8mb4  NULL DEFAULT NULL COMMENT '规则' AFTER `name`;
+
+-- 会员组 添加等级徽章
+ALTER TABLE `__PREFIX__user_group` ADD COLUMN `image` varchar(255) CHARACTER SET utf8mb4 NULL DEFAULT NULL COMMENT '等级徽章' AFTER `rules`;
+
+-- 配置 更改字段为空
+ALTER TABLE `__PREFIX__shopro_config` MODIFY COLUMN `content` longtext CHARACTER SET utf8mb4 NULL DEFAULT NULL COMMENT '变量字典数据';
+-- 1.0.7更新 ↑
+
+
+-- 1.2.0 标准版更新 ↓
+
+ALTER TABLE `__PREFIX__shopro_order_item` ADD COLUMN `pay_price` decimal(10, 2) NOT NULL COMMENT '支付金额(不含运费)' AFTER `goods_num`;
+
+CREATE TABLE `__PREFIX__shopro_store_apply`  (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` int(11) NOT NULL COMMENT '用户',
+  `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '门店名称',
+  `images` varchar(2500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '门店图片',
+  `realname` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '联系人',
+  `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '联系电话',
+  `province_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '省',
+  `city_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '市',
+  `area_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '区',
+  `province_id` int(11) NOT NULL COMMENT '省ID',
+  `city_id` int(11) NOT NULL COMMENT '市ID',
+  `area_id` int(11) NOT NULL COMMENT '区ID',
+  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '详细地址',
+  `latitude` decimal(10, 6) NOT NULL DEFAULT 0.000000 COMMENT '纬度',
+  `longitude` decimal(10, 6) NOT NULL DEFAULT 0.000000 COMMENT '经度',
+  `openhours` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '营业时间',
+  `openweeks` set('1','2','3','4','5','6','7') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1,2,3,4,5,6,7' COMMENT '营业天数',
+  `apply_num` int(10) NOT NULL DEFAULT 0 COMMENT '申请次数',
+  `status` enum('-1','0','1') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT '审核状态:-1驳回,0=未审核,1=已通过',
+  `status_msg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '驳回原因',
+  `createtime` int(11) NOT NULL COMMENT '创建时间',
+  `updatetime` int(11) NOT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '门店入驻';
+
+CREATE TABLE `__PREFIX__shopro_chat`  (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `admin_id` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '绑定管理员',
+  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客服昵称',
+  `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客服头像',
+  `max_num` tinyint(3) UNSIGNED NOT NULL DEFAULT 1 COMMENT '接待上限',
+  `lasttime` int(10) NOT NULL DEFAULT 0 COMMENT '上次服务时间',
+  `status` enum('offline','online','busy') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'offline' COMMENT '状态:offline=离线,online=在线',
+  `createtime` int(10) NULL DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) NULL DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '客服表';
+
+CREATE TABLE `__PREFIX__shopro_chat_connection`  (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `session_id` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户标识',
+  `user_id` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '用户',
+  `nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '昵称',
+  `customer_service_id` int(10) NOT NULL DEFAULT 0 COMMENT '客服',
+  `starttime` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '开始时间',
+  `endtime` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '结束时间',
+  `status` enum('waiting','ing','end') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'waiting' COMMENT '状态:watting=等待中,ing=服务中,end=已结束',
+  `createtime` int(10) NULL DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) NULL DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `session_id`(`session_id`) USING BTREE,
+  INDEX `user_id`(`user_id`) USING BTREE,
+  INDEX `customer_service_id`(`customer_service_id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '连接表';
+
+CREATE TABLE `__PREFIX__shopro_chat_fast_reply`  (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '名称',
+  `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '内容',
+  `status` enum('normal','hidden') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'normal' COMMENT '状态:normal=启用,hidden=隐藏',
+  `weigh` int(10) NOT NULL DEFAULT 0 COMMENT '权重',
+  `createtime` int(10) NULL DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) NULL DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '快捷回复';
+
+INSERT INTO `__PREFIX__shopro_chat_fast_reply` (`id`, `name`, `content`, `status`, `weigh`, `createtime`, `updatetime`) VALUES 
+(1, '退款退回问题', '亲,钱款都是按照原支付路径进行退回的,一般会在1~3三个工作日内完成退款,请注意查收', 'normal', 1, 1608629981, 1608629981),
+(2, '红包退回问题', '亲,如果是双11的红包,因为只能当天使用,所以退款的时候,红包将不会退回', 'normal', 2, 1608630134, 1608630134),
+(3, '发货问题', '<span style=\"white-space:normal;\">亲,一般会在下完单两天之内进行发货,如遇双十一等节日最晚会在一周内发货的,请耐心等待</span>', 'normal', 3, 1608630165, 1608630165);
+
+CREATE TABLE `__PREFIX__shopro_chat_log`  (
+  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `session_id` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '会话ID',
+  `user_id` int(11) NOT NULL DEFAULT 0 COMMENT '用户',
+  `sender_identify` enum('customer_service','user') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'user' COMMENT '发送人身份:customer_service=客服,user=用户',
+  `sender_id` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT '发送人ID',
+  `message_type` enum('text','image','file','system','goods','order') CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'text' COMMENT '消息类型:text=文本,image=图片,file=文件,system=系统消息,goods=商品卡片,order=订单卡片',
+  `message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '消息',
+  `readtime` int(10) UNSIGNED NULL DEFAULT NULL COMMENT '读取时间',
+  `createtime` int(10) UNSIGNED NULL DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) NULL DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `session_id`(`session_id`) USING BTREE,
+  INDEX `user_id`(`user_id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '聊天记录表';
+
+CREATE TABLE `__PREFIX__shopro_chat_question`  (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '标题',
+  `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '内容',
+  `status` enum('normal','hidden') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'normal' COMMENT '状态:normal=启用,hidden=隐藏',
+  `weigh` int(10) NOT NULL DEFAULT 0 COMMENT '权重',
+  `createtime` int(10) NULL DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) NULL DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '常见问题';
+
+CREATE TABLE `__PREFIX__shopro_chat_user`  (
+  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `session_id` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '标识',
+  `user_id` int(10) NOT NULL DEFAULT 0 COMMENT '用户',
+  `nickname` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '昵称',
+  `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '头像',
+  `customer_service_id` int(10) NOT NULL DEFAULT 0 COMMENT '最后接待客服',
+  `lasttime` int(10) UNSIGNED NULL DEFAULT NULL COMMENT '上次上线时间',
+  `createtime` int(10) NULL DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(10) NULL DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `session_id`(`session_id`) USING BTREE COMMENT 'session 标识',
+  INDEX `user_id`(`user_id`) USING BTREE COMMENT 'user_id'
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '客服用户表';
+-- 1.2.0 标准版更新 ↑
+
+CREATE TABLE `__PREFIX__shopro_commission_config`  (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '名称',
+  `value` varchar(2500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '值',
+  `group` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '分组',
+  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '描述',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '分销设置';
+
+INSERT INTO `__PREFIX__shopro_commission_config` (`id`, `name`, `value`, `group`, `description`) VALUES 
+(1, 'commission_level', '2', 'basic', '分销层级'),
+(2, 'self_buy', '1', 'basic', '分销内购'),
+(3, 'invite_lock', 'pay', 'basic', '邀请锁定条件'),
+(4, 'agent_check', '1', 'basic', '分销商审核'),
+(5, 'upgrade_check', '1', 'basic', '升级审核'),
+(6, 'upgrade_jump', '1', 'basic', '允许跃级升级:0=否,1=是'),
+(7, 'become_agent', '{\"type\":\"apply\",\"value\":\"\"}', 'agent', '成为分销商条件'),
+(8, 'agent_form', '{\"background_image\":\"https://file.shopro.top/uploads/20200410/c1516571770ee0d100a569fbd851b41d.png\",\"content\":[{\"name\":\"真实姓名\",\"type\":\"input\"},{\"name\":\"手机号\",\"type\":\"number\"},{\"name\":\"身份证正面\",\"type\":\"image\"}]}', 'agent', '完善资料'),
+(9, 'apply_protocol', '0', 'agent', '申请协议'),
+(10, 'commission_price_type', 'pay_price', 'amount', '佣金基础金额'),
+(11, 'commission_event', 'confirm', 'amount', '佣金结算事件'),
+(12, 'upgrade_display', '0', 'basic', '升级进度显示'),
+(13, 'refund_commission_reward', '1', 'amount', '退款扣除佣金'),
+(14, 'refund_commission_order', '1', 'amount', '退款扣除分销业绩');
+
+-- 1.3.0 标准版更新 ↓
+
+CREATE TABLE `__PREFIX__shopro_stock_warning`  (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `goods_id` int(10) NOT NULL DEFAULT 0 COMMENT '商品',
+  `goods_sku_price_id` int(10) NOT NULL DEFAULT 0 COMMENT '规格',
+  `goods_sku_text` varchar(255) NULL DEFAULT NULL COMMENT '中文规格',
+  `stock_warning` int(11) NULL DEFAULT 0 COMMENT '预警值',
+  `createtime` int(11) NULL DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) NULL DEFAULT NULL COMMENT '更新时间',
+  `deletetime` int(11) NULL DEFAULT NULL COMMENT '删除时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '库存预警';
+
+ALTER TABLE `__PREFIX__shopro_goods_sku_price` ADD COLUMN `stock_warning` int(11) NULL DEFAULT NULL COMMENT '库存预警' AFTER `stock`;
+
+ALTER TABLE `__PREFIX__shopro_order` ADD COLUMN `activity_discount_money` decimal(10, 2) NOT NULL DEFAULT '0.00' COMMENT '活动优惠' AFTER `coupon_fee`;
+ALTER TABLE `__PREFIX__shopro_order` MODIFY COLUMN `ext` varchar(2048) NULL DEFAULT NULL COMMENT '附加字段' AFTER `paytime`;
+ALTER TABLE `__PREFIX__shopro_order` ADD INDEX `user_id`(`user_id`) USING BTREE;
+ALTER TABLE `__PREFIX__shopro_order` ADD INDEX `status`(`status`) USING BTREE;
+ALTER TABLE `__PREFIX__shopro_order` ADD INDEX `createtime`(`createtime`) USING BTREE;
+
+ALTER TABLE `__PREFIX__shopro_order_aftersale` ADD INDEX `user_id`(`user_id`) USING BTREE;
+ALTER TABLE `__PREFIX__shopro_order_aftersale` ADD INDEX `order_id`(`order_id`) USING BTREE;
+
+ALTER TABLE `__PREFIX__shopro_order_item` MODIFY COLUMN `goods_sku_text` varchar(60) NULL DEFAULT NULL COMMENT '规格名' AFTER `item_goods_sku_price_id`;
+ALTER TABLE `__PREFIX__shopro_order_item` ADD COLUMN `goods_weight` int(11) NOT NULL DEFAULT 0 COMMENT '商品重量' AFTER `goods_num`;
+ALTER TABLE `__PREFIX__shopro_order_item` ADD INDEX `order_id`(`order_id`) USING BTREE;
+ALTER TABLE `__PREFIX__shopro_order_item` ADD INDEX `store_id`(`store_id`) USING BTREE;
+ALTER TABLE `__PREFIX__shopro_order_item` ADD INDEX `activity_id`(`activity_id`) USING BTREE;
+ALTER TABLE `__PREFIX__shopro_order_item` ADD INDEX `goods_id`(`goods_id`) USING BTREE;
+
+ALTER TABLE `__PREFIX__shopro_share` MODIFY COLUMN `platform` varchar(20) NULL DEFAULT NULL COMMENT '识别平台' AFTER `type_id`;
+ALTER TABLE `__PREFIX__shopro_share` ADD COLUMN `share_platform` varchar(20) NULL DEFAULT NULL COMMENT '分享来源' AFTER `platform`;
+ALTER TABLE `__PREFIX__shopro_share` ADD COLUMN `from` varchar(20) NULL DEFAULT NULL COMMENT '分享方式' AFTER `share_platform`;
+
+ALTER TABLE `__PREFIX__shopro_user_bank` ADD COLUMN `type` enum('bank','alipay') NULL DEFAULT NULL COMMENT '账户类型:bank=银行卡,alipay=支付宝账户' AFTER `user_id`;
+
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` ADD COLUMN `apply_sn` varchar(60) NULL DEFAULT NULL COMMENT '提现单号' AFTER `user_id`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` CHANGE `get_type` `apply_type` enum('bank','wechat','alipay') NULL DEFAULT NULL COMMENT '收款类型:bank=银行卡,wechat=微信零钱,alipay=支付宝' AFTER `apply_sn`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` ADD COLUMN `actual_money` decimal(10, 2) NOT NULL DEFAULT '0.00' COMMENT '实际到账' AFTER `money`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` MODIFY COLUMN `service_fee` decimal(10, 3) NULL DEFAULT NULL COMMENT '手续费率' AFTER `charge_money`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` CHANGE `bank_info` `apply_info` varchar(255) NULL DEFAULT NULL COMMENT '打款信息' AFTER `service_fee`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` MODIFY COLUMN `status` tinyint(1) NULL DEFAULT 0 COMMENT '提现状态:-1=已拒绝,0=待审核,1=处理中,2=已处理' AFTER `apply_info`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` ADD COLUMN `platform` varchar(20) NULL DEFAULT NULL COMMENT '平台' AFTER `status`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` ADD COLUMN `payment_json` varchar(2500) NULL DEFAULT NULL COMMENT '交易原始数据' AFTER `platform`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` ADD COLUMN `log` text NULL COMMENT '操作日志' AFTER `updatetime`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` ADD UNIQUE INDEX `apply_sn`(`apply_sn`) USING BTREE COMMENT '提现单号';
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` DROP COLUMN `bank_id`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` DROP COLUMN `real_name`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` DROP COLUMN `status_msg`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_apply` DROP COLUMN `deletetime`;
+
+ALTER TABLE `__PREFIX__shopro_user_wallet_log` MODIFY COLUMN `type` varchar(30) NOT NULL COMMENT '变动类型' AFTER `wallet_type`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_log` ADD COLUMN `before` decimal(10, 2) NOT NULL COMMENT '变动前' AFTER `type`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_log` ADD COLUMN `after` decimal(10, 2) NOT NULL COMMENT '变动后' AFTER `before`;
+ALTER TABLE `__PREFIX__shopro_user_wallet_log` ADD COLUMN `memo` varchar(255) NULL DEFAULT '' COMMENT '备注' AFTER `item_id`;
+
+ALTER TABLE `__PREFIX__shopro_wechat_fans` MODIFY COLUMN `headimgurl` varchar(255) NULL DEFAULT NULL COMMENT '粉丝头像' AFTER `nickname`;
+ALTER TABLE `__PREFIX__shopro_wechat_fans` MODIFY COLUMN `openid` varchar(30) NULL DEFAULT NULL COMMENT 'openid' AFTER `headimgurl`;
+ALTER TABLE `__PREFIX__shopro_wechat_fans` MODIFY COLUMN `sex` int(11) NULL DEFAULT 0 COMMENT '性别' AFTER `openid`;
+ALTER TABLE `__PREFIX__shopro_wechat_fans` MODIFY COLUMN `country` varchar(50) NULL DEFAULT NULL COMMENT '国家' AFTER `sex`;
+ALTER TABLE `__PREFIX__shopro_wechat_fans` MODIFY COLUMN `province` varchar(50) NULL DEFAULT NULL COMMENT '省' AFTER `country`;
+ALTER TABLE `__PREFIX__shopro_wechat_fans` MODIFY COLUMN `city` varchar(50) NULL DEFAULT NULL COMMENT '市' AFTER `province`;
+ALTER TABLE `__PREFIX__shopro_wechat_fans` MODIFY COLUMN `subscribe` enum('0','1') NULL DEFAULT NULL COMMENT '关注状态:0=取消关注,1=已关注' AFTER `city`;
+ALTER TABLE `__PREFIX__shopro_wechat_fans` MODIFY COLUMN `subscribe_time` int(11) NULL DEFAULT NULL COMMENT '关注时间' AFTER `subscribe`;
+ALTER TABLE `__PREFIX__shopro_wechat_fans` MODIFY COLUMN `createtime` int(11) NULL DEFAULT NULL COMMENT '创建时间' AFTER `subscribe_time`;
+ALTER TABLE `__PREFIX__shopro_wechat_fans` MODIFY COLUMN `updatetime` int(11) NULL DEFAULT NULL COMMENT '更新时间' AFTER `createtime`;
+
+ALTER TABLE `__PREFIX__shopro_user_oauth` MODIFY COLUMN `country` varchar(50) NULL DEFAULT NULL COMMENT '国家' AFTER `sex`;
+ALTER TABLE `__PREFIX__shopro_user_oauth` MODIFY COLUMN `province` varchar(50) NULL DEFAULT NULL COMMENT '省' AFTER `country`;
+ALTER TABLE `__PREFIX__shopro_user_oauth` MODIFY COLUMN `city` varchar(50) NULL DEFAULT NULL COMMENT '市' AFTER `province`;
+ALTER TABLE `__PREFIX__shopro_user_oauth` ADD INDEX `openid`(`openid`) USING BTREE;
+-- 1.3.0 标准版更新 ↑
+
+
+
+-- 1.3.2 标准版更新 ↓
+
+ALTER TABLE `__PREFIX__shopro_order` ADD COLUMN `dispatch_discount_money` decimal(10, 2) NOT NULL DEFAULT '0.00' COMMENT '运费优惠' AFTER `activity_discount_money`;
+
+-- 1.3.2 标准版更新 ↑
+
+COMMIT;

+ 57 - 0
addons/shopro/job/ActivityAutoOper.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace addons\shopro\job;
+
+use addons\shopro\library\traits\ActivityCache;
+use addons\shopro\model\Activity;
+use think\queue\Job;
+
+
+/**
+ * 订单自动操作
+ */
+class ActivityAutoOper extends BaseJob
+{
+    use ActivityCache;
+
+    /**
+     * 活动自动删除
+     */
+    public function autoClose(Job $job, $data){
+        try {
+            $activity = $data['activity'];
+
+            $activity = Activity::get($activity['id']);
+
+            // 一个活动会存在多个队列,要排重
+            if ($activity) {
+                // 如果活动还没被删除
+
+                // 规则
+                $rules = $activity['rules'];
+
+                // 当前配置应该自动结束的时间
+                $laterTime = $activity['endtime'];
+                if (isset($rules['activity_auto_close']) && $rules['activity_auto_close'] > 0) {
+                    $laterTime += ($rules['activity_auto_close'] * 60);
+                }
+
+                // 如果当前时间大于 laterTime,可以执行删除
+                if (time() >= $laterTime) {
+                    // 删除活动 【软删】
+                    $activity->delete();
+
+                    // 删除活动缓存
+                    $this->delActivity($activity);
+                }
+            }
+
+            // 删除 job
+            $job->delete();
+        } catch (\Exception $e) {
+            // 队列执行失败
+            \think\Log::write('queue-' . get_class() . '-autoClose' . ':执行失败,错误信息:' . $e->getMessage());
+        }
+    }
+    
+}

+ 57 - 0
addons/shopro/job/ActivityGrouponAutoOper.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace addons\shopro\job;
+
+use addons\shopro\library\traits\ActivityCache;
+use addons\shopro\library\traits\Groupon;
+use addons\shopro\model\Activity;
+use addons\shopro\model\ActivityGroupon;
+use think\queue\Job;
+
+
+/**
+ * 订单自动操作
+ */
+class ActivityGrouponAutoOper extends BaseJob
+{
+    use ActivityCache, Groupon;
+
+    /**
+     * 拼团判断,将团结束, 
+     */
+    public function expire(Job $job, $data){
+        try {
+            $activity = $data['activity'];
+            $activity_groupon_id = $data['activity_groupon_id'];
+            $activityGroupon = ActivityGroupon::where('id', $activity_groupon_id)->find();
+
+            // 活动正在进行中, 走这里的说明人数 都没满
+            if ($activityGroupon && $activityGroupon['status'] == 'ing') {
+                \think\Db::transaction(function () use ($activity, $activityGroupon) {
+                    $rules = $activity['rules'];
+                    // 是否虚拟成团
+                    $is_fictitious = $rules['is_fictitious'] ?? 0;
+                    // 最大虚拟人数 ,不填或者 "" 不限制人数,都允许虚拟成团, 0相当于不允许虚拟成团
+                    $fictitious_num = (!isset($rules['fictitious_num']) || $rules['fictitious_num'] == '') ? 'no-limit' : $rules['fictitious_num'];
+                    // 拼团剩余人数
+                    $surplus_num = $activityGroupon['num'] - $activityGroupon['current_num'];
+
+                    if ($is_fictitious && ($fictitious_num == 'no-limit' || $fictitious_num >= $surplus_num)) {
+                        // 虚拟成团,如果虚拟用户不够,则自动解散
+                        $this->finishFictitiousGroupon($activityGroupon);
+                    } else {
+                        // 解散退款
+                        $this->invalidRefundGroupon($activityGroupon);
+                    }
+                });
+            }
+
+            // 删除 job
+            $job->delete();
+        } catch (\Exception $e) {
+            // 队列执行失败
+            \think\Log::write('queue-' . get_class() . '-expire' . ':执行失败,错误信息:' . $e->getMessage());
+        }
+    }
+    
+}

+ 25 - 0
addons/shopro/job/BaseJob.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace addons\shopro\job;
+
+use addons\shopro\model\Order;
+use addons\shopro\model\OrderAction;
+use think\queue\Job;
+
+
+/**
+ * BaseJob 基类
+ */
+class BaseJob
+{
+
+    public function failed($data){
+        // 记录日志
+        \think\Db::name('shopro_failed_job')->insert([
+            'data' => json_encode($data),
+            'createtime' => time(),
+            'updatetime' => time()
+        ]);
+    }
+
+}

+ 40 - 0
addons/shopro/job/Notification.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace addons\shopro\job;
+
+use think\queue\Job;
+
+/**
+ * 队列消息通知
+ */
+class Notification extends BaseJob
+{
+    /**
+     * 发送通知
+     */
+    public function send(Job $job, $data){
+        try {
+            // 这里获取到的 $notifiables 和 notification 两个都是数组,不是类,尴尬, 更可恨的 notification 只是 {"delay":0,"event":"changemobile"}
+            $notifiables = $data['notifiables'];
+            $notification = $data['notification'];
+            // 因为 notification 只有参数,需要把对应的类传过来,在这里重新初始化
+            $notification_name = $data['notification_name'];
+
+            // 重新实例化 notification 实例
+            if (class_exists($notification_name)) {
+                $notification = new $notification_name($notification['data']);
+
+                // 发送消息
+                \addons\shopro\library\notify\Notify::sendNow($notifiables, $notification);
+            }
+            
+            // 删除 job
+            $job->delete();
+        } catch (\Exception $e) {
+            // 队列执行失败
+            \think\Log::error('queue-' . get_class()
+                . (isset($notification->event) ? ('-' . $notification->event) : '') 
+                . ':执行失败,错误信息:' . $e->getMessage());
+        }
+    }
+}

+ 135 - 0
addons/shopro/job/OrderAutoOper.php

@@ -0,0 +1,135 @@
+<?php
+
+namespace addons\shopro\job;
+
+use addons\shopro\model\GoodsComment;
+use addons\shopro\model\Order;
+use addons\shopro\model\OrderAction;
+use addons\shopro\model\OrderItem;
+use addons\shopro\model\Config;
+use think\queue\Job;
+
+
+/**
+ * 订单自动操作
+ */
+class OrderAutoOper extends BaseJob
+{
+
+    /**
+     * 订单自动关闭
+     */
+    public function autoClose(Job $job, $data){
+        try {
+            $order = $data['order'];
+
+            $order = Order::get($order['id']);
+
+            if ($order && $order['status'] == 0) {
+                \think\Db::transaction(function () use ($order, $data) {
+                    // 订单关闭前
+                    \think\Hook::listen('order_close_before', $data);
+                    // 执行关闭
+                    $order->status = Order::STATUS_INVALID;
+                    $order->ext = json_encode($order->setExt($order, ['invalid_time' => time()]));      // 取消时间
+                    $order->save();
+    
+                    OrderAction::operAdd($order, null, null, 'system', '系统自动失效订单');
+    
+                    // 订单自动关闭之后 行为 返还用户优惠券,积分
+                    $data = ['order' => $order];
+                    \think\Hook::listen('order_close_after', $data);
+                });
+            }
+
+            // 删除 job
+            $job->delete();
+        } catch (\Exception $e) {
+            // 队列执行失败
+            \think\Log::write('queue-' . get_class() . '-autoClose' . ':执行失败,错误信息:' . $e->getMessage());
+        }
+    }
+
+
+    /**
+     * 订单自动确认
+     */
+    public function autoConfirm(Job $job, $data) {
+        try {
+            $order = $data['order'];
+            $item = $data['item'];
+
+            // 只要没有退款成功,所有队列正常执行
+            $item = OrderItem::where('id', $item['id'])
+                            ->where('dispatch_status', OrderItem::DISPATCH_STATUS_SENDED)
+                            ->where('refund_status', 'not in', [OrderItem::REFUND_STATUS_OK, OrderItem::REFUND_STATUS_FINISH])
+                            ->find();
+
+            if ($item) {
+                \think\Db::transaction(function () use ($order, $item, $data) {
+                    (new Order())->getedItem($order, $item, ['oper_type' => 'system']);
+                });
+            }
+
+            // 删除 job
+            $job->delete();
+        } catch (\Exception $e) {
+            // 队列执行失败
+            \think\Log::write('queue-' . get_class() . '-autoConfirm' . ':执行失败,错误信息:' . $e->getMessage());
+        }
+    }
+
+
+
+    public function autoComment(Job $job, $data) {
+        try {
+            $order = $data['order'];
+            $item = $data['item'];
+
+            // 只要没有退款成功,所有队列正常执行
+            $item = OrderItem::where('id', $item['id'])
+                ->where('dispatch_status', OrderItem::DISPATCH_STATUS_GETED)
+                ->where('comment_status', OrderItem::COMMENT_STATUS_NO)
+                ->where('refund_status', 'not in', [OrderItem::REFUND_STATUS_OK, OrderItem::REFUND_STATUS_FINISH])
+                ->find();
+
+            if ($item) {
+                \think\Db::transaction(function () use ($order, $item, $data) {
+                    // 订单评价前
+                    \think\Hook::listen('order_comment_before', $data);
+
+                    // 获取自动好评内容
+                    $config = Config::where('name', 'order')->cache(300)->find();        // 读取配置自动缓存 5 分钟
+                    $config = isset($config) ? json_decode($config['value'], true) : [];
+                    $comment_content = (isset($config['order_comment_content']) && $config['order_comment_content'])
+                                ? $config['order_comment_content'] : '用户默认好评';       // 单位天 
+
+                    GoodsComment::create([
+                        'goods_id' => $item['goods_id'],
+                        'order_id' => $order['id'],
+                        'user_id' => $order['user_id'],
+                        'level' => 5,           // 自动好评
+                        'content' => $comment_content,
+                        'images' => '',
+                        'status' => 'show'
+                    ]);
+
+                    $item->comment_status = OrderItem::COMMENT_STATUS_OK;        // 评价成功
+                    $item->save();
+
+                    OrderAction::operAdd($order, $item, null, 'system', '系统自动评价成功');
+
+                    // 订单评价后
+                    $data = ['order' => $order, 'item' => $item];
+                    \think\Hook::listen('order_comment_after', $data);
+                });
+            }
+
+            // 删除 job
+            $job->delete();
+        } catch (\Exception $e) {
+            // 队列执行失败
+            \think\Log::write('queue-' . get_class() . '-autoComment' . $e->getMessage());
+        }
+    }
+}

+ 66 - 0
addons/shopro/job/OrderPayed.php

@@ -0,0 +1,66 @@
+<?php
+
+namespace addons\shopro\job;
+
+use addons\shopro\library\traits\ActivityCache;
+use addons\shopro\library\traits\Groupon;
+use addons\shopro\library\traits\StockSale;
+use addons\shopro\model\GoodsComment;
+use addons\shopro\model\Order;
+use addons\shopro\model\OrderAction;
+use addons\shopro\model\OrderItem;
+use think\queue\Job;
+
+/**
+ * 订单支付完成
+ */
+class OrderPayed extends BaseJob
+{
+    use StockSale, ActivityCache, Groupon;
+
+    /**
+     * 订单支付完成
+     */
+    public function payed(Job $job, $data){
+        try {
+            $order = $data['order'];
+            $user = $data['user'];
+
+            $order = Order::with('item')->where('id', $order['id'])->find();
+
+            // 数据库删订单的问题常见,这里被删的订单直接把队列移除
+            if ($order) {
+                \think\Db::transaction(function () use ($order, $user, $data) {
+                    // 订单减库存
+                    $this->realForwardStockSale($order);
+    
+                    // 判断,如果是拼团 真实加入团
+                    if (strpos($order['activity_type'], 'groupon') !== false) {
+                        $this->joinGroupon($order, $user);
+                    }
+
+                    // 触发订单支付完成事件, 如果这个订单刚好完成拼团,并且是自动发货订单,则这个订单的自动发货事件会比订单支付之后事件早
+                    $data = ['order' => $order];
+                    \think\Hook::listen('order_payed_after', $data);
+
+                    // 检测有没有自动发货的商品,有就自动发货
+                    $order->checkDispatchAndSend($order, ['user' => $user]);
+                });
+            }
+            
+            // 删除 job
+            $job->delete();
+        } catch (\Exception $e) {
+            // 队列执行失败
+            $error = json_encode([
+            'a' => $e->getLine(),
+            'b' => $e->getFile(),
+            'c' =>$e->getTrace(),
+            'd' => $e->getMessage()
+            ], JSON_UNESCAPED_UNICODE);
+
+            
+            \think\Log::error('queue-' . get_class() . '-payed' . ':执行失败,错误信息:' . $error);
+        }
+    }
+}

+ 74 - 0
addons/shopro/job/Wechat.php

@@ -0,0 +1,74 @@
+<?php
+
+namespace addons\shopro\job;
+
+use think\queue\Job;
+
+/**
+ * 微信任务
+ */
+class Wechat extends BaseJob
+{
+    /**
+     * 异步分批创建新的队列任务
+     */
+    public function createQueueByOpenIdsArray(Job $job, $openIdsArray)
+    {
+        try {
+            $count = count($openIdsArray);
+            if ($count > 0) {
+                $page = ceil($count / 100);
+                for ($i = 0; $i < $page; $i++) {
+                    \think\Queue::push('\addons\shopro\job\Wechat@saveSubscribeUserInfo', array_slice($openIdsArray, $i * 100, 100), 'shopro');
+                }
+            }
+            // 删除 job
+            $job->delete();
+        } catch (\Exception $e) {
+            // 队列执行失败
+            \think\Log::error('queue-' . get_class() . '-createQueueByOpenIdsArray' . ':执行失败,错误信息:' . $e->getMessage());
+        }
+    }
+
+    /**
+     * 保存更新关注用户
+     */
+    public function saveSubscribeUserInfo(Job $job, $openIdsArray)
+    {
+        try {
+            $wechat = new \addons\shopro\library\Wechat('wxOfficialAccount');
+            $result = $wechat->getSubscribeUserInfoByOpenId($openIdsArray);
+
+            if (isset($result['user_info_list'])) {
+                $userInfoList = $result['user_info_list'];
+                $insertData = [];
+                foreach ($userInfoList as $u) {
+                    $wechatFans = \app\admin\model\shopro\wechat\Fans::get(['openid' => $u['openid']]);
+                    if ($wechatFans) {
+                        $wechatFans->save([
+                            'nickname' => $u['nickname'],
+                            'headimgurl' => $u['headimgurl'],
+                            'sex' => $u['sex'],
+                            'country' => $u['country'],
+                            'province' => $u['province'],
+                            'city' => $u['city'],
+                            'subscribe' => 1,
+                            'subscribe_time' => $u['subscribe_time']
+                        ]);
+                    }else{
+                        $insertData[] = $u;
+                    }
+                }
+                if (count($insertData) > 0) {
+                    $wechatFans = new \app\admin\model\shopro\wechat\Fans;
+                    $wechatFans->allowField(true)->saveAll($insertData);
+                }
+
+            }
+            $job->delete();
+        } catch (\Exception $e) {
+            // 队列执行失败
+            \think\Log::error('queue-' . get_class() . '-saveSubscribeUserInfo' . ':执行失败,错误信息2:' . $e->getMessage() . '|' . json_encode($insertData, JSON_UNESCAPED_UNICODE));
+        }
+    }
+}

+ 84 - 0
addons/shopro/lang/zh-cn.php

@@ -0,0 +1,84 @@
+<?php
+
+return [
+    'Keep login'                                  => '保持会话',
+    'Username'                                    => '用户名',
+    'User id'                                     => '会员ID',
+    'Nickname'                                    => '昵称',
+    'Password'                                    => '密码',
+    'Sign up'                                     => '注 册',
+    'Sign in'                                     => '登 录',
+    'Sign out'                                    => '注 销',
+    'Guest'                                       => '游客',
+    'Welcome'                                     => '%s,你好!',
+    'Add'                                         => '添加',
+    'Edit'                                        => '编辑',
+    'Delete'                                      => '删除',
+    'Move'                                        => '移动',
+    'Name'                                        => '名称',
+    'Status'                                      => '状态',
+    'Weigh'                                       => '权重',
+    'Operate'                                     => '操作',
+    'Warning'                                     => '温馨提示',
+    'Default'                                     => '默认',
+    'Article'                                     => '文章',
+    'Page'                                        => '单页',
+    'OK'                                          => '确定',
+    'Cancel'                                      => '取消',
+    'Loading'                                     => '加载中',
+    'More'                                        => '更多',
+    'Normal'                                      => '正常',
+    'Hidden'                                      => '隐藏',
+    'Submit'                                      => '提交',
+    'Reset'                                       => '重置',
+    'Execute'                                     => '执行',
+    'Close'                                       => '关闭',
+    'Search'                                      => '搜索',
+    'Refresh'                                     => '刷新',
+    'First'                                       => '首页',
+    'Previous'                                    => '上一页',
+    'Next'                                        => '下一页',
+    'Last'                                        => '末页',
+    'None'                                        => '无',
+    'Home'                                        => '主页',
+    'Online'                                      => '在线',
+    'Logout'                                      => '注销',
+    'Profile'                                     => '个人资料',
+    'Index'                                       => '首页',
+    'Hot'                                         => '热门',
+    'Recommend'                                   => '推荐',
+    'Dashboard'                                   => '控制台',
+    'Code'                                        => '编号',
+    'Message'                                     => '内容',
+    'Line'                                        => '行号',
+    'File'                                        => '文件',
+    'Menu'                                        => '菜单',
+    'Type'                                        => '类型',
+    'Title'                                       => '标题',
+    'Content'                                     => '内容',
+    'Append'                                      => '追加',
+    'Memo'                                        => '备注',
+    'Parent'                                      => '父级',
+    'Params'                                      => '参数',
+    'Permission'                                  => '权限',
+    'Advance search'                              => '高级搜索',
+    'Check all'                                   => '选中全部',
+    'Expand all'                                  => '展开全部',
+    'Begin time'                                  => '开始时间',
+    'End time'                                    => '结束时间',
+    'Create time'                                 => '创建时间',
+    'Flag'                                        => '标志',
+    'Please login first'                          => '请登录后操作',
+    'Redirect now'                                => '立即跳转',
+    'Operation completed'                         => '操作成功!',
+    'Operation failed'                            => '操作失败!',
+    'Unknown data format'                         => '未知的数据格式!',
+    'Network error'                               => '网络错误!',
+    'Advanced search'                             => '高级搜索',
+    'Invalid parameters'                          => '未知参数',
+    'No results were found'                       => '记录未找到',
+    'Parameter %s can not be empty'               => '参数%s不能为空',
+    'You have no permission'                      => '你没有权限访问',
+    'An unexpected error occurred'                => '发生了一个意外错误,程序猿正在紧急处理中',
+    'This page will be re-directed in %s seconds' => '页面将在 %s 秒后自动跳转',
+];

+ 8 - 0
addons/shopro/lang/zh-cn/common.php

@@ -0,0 +1,8 @@
+<?php
+
+return [
+    'No file upload or server upload limit exceeded' => '未上传文件或超出服务器上传限制',
+    'Uploaded file format is limited'                => '上传文件格式受限制',
+    'Uploaded file is not a valid image'             => '上传文件不是有效的图片文件',
+    'Upload successful'                              => '上传成功',
+];

+ 39 - 0
addons/shopro/lang/zh-cn/user.php

@@ -0,0 +1,39 @@
+<?php
+
+return [
+    'User center'                           => '会员中心',
+    'Register'                              => '注册',
+    'Login'                                 => '登录',
+    'Sign up successful'                    => '注册成功',
+    'Username can not be empty'             => '用户名不能为空',
+    'Username must be 6 to 30 characters'   => '用户名必须6-30个字符',
+    'Password can not be empty'             => '密码不能为空',
+    'Password must be 6 to 30 characters'   => '密码必须6-30个字符',
+    'Mobile is incorrect'                   => '手机格式不正确',
+    'Username already exist'                => '用户名已经存在',
+    'Email already exist'                   => '邮箱已经存在',
+    'Mobile already exists'                 => '手机号已经存在',
+    'Mobile is binded'                      => '绑定成功',
+    'Username is incorrect'                 => '用户名不正确',
+    'Email is incorrect'                    => '邮箱不正确',
+    'Account is locked'                     => '账户已经被锁定',
+    'Password is incorrect'                 => '密码不正确',
+    'Account is incorrect'                  => '账户不正确',
+    'Account not exist'                     => '账户不存在',
+    'User not found'                     =>    '账户不存在',
+    'Account can not be empty'              => '账户不能为空',
+    'Username or password is incorrect'     => '用户名或密码不正确',
+    'You are not logged in'                 => '你当前还未登录',
+    'You\'ve logged in, do not login again' => '你已经存在,请不要重复登录',
+    'Profile'                               => '个人资料',
+    'Verify email'                          => '邮箱验证',
+    'Change password'                       => '修改密码',
+    'Captcha is incorrect'                  => '验证码不正确',
+    'Logged in successful'                  => '登录成功',
+    'Logout successful'                     => '注销成功',
+    'Operation failed'                      => '操作失败',
+    'Invalid parameters'                    => '参数不正确',
+    'Change password failure'               => '修改密码失败',
+    'Change password successful'            => '修改密码成功',
+    'Reset password successful'             => '重置密码成功',
+];

+ 116 - 0
addons/shopro/library/Export.php

@@ -0,0 +1,116 @@
+<?php
+
+namespace addons\shopro\library;
+
+use EasyWeChat\Factory;
+use PhpOffice\PhpSpreadsheet\Spreadsheet;
+use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
+use League\Flysystem\Adapter\Local;
+use League\Flysystem\Filesystem;
+use Cache\Adapter\Filesystem\FilesystemCachePool;
+use addons\shopro\library\Redis;
+/**
+ *
+ */
+class Export
+{
+
+
+    public function __construct()
+    {
+    }
+
+    public function exportExcel($expTitle, $expCellName, $expTableData, &$spreadsheet = null, &$sheet = null, $pages = [])
+    {
+        $page = $pages['page'] ?? 1;
+        $page_size = $pages['page_size'] ?? 1000;
+        $is_last_page = $pages['is_last_page'] ?? 1;
+        $current_total = $pages['current_total'] ?? 0;
+
+        if ($current_total) {
+            // 每次传来的 expTableData 数据条数不等,比如订单导出
+            $base_cell = $current_total - count($expTableData) + 2;
+        }else {
+            $base_cell = ($page - 1) * $page_size + 2;
+        }
+
+        $fileName = $expTitle;
+        $cellNum = count($expCellName);
+        $dataNum = count($expTableData);
+        $cellName = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ');
+
+        if ($page == 1) {
+            // 不限时
+            set_time_limit(0);
+            // 根据需要调大内存限制
+            ini_set('memory_limit', '512M');
+            
+            $cache_type = 'redis';
+            // 设置缓存
+            if ($cache_type == 'redis' && class_exists(\Cache\Adapter\Redis\RedisCachePool::class)) {
+                // 将表格数据暂存 redis,可以降低 php 进程内存占用,需要安装扩展包  composer require cache/simple-cache-bridge cache/redis-adapter
+                $options = [
+                    // 'select' => 0        // 注释解开,并且换成一个空的 select 库,redis 库默认是 0-15 共 16 个库
+                ];
+
+                $redis = (new Redis($options))->getRedis();
+                $pool = new \Cache\Adapter\Redis\RedisCachePool($redis);
+                $simpleCache = new \Cache\Bridge\SimpleCache\SimpleCacheBridge($pool);
+
+                \PhpOffice\PhpSpreadsheet\Settings::setCache($simpleCache);
+            } else if ($cache_type == 'file' && class_exists(FilesystemCachePool::class)) {
+                // 将数据暂存磁盘,可以降低内存,但是导出速度会大幅下降 需要安装扩展包  composer require cache/filesystem-adapter
+                $path = ROOT_PATH . 'runtime' . DS . 'export/';
+                @mkdir($path);
+                $filesystemAdapter = new Local($path);
+                $filesystem        = new Filesystem($filesystemAdapter);
+                $pool = new FilesystemCachePool($filesystem);
+    
+                \PhpOffice\PhpSpreadsheet\Settings::setCache($pool);
+            }
+
+            // 实例化excel
+            $spreadsheet = new Spreadsheet();
+            // 初始化工作簿
+            $sheet = $spreadsheet->getActiveSheet(0);
+            // 给表头设置边框
+            $sheet->getStyle('A1:' . $cellName[$cellNum - 1] . '1')->getFont()->setBold(true);
+
+            // 表头
+            $i = 0;
+            foreach ($expCellName as $key => $cell) {
+                $sheet->setCellValue($cellName[$i] . '1', $cell);
+                $i++;
+            }
+        }
+
+        // for ($i = 0; $i < $cellNum; $i++) {
+        //     $sheet->getColumnDimension($cellName[$i])->setWidth(30);
+        // }
+
+        // 写入数据
+        for ($i = 0; $i < $dataNum; $i++) {
+            if ($is_last_page && $i == ($dataNum - 1)) {
+                $sheet->mergeCells('A' . ($i + $base_cell) . ':' . $cellName[$cellNum - 1] . ($i + $base_cell));
+                $sheet->setCellValue('A' . ($i + $base_cell), $expTableData[$i][key($expCellName)]);
+            } else {
+                $j = 0;
+                foreach ($expCellName as $key => $cell) {
+                    $sheet->setCellValue($cellName[$j] . ($i + $base_cell), $expTableData[$i][$key]);
+                    $j++;
+                }
+            }
+        }
+
+        if ($is_last_page) {
+            // ini_set('memory_limit', '256M');
+
+            ob_end_clean();
+            header('pragma:public');
+            header('Content-type:application/vnd.ms-excel;charset=utf-8;name="' . $fileName . '.xlsx"');
+            header("Content-Disposition:attachment;filename=$fileName.xlsx"); //attachment新窗口打印inline本窗口打印
+            $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
+            $writer->save('php://output');
+        }
+    }
+}

+ 230 - 0
addons/shopro/library/Express.php

@@ -0,0 +1,230 @@
+<?php
+
+namespace addons\shopro\library;
+
+use fast\Http;
+
+class Express
+{
+    // 查询接口
+    const REQURL = "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx";
+    // 订阅接口
+    const SUBURL = "https://api.kdniao.com/api/dist";
+    // 电子面单下单接口
+    const API_EORDER = "https://api.kdniao.com/api/EOrderService";
+    protected $config = [];
+
+    /**
+     * 构造函数
+     */
+    public function __construct()
+    {
+        $config = \addons\shopro\model\Config::get(['name' => 'services']);
+        $config = ($config && $config->value) ? json_decode($config->value, true) : [];
+
+        $expressConfig = $config['express'] ?? [];
+        if (!$expressConfig || !$expressConfig['ebusiness_id'] || !$expressConfig['appkey']) {
+            throw new \Exception('请配置快递接口');
+        }
+
+        $this->config = $expressConfig;
+    }
+
+
+    /**
+     * Json方式  物流信息订阅
+     */
+    public function subscribe($data = [], $orderExpress = null, $order = null)
+    {
+        $requestData = $this->getRequestData($data, $orderExpress, $order);
+
+        $datas = [
+            'EBusinessID' => $this->config['ebusiness_id'],
+            'RequestType' => $this->config['type'] == 'free' ? '1008' : '8008',
+            'RequestData' => urlencode($requestData),
+            'DataType' => '2',
+        ];
+        $datas['DataSign'] = $this->encrypt($requestData, $this->config['appkey']);
+
+        $result = Http::sendRequest(self::SUBURL, $datas, 'POST', []);
+
+        if ($result['ret'] == 1) {
+            $exResult = json_decode($result['msg'], true);
+
+            if (!$exResult['Success']) {
+                throw new \Exception($exResult['Reason']);
+            }
+
+            return $exResult;
+        } else {
+            throw new \Exception($result['msg']);
+        }
+    }
+
+
+    // 查询快递信息
+    public function search($data = [], $orderExpress = null, $order = null)
+    {
+        $requestData = $this->getRequestData($data, $orderExpress, $order);
+        
+        $datas = [
+            'EBusinessID' => $this->config['ebusiness_id'],
+            'RequestType' => $this->config['type'] == 'free' ? '1002' : '8001',
+            'RequestData' => urlencode($requestData),
+            'DataType' => '2',
+        ];
+        $datas['DataSign'] = $this->encrypt($requestData, $this->config['appkey']);
+        $result = Http::sendRequest(self::REQURL, $datas, 'POST', []);
+
+        if ($result['ret'] == 1) {
+            $exResult = json_decode($result['msg'], true);
+
+            if (!$exResult['Success']) {
+                throw new \Exception($exResult['Reason']);
+            }
+
+            return $exResult;
+        } else {
+            throw new \Exception($result['msg']);
+        }
+    }
+
+
+    // 组装请求数据
+    private function getRequestData($data = [], $orderExpress = null, $order = null) {
+        $requestData = [
+            'OrderCode' => $order ? $order->order_sn : '',
+            'ShipperCode' => $data['express_code'],
+            'LogisticCode' => $data['express_no'],
+        ];
+
+        if ($data['express_code'] == 'JD') {
+            // 京东青龙配送单号
+            $requestData['CustomerName'] = $this->config['jd_code'];
+        } else if ($data['express_code'] == 'SF') {
+            // 收件人手机号后四位
+            $requestData['CustomerName'] = substr($order->phone, 7);
+        }
+
+        $requestData = json_encode($requestData);
+
+        return $requestData;
+    }
+
+
+
+    // 差异更新物流信息
+    public function checkAndAddTraces ($orderExpress, $express) {
+        $traces = $express['Traces'];
+
+        // 查询现有轨迹记录
+        $orderExpressLog = \addons\shopro\model\OrderExpressLog::where('order_express_id', $orderExpress->id)->select();
+
+        $log_count = count($orderExpressLog);
+        if ($log_count > 0) {
+            // 移除已经存在的记录
+            array_splice($traces, 0, $log_count);
+        }
+
+        // 增加包裹记录
+        foreach ($traces as $k => $trace) {
+            $orderExpressLog = new \addons\shopro\model\OrderExpressLog();
+    
+            $orderExpressLog->user_id = $orderExpress['user_id'];
+            $orderExpressLog->order_id = $orderExpress['order_id'];
+            $orderExpressLog->order_express_id = $orderExpress['id'];
+            $orderExpressLog->status = $trace['Action'] ?? $express['State'];
+            $orderExpressLog->content = $trace['AcceptStation'];
+            $orderExpressLog->changedate = substr($trace['AcceptTime'], 0, 19);     // 快递鸟测试数据 返回的是个 2020-08-03 16:58:272 格式
+            $orderExpressLog->location = $trace['Location'] ?? ($express['Location'] ?? null);
+            $orderExpressLog->save();
+        }
+    }
+
+    public function eorder($order, $item_lists)
+    {
+        if($this->config['type'] !== 'vip') {
+            throw new \Exception('请使用快递鸟标准版开通此功能');
+        }
+        $orderData = [
+            "OrderCode" => $order->order_sn,
+            "CustomerName" => $this->config['CustomerName'],
+            "CustomerPwd" => $this->config['CustomerPwd'],
+            "ShipperCode" => $this->config['ShipperCode'],
+            "PayType" => $this->config['PayType'],
+            "ExpType" => $this->config['ExpType'],
+            "IsReturnPrintTemplate" => 0,   //返回打印面单模板
+            "TemplateSize" => '130',    // 一联单   
+            "Sender" => $this->config['Sender'],
+            "Volume" => 0,
+            "Remark" => $order->remark ? $order->remark : "小心轻放"
+          ];
+          $totalCount = 0;
+          $totalWeight = 0;
+          foreach($item_lists as $k => $item) {
+            if($item->goods_sku_text) {
+                $goodsName = $item->goods_title . '-' . $item->goods_sku_text;
+            }else {
+                $goodsName = $item->goods_title;
+            }
+            $orderData['Commodity'][] = [
+                "GoodsName" =>  $goodsName,
+                "Goodsquantity" => $item->goods_num,
+                "GoodsWeight" => $item->goods_num * $item->goods_weight
+            ];
+            $totalCount += $item->goods_num;
+            $totalWeight += $item->goods_num * $item->goods_weight;
+          }
+          $orderData['Quantity'] = $totalCount; // 商品数量
+          $orderData['Weight'] = $totalWeight;
+          $orderData['Receiver'] = [
+            "Name" => $order->consignee,
+            "Mobile" => $order->phone,
+            "ProvinceName" => $order->province_name,
+            "CityName" => $order->city_name,
+            "ExpAreaName" => $order->area_name,
+            "Address" => $order->address
+          ];
+          $data = json_encode($orderData, JSON_UNESCAPED_UNICODE);
+          $datas = [
+            'EBusinessID' => $this->config['ebusiness_id'],
+            'RequestType' => '1007',
+            'RequestData' => urlencode($data),
+        ];
+        $datas['DataSign'] = $this->encrypt($data, $this->config['appkey']);
+
+        $result = Http::sendRequest(self::API_EORDER, $datas, 'POST', []);
+     
+        if ($result['ret'] == 1) {
+            $exResult = json_decode($result['msg'], true);
+
+            if (!$exResult['Success']) {
+                throw new \Exception($exResult['Reason']);
+            }
+
+            return $exResult;
+        } else {
+            throw new \Exception($result['msg']);
+        }
+    }
+
+
+    // 组装返回结果
+    public function setPushResult($success = false, $reason = '') {
+        $result = [
+            "EBusinessID" => $this->config['ebusiness_id'],
+            "UpdateTime" => date('Y-m-d H:i:s'),
+            "Success" => $success,
+            "Reason" => $reason
+        ];
+
+        return json_encode($result);
+    }
+
+
+    // 加签
+    function encrypt($data, $appkey)
+    {
+        return urlencode(base64_encode(md5($data . $appkey)));
+    }
+}

+ 25 - 0
addons/shopro/library/Hook.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace addons\shopro\library;
+
+class Hook
+{
+
+    public function __construct()
+    {
+        
+    }
+
+    public static function register ($behaviors = []) {
+        $default = require ROOT_PATH . 'addons/shopro/hooks.php';
+
+        $behaviors = array_merge($default, $behaviors);
+        foreach ($behaviors as $tag => $behavior) {
+            // 数组反转 保证最上面的行为优先级最高    
+            $behavior = array_reverse($behavior);
+            foreach ($behavior as $be) {
+                \think\Hook::add($tag, $be, true);      // 所有行为都插入最前面
+            }
+        }
+    }
+}

+ 0 - 0
addons/shopro/library/Oauth.php


+ 71 - 0
addons/shopro/library/Oper.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace addons\shopro\library;
+
+use app\admin\library\Auth as AdminAuth;
+use addons\shopro\model\Store;
+use addons\shopro\model\User;
+
+class Oper
+{
+    public static function set($operType = '', $operId = 0)
+    {
+        if ($operType === '') {
+            // 自动获取操作人
+            $admin = AdminAuth::instance();     // 没有登录返回的还是这个类实例
+            if ($admin->isLogin()) {
+                // 后台管理员
+                $operType = 'admin';
+                $operId = $admin->id;
+            } else if (strpos(request()->url(), 'store.store') !== false) {
+                // 门店
+                $store = Store::info();
+                if ($store) {
+                    $operType = 'store';
+                    $operId = $store['id'];
+                }
+            } else if (strpos(request()->url(), 'addons/shopro') !== false) {
+                // 用户
+                $user = User::info();
+                if ($user) {
+                    $operType = 'user';
+                    $operId = $user->id;
+                }
+            }
+        }
+        if ($operType === '') {
+            $operType = 'system';
+        }
+        return [
+            'oper_type' => $operType,
+            'oper_id' => $operId
+        ];
+    }
+
+    public static function get($operType, $operId)
+    {
+        $operator = null;
+        if ($operType === 'admin') {
+            $operator = \app\admin\model\Admin::where('id', $operId)->field('nickname as name, avatar')->find();
+            $operator['type'] = '管理员';
+        } elseif ($operType === 'user') {
+            $operator = \addons\shopro\model\User::where('id', $operId)->field('nickname as name, avatar')->find();
+            $operator['type'] = '用户';
+        } elseif ($operType === 'store') {
+            $operator = \addons\shopro\model\Store::where('id', $operId)->field('name')->find();
+            $operator['type'] = '用户';
+            $operator['avatar'] = '';
+        } else {
+            $operator = [
+                'name' => '系统',
+                'avatar' => '',
+                'type' => '系统'
+            ];
+        }
+        if(!isset($operator['name'])) {
+            $operator['name'] = '已删除';
+            $operator['avatar'] = '';
+        }
+        return $operator;
+    }
+}

+ 291 - 0
addons/shopro/library/PayService.php

@@ -0,0 +1,291 @@
+<?php
+
+namespace addons\shopro\library;
+
+use Yansongda\Pay\Pay;
+use Yansongda\Pay\Log;
+use addons\shopro\exception\Exception;
+
+class PayService
+{
+    protected $config;
+    protected $platform;
+    protected $payment;
+    protected $notify_url;
+    public $method;
+
+
+    public function __construct($payment, $platform = '', $notify_url = '', $type = 'pay')
+    {
+        $this->platform = $platform;
+        $this->payment = $payment;
+        $this->notify_url = $notify_url;
+        $this->type = $type;
+
+        $this->setPaymentConfig();
+    }
+
+    private function setPaymentConfig()
+    {
+        $paymentConfig = json_decode(\addons\shopro\model\Config::get(['name' => $this->payment])->value, true);
+
+        // 如果是支付,并且不是 复制地址的支付宝支付
+        if ($this->type == 'pay' && $this->platform != 'url' && !in_array($this->platform, $paymentConfig['platform'])) {
+            new Exception('暂不支持该方式付款');
+        }
+
+        $this->config = $paymentConfig;
+        $this->config['notify_url'] = $this->notify_url;
+
+        if ($this->payment === 'wechat') {
+            // 根据不同平台设置相应的 appid
+            $this->setWechatAppId();
+        }
+
+        // 设置支付证书路径
+        $this->setCert();
+    }
+
+    private function setWechatAppId()
+    {
+        switch ($this->platform) {
+            case 'wxOfficialAccount':
+                $platformConfig = json_decode(\addons\shopro\model\Config::get(['name' => $this->platform])->value, true);
+                if (isset($this->config['mode']) && $this->config['mode'] === 'service') {
+                    $this->config['sub_app_id'] = $platformConfig['app_id'];
+                } else {
+                    $this->config['app_id'] = $platformConfig['app_id'];
+                }
+                break;
+            case 'wxMiniProgram':
+                $platformConfig = json_decode(\addons\shopro\model\Config::get(['name' => $this->platform])->value, true);
+                if (isset($this->config['mode']) && $this->config['mode'] === 'service') {
+                    $this->config['sub_miniapp_id'] = $platformConfig['app_id'];
+                    // $this->config['sub_app_id'] = $platformConfig['app_id'];
+                } else {
+                    $this->config['miniapp_id'] = $platformConfig['app_id'];
+                    $this->config['app_id'] = $platformConfig['app_id'];        // 小程序微信企业付款
+                }
+                break;
+            case 'H5':
+                $platformConfig = json_decode(\addons\shopro\model\Config::get(['name' => $this->platform])->value, true);
+                if (isset($this->config['mode']) && $this->config['mode'] === 'service') {
+                    $this->config['sub_app_id'] = $platformConfig['app_id'];
+                } else {
+                    $this->config['app_id'] = $platformConfig['app_id'];
+                }
+                break;
+            case 'App':
+                $platformConfig = json_decode(\addons\shopro\model\Config::get(['name' => 'App'])->value, true);
+                if (isset($this->config['mode']) && $this->config['mode'] === 'service') {
+                    $this->config['sub_appid'] = $platformConfig['app_id'];
+                    $this->config['sub_app_id'] = $platformConfig['app_id'];
+                } else {
+                    $this->config['appid'] = $platformConfig['app_id'];         // 微信 App 支付使用这个
+                    $this->config['app_id'] = $platformConfig['app_id'];        // 微信 App 支付退款使用的是这个
+                }
+
+                break;
+        }
+    }
+
+
+    // 处理证书路径
+    private function setCert()
+    {
+        // 处理证书路径
+        if ($this->payment == 'wechat') {
+            // 微信支付证书
+            $this->config['cert_client'] = ROOT_PATH . 'public' . $this->config['cert_client'];
+            $this->config['cert_key'] = ROOT_PATH . 'public' . $this->config['cert_key'];
+        } else {
+            // 支付宝证书路径
+            $end = substr($this->config['ali_public_key'], -4);
+            if ($end == '.crt') {
+                $this->config['ali_public_key'] = ROOT_PATH . 'public' . $this->config['ali_public_key'];
+            }
+            $this->config['app_cert_public_key'] = ROOT_PATH . 'public' . $this->config['app_cert_public_key'];
+            $this->config['alipay_root_cert'] = ROOT_PATH . 'public' . $this->config['alipay_root_cert'];
+        }
+    }
+
+
+    private function setPaymentMethod()
+    {
+        $method = [
+            'wechat' => [
+                'wxOfficialAccount' => 'mp',   //公众号支付 Collection
+                'wxMiniProgram' => 'miniapp', //小程序支付
+                'H5' => 'wap', //手机网站支付 Response
+                'App' => 'app' //APP 支付 JsonResponse
+            ],
+            'alipay' => [
+                'wxOfficialAccount' => 'wap',   //手机网站支付 Response
+                'wxMiniProgram' => 'wap', //小程序支付
+                'H5' => 'wap', //手机网站支付 Response
+                'url' => 'wap', //手机网站支付 Response
+                'App' => 'app' //APP 支付 JsonResponse
+            ],
+        ];
+
+        $this->method = $method[$this->payment][$this->platform];
+    }
+
+    public function create($order)
+    {
+        //        $order = [
+        //            'out_trade_no' => time(),
+        //            'total_fee' => '1', // **单位:分**
+        //            'body' => 'test body - 测试',
+        //            'openid' => 'onkVf1FjWS5SBIixxxxxxx', //微信需要带openid过来
+        //        ];
+
+        // 设置支付方式
+        $this->setPaymentMethod();
+
+        $method = $this->method;
+        switch ($this->payment) {
+            case 'wechat':
+                if (isset($this->config['mode']) && $this->config['mode'] === 'service') {
+                    $order['sub_openid'] = $order['openid'];
+                    unset($order['openid']);
+                }
+                $order['total_fee'] = $order['total_fee'] * 100;
+                $pay = Pay::wechat($this->config)->$method($order);
+
+                break;
+            case 'alipay':
+                if (in_array($this->platform, ['wxOfficialAccount', 'wxMiniProgram', 'H5'])) {
+                    // 返回支付宝支付链接
+                    $pay = request()->domain() . '/addons/shopro/pay/alipay?order_sn=' . $order['out_trade_no'];
+                } else {
+                    if ($this->method == 'wap') {
+                        // 支付宝 wap 支付,增加 return_url
+                        // 获取 h5 域名
+                        $platformConfig = json_decode(\addons\shopro\model\Config::get(['name' => 'shopro'])->value, true);
+                        // 如果域名存在,增加 return_url
+                        if ($platformConfig && isset($platformConfig['domain'])) {
+                            $start = substr($platformConfig['domain'], -1) == '/' ? "" : "/";
+                            $this->config['return_url'] = $platformConfig['domain'] . $start . "pages/order/payment/result?orderSn=" . $order['out_trade_no'] . "&type=alipay&pay=1";
+                        }
+                    }
+
+                    $pay = Pay::alipay($this->config)->$method($order);
+                }
+
+                break;
+        }
+
+        return $pay;
+    }
+
+    // 企业付款
+    public function transfer($payload)
+    {
+        $code = 0;
+        $response = [];
+        // 支付宝返回结果
+        // [code] => 10000
+        // [msg] => Success
+        // [order_id] => 20210309110070000006730051669626
+        // [out_biz_no] => W202107231625700647008000
+        // [pay_fund_order_id] => 20210309110070001506730065959451
+        // [status] => SUCCESS
+        // [trans_date] => 2021-03-09 10:42:23
+
+        // 微信返回结果
+        // [return_code] => SUCCESS
+        // [return_msg] => Array
+        //     (
+        //     )
+        // [mch_appid] => wx38939920ace0d244
+        // [mchid] => 1481069012
+        // [nonce_str] => O9fwzb6HDGO2zU6H
+        // [result_code] => SUCCESS
+        // [partner_trade_no] => W202106361960501154008000
+        // [payment_no] => 10100294905592102257932685920233
+        // [payment_time] => 2021-02-25 18:36:30
+        switch ($this->payment) {
+            case 'wechat':
+                $payload['amount'] = $payload['amount'] * 100;
+                $response = Pay::wechat($this->config)->transfer($payload);
+                if ($response['return_code'] === 'SUCCESS' && $response['result_code'] === 'SUCCESS') {
+                    $code = 1;
+                }
+                break;
+            case 'alipay':
+                $response = Pay::alipay($this->config)->transfer($payload);
+                if ($response['code'] === '10000' && $response['status'] === 'SUCCESS') {
+                    $code = 1;
+                }
+                break;
+        }
+
+        return [$code, $response];
+    }
+
+
+    public function notify($callback)
+    {
+        $pay = $this->getPay();
+
+        try {
+            $data = $pay->verify(); // 是的,验签就这么简单!
+
+            $result = $callback($data, $pay);
+
+            // Log::debug('Wechat notify', $data->all());
+        } catch (\Exception $e) {
+            // $e->getMessage();
+        }
+
+        return $result;
+    }
+
+
+    public function refund($order_data)
+    {
+        $pay = $this->getPay();
+
+        $order_data['type'] = $this->platform == 'wxMiniProgram' ? 'miniapp' : '';
+
+        $result = $pay->refund($order_data);
+
+        return $result;
+    }
+
+
+    public function notifyRefund($callback)
+    {
+        $pay = $this->getPay();
+
+        try {
+            $data = $pay->verify(null, true); // 是的,验签就这么简单!
+
+            $result = $callback($data, $pay);
+
+            // Log::debug('Wechat notify', $data->all());
+        } catch (\Exception $e) {
+            // $e->getMessage();
+        }
+
+        return $result;
+    }
+
+
+    private function getPay()
+    {
+        switch ($this->payment) {
+            case 'wechat':
+                $pay = Pay::wechat($this->config);
+                break;
+            case 'alipay':
+                $pay = Pay::alipay($this->config);
+                break;
+            default:
+                new Exception('支付方式不支持');
+        }
+
+        return $pay;
+    }
+}

+ 68 - 0
addons/shopro/library/Redis.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace addons\shopro\library;
+
+use addons\shopro\exception\Exception;
+
+class Redis
+{
+    protected $handler = null;
+
+    protected $options = [
+        'host'       => '127.0.0.1',
+        'port'       => 6379,
+        'password'   => '',
+        'select'     => 0,
+        'timeout'    => 0,
+        'expire'     => 0,
+        'persistent' => false,
+        'prefix'     => '',
+    ];
+
+    /**
+     * 构造函数
+     * @param array $options 缓存参数
+     * @access public
+     */
+    public function __construct($options = [])
+    {
+        if (!extension_loaded('redis')) {
+            throw new \BadFunctionCallException('not support: redis');
+        }
+
+        // 获取 redis 配置
+        $config = \think\Config::get('redis');
+        if (empty($config) && empty($options)) {
+            throw new \Exception('redis connection fail: no redis config');
+        } 
+
+        if (!empty($config)) {
+            $this->options = array_merge($this->options, $config);
+        }
+
+        if (!empty($options)) {
+            $this->options = array_merge($this->options, $options);
+        }
+        $this->handler = new \Redis();
+        if ($this->options['persistent']) {
+            $this->handler->pconnect($this->options['host'], $this->options['port'], $this->options['timeout'], 'persistent_id_' . $this->options['select']);
+        } else {
+            $this->handler->connect($this->options['host'], $this->options['port'], $this->options['timeout']);
+        }
+
+        if ('' != $this->options['password']) {
+            $this->handler->auth($this->options['password']);
+        }
+
+        if (0 != $this->options['select']) {
+            $this->handler->select($this->options['select']);
+        }
+
+        // 赋值全局,避免多次实例化
+        $GLOBALS['SPREDIS'] = $this->handler;
+    }
+
+    public function getRedis() {
+        return $this->handler;
+    }
+}

+ 327 - 0
addons/shopro/library/Wechat.php

@@ -0,0 +1,327 @@
+<?php
+
+namespace addons\shopro\library;
+
+use EasyWeChat\Factory;
+use addons\shopro\model\Config;
+use think\Model;
+use fast\Http;
+
+/**
+ *
+ */
+class Wechat extends Model
+{
+    protected $config;
+    protected $app;
+
+
+    public function __construct($platform)
+    {
+        $this->setConfig($platform);
+        switch ($platform) {
+            case 'wxOfficialAccount':
+                $this->app    = Factory::officialAccount($this->config);
+                break;
+            case 'wxMiniProgram':
+                $this->app    = Factory::miniProgram($this->config);
+                break;
+            case 'App':
+                $this->app    = Factory::openPlatform($this->config);
+                break;
+        }
+
+        // 重新绑定 easywechat 缓存(如果需要负载均衡,必须要开启)
+        // $this->rebindCache();
+    }
+
+    // 返回实例
+    public function getApp() {
+        return $this->app;
+    }
+
+    //小程序:获取openid&session_key
+    public function code($code)
+    {
+        return $this->app->auth->session($code);
+    }
+
+    public function oauth()
+    {
+        $oauth = $this->app->oauth;
+        return $oauth;
+    }
+
+    //解密信息
+    public function decryptData($session, $iv, $encryptData)
+    {
+        $data = $this->app->encryptor->decryptData($session, $iv, $encryptData);
+
+        return $data;
+    }
+
+    public function unify($orderBody)
+    {
+        $result = $this->app->order->unify($orderBody);
+        return $result;
+    }
+
+    public function bridgeConfig($prepayId)
+    {
+        $jssdk = $this->app->jssdk;
+        $config = $jssdk->bridgeConfig($prepayId, false);
+        return $config;
+    }
+
+    public function notify()
+    {
+        $result = $this->app;
+        return $result;
+    }
+
+    //获取accessToken
+    public function getAccessToken()
+    {
+        $accessToken = $this->app->access_token;
+        $token = $accessToken->getToken(); // token 数组  token['access_token'] 字符串
+        //$token = $accessToken->getToken(true); // 强制重新从微信服务器获取 token.
+        return $token;
+    }
+
+
+    /**
+     * 重写 jssdk buildConfig 方法
+     *
+     * @param [type] $jssdk jssdk 实例
+     * @param [type] $apis  要请求的 api 列表
+     * @param boolean $debug    debug 
+     * @param boolean $beta 
+     * @param boolean $json 是否返回 json
+     * @param array $openTagList    开放标签列表
+     * @return void
+     */
+    public function buildConfig($jssdk, $jsApiList, $debug = false, $beta = false, $json = false, $openTagList = [], $url = '')
+    {
+        $url = $url ?: $jssdk->getUrl();
+        $nonce = \EasyWeChat\Kernel\Support\Str::quickRandom(10);
+        $timestamp = time();
+
+        $signature = [
+            'appId' => $this->config['app_id'],
+            'nonceStr' => $nonce,
+            'timestamp' => $timestamp,
+            'url' => $url,
+            'signature' => $jssdk->getTicketSignature($jssdk->getTicket()['ticket'], $nonce, $timestamp, $url),
+        ];
+
+        $config = array_merge(compact('debug', 'beta', 'jsApiList', 'openTagList'), $signature);
+
+        return $json ? json_encode($config) : $config;
+    }
+
+
+    public function sendTemplateMessage($attributes)
+    {
+        extract($attributes);
+        $this->app->template_message->send([
+            'touser' => $openId,
+            'template_id' => $templateId,
+            'page' => $page,
+            'form_id' => $formId,
+            'data' => $data,
+            'emphasis_keyword' => $emphasis_keyword
+        ]);
+    }
+
+
+    /**
+     * 发送公众号订阅消息
+     *
+     * @return void
+     */
+    public function bizsendSubscribeMessage($data) {
+        $access_token = $this->getAccessToken();
+
+        $bizsendUrl = "https://api.weixin.qq.com/cgi-bin/message/subscribe/bizsend?access_token={$access_token['access_token']}";
+
+        $headers = ['Content-type: application/json'];
+        $options = [
+            CURLOPT_HTTPHEADER => $headers
+        ];
+        $result = Http::sendRequest($bizsendUrl, json_encode($data), 'POST', $options);
+
+        if (isset($result['ret']) && $result['ret']) {
+            // 请求成功
+            $result = json_decode($result['msg'], true);
+            
+            return $result;
+        }
+        
+        // 请求失败
+        return ['errcode' => -1, 'msg' => $result];
+    }
+
+    // 同步小程序直播
+    public function live(Array $params = [])
+    {
+        $default = [
+            'start' => 0,
+            'limit' => 10
+        ];
+        $params = array_merge($default, $params);
+        $default = json_encode($params);
+
+
+        $access_token = $this->app->access_token->getToken();
+        $getRoomsListUrl = "https://api.weixin.qq.com/wxa/business/getliveinfo?access_token={$access_token['access_token']}";
+        $headers = ['Content-type: application/json'];
+        $options = [
+            CURLOPT_HTTPHEADER => $headers
+        ];
+        $result = Http::sendRequest($getRoomsListUrl, $default, 'POST', $options);
+        if (isset($result['ret']) && $result['ret']) {
+            $msg = json_decode($result['msg'], true);
+            $result = $msg;
+        }
+
+//        $result = $this->app->live->getRooms(...array_values($params));
+
+        $rooms = [];
+        if ($result && $result['errcode'] == 0 && $result['errmsg'] === 'ok') {
+            $rooms = $result['room_info'];
+        }
+
+        return $rooms;
+    }
+
+    // 小程序直播回放
+    public function liveReplay(array $params = [])
+    {
+        $default = [
+            'room_id' => 0,
+            'start' => 0,
+            'limit' => 20
+        ];
+
+        $params = array_merge($default, $params);
+        $default = json_encode($params);
+        $access_token = $this->app->access_token->getToken();
+        $getPlayBackListUrl = "https://api.weixin.qq.com/wxa/business/getliveinfo?access_token={$access_token['access_token']}";
+        $headers = ['Content-type: application/json'];
+        $options = [
+            CURLOPT_HTTPHEADER => $headers
+        ];
+        $result = Http::sendRequest($getPlayBackListUrl, $default, 'POST', $options);
+        if (isset($result['ret']) && $result['ret']) {
+            $msg = json_decode($result['msg'], true);
+            $result = $msg;
+        }
+//        $result = $this->app->live->getPlaybacks(...array_values($params));
+
+        $liveReplay = [];
+        if ($result && $result['errcode'] == 0 && $result['errmsg'] === 'ok') {
+            $liveReplay = $result['live_replay'];
+        }
+
+        return $liveReplay;
+    }
+
+    public function menu($act = 'create', $buttons = '')
+    {
+        $result = $this->app->menu->$act($buttons);
+        return $result;
+
+    }
+
+    // 公众号 获取所有粉丝
+    public function asyncFans($nextOpenId = null, $currentPage = 1, $totalPage = 1)
+    {
+        $fans = $this->app->user->list($nextOpenId);
+        $openIdsArray = $fans['data']['openid'];
+        //放入最大10000条openid队列去执行
+        \think\Queue::push('\addons\shopro\job\Wechat@createQueueByOpenIdsArray', $openIdsArray, 'shopro');
+        //第一次计算总页数
+        if ($currentPage === 1) {
+            $totalPage = intval($fans['total'] % $fans['count'] === 0 ? $fans['total'] / $fans['count'] : ceil($fans['total'] / $fans['count']));
+        }
+        //有分页 递归下一页
+        if ($currentPage < $totalPage) {
+            $openIdsArray = array_merge($openIdsArray, $this->asyncFans($fans['next_openid'], $currentPage++, $totalPage));
+        }
+        if ($currentPage == $totalPage) {
+            if ($totalPage == 1) {
+                $code = 1;
+                $msg = '同步成功';
+            }else{
+                $code = 1;
+                $msg = '数据较大,请稍后再查看...';
+            }
+            return [
+                'code' => $code,
+                'msg' => $msg
+            ];
+        }
+        return $openIdsArray;
+    }
+
+    //通过openid获取已经关注的用户信息
+    public function getSubscribeUserInfoByOpenId(array $openIdsArray)
+    {
+        $result = $this->app->user->select($openIdsArray);
+        return $result;
+    }
+
+
+    /**
+     * 重新绑定 easywechat 缓存
+     *
+     * @return void
+     */
+    private function rebindCache() {
+        $options = [
+            // 'select' => 0        // 默认和活动缓存使用同一个 select 库,如需自定义,解开注释,并填写对应 select 库
+        ];
+        $redis = (new Redis($options))->getRedis();
+        $cache = new \Symfony\Component\Cache\Adapter\RedisAdapter($redis);
+
+        // 替换应用中的缓存
+        $this->app->rebind('cache', $cache);
+    }
+
+
+
+    /**
+     * 合并默认配置
+     *
+     * @param [type] $platform
+     * @return void
+     */
+    private function setConfig($platform) {
+        $debug = config('app_debug');
+
+        $defaultConfig = [
+            'log' => [
+                'default' => $debug ? 'dev' : 'prod', // 默认使用的 channel,生产环境可以改为下面的 prod
+                'channels' => [
+                    // 测试环境
+                    'dev' => [
+                        'driver' => 'single',
+                        'path' => '/tmp/easywechat.log',
+                        'level' => 'debug',
+                    ],
+                    // 生产环境
+                    'prod' => [
+                        'driver' => 'daily',
+                        'path' => '/tmp/easywechat.log',
+                        'level' => 'info',
+                    ],
+                ],
+            ],
+        ];
+
+        // 获取对应平台的配置
+        $this->config = Config::getEasyWechatConfig($platform);
+        // 根据框架 debug 合并 log 配置
+        $this->config = array_merge($this->config, $defaultConfig);
+    }
+}

+ 138 - 0
addons/shopro/library/apple-signin/ASDecoder.php

@@ -0,0 +1,138 @@
+<?php
+
+namespace AppleSignIn;
+
+use AppleSignIn\Vendor\JWK;
+use AppleSignIn\Vendor\JWT;
+
+use Exception;
+
+class ASDecoder
+{
+    /**
+     * Parse a provided Sign In with Apple identity token.
+     * @param $identityToken
+     * @return ASPayload
+     * @throws Exception
+     */
+    public static function getAppleSignInPayload($identityToken)
+    {
+        $identityPayload = self::decodeIdentityToken($identityToken);
+        return new ASPayload($identityPayload);
+    }
+
+    /**
+     * Decode the Apple encoded JWT using Apple's public key for the signing.
+     * @param $identityToken
+     * @return object
+     * @throws Exception
+     */
+    public static function decodeIdentityToken($identityToken)
+    {
+        $publicKeyData = self::fetchPublicKey($identityToken);
+
+        $publicKey = $publicKeyData['publicKey'];
+        $alg = $publicKeyData['alg'];
+        $payload = JWT::decode($identityToken, $publicKey, [$alg]);
+        return $payload;
+    }
+
+    /**
+     * Fetch Apple's public key from the auth/keys REST API to use to decode
+     * the Sign In JWT.
+     *
+     * @param $identityToken
+     * @return array
+     * @throws Exception
+     */
+    public static function fetchPublicKey($identityToken)
+    {
+        $publicKeys = file_get_contents('https://appleid.apple.com/auth/keys');
+        $decodedPublicKeys = json_decode($publicKeys, true);
+
+        if (!isset($decodedPublicKeys['keys']) || count($decodedPublicKeys['keys']) < 1) {
+            throw new Exception('Invalid key format.');
+        }
+
+        // 苹果公钥返回的 keys 内数据不是固定顺序,此处按索引取 auth keys,取正确的 key
+        // value by index
+        try {
+            $tks = explode('.', $identityToken);
+            if (count($tks) != 3) {
+                throw new Exception('Wrong number of segments');
+            }
+            list($headb64, $bodyb64, $cryptob64) = $tks;
+            $header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64));
+            $kid = $header->kid;
+
+            if (count($decodedPublicKeys['keys']) > 1) {
+                $indexPublicInfo = array_column($decodedPublicKeys['keys'], null, 'kid');
+                $parsedKeyData = isset($indexPublicInfo[$kid]) ? $indexPublicInfo[$kid] : $decodedPublicKeys['keys'][0];
+            } else {
+                $parsedKeyData = $decodedPublicKeys['keys'][0];
+            }
+        } catch (\Exception $exception) {
+            $parsedKeyData = $decodedPublicKeys['keys'][0];
+        }
+
+        $parsedPublicKey = JWK::parseKey($parsedKeyData);
+        $publicKeyDetails = openssl_pkey_get_details($parsedPublicKey);
+
+        if (!isset($publicKeyDetails['key'])) {
+            throw new Exception('Invalid public key details.');
+        }
+
+        return [
+            'publicKey' => $publicKeyDetails['key'],
+            'alg'       => $parsedKeyData['alg']
+        ];
+    }
+}
+
+/**
+ * A class decorator for the Sign In with Apple payload produced by
+ * decoding the signed JWT from a client.
+ */
+class ASPayload
+{
+    protected $_instance;
+
+    public function __construct($instance)
+    {
+        if (is_null($instance)) {
+            throw new Exception('ASPayload received null instance.');
+        }
+        $this->_instance = $instance;
+    }
+
+    public function __call($method, $args)
+    {
+        return call_user_func_array(array($this->_instance, $method), $args);
+    }
+
+    public function __get($key)
+    {
+        return $this->_instance->$key;
+    }
+
+    public function __set($key, $val)
+    {
+        return $this->_instance->$key = $val;
+    }
+
+    public function getEmail()
+    {
+        return (isset($this->_instance->email)) ? $this->_instance->email : null;
+    }
+
+    public function getUser()
+    {
+        return (isset($this->_instance->sub)) ? $this->_instance->sub : null;
+    }
+
+    public function verifyUser($user)
+    {
+        return $user === $this->getUser();
+    }
+
+}

+ 7 - 0
addons/shopro/library/apple-signin/LICENSE

@@ -0,0 +1,7 @@
+Copyright (c) 2019, Griffin Ledingham
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 8 - 0
addons/shopro/library/apple-signin/Vendor/BeforeValidException.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace AppleSignIn\Vendor;
+
+class BeforeValidException extends \UnexpectedValueException
+{
+
+}

+ 8 - 0
addons/shopro/library/apple-signin/Vendor/ExpiredException.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace AppleSignIn\Vendor;
+
+class ExpiredException extends \UnexpectedValueException
+{
+
+}

+ 158 - 0
addons/shopro/library/apple-signin/Vendor/JWK.php

@@ -0,0 +1,158 @@
+<?php
+
+namespace AppleSignIn\Vendor;
+
+use \UnexpectedValueException;
+
+/**
+ * JSON Web Key implementation, based on this spec:
+ * https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41
+ *
+ * PHP version 5
+ *
+ * @package  Firebase\JWT
+ * @author   Bui Sy Nguyen <nguyenbs@gmail.com>
+ * @license  http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
+ * @link     https://github.com/fproject/php-jwt
+ */
+class JWK
+{
+    /**
+     * Parse a set of JWK keys
+     * @param $source
+     * @return array an associative array represents the set of keys
+     */
+    public static function parseKeySet($source)
+    {
+        $keys = [];
+        if (is_string($source)) {
+            $source = json_decode($source, true);
+        } else if (is_object($source)) {
+            if (property_exists($source, 'keys'))
+                $source = (array)$source;
+            else
+                $source = [$source];
+        }
+
+        if (is_array($source)) {
+            if (isset($source['keys']))
+                $source = $source['keys'];
+
+            foreach ($source as $k => $v) {
+                if (!is_string($k)) {
+                    if (is_array($v) && isset($v['kid']))
+                        $k = $v['kid'];
+                    elseif (is_object($v) && property_exists($v, 'kid'))
+                        $k = $v->{'kid'};
+                }
+                try {
+                    $v = self::parseKey($v);
+                    $keys[$k] = $v;
+                } catch (UnexpectedValueException $e) {
+                    //Do nothing
+                }
+            }
+        }
+        if (0 < count($keys)) {
+            return $keys;
+        }
+        throw new UnexpectedValueException('Failed to parse JWK');
+    }
+
+    /**
+     * Parse a JWK key
+     * @param $source
+     * @return resource|array an associative array represents the key
+     */
+    public static function parseKey($source)
+    {
+        if (!is_array($source))
+            $source = (array)$source;
+        if (!empty($source) && isset($source['kty']) && isset($source['n']) && isset($source['e'])) {
+            switch ($source['kty']) {
+                case 'RSA':
+                    if (array_key_exists('d', $source))
+                        throw new UnexpectedValueException('Failed to parse JWK: RSA private key is not supported');
+
+                    $pem = self::createPemFromModulusAndExponent($source['n'], $source['e']);
+                    $pKey = openssl_pkey_get_public($pem);
+                    if ($pKey !== false)
+                        return $pKey;
+                    break;
+                default:
+                    //Currently only RSA is supported
+                    break;
+            }
+        }
+
+        throw new UnexpectedValueException('Failed to parse JWK');
+    }
+
+    /**
+     *
+     * Create a public key represented in PEM format from RSA modulus and exponent information
+     *
+     * @param string $n the RSA modulus encoded in Base64
+     * @param string $e the RSA exponent encoded in Base64
+     * @return string the RSA public key represented in PEM format
+     */
+    private static function createPemFromModulusAndExponent($n, $e)
+    {
+        $modulus = JWT::urlsafeB64Decode($n);
+        $publicExponent = JWT::urlsafeB64Decode($e);
+
+
+        $components = array(
+            'modulus' => pack('Ca*a*', 2, self::encodeLength(strlen($modulus)), $modulus),
+            'publicExponent' => pack('Ca*a*', 2, self::encodeLength(strlen($publicExponent)), $publicExponent)
+        );
+
+        $RSAPublicKey = pack(
+            'Ca*a*a*',
+            48,
+            self::encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
+            $components['modulus'],
+            $components['publicExponent']
+        );
+
+
+        // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
+        $rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
+        $RSAPublicKey = chr(0) . $RSAPublicKey;
+        $RSAPublicKey = chr(3) . self::encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
+
+        $RSAPublicKey = pack(
+            'Ca*a*',
+            48,
+            self::encodeLength(strlen($rsaOID . $RSAPublicKey)),
+            $rsaOID . $RSAPublicKey
+        );
+
+        $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
+            chunk_split(base64_encode($RSAPublicKey), 64) .
+            '-----END PUBLIC KEY-----';
+
+        return $RSAPublicKey;
+    }
+
+    /**
+     * DER-encode the length
+     *
+     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
+     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
+     *
+     * @access private
+     * @param int $length
+     * @return string
+     */
+    private static function encodeLength($length)
+    {
+        if ($length <= 0x7F) {
+            return chr($length);
+        }
+
+        $temp = ltrim(pack('N', $length), chr(0));
+        return pack('Ca*', 0x80 | strlen($temp), $temp);
+    }
+
+}

+ 380 - 0
addons/shopro/library/apple-signin/Vendor/JWT.php

@@ -0,0 +1,380 @@
+<?php
+
+namespace AppleSignIn\Vendor;
+use \DomainException;
+use \InvalidArgumentException;
+use \UnexpectedValueException;
+use \DateTime;
+
+/**
+ * JSON Web Token implementation, based on this spec:
+ * https://tools.ietf.org/html/rfc7519
+ *
+ * PHP version 5
+ *
+ * @category Authentication
+ * @package  Authentication_JWT
+ * @author   Neuman Vong <neuman@twilio.com>
+ * @author   Anant Narayanan <anant@php.net>
+ * @license  http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
+ * @link     https://github.com/firebase/php-jwt
+ */
+class JWT
+{
+
+    /**
+     * The server leeway time in seconds, to aware the acceptable different time between clocks
+     * of token issued server and relying parties.
+     * When checking nbf, iat or expiration times, we want to provide some extra leeway time to
+     * account for clock skew.
+     */
+    public static $leeway = 0;
+
+    /**
+     * Allow the current timestamp to be specified.
+     * Useful for fixing a value within unit testing.
+     *
+     * Will default to PHP time() value if null.
+     */
+    public static $timestamp = null;
+
+    public static $supported_algs = array(
+        'HS256' => array('hash_hmac', 'SHA256'),
+        'HS512' => array('hash_hmac', 'SHA512'),
+        'HS384' => array('hash_hmac', 'SHA384'),
+        'RS256' => array('openssl', 'SHA256'),
+        'RS384' => array('openssl', 'SHA384'),
+        'RS512' => array('openssl', 'SHA512'),
+    );
+
+    /**
+     * Decodes a JWT string into a PHP object.
+     *
+     * @param string        $jwt            The JWT
+     * @param string|array  $key            The key, or map of keys.
+     *                                      If the algorithm used is asymmetric, this is the public key
+     * @param array         $allowed_algs   List of supported verification algorithms
+     *                                      Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256'
+     *
+     * @return object The JWT's payload as a PHP object
+     *
+     * @throws UnexpectedValueException     Provided JWT was invalid
+     * @throws SignatureInvalidException    Provided JWT was invalid because the signature verification failed
+     * @throws BeforeValidException         Provided JWT is trying to be used before it's eligible as defined by 'nbf'
+     * @throws BeforeValidException         Provided JWT is trying to be used before it's been created as defined by 'iat'
+     * @throws ExpiredException             Provided JWT has since expired, as defined by the 'exp' claim
+     *
+     * @uses jsonDecode
+     * @uses urlsafeB64Decode
+     */
+    public static function decode($jwt, $key, array $allowed_algs = array())
+    {
+        $timestamp = is_null(static::$timestamp) ? time() : static::$timestamp;
+
+        if (empty($key)) {
+            throw new InvalidArgumentException('Key may not be empty');
+        }
+        $tks = explode('.', $jwt);
+        if (count($tks) != 3) {
+            throw new UnexpectedValueException('Wrong number of segments');
+        }
+        list($headb64, $bodyb64, $cryptob64) = $tks;
+        if (null === ($header = static::jsonDecode(static::urlsafeB64Decode($headb64)))) {
+            throw new UnexpectedValueException('Invalid header encoding');
+        }
+        if (null === $payload = static::jsonDecode(static::urlsafeB64Decode($bodyb64))) {
+            throw new UnexpectedValueException('Invalid claims encoding');
+        }
+        if (false === ($sig = static::urlsafeB64Decode($cryptob64))) {
+            throw new UnexpectedValueException('Invalid signature encoding');
+        }
+        if (empty($header->alg)) {
+            throw new UnexpectedValueException('Empty algorithm');
+        }
+        if (empty(static::$supported_algs[$header->alg])) {
+            throw new UnexpectedValueException('Algorithm not supported');
+        }
+        if (!in_array($header->alg, $allowed_algs)) {
+            throw new UnexpectedValueException('Algorithm not allowed');
+        }
+        if (is_array($key) || $key instanceof \ArrayAccess) {
+            if (isset($header->kid)) {
+                if (!isset($key[$header->kid])) {
+                    throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key');
+                }
+                $key = $key[$header->kid];
+            } else {
+                throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
+            }
+        }
+
+        // Check the signature
+        if (!static::verify("$headb64.$bodyb64", $sig, $key, $header->alg)) {
+            throw new SignatureInvalidException('Signature verification failed');
+        }
+
+        // Check if the nbf if it is defined. This is the time that the
+        // token can actually be used. If it's not yet that time, abort.
+        if (isset($payload->nbf) && $payload->nbf > ($timestamp + static::$leeway)) {
+            throw new BeforeValidException(
+                'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->nbf)
+            );
+        }
+
+        // Check that this token has been created before 'now'. This prevents
+        // using tokens that have been created for later use (and haven't
+        // correctly used the nbf claim).
+        if (isset($payload->iat) && $payload->iat > ($timestamp + static::$leeway)) {
+            throw new BeforeValidException(
+                'Cannot handle token prior to ' . date(DateTime::ISO8601, $payload->iat)
+            );
+        }
+
+        // Check if this token has expired.
+        if (isset($payload->exp) && ($timestamp - static::$leeway) >= $payload->exp) {
+            throw new ExpiredException('Expired token');
+        }
+
+        return $payload;
+    }
+
+    /**
+     * Converts and signs a PHP object or array into a JWT string.
+     *
+     * @param object|array  $payload    PHP object or array
+     * @param string        $key        The secret key.
+     *                                  If the algorithm used is asymmetric, this is the private key
+     * @param string        $alg        The signing algorithm.
+     *                                  Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256'
+     * @param mixed         $keyId
+     * @param array         $head       An array with header elements to attach
+     *
+     * @return string A signed JWT
+     *
+     * @uses jsonEncode
+     * @uses urlsafeB64Encode
+     */
+    public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $head = null)
+    {
+        $header = array('typ' => 'JWT', 'alg' => $alg);
+        if ($keyId !== null) {
+            $header['kid'] = $keyId;
+        }
+        if ( isset($head) && is_array($head) ) {
+            $header = array_merge($head, $header);
+        }
+        $segments = array();
+        $segments[] = static::urlsafeB64Encode(static::jsonEncode($header));
+        $segments[] = static::urlsafeB64Encode(static::jsonEncode($payload));
+        $signing_input = implode('.', $segments);
+
+        $signature = static::sign($signing_input, $key, $alg);
+        $segments[] = static::urlsafeB64Encode($signature);
+
+        return implode('.', $segments);
+    }
+
+    /**
+     * Sign a string with a given key and algorithm.
+     *
+     * @param string            $msg    The message to sign
+     * @param string|resource   $key    The secret key
+     * @param string            $alg    The signing algorithm.
+     *                                  Supported algorithms are 'HS256', 'HS384', 'HS512' and 'RS256'
+     *
+     * @return string An encrypted message
+     *
+     * @throws DomainException Unsupported algorithm was specified
+     */
+    public static function sign($msg, $key, $alg = 'HS256')
+    {
+        if (empty(static::$supported_algs[$alg])) {
+            throw new DomainException('Algorithm not supported');
+        }
+        list($function, $algorithm) = static::$supported_algs[$alg];
+        switch($function) {
+            case 'hash_hmac':
+                return hash_hmac($algorithm, $msg, $key, true);
+            case 'openssl':
+                $signature = '';
+                $success = openssl_sign($msg, $signature, $key, $algorithm);
+                if (!$success) {
+                    throw new DomainException("OpenSSL unable to sign data");
+                } else {
+                    return $signature;
+                }
+        }
+    }
+
+    /**
+     * Verify a signature with the message, key and method. Not all methods
+     * are symmetric, so we must have a separate verify and sign method.
+     *
+     * @param string            $msg        The original message (header and body)
+     * @param string            $signature  The original signature
+     * @param string|resource   $key        For HS*, a string key works. for RS*, must be a resource of an openssl public key
+     * @param string            $alg        The algorithm
+     *
+     * @return bool
+     *
+     * @throws DomainException Invalid Algorithm or OpenSSL failure
+     */
+    private static function verify($msg, $signature, $key, $alg)
+    {
+        if (empty(static::$supported_algs[$alg])) {
+            throw new DomainException('Algorithm not supported');
+        }
+
+        list($function, $algorithm) = static::$supported_algs[$alg];
+        switch($function) {
+            case 'openssl':
+                $success = openssl_verify($msg, $signature, $key, $algorithm);
+                if ($success === 1) {
+                    return true;
+                } elseif ($success === 0) {
+                    return false;
+                }
+                // returns 1 on success, 0 on failure, -1 on error.
+                throw new DomainException(
+                    'OpenSSL error: ' . openssl_error_string()
+                );
+            case 'hash_hmac':
+            default:
+                $hash = hash_hmac($algorithm, $msg, $key, true);
+                if (function_exists('hash_equals')) {
+                    return hash_equals($signature, $hash);
+                }
+                $len = min(static::safeStrlen($signature), static::safeStrlen($hash));
+
+                $status = 0;
+                for ($i = 0; $i < $len; $i++) {
+                    $status |= (ord($signature[$i]) ^ ord($hash[$i]));
+                }
+                $status |= (static::safeStrlen($signature) ^ static::safeStrlen($hash));
+
+                return ($status === 0);
+        }
+    }
+
+    /**
+     * Decode a JSON string into a PHP object.
+     *
+     * @param string $input JSON string
+     *
+     * @return object Object representation of JSON string
+     *
+     * @throws DomainException Provided string was invalid JSON
+     */
+    public static function jsonDecode($input)
+    {
+        if (version_compare(PHP_VERSION, '5.4.0', '>=') && !(defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) {
+            /** In PHP >=5.4.0, json_decode() accepts an options parameter, that allows you
+             * to specify that large ints (like Steam Transaction IDs) should be treated as
+             * strings, rather than the PHP default behaviour of converting them to floats.
+             */
+            $obj = json_decode($input, false, 512, JSON_BIGINT_AS_STRING);
+        } else {
+            /** Not all servers will support that, however, so for older versions we must
+             * manually detect large ints in the JSON string and quote them (thus converting
+             *them to strings) before decoding, hence the preg_replace() call.
+             */
+            $max_int_length = strlen((string) PHP_INT_MAX) - 1;
+            $json_without_bigints = preg_replace('/:\s*(-?\d{'.$max_int_length.',})/', ': "$1"', $input);
+            $obj = json_decode($json_without_bigints);
+        }
+
+        if (function_exists('json_last_error') && $errno = json_last_error()) {
+            static::handleJsonError($errno);
+        } elseif ($obj === null && $input !== 'null') {
+            throw new DomainException('Null result with non-null input');
+        }
+        return $obj;
+    }
+
+    /**
+     * Encode a PHP object into a JSON string.
+     *
+     * @param object|array $input A PHP object or array
+     *
+     * @return string JSON representation of the PHP object or array
+     *
+     * @throws DomainException Provided object could not be encoded to valid JSON
+     */
+    public static function jsonEncode($input)
+    {
+        $json = json_encode($input);
+        if (function_exists('json_last_error') && $errno = json_last_error()) {
+            static::handleJsonError($errno);
+        } elseif ($json === 'null' && $input !== null) {
+            throw new DomainException('Null result with non-null input');
+        }
+        return $json;
+    }
+
+    /**
+     * Decode a string with URL-safe Base64.
+     *
+     * @param string $input A Base64 encoded string
+     *
+     * @return string A decoded string
+     */
+    public static function urlsafeB64Decode($input)
+    {
+        $remainder = strlen($input) % 4;
+        if ($remainder) {
+            $padlen = 4 - $remainder;
+            $input .= str_repeat('=', $padlen);
+        }
+        return base64_decode(strtr($input, '-_', '+/'));
+    }
+
+    /**
+     * Encode a string with URL-safe Base64.
+     *
+     * @param string $input The string you want encoded
+     *
+     * @return string The base64 encode of what you passed in
+     */
+    public static function urlsafeB64Encode($input)
+    {
+        return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
+    }
+
+    /**
+     * Helper method to create a JSON error.
+     *
+     * @param int $errno An error number from json_last_error()
+     *
+     * @return void
+     */
+    private static function handleJsonError($errno)
+    {
+        $messages = array(
+            JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
+            JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
+            JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
+            JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
+            JSON_ERROR_UTF8 => 'Malformed UTF-8 characters' //PHP >= 5.3.3
+        );
+        throw new DomainException(
+            isset($messages[$errno])
+            ? $messages[$errno]
+            : 'Unknown JSON error: ' . $errno
+        );
+    }
+
+    /**
+     * Get the number of bytes in cryptographic strings.
+     *
+     * @param string
+     *
+     * @return int
+     */
+    private static function safeStrlen($str)
+    {
+        if (function_exists('mb_strlen')) {
+            return mb_strlen($str, '8bit');
+        }
+        return strlen($str);
+    }
+}

+ 30 - 0
addons/shopro/library/apple-signin/Vendor/LICENSE

@@ -0,0 +1,30 @@
+Copyright (c) 2011, Neuman Vong
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Neuman Vong nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 8 - 0
addons/shopro/library/apple-signin/Vendor/SignatureInvalidException.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace AppleSignIn\Vendor;
+
+class SignatureInvalidException extends \UnexpectedValueException
+{
+
+}

+ 169 - 0
addons/shopro/library/chat/Events.php

@@ -0,0 +1,169 @@
+<?php
+
+namespace addons\shopro\library\chat;
+
+/**
+ * This file is part of workerman.
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the MIT-LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @author walkor<walkor@workerman.net>
+ * @copyright walkor<walkor@workerman.net>
+ * @link http://www.workerman.net/
+ * @license http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+
+/**
+ * 用于检测业务代码死循环或者长时间阻塞等问题
+ * 如果发现业务卡死,可以将下面declare打开(去掉//注释),并执行php start.php reload
+ * 然后观察一段时间workerman.log看是否有process_timeout异常
+ */
+//declare(ticks=1);
+
+use GatewayWorker\Lib\Gateway;
+use Workerman\Lib\Timer;
+
+/**
+ * 主逻辑
+ * 主要是处理 onConnect onMessage onClose 三个方法
+ * onConnect 和 onClose 如果不需要可以不用实现并删除
+ */
+class Events
+{
+
+    public static function onWorkerStart($businessWorker)
+    {
+        // 5 秒同步一下 客服当前接待客户数,计算客服忙碌度
+        Timer::add(5, function () {
+            // 获取当前连接的客服
+            $clientIds = Gateway::getClientIdListByGroup(Online::getGrouponName('online_customer_service'));
+
+            foreach ($clientIds as $client_id) {
+                $session = Gateway::getSession($client_id);
+                $customerService = $session['user'];
+                $customer_service_id = $session['uid'] ?? 0;        // 客服 id
+
+                if ($customer_service_id) {
+                    // 当前客服分组名
+                    $customerServiceGroupName = Online::getGrouponName('customer_service_user', ['customer_service_id' => $customer_service_id]);
+                    // 获取并设置当前客服正在服务的用户
+                    $customerService['current_num'] = Gateway::getClientIdCountByGroup($customerServiceGroupName);
+                    $customerService['busy_percent'] = $customerService['current_num'] / $customerService['max_num'];   // 繁忙程度,越大越繁忙
+                    Gateway::updateSession($client_id, ['user' => $customerService]);
+                }
+            }
+        });
+
+        // 初始化上传配置
+        Online::uploadConfigInit();
+    }
+
+
+    public static function onWebSocketConnect($client_id, $data) 
+    {
+        // 存储当前请求信息
+        $_SESSION['server'] = $data['server'] ?? [];
+
+        $request = $data['get'];
+
+        $linkerData = [];
+        $linkerData['identify'] = $request['identify'] ?? '';
+        $linkerData['session_id'] = $request['session_id'] ?? '';
+        $linkerData['token'] = $request['token'] ?? '';
+        $linkerData['expire_time'] = $request['expire_time'] ?? '';
+        $linkerData['customer_service_id'] = $request['customer_service_id'] ?? 0;
+
+        if (empty($linkerData['identify'])) {
+            // 缺少参数
+            Sender::error($client_id, [
+                'type' => 'connect_error',
+                'msg' => '连接错误'
+            ]);
+            Gateway::closeClient($client_id);
+            return false;
+        }
+
+        // 连接者
+        $linker = new Linker($client_id, $linkerData);
+
+        if ($linker->checkAndBind()) {
+            // init
+            $linker->init();
+        }
+    }
+
+
+    /**
+     * 当客户端发来消息时触发
+     * @param int $client_id 连接id
+     * @param mixed $message 具体消息
+     */
+    public static function onMessage($client_id, $requestData)
+    {
+        $requestData = json_decode($requestData, true);
+        $identify = $_SESSION['identify'] ?? '';
+        $type = $requestData['type'] ?? '';     // 消息类型
+        $data = $requestData['data'] ?? [];              // 要做的事件,参数
+        $message = $requestData['message'] ?? [];        // 发送的消息
+
+        if (empty($type) || empty($identify)) {
+            // 缺少参数
+            Sender::error($client_id, [
+                'type' => 'params_error',
+                'msg' => '参数错误'
+            ]);
+            Gateway::closeClient($client_id);
+            return false;
+        }
+
+        if ($type == 'ping') {
+            // 心跳检测,直接返回
+            return true;
+        }
+
+        if ($identify == 'customer_service') {
+            $session_id = $requestData['session_id'] ?? '';        // 如果是客服,接受传入的 session_id
+        } else {
+            $session_id = $_SESSION['uid'] ?? '';
+        }
+
+        $linkerData = [
+            'identify' => $identify,
+        ];
+
+        // 连接者
+        $linker = new Linker($client_id, $linkerData);
+
+        $linker->message($session_id, $type, $message, $data);
+    }
+    
+    /**
+     * 当用户断开连接时触发
+     * @param int $client_id 连接id
+     */
+    public static function onClose($client_id)
+    {
+        $identify = $_SESSION['identify'] ?? '';
+        if (empty($identify)) {
+            // 缺少参数
+            Sender::error($client_id, [
+                'type' => 'params_error',
+                'msg' => '参数错误'
+            ]);
+            Gateway::closeClient($client_id);
+            return false;
+        }
+
+        // 只能通过 $identify 获取 session
+        $linkerData = [
+            'identify' => $identify,
+        ];
+
+        // 连接者
+        $linker = new Linker($client_id, $linkerData);
+
+        $linker->close($client_id);
+    }
+}

+ 49 - 0
addons/shopro/library/chat/FileMonitor/start.php

@@ -0,0 +1,49 @@
+<?php
+use Workerman\Worker;
+use Workerman\Lib\Timer;
+
+// watch Applications catalogue
+$monitor_dir = realpath(__DIR__.'/..');
+
+// worker
+$worker = new Worker();
+$worker->name = 'FileMonitor';
+$worker->reloadable = false;
+$last_mtime = time();
+
+$worker->onWorkerStart = function()
+{
+    global $monitor_dir;
+    // watch files only in daemon mode
+    if(!Worker::$daemonize)
+    {
+        // chek mtime of files per second 
+        Timer::add(1, 'check_files_change', array($monitor_dir));
+    }
+};
+
+// check files func
+function check_files_change($monitor_dir)
+{
+    global $last_mtime;
+    // recursive traversal directory
+    $dir_iterator = new RecursiveDirectoryIterator($monitor_dir);
+    $iterator = new RecursiveIteratorIterator($dir_iterator);
+    foreach ($iterator as $file)
+    {
+        // only check php files
+        if(pathinfo($file, PATHINFO_EXTENSION) != 'php')
+        {
+            continue;
+        }
+        // check mtime
+        if($last_mtime < $file->getMTime())
+        {
+            echo $file." update and reload\n";
+            // send SIGUSR1 signal to master process for reload
+            posix_kill(posix_getppid(), SIGUSR1);
+            $last_mtime = $file->getMTime();
+            break;
+        }
+    }
+}

+ 39 - 0
addons/shopro/library/chat/Linker.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace addons\shopro\library\chat;
+
+
+class Linker
+{
+    public $data = [];
+
+    public $linker = null;
+
+    public function __construct($client_id, $data)
+    {
+        $this->data = $data;
+
+        $identify = $data['identify'];
+        
+        $identify = "\\addons\\shopro\\library\\chat\\linker\\" . ucfirst(camelize($identify));
+        if (!class_exists($identify)) {
+            // 连接身份不存在
+
+        }
+
+        $this->linker = new $identify($this, $client_id, $data);
+    }
+
+
+
+    public function linker() {
+        return $this->linker;
+    }
+
+
+    // 代理身份相关的方法
+    public function __call($method, $parameters)
+    {
+        return $this->linker()->{$method}(...$parameters);
+    }
+}

+ 1085 - 0
addons/shopro/library/chat/Online.php

@@ -0,0 +1,1085 @@
+<?php
+
+namespace addons\shopro\library\chat;
+
+use \GatewayWorker\Lib\Gateway;
+use addons\shopro\model\chat\Connection;
+use addons\shopro\model\chat\CustomerService;
+use addons\shopro\model\chat\Log as ChatLog;
+use addons\shopro\model\chat\User as ChatUser;
+use addons\shopro\library\chat\traits\GetLinkerTrait;
+use addons\shopro\model\chat\Question;
+use addons\shopro\model\User;
+use app\admin\model\Admin;
+
+class Online 
+{
+    use GetLinkerTrait;
+
+
+    public static function getConfig($type) {
+        // 初始化 workerman 的时候不能读取数据库,会导致数据库连接异常
+        $config = require(ROOT_PATH . 'addons' . DS . 'shopro' . DS . 'library' . DS . 'chat' . DS . 'config.php');
+
+        $system = $config[$type] ?? [];
+        return $system;
+    }
+
+
+
+    /**
+     * 先判断是否有对象存储,将对象存储配置注入到 upload 配置
+     *
+     * @return void
+     */
+    public static function uploadConfigInit() {
+        // 获取绑定的 插件 钩子
+        $hooks = config('addons.hooks');
+        $upload_config_inits = isset($hooks['upload_config_init']) && $hooks['upload_config_init'] ? $hooks['upload_config_init'] : [];
+        if ($upload_config_inits) {
+            $storage = end($upload_config_inits);
+            \think\Hook::add('upload_config_init', 'addons\\' . ucfirst($storage) . '\\' . ucfirst($storage));
+            // 注入 storage 配置
+            $upload = \app\common\model\Config::upload();
+            \think\Hook::listen("upload_config_init", $upload);
+            \think\Config::set('upload', array_merge(\think\Config::get('upload'), $upload));
+        }
+    }
+
+    /**
+     * 客服自定义 cdnurl 方法
+     * 1、提供默认域名,如果没配置对象存储,拼接当前接口域名(访问域名的直接获取,websocket 的从 websocket SESSION['server']请求头中获取)
+     * 2、调用默认 cdnurl 方法
+     * 
+     * @param [type] $val
+     * @param [type] $domain
+     * @return void
+     */
+    public static function cdnurl($val, $domain = null) {
+        $domain = $domain ? : self::getDomain();
+
+        return cdnurl($val, $domain);
+    }
+
+
+    /**
+     * 获取 websocket 的域名拼接 cdnurl
+     *
+     * @return void
+     */
+    public static function getDomain() {
+        // 优先以正常访问方式获取域名
+        $domain = request()->domain();
+        $host = request()->host();
+        if (!$domain || !$host) {
+            // 如果不能获取,说明是 websocket 连接,获取当前 server 中的 domain
+            $server = $_SESSION['server'];
+            $systemConfig = self::getConfig('system');
+            $is_ssl = $systemConfig['is_ssl'] ? true : false;
+            $domain = ($is_ssl ? 'https://' : 'http://') . $server['SERVER_NAME'];
+        }
+
+        return $domain;
+    }
+
+
+    // 主要为了记录当前系统总共有多少种分组
+    public static function getGrouponName($type, $data = []) {
+        switch($type) {
+            case 'online_user' :                        // 当前在线用户分组
+                $group_name = 'online_user';
+                break;
+            case 'online_waiting' :                        // 当前在线用户待分配客服分组
+                $group_name = 'online_waiting';
+                break;
+            case 'online_customer_service' :                        // 当前在线客服数组
+                $group_name = 'online_customer_service';
+                break;
+            case 'customer_service_user':               // 当前在线用户所在的客服分组
+                $group_name = 'customer_service_user:' . ($data['customer_service_id'] ?? 0);
+                break;
+            default :
+                $group_name = $type;
+                break;
+        }
+
+        return $group_name;
+    }
+
+    public static function getUId($id, $type)
+    {
+        $ids = is_array($id) ? $id : [$id];
+        foreach ($ids as &$i) {
+            $i = $type . '-' . $i;
+        }
+
+        return is_array($id) ? $ids : $ids[0];
+    }
+
+
+    public static function updateChatUser($session_id, $user) {
+        $chatUser = ChatUser::where(function ($query) use ($session_id, $user) {
+            $query->where('session_id', $session_id)
+                ->whereOr(function ($query) use ($user) {
+                    $query->where('user_id', '<>', 0)
+                        ->where('user_id', ($user ? $user['id'] : 0));
+                });
+        })->find();
+
+        $defaultAvatar = null;
+        $config = \addons\shopro\model\Config::where('name', 'user')->find();
+        if ($config) {
+            $userConfig = json_decode($config['value'], true);
+            $defaultAvatar = $userConfig['avatar'];
+        }
+
+        if (!$chatUser) {
+            $chatUser = new ChatUser();
+            
+            $chatUser->session_id = $session_id;
+            $chatUser->user_id = $user ? $user['id'] : 0;
+            $chatUser->nickname = $user ? $user['nickname'] : ('游客-' . substr($session_id, 0, 5));
+            $chatUser->avatar = $user ? $user->getData('avatar') : $defaultAvatar;
+            $chatUser->customer_service_id = 0;      // 断开连接的时候存入
+            $chatUser->lasttime = time();
+            
+        } else {
+            if ($user) {
+                // 更新用户信息
+                $chatUser->user_id = $user['id'] ?? 0;
+                $chatUser->nickname = $user['nickname'] ? $user['nickname'] : ('游客-' . substr($session_id, 0, 5));
+                $chatUser->avatar = $user['avatar'] ? $user->getData('avatar') : $defaultAvatar;
+            }
+
+            $chatUser->lasttime = time();        // 更新时间
+        }
+
+        $chatUser->save();
+        return $chatUser->toArray();
+    }
+
+    
+    /**
+     * 根据 id 获取客服
+     */
+    public static function customerServiceById($customer_service_id)
+    {
+        $customerService = CustomerService::where('id', $customer_service_id)->find();
+
+        return $customerService;
+    }
+
+
+
+    /**
+     * 检查客服身份
+     *
+     * @param string $token
+     * @param string $customer_service_id
+     * @param string $expire_time
+     * @return array
+     */
+    public static function checkAdmin($token, $customer_service_id, $expire_time) {
+        if ($token && $customer_service_id) {
+            // 获取客服信息
+            $customerService = self::customerServiceById($customer_service_id);
+            if (!$customerService) {
+                return false;
+            }
+            $customerService = $customerService->toArray();
+
+            // 获取 admin
+            $admin = Admin::get($customerService['admin_id']);
+            if (!$admin) {
+                return false;
+            }
+            $admin = $admin->toArray();
+
+            $current_token = md5($admin['username'] . $expire_time);
+            if (($expire_time + (86400 * 30)) > time() && $current_token == $token) {
+                // 验证通过
+                return [
+                    'customerService' => $customerService,
+                    'admin' => $admin
+                ];
+            }
+        }
+
+        return false;
+    }
+
+
+
+    /**
+     * 检测并获取用户
+     *
+     * @param [type] $token
+     * @return void
+     */
+    public static function checkUser($token) {
+        $data = \app\common\library\Token::get($token);
+
+        if (!$data) {
+            return false;
+        }
+
+        $user_id = intval($data['user_id']);
+        if ($user_id <= 0) {
+            return false;
+        }
+        
+        // 这个 user 不能转数组,用到了 $user->getData('avatar') 去拿原始的未拼接 cdnurl 头像地址
+        $user = User::where('id', $user_id)->find();
+        if (!$user) {
+            return false;
+        } 
+
+        return $user;
+    }
+
+
+
+    /**
+     * 判断客服在线状态, 只能客服用
+     *
+     * @param [type] $customer_service_id
+     * @return void
+     */
+    public static function customerServiceStatusById($customer_service_id, $oper_type = 'customer_service', $data = [])
+    {
+        $current_client_id = $data['client_id'] ?? '';      // oper_type = customer_service 时存在
+        
+        // 获取当前用户的所有session,并且当前连接的session是最新的
+        $customerServiceSessions = self::onlineCustomerServiceNewSessionById($customer_service_id, $current_client_id);
+        
+        $status = false;
+        foreach ($customerServiceSessions as $key => $customerServiceSession) {
+            $customerService = $customerServiceSession['user'] ?? [];
+            if ($customerService && in_array($customerService['status'], ['online', 'busy'])) {
+                // 只要其中一个在线,即为在线
+                $status = true;
+            }
+        }
+
+        return $status;
+    }
+
+
+
+    /**
+     * 客服上线
+     *
+     * @param string $client_id
+     * @param object $customerService
+     * @return object
+     */
+    public static function customerServiceOnline($client_id, $customerService)
+    {
+        // 更新客服状态
+        CustomerService::where('id', $customerService['id'])->update([
+            'status' => 'online'
+        ]);
+
+        // 重新更新客服信息
+        $customerService['status'] = 'online';
+
+        // 更新客服 session 为 online
+        $_SESSION['user']['status'] = 'online';
+
+        // 加入在线客服组
+        Gateway::joinGroup($client_id, Online::getGrouponName('online_customer_service'));
+
+        // 通知客服连接成功
+        Sender::customerServiceInit($client_id, $customerService);
+
+        // 通知连接的用户,客服上线了
+        Sender::customerServiceOnline($customerService);
+
+        // 通知所有在线客服,更新当前在线客服列表
+        Sender::customerServiceOnlineList();
+
+        return $customerService;
+    }
+
+
+    /**
+     * 客服忙碌
+     *
+     * @param string $client_id
+     * @param object $customerService
+     * @return object
+     */
+    public static function customerServiceBusy($client_id, $customerService)
+    {
+        // 更新客服状态
+        CustomerService::where('id', $customerService['id'])->update([
+            'status' => 'busy'
+        ]);
+
+        // 重新更新客服信息
+        $customerService['status'] = 'busy';
+
+        // 更新客服 session 为 busy
+        $_SESSION['user']['status'] = 'busy';
+
+        return $customerService;
+    }
+
+
+    /**
+     * 客服下线(这里不更新数据库,并且只更新当前连接为下线,如果当前客服在别的浏览器也有登录,则不受此操作影响)
+     *
+     * @param string $client_id
+     * @param object $customerService
+     * @return object
+     */
+    public static function customerServiceOffline($client_id = null, $customerService)
+    {
+        // 重新更新客服信息
+        $customerService['status'] = 'offline';
+
+        // 更新客服 session 为 offline
+        $_SESSION['user']['status'] = 'offline';
+
+        // 移除在线客服
+        Gateway::leaveGroup($client_id, Online::getGrouponName('online_customer_service'));
+
+        // 获取客服在线状态
+        $onlineStatus = self::customerServiceStatusById($customerService['id'], 'customer_service', ['client_id' => $client_id]);
+        
+        if (!$onlineStatus) {
+            // 绑定该 uid 的所有 session 的客服状态都离线了或者客服真实离线了,通知用户客服下线
+            Sender::customerServiceOffline($customerService);
+        }
+
+        // 通知所有客服更新在线的客服列表
+        Sender::customerServiceOnlineList();
+
+        return $customerService;
+    }
+
+
+
+    /**
+     * 客服真实离线
+     *
+     * @param int $customer_service_id
+     * @param array $customerService
+     * @return void
+     */
+    public static function customerServiceRealOffline($customer_service_id, $customerService) {
+        $isUidOnline = Gateway::isUidOnline(online::getUId($customer_service_id, 'customer_service'));
+
+        if (!$isUidOnline) {
+            // 绑定该 uid 的所有 client_id 都离线了,更新客服数据库为离线状态
+            CustomerService::where('id', $customerService['id'])->update([
+                'status' => 'offline'
+            ]);
+        }
+    }
+
+
+    /**
+     * 更新客服最后接入时间
+     *
+     * @param [type] $customerService
+     * @param [type] $oper_type
+     * @return void
+     */
+    public static function updateCustomerServiceLasttime($customerService, $oper_type)
+    {
+        // 更新 session 的 lasttime
+        if ($oper_type == 'customer_service') {
+            // 如果是客服自己操作接入
+            $_SESSION['user']['lasttime'] = time();
+        } else {
+            // 获取客服 client_id;
+            $customerServiceClientIds = Gateway::getClientIdByUid(Online::getUId($customerService['id'], 'customer_service'));
+
+            foreach ($customerServiceClientIds as $customer_service_client_id) {
+                $session = Gateway::getSession($customer_service_client_id);
+                $customerService = $session['user'];        // 客服信息
+                $customerService['lasttime'] = time();      // 更新最后接入时间
+    
+                // 更新 session 缓存
+                Gateway::updateSession($customer_service_client_id, [
+                    'user' => $customerService,
+                ]);
+            }
+        }
+
+        // 更新数据库
+        CustomerService::where('id', $customerService['id'])->update([
+            'lasttime' => time()
+        ]);
+    }
+
+
+
+    /**
+     * 用户最后一次的链接
+     *
+     * @param integer $user_id
+     * @param string $session_id
+     * @return array
+     */
+    public static function userLastConnection($user_id = 0, $session_id = '') {
+        $lastConnection = Connection::where(function ($query) use ($user_id, $session_id) {
+            if ($session_id) {
+                $query->where(function ($query) use ($session_id) {
+                    $query->where('session_id', '<>', '')
+                        ->where('session_id', 'not null')
+                        ->where('session_id', $session_id);
+                });
+            }
+            if ($user_id) {
+                $query->where(function ($query) use ($user_id) {
+                    $query->where('user_id', '<>', 0)
+                        ->where('user_id', 'not null')
+                        ->where('user_id', $user_id);
+                });
+            }
+        })->where('customer_service_id', '<>', 0)->order('id', 'desc')->find();
+
+        return $lastConnection;
+    }
+
+
+
+    /**
+     * 关闭当前 session_id 的所有连接
+     */
+    public static function closeConnectionBySessionId($session_id)
+    {
+        Connection::where('session_id', $session_id)->where('status', 'in', ['ing', 'waiting'])->update([
+            'status' => 'end'
+        ]);
+    }
+
+
+    /**
+     * 分配客服
+     *
+     * @param string $session_id
+     * @param string $user_id
+     * @return array
+     */
+    public static function allocatCustomerService($session_id, $user_id) {
+        $config = self::getConfig('basic');
+        $last_customer_service = $config['last_customer_service'] ?? 1;
+        $allocate = $config['allocate'] ?? 'busy';
+
+        // 分配的客服
+        $currentCustomerService = null;
+
+        // 使用上次客服
+        if ($last_customer_service) {
+            // 获取上次连接的信息
+            $lastConnection = self::userLastConnection($user_id, $session_id);
+
+            $lastCustomerService = null;
+            $currentCustomerService = null;
+            if ($lastConnection) {
+                // 获取上次客服信息
+                // $lastCustomerService = Online::customerServiceById($lastConnection['customer_service_id']);          // 读取数据库,不准确
+                $lastCustomerService = Self::onlineCustomerServiceById($lastConnection['customer_service_id']);       // 获取socket 连接里面上次客服是否在线
+
+                // 判断客服是否在线
+                if ($lastCustomerService) {
+                    if ($lastCustomerService['status'] == 'online') {
+                        $currentCustomerService = $lastCustomerService;
+                    }
+                }
+            }
+        }
+        
+        // 没有客服,随机分配
+        if (!$currentCustomerService) {
+            // 在线客服列表
+            $onlineCustomerServices = self::onlineCustomerServices();
+
+            if ($onlineCustomerServices) {
+                if ($allocate == 'busy') {
+                    // 将客服列表,按照工作繁忙程度正序排序, 这里没有离线的客服
+                    $onlineCustomerServices = array_column($onlineCustomerServices, null, 'busy_percent');
+                    ksort($onlineCustomerServices);
+                    
+                    // 取忙碌度最小,并且客服为 正常在线状态
+                    foreach ($onlineCustomerServices as $customerService) {
+                        if ($customerService['status'] == 'online') {
+                            $currentCustomerService = $customerService;
+                            break;
+                        }
+                    }
+
+                    if (!$currentCustomerService) {
+                        // 如果都不是 online 状态,默认取第一条
+                        $currentCustomerService = $onlineCustomerServices[0] ?? null;
+                    }
+                } else if ($allocate == 'turns') {
+                    // 按照最后接入时间正序排序,这里没有离线的客服
+                    $onlineCustomerServices = array_column($onlineCustomerServices, null, 'lasttime');
+                    ksort($onlineCustomerServices);
+
+                    // 取忙碌度最小,并且客服为 正常在线状态
+                    foreach ($onlineCustomerServices as $customerService) {
+                        if ($customerService['status'] == 'online') {
+                            $currentCustomerService = $customerService;
+                            break;
+                        }
+                    }
+
+                    if (!$currentCustomerService) {
+                        // 如果都不是 online 状态,默认取第一条
+                        $currentCustomerService = $onlineCustomerServices[0] ?? null;
+                    }
+                } else if ($allocate == 'random') {
+                    // 随机获取一名客服
+                    $onlineCustomerServices = array_column($onlineCustomerServices, null, 'id');
+
+                    $customer_service_id = 0;
+                    if ($onlineCustomerServices) {
+                        $customer_service_id = array_rand($onlineCustomerServices);
+                    }
+
+                    $currentCustomerService = $onlineCustomerServices[$customer_service_id] ?? null;
+                }
+            }
+        }
+
+        return $currentCustomerService;
+    }
+
+
+    /**
+     * 通过 session_id 记录客服信息,并且加入对应的客服组
+     *
+     * @param string $session_id    用户
+     * @param array $customerService    客服信息
+     * @return null
+     */
+    public static function bindCustomerServiceBySessionId($session_id, $customerService, $oper_type = 'customer_service') {
+        $uid = Online::getUId($session_id, 'user');
+        $client_ids = Gateway::getClientIdByUid($uid);
+
+        // 将当前 session_id 绑定的 client_id 都加入当前客服组
+        foreach ($client_ids as $client_id) {
+            self::bindCustomerService($client_id, $customerService, $oper_type);
+        }
+    }
+
+
+    /**
+     * 记录客服信息,并且加入对应的客服组
+     *
+     * @param string $client_id    用户
+     * @param array $customerService    客服信息
+     * @return null
+     */
+    public static function bindCustomerService($client_id, $customerService, $oper_type = 'user') {
+        // 当前用户使用 updateSession 会吧之前的内容覆盖掉,并且 getSession 无法获取刚刚设置的 session
+
+        // 更新用户的客服信息
+        if ($oper_type == 'user') {
+            // 当前连接者
+            $_SESSION['customer_service_id'] = $customerService['id'];
+            $_SESSION['customer_service'] = $customerService;
+        } else {
+            // 其他连接着
+            Gateway::updateSession($client_id, [
+                'customer_service_id' => $customerService['id'],
+                'customer_service' => $customerService
+            ]);
+        }
+        
+        // 更新客服的最后接入用户时间
+        self::updateCustomerServiceLasttime($customerService, $oper_type);
+
+        // 加入对应客服组,统计客服信息 customer_service_user:客服 ID
+        Gateway::joinGroup($client_id, Online::getGrouponName('customer_service_user', ['customer_service_id' => $customerService['id']]));
+        // 从等待接入组移除
+        Gateway::leaveGroup($client_id, Online::getGrouponName('online_waiting'));
+    }
+
+
+
+    /**
+     * 通过 session_id 将用户移除客服组
+     *
+     * @param string $session_id    用户
+     * @param array $customerService    客服信息
+     * @return null
+     */
+    public static function unBindCustomerServiceBySessionId($session_id, $customerService, $oper_type = 'customer_service')
+    {
+        $uid = Online::getUId($session_id, 'user');
+        $client_ids = Gateway::getClientIdByUid($uid);
+
+        // 将当前 session_id 绑定的 client_id 都移除当前客服组
+        foreach ($client_ids as $client_id) {
+            // 这里新客服已经绑定了,不需要移除session 了,所以 remove_session 为 false
+            self::unBindCustomerService($client_id, $customerService, false, $oper_type);
+        }
+    }
+
+
+    /**
+     * 将用户的客服信息移除
+     *
+     * @param string $client_id    用户
+     * @param array $customerService    客服信息
+     * @return null
+     */
+    public static function unBindCustomerService($client_id, $customerService, $remove_session = false, $oper_type = false)
+    {
+        if ($remove_session) {
+            if ($oper_type == 'user') {
+                // 当前连接者
+                $_SESSION['customer_service_id'] = 0;
+                $_SESSION['customer_service'] = [];
+            } else {
+                // 其他连接着
+                Gateway::updateSession($client_id, [
+                    'customer_service_id' => 0,
+                    'customer_service' => []
+                ]);
+            }
+        }
+
+        // 移除对应客服组
+        Gateway::leaveGroup($client_id, Online::getGrouponName('customer_service_user', ['customer_service_id' => $customerService['id']]));
+    }
+
+
+    // 转接用户
+    public static function transferCustomerServiceBySessionId($session_id, $newCustomerService, $oldCustomerService, $oper_type = 'customer_service') {
+        // 将老客服的服务记录直接保存
+        $chatUser = Self::getChatUserBySessionId($session_id);
+        if ($chatUser && $chatUser->user_id) {
+            $user = User::get($chatUser->user_id);
+        }
+        $userData = [
+            'user' => $user ?? null,
+            'session_id' => $session_id,
+            'chat_user' => $chatUser
+        ];
+
+        // 创建并结束 connection
+        $connection = Online::checkOrCreateConnection($userData, $oldCustomerService, true);
+
+        // 新客服接入用户
+        self::bindCustomerServiceBySessionId($session_id, $newCustomerService, $oper_type);
+
+        // 将用户从旧的客服组移除
+        self::unBindCustomerServiceBySessionId($session_id, $oldCustomerService, $oper_type);
+    }
+
+
+    /**
+     * 排队的用户,将用户加入 waiting 组
+     *
+     * @param string $client_id
+     * @return null
+     */
+    public static function bindWaiting ($client_id) {
+        Gateway::joinGroup($client_id, Online::getGrouponName('online_waiting'));
+    }
+
+
+    /**
+     * 判断是否有链接,如果没有创建新链接(为了避免用户刷新,然后这里重新创建新纪录)
+     */
+    public static function checkOrCreateConnection($userData, $customerService, $set_end = false) {
+        $user = $userData['user'] ?? null;
+        $chatUser = $userData['chat_user'] ?? null;
+        $session_id = $userData['session_id'] ?? '';
+
+        // 正在进行中的连接
+        $ingConnection = Connection::where('customer_service_id', $customerService['id'])
+                ->where('status', 'in', ['ing', 'waiting'])
+                ->where(function ($query) use ($user, $session_id) {
+                    $query->where('session_id', $session_id)->whereOr('user_id', ($user->id ?? 0));
+                })->find();
+        
+        if (!$ingConnection) {
+            // 不存在,创建新的
+            $ingConnection = new Connection();
+    
+            $ingConnection->user_id = $user ? $user['id'] : 0;
+            $ingConnection->nickname = $chatUser['nickname'];
+            $ingConnection->session_id = $session_id;
+            $ingConnection->customer_service_id = $customerService ? $customerService['id'] : 0;        // 0 没有客服在;
+            $ingConnection->starttime = time();
+            $ingConnection->endtime = $set_end ? time() : 0;
+            $ingConnection->status = $set_end ? 'end' : ($customerService ? 'ing' : 'waiting');
+            $ingConnection->createtime = time();
+            $ingConnection->updatetime = time();
+            $ingConnection->save();
+        } else {
+            if ($ingConnection->status == 'waiting' && $customerService) {
+                // 如果是 waiting, 并且存在客服,修改为 ing
+                $ingConnection->customer_service_id = $customerService['id'];
+                $ingConnection->status = 'ing';
+            }
+
+            if ($set_end) {
+                $ingConnection->status = 'end';
+                $ingConnection->endtime = time();
+            }
+
+            $ingConnection->save();
+        }
+
+        return $ingConnection;
+    }
+
+
+    /**
+     * 用户登录,更新当前 session_id 没有 user_id 的记录
+     */
+    public static function sessionUserSave($user, $session_id) {
+        // 更新用户连接
+        $connection = Connection::where('session_id', $session_id)->where('user_id', 0)->update([
+            'user_id' => $user['id'],
+            'nickname' => $user['nickname']
+        ]);
+
+        // 更新用户消息记录
+        $connection = ChatLog::where('session_id', $session_id)->where('user_id', 0)->update([
+            'user_id' => $user['id']
+        ]);
+
+        return true;
+    }
+
+
+    /**
+     * 通过连接 id 获取连接
+     */
+    public static function connectionById($connection_id = 0) {
+        $connection = Connection::where('id', $connection_id)->find();
+
+        return $connection;
+    }
+
+
+    /**
+     * 通过客服 id 获取当前客服正在服务的客户
+     */
+    public static function onlineByCustomerServiceId($customerService) {
+        $onlines = Connection::where('status', 'ing')->where('customer_service_id', $customerService['id'])->select();
+
+        return $onlines;
+    }
+
+
+    // 通过客服 id 获取当前客服历史服务过的客户
+    public static function historyByCustomerServiceId($customerService, $data)
+    {
+        $except = $data['except'] ?? [];
+
+        // 关闭 sql mode 的 ONLY_FULL_GROUP_BY
+        $oldModes = closeStrict(['ONLY_FULL_GROUP_BY']);
+
+        $historieLogs = Connection::with(['chat_user'])
+                ->where('customer_service_id', $customerService['id'])
+                ->where('session_id', 'not in', $except)
+                ->group('session_id')
+                ->select();
+
+        // 恢复 sql mode
+        recoverStrict($oldModes);
+
+        $histories = array_column($historieLogs, 'chat_user');
+
+        return array_values(array_filter($histories));
+    }
+
+    // 获取当前所有正在排队的用户
+    public static function waiting()
+    {
+        $waiting = Connection::where('status', 'waiting')->select();
+
+        return $waiting;
+    }
+
+
+    /**
+     * 通过 session_id 删除客户服务记录
+     *
+     * @param array $customerService
+     * @param string $session_id
+     * @return void
+     */
+    public static function delUserBySessionId($customerService, $session_id) {
+        return Connection::where('customer_service_id', $customerService['id'])->where('session_id', $session_id)->delete();
+    }
+
+
+    /**
+     * 删除所有客户服务记录
+     *
+     * @param array $customerService
+     * @param string $session_id
+     * @return void
+     */
+    public static function delAllUserBySessionId($customerService)
+    {
+        return Connection::where('customer_service_id', $customerService['id'])->delete();
+    }
+
+
+
+
+    /**
+     * 发送消息
+     *
+     * @param string $name  要调用的方法名,这里未使用
+     * @param string $arguments 给要调用的方法的参数
+     * @return object
+     */
+    public static function addMessage($name, $arguments) {
+        $receive_id = $arguments[0] ?? 0;
+        $content = $arguments[1] ?? [];
+        $params = $arguments[2] ?? [];      // 额外参数
+        $sender = $params['sender'] ?? [];
+
+        // 判断是否传入的发送人
+        if ($sender) {
+            // 传入了发送人信息
+            extract($sender);
+        } else {
+            // 默认对发 用户 发送给客服, 客服发送给用户
+            $sender_identify = $_SESSION['identify'];
+
+            if ($sender_identify == 'customer_service') {
+                // 获取发送信息
+                extract(self::getCustomerServiceSenderData($receive_id, $content));
+            } else {
+                // 用户
+                $session_id = $_SESSION['uid'];
+                $user_id = $_SESSION['user_id'] ?? 0;       // 如果是游客,这里为 0
+                $user = $_SESSION['user'];
+                $sender_id = $_SESSION['chat_user'] ? $_SESSION['chat_user']['id'] : 0;
+            }
+        }
+
+        // 返回 message_type message
+        extract(self::getMessageData($content));
+
+        $chatLog = new ChatLog();
+
+        $chatLog->session_id = $session_id;
+        $chatLog->user_id = $user_id;
+        $chatLog->sender_identify = $sender_identify;
+        $chatLog->sender_id = $sender_id;
+        $chatLog->message_type = $message_type;
+        $chatLog->message = $message;
+        $chatLog->save();
+
+        // 加载消息人
+        $chatLog->identify = $chatLog->identify;
+
+        return $chatLog;
+    }
+
+
+
+    /**
+     * 客服给用户发消息是,获取发送参数
+     *
+     * @param [type] $receive_id
+     * @param [type] $content
+     * @return array
+     */
+    public static function getCustomerServiceSenderData($receive_id, $content) {
+        // 客服
+        $sender_id = $customer_service_id = $_SESSION['uid'];
+        $customerService = $_SESSION['user'];
+        $session_id = $receive_id;
+
+        $user_id = 0;
+        $uid = Online::getUId($session_id, 'user');
+        if (Gateway::isUidOnline($uid)) {
+            // 接受者在线, 通过 uid 获取 client_id, 返回的是一个数组,取第一个,只是为了取对应的 user_id
+            $client_ids = Gateway::getClientIdByUid($uid);
+
+            // 获取数组第一个
+            $client_ids = array_values(array_filter($client_ids));
+            $client_id = $client_ids[0] ?? 0;
+
+            $receiveSession = Gateway::getSession($client_id);
+            if ($receiveSession && $receiveSession['user_id']) {
+                $user_id = $receiveSession['user_id'];
+            }
+        } else {
+            // 通过 chatUser 获取 user_id
+            $chatUser = self::getChatUserBySessionId($session_id);
+            if ($chatUser) {
+                $user_id = $chatUser['user_id'];
+            }
+        }
+
+        return compact("session_id", "user_id", "sender_id");
+    }
+
+
+    
+    /**
+     * 获取消息类型
+     *
+     * @param [type] $content
+     * @return array
+     */
+    public static function getMessageData ($content) {
+        $type = $content['type'] ?? '';
+        $msg = $content['msg'] ?? '';
+        $data = $content['data'] ?? [];         // 特定 type 类型存在,包含 type = message
+        $messageData = $data['message'] ?? [];      // type=message 存在 
+
+        if (in_array($type, ['init', 'access'])) {
+            // 系统消息
+            $message_type = 'system';
+            $message = $msg;
+        } else if ($type == 'message') {
+            $message_type = $messageData['message_type'] ?? 'text';
+            $message_content = $messageData['message'] ?? '';
+
+            switch ($message_type) {
+                case 'text':
+                    $message = $message_content;
+                    break;
+                default:
+                    $message = is_array($message_content) ? json_encode($message_content) : $message_content;
+                    break;
+            }
+        }
+
+        return compact("message_type", "message");
+    }
+
+    /**
+     * 将消息标记为已读
+     *
+     * @param array $linker 用户信息,user_id session_id
+     * @param string $select_identify user & customer_service
+     * @return void 
+     */
+    public static function readMessage($linker, $select_identify = 'user')
+    {
+        $session_id = $linker['session_id'] ?? '';
+        $user_id = $linker['user_id'] ?? '';
+        $select_identify = camelize($select_identify);      // 处理为 驼峰
+
+        ChatLog::where(function ($query) use ($session_id, $user_id) {
+            $query->where(function ($query) use ($session_id) {
+                $query->where('session_id', $session_id)
+                    ->where('session_id', 'not null')
+                    ->where('session_id', '<>', '');
+            })
+            ->whereOr(function ($query) use ($user_id) {
+                $query->where('user_id', $user_id)
+                    ->where('user_id', '<>', 0);
+            });
+        })->{$select_identify}()->update([
+            'readtime' => time()
+        ]);
+    }
+
+
+
+    /**
+     * 获取消息列表
+     *
+     * @param array $linker     要获取的用户
+     * @param array $data       参数
+     * @return array
+     */
+    public static function messageList($linker, $data) {
+        $session_id = $linker['session_id'] ?? '';
+        $user_id = $linker['user_id'] ?? '';
+
+        $page = $data['page'] ?? 1;
+        $per_page = $data['per_page'] ?? 20;
+        $last_id = $data['last_id'] ?? 0;
+
+        $messageList = ChatLog::where(function ($query) use ($session_id, $user_id) {
+            $query->where(function ($query) use ($session_id) {
+                $query->where('session_id', $session_id)
+                    ->where('session_id', 'not null')
+                    ->where('session_id', '<>', '');
+            })
+            ->whereOr(function ($query) use ($user_id) {
+                $query->where('user_id', $user_id)
+                    ->where('user_id', '<>', 0);
+            });
+        });
+
+        // 避免消息重复
+        if ($last_id) {
+            $messageList = $messageList->where('id', '<=', $last_id);
+        }
+
+        $messageList = $messageList->order('id', 'desc')->paginate($per_page, false, [
+            'page' => $page
+        ]);
+
+        $messageData = $messageList->items();
+        if ($messageData) {
+            // 批量处理消息发送人
+            $messageData = ChatLog::formatIdentify($messageData);
+            $messageList->data = $messageData;
+        }
+
+        return $messageList;
+    }
+
+
+
+    /**
+     * 用户列表增加最后一条聊天记录
+     * @param array $chatUsers
+     * @param string $select_identify 查询对象,默认客服查用户的,用户查客服的
+     * @return array
+     */
+    public static function userSetMessage($chatUsers, $select_identify = 'user') {
+        foreach ($chatUsers as &$chatUser) {
+            $chatUser['last_message'] = ChatLog::where('session_id', $chatUser['session_id'])->order('id', 'desc')->find();
+            $chatUser['message_unread_num'] = ChatLog::where('session_id', $chatUser['session_id'])->where('readtime', 'null')->{$select_identify}()->count();
+        }
+
+        return $chatUsers;
+    }
+
+
+    public static function userRealOffline($session_id, $customerService) {
+        // 判断 uid 是否还在线,如果是刷新浏览器,只会出现很短暂的掉线,这里检测依然还是在线状态
+        $isUidOnline = Gateway::isUidOnline(online::getUId($session_id, 'user'));
+        if (!$isUidOnline) {
+            // 不在线,关闭这个用户所有连接
+            self::closeConnectionBySessionId($session_id);
+
+            // 记录用户本次客服人员,并且更新最后服务时间
+            $chatUser = self::getChatUserBySessionId($session_id);
+            $chatUser->customer_service_id = $customerService['id'] ?? 0;
+            $chatUser->lasttime = time();
+            $chatUser->save();
+        }
+    }
+
+
+    /**
+     * 常见问题
+     *
+     * @param int $question_id
+     * @param array $receives
+     * @return void
+     */
+    public static function questionReply ($question_id, $receives) {
+        $question = Question::get($question_id);
+
+        if ($question) {
+            Sender::questionReply($question, $receives);
+        }
+    }
+}

+ 269 - 0
addons/shopro/library/chat/Sender.php

@@ -0,0 +1,269 @@
+<?php
+
+namespace addons\shopro\library\chat;
+
+use GatewayWorker\Lib\Gateway;
+use addons\shopro\library\chat\traits\SenderTrait;
+use addons\shopro\library\chat\traits\GetLinkerTrait;
+
+/**
+ * 通知类
+ */
+class Sender
+{
+    use SenderTrait, GetLinkerTrait;
+
+
+    /**
+     * 通知客服用户上线
+     *
+     * @param string $session_id    上线用户
+     * @return void
+     */
+    public static function userOnline($session_id, $chatUser) {
+        // 获取所有在线客服的 client_ids 
+        $onlineCustomerServiceClientIds = self::onlineCustomerServiceClientIds();
+
+        Sender::successAll([
+            'type' => 'user_online',
+            'msg' => '用户上线',
+            'data' => [
+                'session_id' => $session_id,
+                'user' => $chatUser,
+                'customer_service' => $_SESSION['customer_service'] ? : null,
+            ]
+        ], $onlineCustomerServiceClientIds);
+    }
+
+
+    /**
+     * 通知在线客服用户下线
+     *
+     * @param string $session_id    下线用户
+     * @return void
+     */
+    public static function userOffline($session_id) {
+        // 获取所有在线客服的 client_ids
+        $onlineCustomerServiceClientIds = self::onlineCustomerServiceClientIds();
+
+        // 通知在线客服,用户下线
+        Sender::successAll([
+            'type' => 'user_offline',
+            'msg' => '用户下线',
+            'data' => [
+                'session_id' => $session_id,
+            ]
+        ], $onlineCustomerServiceClientIds);
+    }
+
+
+    /**
+     * 通知所有客服用户已被接入
+     *
+     * @return void
+     */
+    public static function userAccessed($session_id, $customerService) {
+        // 获取所有在线客服的 client_ids
+        $onlineCustomerServiceClientIds = self::onlineCustomerServiceClientIds();
+
+        // 通知在线客服,用户被接入
+        Sender::successAll([
+            'type' => 'user_accessed',
+            'msg' => '用户被接入',
+            'data' => [
+                'session_id' => $session_id,
+                'customer_service' => $customerService
+            ]
+        ], $onlineCustomerServiceClientIds);
+    }
+
+
+    public static function userAccess($customerService, $session_id, $oper_type = 'user') {
+        $customer_service_id = $customerService['id'] ?? 0;
+        
+        if ($oper_type == 'user') {
+            $chatUser = $_SESSION['chat_user'];
+        } else {
+            $chatUser = Online::getChatUserBySessionId($session_id);
+        }
+
+        Sender::successByCustomerServiceId($customer_service_id, [
+            'type' => 'user_access',
+            'msg' => '有新的用户接入',
+            'data' => [
+                'session_id' => $session_id,
+                'chat_user' => Online::userSetMessage([$chatUser])[0]        // 额外获取最后一条消息
+            ]
+        ]);
+    }
+
+
+    /**
+     * 客服初始化通知
+     *
+     * @param string $client_id
+     * @param array $customerService
+     * @return void
+     */
+    public static function customerServiceInit($client_id, $customerService) {
+        // 客服正在服务的用户, 并且追加最后一条 message
+        $onlines = Online::userSetMessage(self::customerServiceOnlineUsers($customerService));
+
+        // 在线用户 的 session_id
+        $onlineSessionIds = array_column($onlines, 'session_id');
+
+        // 历史服务客户, 并且追加最后一条 message
+        $histories = Online::userSetMessage(self::customerServiceHistoryUsers($customerService, $onlineSessionIds));
+
+        // 等待接待用户, 并且追加最后一条 message
+        $waitings = Online::userSetMessage(self::onlineWaitingUsers());
+
+        Sender::success($client_id, [
+            'type' => 'init',
+            'msg' => '连接成功',
+            'data' => [
+                'client_id' => $client_id,
+                'onlines' => $onlines,
+                'histories' => $histories,
+                'waitings' => $waitings,
+                'customer_service' => $_SESSION['user'] ?? null
+            ]
+        ]);
+    }
+
+
+    /**
+     * 通知正在连接的用户,客服上线了
+     *
+     * @param array $customerService
+     * @return void
+     */
+    public static function customerServiceOnline($customerService) {
+        // 通知正在连接的用户,客服上线了
+        $userClientIds = self::customerServiceUserClientIds($customerService);
+
+        Sender::successAll([
+            'type' => 'customer_service_online',
+            'msg' => '客服 ' . $customerService['name'] . ' 上线',
+            'data' => [
+                'customer_service' => $customerService
+            ]
+        ], $userClientIds);
+    }
+
+
+    /**
+     * 通知正在连接的用户,客服下线
+     *
+     * @param array $customerService
+     * @return void
+     */
+    public static function customerServiceOffline($customerService) {
+        // 通知正在连接的用户,客服下线了
+        $userClientIds = self::customerServiceUserClientIds($customerService);
+
+        Sender::successAll([
+            'type' => 'customer_service_offline',
+            'msg' => '客服 ' . $customerService['name'] . ' 离线',
+            'data' => [
+                'customer_service' => $customerService
+            ]
+        ], $userClientIds);
+    }
+
+
+
+    /**
+     * 通知所有在线客服,更新在线客服列表
+     *
+     * @return void
+     */
+    public static function customerServiceOnlineList() {
+        // 通知所有在线客服,更新当前在线客服列表
+        $onlineCustomerServiceClientIds = self::onlineCustomerServiceClientIds();
+
+        // 获取所有在线客服信息,自动过滤重复
+        $customerServices = self::onlineCustomerServices();
+        
+        // 通知在线客服,更新当前在线客服列表
+        Sender::successAll([
+            'type' => 'customer_service_update',
+            'msg' => '更新客服列表',
+            'data' => [
+                'customer_services' => $customerServices,
+            ]
+        ], $onlineCustomerServiceClientIds);
+    }
+
+
+
+    /**
+     * 问题快速回答
+     *
+     * @param array $question
+     * @param array $receives
+     * @return void
+     */
+    public static function questionReply($question, $receives) {
+        $client_id = $receives['client_id'] ?? '';
+        $session_id = $receives['session_id'] ?? '';
+        $user_id = $receives['user_id'] ?? '';
+        $customer_service_id = $receives['customer_service_id'] ?? 0;
+        $customerService = $receives['customer_service'] ?? [];
+
+        $result = null;
+        if ($session_id) {
+            // 通知用户
+            $result = Sender::messageBySessionId($session_id, [
+                    'type' => 'message',
+                    'msg' => '收到消息',
+                    'data' => [
+                        'message' => [
+                            'message_type' => 'text',
+                            'message' => $question['content']
+                        ],
+                        'customer_service' => $customerService
+                    ]
+                ], [
+                    'sender' => array_merge([
+                        'sender_identify' => 'customer_service',
+                        'sender_id' => $customer_service_id
+                    ], $receives)
+                ]
+            );
+        } 
+        
+        if ($customer_service_id && $result && isset($result['data']['message'])){
+            // 通知客服
+            Sender::successByCustomerServiceId($customer_service_id, [
+                    'type' => 'message',
+                    'msg' => '收到消息',
+                    'data' => [
+                        'message' => $result['data']['message'],
+                        'session_id' => $session_id
+                    ]
+                ]
+            );
+        }
+    }
+
+
+    
+    /**
+     * 删除用户
+     *
+     * @param string $client_id
+     * @param int $result
+     * @param array $data
+     * @return void
+     */
+    public static function delUser($client_id, $data = []) {
+
+        Sender::success($client_id, [
+            'type' => 'del_success',
+            'msg' => '删除成功',
+            'data' => $data
+        ]);
+    }
+}
+    

+ 98 - 0
addons/shopro/library/chat/Start.php

@@ -0,0 +1,98 @@
+<?php
+
+namespace addons\shopro\library\chat;
+
+use GatewayWorker\BusinessWorker;
+use GatewayWorker\Gateway;
+use GatewayWorker\Register;
+use Workerman\Worker;
+
+/**
+ * 启动 gateway
+ */
+class Start
+{
+    public $config = null;
+
+    public function __construct() {
+        $this->config = Online::getConfig('system');
+    }
+
+
+    // 启动 register
+    public function register () {
+        $register = new Register('text://0.0.0.0:' . $this->config['business_worker_port']);
+    }
+
+
+    // 启动 businessWorker
+    public function businessWorker() {
+        // bussinessWorker 进程
+        $worker = new BusinessWorker();
+        // worker名称
+        $worker->name = 'ShoproChatBusinessWorker';
+        // bussinessWorker进程数量
+        $worker->count = $this->config['business_worker_num'];
+        // 服务注册地址
+        $worker->registerAddress = '127.0.0.1:' . $this->config['business_worker_port'];
+        //设置Event 类
+        $worker->eventHandler = 'addons\shopro\library\chat\Events';
+    }
+
+
+
+    // 启动 gateway
+    public function gateway() {
+        $is_ssl = $this->config['is_ssl'] ?? 0;
+        $ssl_type = $this->config['ssl_type'] ?? 'cert';
+        $ssl_cert = $this->config['ssl_cert'] ?? '';
+        $ssl_key = $this->config['ssl_key'] ?? '';
+
+        $context = [];
+        if ($is_ssl && $ssl_type == 'cert') {
+            // is_ssl 并且是证书模式
+            $context['ssl'] = [
+                'local_cert' => $ssl_cert,
+                'local_pk' => $ssl_key,
+                'verify_peer' => false
+            ];
+        }
+
+        // gateway 进程,这里使用Text协议,可以用telnet测试
+        $gateway = new Gateway("websocket://0.0.0.0:" . $this->config['gateway_port'], $context);
+
+        if ($is_ssl && $ssl_type == 'cert') {
+            // 开启 ssl 传输
+            $gateway->transport = 'ssl';
+        }
+
+        // gateway名称,status方便查看
+        $gateway->name = 'ShoproChatGateway';
+        // gateway进程数
+        $gateway->count = $this->config['gateway_num'];
+        // 本机ip,分布式部署时使用内网ip
+        $gateway->lanIp = '127.0.0.1';
+        // 内部通讯起始端口,假如$gateway->count=4,起始端口为4000
+        // 则一般会使用4000 4001 4002 4003 4个端口作为内部通讯端口 
+        $gateway->startPort = $this->config['gateway_start_port'];
+        // 服务注册地址
+        $gateway->registerAddress = '127.0.0.1:' . $this->config['business_worker_port'];
+
+        // 心跳间隔
+        $gateway->pingInterval = 30;
+        // 心跳数据
+        $gateway->pingData = '';        // 客户端定时发送心跳
+        // 客户端在30秒内有1次未回复就断开连接
+        $gateway->pingNotResponseLimit = 3;
+    }
+
+
+
+    // 设置日志
+    public function setLog($basePath) {
+        // 日志文件
+        Worker::$logFile = $basePath . 'library/chat/log/shopro_chat.log';
+        // Worker::$stdoutFile = $basePath . 'library/chat/log/std_out.log';        // 如果部署的时候部署错误(比如未删除php禁用函数),会产生大量日志,先关掉
+        Worker::$pidFile = $basePath . 'library/chat/log/shopro_chat.pid';
+    }
+}

+ 23 - 0
addons/shopro/library/chat/config.php

@@ -0,0 +1,23 @@
+<?php
+
+return array (
+  'type' => 'shopro',
+  'basic' => 
+  array (
+    'last_customer_service' => 1,
+    'allocate' => 'busy',
+    'notice' => '显示在用户端头部',
+  ),
+  'system' => 
+  array (
+    'is_ssl' => 1,
+    'ssl_type' => 'reverse_proxy',
+    'ssl_cert' => '/www/server/panel/vhost/cert/****/fullchain.pem',
+    'ssl_key' => '/www/server/panel/vhost/cert/****/privkey.pem',
+    'gateway_port' => '1818',
+    'gateway_num' => 2,
+    'gateway_start_port' => '2020',
+    'business_worker_port' => '2248',
+    'business_worker_num' => 4,
+  ),
+);

+ 290 - 0
addons/shopro/library/chat/linker/CustomerService.php

@@ -0,0 +1,290 @@
+<?php
+
+namespace addons\shopro\library\chat\linker;
+
+use app\common\library\Auth;
+use addons\shopro\library\chat\Online;
+use addons\shopro\library\chat\Sender;
+use addons\shopro\library\chat\traits\GetLinkerTrait;
+use addons\shopro\model\chat\User as ChatUser;
+use GatewayWorker\Lib\Gateway;
+use app\admin\model\Admin;
+use Workerman\Lib\Timer;
+
+class CustomerService
+{
+
+    use GetLinkerTrait;
+
+    public $linker = null;      // addons\shopro\library\customerservice\Linker
+
+    public $identify = 'customer_service';
+
+    public $client_id = null;
+
+    public $admin = null;       // 当前客服对应的 fastadmin 管理员
+
+    public $user = null;        // 当前 fastadmin 管理员对应的 客服
+
+
+    public function __construct($linker, $client_id, $data)
+    {
+        // 初始化获取当前连接着身份
+        $this->linker = $linker;
+
+        $this->client_id = $client_id;           // 当前 client_id
+        
+
+        // 获取当前 session
+        if (isset($_SESSION['uid']) && !empty($_SESSION['uid']))
+        {
+            $this->user = $_SESSION['user'];
+            $this->admin = $_SESSION['admin'];
+        } else {
+            $token = $data['token'] ?? '';
+            $expire_time = $data['expire_time'] ?? 0;
+            $customer_service_id = $data['customer_service_id'] ?? 0;
+
+            $data = Online::checkAdmin($token, $customer_service_id, $expire_time);
+            if ($data) {
+                $this->user = $data['customerService'];
+                $this->admin = $data['admin'];
+            }
+        }
+    }
+
+
+
+    /**
+     * 检测并绑定 Uid
+     */
+    public function checkAndBind()
+    {
+        if (!$this->admin) {
+            Sender::error($this->client_id, [
+                'type' => 'nologin',
+                'msg' => '请先登录管理后台'
+            ]);
+
+            Gateway::closeClient($this->client_id);
+            return false;
+        }
+
+        if (!$this->user) {
+            Sender::error($this->client_id, [
+                'type' => 'no_customer_service',
+                'msg' => '您还不是客服'
+            ]);
+
+            Gateway::closeClient($this->client_id);
+            return false;
+        }
+
+        // 绑定 uid
+        Gateway::bindUid($this->client_id, Online::getUId($this->user['id'], 'customer_service'));
+
+        $_SESSION['uid'] = $this->user['id'];
+        $_SESSION['user'] = $this->user;
+        $_SESSION['admin_id'] = $this->admin ? $this->admin['id'] : 0;
+        $_SESSION['admin'] = $this->admin;
+        $_SESSION['identify'] = $this->identify;
+
+        return true;
+    }
+
+
+    /**
+     * 初始化客服
+     */
+    public function init() {
+        $customerService = $this->user;
+
+        // 客服上线
+        Online::customerServiceOnline($this->client_id, $this->user);
+    }
+
+
+
+    public function message($session_id, $type, $message, $data)
+    {
+        if ($type == 'message') {
+            // 给用户发消息
+            Sender::messageBySessionId($session_id, [
+                'type' => 'message',
+                'msg' => '收到消息',
+                'data' => [
+                    'message' => $message,
+                    'customer_service' => $_SESSION['user']
+                ]
+            ]);
+
+            Sender::success($this->client_id, [
+                'type' => 'receipt',
+                'msg' => '发送成功', 
+            ]);
+        } else if ($type == 'access') {     // 接入
+            // 客服信息
+            $customerService = $this->user;
+            
+            // 接入客户
+            Online::bindCustomerServiceBySessionId($session_id, $customerService, 'customer_service');
+
+            $msg = '您好,客服 ' . $customerService['name'] . " 为您服务";
+
+            // 通知用户客服接入
+            Sender::successBySessionId($session_id, [
+                'type' => 'access',
+                'msg' => '客服接入',
+                'data' => [
+                    'message' => [
+                        'message_type' => 'system',
+                        'message' => $msg,
+                        'createtime' => time()
+                    ],
+                    'customer_service' => $customerService
+                ]
+            ]);
+
+            // 通知所有客服,这个用户已接入,把这个用户从客服待接入列表删除
+            Sender::userAccessed($session_id, $customerService);
+
+            // 通知客服自己,有新的用户接入
+            Sender::userAccess($customerService, $session_id, 'customer_service');
+        } else if ($type == 'transfer') {     // 转接
+            // 当前客服信息
+            $customerService = $this->user;
+            $new_customer_service_id = $data['customer_service_id'] ?? 0;
+
+            if (!$new_customer_service_id) {
+                // 没有传入转接客服 id
+                Sender::error($this->client_id, [
+                    'type' => 'transfer_error',
+                    'msg' => '请选择要转接的客服'
+                ]);
+            }
+
+            // 获取被转接入的客服, 自动只取用户信息,过滤重复
+            $newCustomerService = Self::onlineCustomerServiceById($new_customer_service_id);
+
+            // 不能转接给自己
+            if ($new_customer_service_id == $customerService['id']) {
+                // 没有传入转接客服 id
+                Sender::error($this->client_id, [
+                    'type' => 'transfer_error',
+                    'msg' => '您不能转接给自己'
+                ]);
+            }
+
+            // 转接客户,加入新客服,移除老客服
+            Online::transferCustomerServiceBySessionId($session_id, $newCustomerService, $customerService, 'customer_service');
+
+            // 通知用户客服已切换
+            $msg = '您好,您的客服已由 ' . $customerService['name'] . " 切换为 " . $newCustomerService['name'];
+            Sender::successBySessionId($session_id, [
+                'type' => 'access',
+                'msg' => '新客服接入',
+                'data' => [
+                    'message' => [
+                        'message_type' => 'system',
+                        'message' => $msg,
+                        'createtime' => time()
+                    ],
+                    'customer_service' => $newCustomerService
+                ]
+            ]);
+
+            // 通知所有客服,用户被接入(用户接入客服变了,要改变历史里面的当前服务客服)
+            Sender::userAccessed($session_id, $newCustomerService); 
+
+            // 通知新的客服,有新的用户接入
+            Sender::userAccess($newCustomerService, $session_id, 'customer_service');
+
+            // 通知当前客服,用户被转接成功
+            Sender::successByCustomerServiceId($customerService['id'], [
+                'type' => 'transfer_success',
+                'msg' => '转接成功',
+                'data' => [
+                    'session_id' => $session_id
+                ]
+            ]);
+        } else if ($type == 'message_list') {
+            // 获取 session_id 身份
+            $customerUser = ChatUser::where('session_id', $session_id)->find();
+
+            // 获取消息列表
+            $linker = [
+                'session_id' => $session_id,
+                'user_id' => $customerUser ? $customerUser['user_id'] : 0
+            ];
+
+            // 将用户发给自己的消息标记为 已读
+            Online::readMessage($linker, 'user');
+            // 通知用户消息列表
+            $messageList = Online::messageList($linker, $data);
+            Sender::success($this->client_id, [
+                'type' => 'message_list',
+                'msg' => '获取成功',
+                'data' => [
+                    'message_list' => $messageList
+                ]
+            ]);
+        } else if ($type == 'switch_status') {
+            // 客服信息
+            $customerService = $this->user;
+            $status = $data['status'];
+            
+            switch($status) {
+                case 'online':      // 切换为在线
+                    Online::customerServiceOnline($this->client_id, $customerService);
+                    break;
+                case 'offline':     // 切换为离线
+                    Online::customerServiceOffline($this->client_id, $customerService);
+                    break;
+                case 'busy':        // 切换为忙碌
+                    Online::customerServiceBusy($this->client_id, $customerService);
+                    break;
+            }
+
+            Sender::success($this->client_id, [
+                'type' => 'switch_ok',
+                'msg' => '切换成功',
+                'data' => [
+                    'status' => $status
+                ]
+            ]);
+        } else if ($type == 'del_user') {
+            $customerService = $this->user;
+            $session_id = $data['session_id'];
+
+            // 返回删除条数,如果用户刚连上,connection 还不存在,这里result 不做使用
+            $result = Online::delUserBySessionId($customerService, $session_id);
+
+            Sender::delUser($this->client_id, [
+                'session_id' => $session_id
+            ]);
+        } else if ($type == 'del_all_user') {
+            $customerService = $this->user;
+
+            // 返回删除条数,如果用户刚连上,connection 还不存在,这里result 不做使用
+            $result = Online::delAllUserBySessionId($customerService);
+
+            Sender::delUser($this->client_id);
+        }
+    }
+
+
+    public function close()
+    {
+        $customer_service_id = $_SESSION['uid'];
+        $customerService = $_SESSION['user'];
+        $admin_id = $_SESSION['admin_id'];
+
+        // 客服下线,只更新当前连接的在线状态
+        Online::customerServiceOffline($this->client_id, $customerService);
+
+        // 定时器十秒检测,如果客服是真的下线了,更新为真实下线
+        Timer::add(10, function ($customer_service_id, $customerService) {
+            Online::customerServiceRealOffline($customer_service_id, $customerService);
+        }, [$customer_service_id, $customerService], false);
+    }
+}

+ 257 - 0
addons/shopro/library/chat/linker/User.php

@@ -0,0 +1,257 @@
+<?php
+
+namespace addons\shopro\library\chat\linker;
+
+use app\common\library\Auth;
+use addons\shopro\library\chat\Online;
+use addons\shopro\library\chat\Sender;
+use GatewayWorker\Lib\Gateway;
+use Workerman\Lib\Timer;
+
+class User 
+{
+    public $linker = null;      // addons\shopro\library\customerservice\Linker
+
+    public $identify = 'user';
+
+    public $session_id = null;  // 前端用户标识
+
+    public $client_id = null;
+
+    public $user = null;        // 当前 fastadmin 用户
+
+    public $chatUser = null;     // 当前用户对应的顾客表(chat_user) 信息 
+
+    public function __construct($linker, $client_id, $data)
+    {
+        // 初始化获取当前连接着身份
+        $this->linker = $linker;
+        $this->client_id = $client_id;           // 当前 client_id
+
+        if (isset($_SESSION['uid']) && !empty($_SESSION['uid'])) {
+            $this->session_id = $_SESSION['uid'] ?? '';
+            $this->user = $_SESSION['user'] ?? null;
+        } else {
+            $token = $data['token'] ?? '';                     // fastadmin token
+            $this->session_id = $data['session_id'] ?? '';           // session_id 如果没有,则后端生成
+            
+            // 根据 token 获取对应的 fastadmin 用户
+            if ($token) {
+                $user = Online::checkUser($token);
+                if ($user) {
+                    $this->user = $user;
+                }
+                $_SESSION['user'] = $this->user;
+            }
+
+            // 初始化连接,需要获取 session_id
+            if (!$this->session_id) {
+                // 如果没有 session_id
+                if ($this->user) {
+                    // 如果存在 user
+                    $chatUser = Online::getChatUserByUserId($this->user['id']);
+                    $this->session_id = $chatUser ? $chatUser['session_id'] : '';
+                }
+            }
+
+            if (!$this->session_id) {
+                // 如果依然没有 session_id, 随机生成 session_id
+                $this->session_id = md5(time() . mt_rand(1000000, 9999999));
+            }
+        }
+
+        // 更新顾客用户信息
+        $this->chatUser = Online::updateChatUser($this->session_id, $this->user);
+        $this->chatUser['status'] = 1;       // 用户在线状态:在线
+        $_SESSION['chat_user'] = $this->chatUser;     // 转为数组
+    }
+
+
+    /**
+     * 检测并绑定 Uid
+     */
+    public function checkAndBind() 
+    {
+
+        if (!$this->session_id) {
+            Gateway::closeClient($this->client_id);
+            return false;
+        }
+
+        // 绑定 uid
+        Gateway::bindUid($this->client_id, Online::getUId($this->session_id, 'user'));
+
+        $_SESSION['uid'] = $this->session_id;
+        $_SESSION['user_id'] = $this->user ? $this->user['id'] : 0;
+        $_SESSION['user'] = $this->user;
+        $_SESSION['identify'] = $this->identify;
+        $_SESSION['customer_service_id'] = 0;       // 分配的客服id 
+        $_SESSION['customer_service'] = [];       // 分配的客服 
+
+        // 加入在线用户组
+        Gateway::joinGroup($this->client_id, Online::getGrouponName('online_user'));
+
+        return true;
+    }
+
+
+    /**
+     * 初始化用户
+     */
+    public function init() 
+    {
+        $user_id = $this->user ? $this->user['id'] : 0;
+
+        // 用户初始化成功
+        Sender::success($this->client_id, [
+            'type' => 'init',
+            'msg' => '连接成功',
+            'data' => [
+                'client_id' => $this->client_id,
+                'session_id' => $this->session_id
+            ]
+        ]);
+
+        if ($user_id) {
+            // 处理用户登录
+            Online::sessionUserSave($this->user, $this->session_id);
+        }
+
+        // 分配客服
+        $currentCustomerService = Online::allocatCustomerService($this->session_id, $user_id);
+
+        if ($currentCustomerService) {
+            // 记录客服信息,并将用户加入客服组
+            Online::bindCustomerService($this->client_id, $currentCustomerService, 'user');
+
+            // 通知用户已连接上客服
+            $msg = '您好,客服 ' . $currentCustomerService['name'] . " 为您服务";
+            Sender::successBySessionId($this->session_id, [
+                'type' => 'access',
+                'msg' => '客服接入',
+                'data' => [
+                    'message' => [
+                        'message_type' => 'system',
+                        'message' => $msg,
+                        'createtime' => time()
+                    ],
+                    'customer_service' => $currentCustomerService
+                ]
+            ]);
+
+            // 通知所有客服用户上线
+            Sender::userOnline($this->session_id, $this->chatUser);
+
+            // 通知所有客服,用户被接入,要把当前用户从别的客服的回话中列表移除
+            Sender::userAccessed($this->session_id, $currentCustomerService);
+
+            // 通知新的客服,有新的用户接入
+            Sender::userAccess($currentCustomerService, $this->session_id, 'user');
+        } else {
+            Sender::success($this->client_id, [
+                'type' => 'waiting',
+                'msg' => '客服不在线',
+                'data' => [
+                    'message' => [
+                        'message_type' => 'system',
+                        'message' => '当前没有客服在线,请耐心等待客服接入',
+                        'createtime' => time()
+                    ]
+                ]
+            ]);
+
+            // 加入等待分配客服分组
+            Online::bindWaiting($this->client_id);
+        }
+    }
+
+
+
+    /**
+     * 消息处理
+     */
+    public function message ($session_id, $type, $message, $data) 
+    {
+        $customerService = $_SESSION['customer_service'];
+        $customer_service_id = $customerService ? $customerService['id'] : 0;
+
+        if ($type == 'message') {
+            // 用户发来消息,通知当前连接的客服
+            Sender::messageByCustomerServiceId($customer_service_id, [
+                'type' => 'message',
+                'msg' => '收到消息', 
+                'data' => [
+                    'message' => $message,
+                    'session_id' => $session_id
+                ]
+            ]);
+
+            Sender::success($this->client_id, [
+                'type' => 'receipt',
+                'msg' => '发送成功'
+            ]);
+
+            if (isset($data['question_id']) && $data['question_id']) {
+                Online::questionReply($data['question_id'], [
+                    'client_id' => $this->client_id,
+                    'session_id' => $session_id,
+                    'user_id' => $_SESSION['user_id'],
+                    'customer_service_id' => $customer_service_id,
+                    'customer_service' => $customerService
+                ]);
+            }
+        } else if ($type == 'message_list') {
+            // 获取消息列表
+            $linker = [
+                'session_id' => $session_id,
+                'user_id' => $this->user ? $this->user['id'] : 0
+            ];
+
+            // 将客服发给自己的消息标记为 已读
+            Online::readMessage($linker, 'customer_service');
+            // 通知用户消息列表
+            $messageList = Online::messageList($linker, $data);
+            Sender::success($this->client_id, [
+                'type' => 'message_list',
+                'msg' => '获取成功',
+                'data' => [
+                    'message_list' => $messageList
+                ]
+            ]);
+        }
+    }
+
+
+    /**
+     * 连接关闭
+     */
+    public function close () 
+    {
+        $customerService = $_SESSION['customer_service'] ?? [];
+        $session_id = $_SESSION['uid'];
+
+        if ($customerService) {
+            // 存在客服,记录当前服务记录,状态依然还是进行中,
+            $userData = [
+                'user' => $_SESSION['user'],
+                'session_id' => $session_id,
+                'chat_user' => $_SESSION['chat_user']
+            ];
+    
+            $connection = Online::checkOrCreateConnection($userData, $customerService);
+
+            // 定时器 10 秒之后 关闭当前用户的所有连接,(规避刷新浏览器问题)
+            Timer::add(10, function ($session_id, $customerService) {
+                Online::userRealOffline($session_id, $customerService);
+            }, [$session_id, $customerService], false);
+        }
+
+        // 多端用户,都离线了,才通知客服,用户离线了
+        $isUidOnline = Gateway::isUidOnline(online::getUId($session_id, 'user'));
+        if (!$isUidOnline) {
+            // 通知所有客服,用户下线
+            Sender::userOffline($this->session_id);
+        }
+    }
+
+}

+ 2 - 0
addons/shopro/library/chat/log/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 2 - 0
addons/shopro/library/chat/start_for_win/shopro_chat_start_for_win.bat

@@ -0,0 +1,2 @@
+php .\start_businessworker.php php .\start_gateway.php php .\start_register.php
+pause

+ 6 - 0
addons/shopro/library/chat/start_for_win/start_businessworker.php

@@ -0,0 +1,6 @@
+<?php
+define('APP_PATH', __DIR__ . '/../../../../../application/');
+define('BIND_MODULE', 'admin/shopro.chat.index/businessWorker');
+
+// 加载框架引导文件
+require __DIR__ . '/../../../../../thinkphp/start.php';

+ 6 - 0
addons/shopro/library/chat/start_for_win/start_gateway.php

@@ -0,0 +1,6 @@
+<?php
+define('APP_PATH', __DIR__ . '/../../../../../application/');
+define('BIND_MODULE', 'admin/shopro/chat.index/gateway');
+
+// 加载框架引导文件
+require __DIR__ . '/../../../../../thinkphp/start.php';

+ 6 - 0
addons/shopro/library/chat/start_for_win/start_register.php

@@ -0,0 +1,6 @@
+<?php
+define('APP_PATH', __DIR__ . '/../../../../../application/');
+define('BIND_MODULE', 'admin/shopro/chat.index/register');
+
+// 加载框架引导文件
+require __DIR__ . '/../../../../../thinkphp/start.php';

+ 267 - 0
addons/shopro/library/chat/traits/GetLinkerTrait.php

@@ -0,0 +1,267 @@
+<?php
+
+namespace addons\shopro\library\chat\traits;
+
+use GatewayWorker\Lib\Gateway;
+use addons\shopro\library\chat\Online;
+use addons\shopro\model\chat\User as ChatUser;
+
+/**
+ * 获取各种连接者身份列表
+ */
+trait GetLinkerTrait
+{
+
+    /**
+     * 获取所有在线客服的 client_ids 
+     *
+     * @return array
+     */
+    public static function onlineCustomerServiceClientIds() {
+        $onlineCustomerServiceClientIds = Gateway::getClientIdListByGroup(Online::getGrouponName('online_customer_service'));
+
+        return $onlineCustomerServiceClientIds ? : [];
+    }
+
+
+    /**
+     * 获取所有在线客服 的sessions,一个客服多浏览器登录会重复,因为是session这里都保留
+     *
+     * @return array
+     */
+    public static function onlineCustomerServiceSessions()
+    {
+        // 获取所有在线客服 session
+        $customerServiceUserSessions = Gateway::getClientSessionsByGroup(Online::getGrouponName('online_customer_service'));
+
+        return $customerServiceUserSessions ? : [];
+    }
+
+
+    /**
+     * 获取所有在线客服的信息,自动过滤重复的信息,因为一个客服可以多浏览器登录
+     *
+     * @return array
+     */
+    public static function onlineCustomerServices() {
+        $customerServiceSessions = self::onlineCustomerServiceSessions();
+        $customerServices = array_column($customerServiceSessions, 'user');
+
+        // 过滤重复
+        $newServices = [];
+        foreach ($customerServices as $customerService) {
+            $newServices[$customerService['id']] = $customerService;
+        }
+
+        return array_values($newServices);
+    }
+
+
+    /**
+     * 通过 客服 id 获取客服 session, 一个客服多浏览器登录会重复,因为是session这里都保留,当前的客服的session 是老的,不会更新
+     *
+     * @param int $customer_service_id
+     * @return array
+     */
+    public static function onlineCustomerServiceSessionById($customer_service_id)
+    {
+        $client_ids = Gateway::getClientIdByUid(Online::getUId($customer_service_id, 'customer_service'));
+
+        $customerServiceSessions = [];
+        // 当前客服绑定的所有session
+        foreach ($client_ids as $client_id) {
+            $customerServiceSessions[] = Gateway::getSession($client_id);
+        }
+
+        return $customerServiceSessions;
+    }
+
+
+    /**
+     * 通过 客服 id 获取客服 session, 一个客服多浏览器登录会重复,因为是session这里都保留,通过 client_id 判断并拿到当前客服最新session
+     *
+     * @param int $customer_service_id
+     * @return array
+     */
+    public static function onlineCustomerServiceNewSessionById($customer_service_id, $current_client_id)
+    {
+        $client_ids = Gateway::getClientIdByUid(Online::getUId($customer_service_id, 'customer_service'));
+
+        $customerServiceSessions = [];
+        // 当前客服绑定的所有session
+        foreach ($client_ids as $client_id) {
+            if ($client_id == $current_client_id) {
+                $customerServiceSession = $_SESSION;
+            } else {
+                // 如果不是自己
+                $customerServiceSession = Gateway::getSession($client_id);
+            }
+
+            $customerServiceSessions[] = $customerServiceSession;
+        }
+
+        return $customerServiceSessions;
+    }
+
+
+    /**
+     * 通过客服 id 获取 客服信息
+     *
+     * @param int $customer_service_id
+     * @return array
+     */
+    public static function onlineCustomerServiceById($customer_service_id)
+    {
+        // 客服多浏览器登录的时候是多个 session
+        $customerServiceSessions = self::onlineCustomerServiceSessionById($customer_service_id);
+
+        // 只需要获取第一条的 user 信息
+        $customerService = (isset($customerServiceSessions[0]) && isset($customerServiceSessions[0]['user'])) ? $customerServiceSessions[0]['user'] : [];
+
+        return $customerService;
+    }
+
+
+    /**
+     * 当前正在等待接入的用户 session
+     *
+     * @return array
+     */
+    public static function onlineWaitingUserSessions () {
+        $onlineWaitingUserSessions = Gateway::getClientSessionsByGroup(Online::getGrouponName('online_waiting'));
+
+        return $onlineWaitingUserSessions ? : [];
+    }
+
+
+
+    /**
+     * 当前正在等待接入的用户
+     *
+     * @return array
+     */
+    public static function onlineWaitingUsers() {
+        $waitingSessionUsers = self::onlineWaitingUserSessions();
+
+        $waitings = array_column($waitingSessionUsers, 'chat_user');
+
+        // 过滤重复
+        $waitingUsers = [];
+        foreach ($waitings as $waiting) {
+            $waitingUsers[$waiting['id']] = $waiting;
+        }
+
+        return array_values($waitingUsers);
+    }
+
+
+    /**
+     * 获取当前客服正在服务的用户 session, 这里同一个用户可能会存在两个 session(多端登录)
+     *
+     * @param array $customerService
+     * @return array
+     */
+    public static function customerServiceUserSessions($customerService) {
+        // 获取当前客服 group_name
+        $customerServiceGroupName = Online::getGrouponName('customer_service_user', ['customer_service_id' => $customerService['id']]);
+        // 获取当前客服正在服务的用户列表 client_id
+        $customerServiceUserSessions = Gateway::getClientSessionsByGroup($customerServiceGroupName);
+
+        return $customerServiceUserSessions ? : [];
+    }
+
+
+
+    /**
+     * 获取当前客服正在服务的用户 (去重)
+     *
+     * @param array $customerService
+     * @return array
+     */
+    public static function customerServiceOnlineUsers($customerService) {
+        // 当前客服服务的所有用户 session
+        $customerServiceUserSessions = self::customerServiceUserSessions($customerService);
+        // 在线用户列表
+        $onlines = array_column($customerServiceUserSessions, 'chat_user');
+
+        // 过滤重复
+        $newUsers = [];
+        foreach ($onlines as $online) {
+            $newUsers[$online['id']] = $online;
+        }
+
+        return array_values($newUsers);
+    }
+
+
+    /**
+     * 获取当前客服正在服务的用户 client_ids
+     *
+     * @param array $customerService
+     * @return array
+     */
+    public static function customerServiceUserClientIds($customerService) {
+        // 获取当前客服 group_name
+        $customerServiceGroupName = Online::getGrouponName('customer_service_user', ['customer_service_id' => $customerService['id']]);
+        // 获取当前客服正在服务的用户列表 client_id
+        $userClientIds = Gateway::getClientIdListByGroup($customerServiceGroupName);
+
+        return $userClientIds ? : [];
+    }
+
+
+
+    /**
+     * 获取当前客服服务的历史用户
+     *
+     * @param array $customerService
+     * @param array $exceptSessionIds
+     * @return array
+     */
+    public static function customerServiceHistoryUsers($customerService, Array $exceptSessionIds = []) {
+        $histories = Online::historyByCustomerServiceId($customerService, ['except' => $exceptSessionIds]);
+        foreach ($histories as $key => &$history) {
+            $status = Gateway::isUidOnline(Online::getUId($history['session_id'], 'user'));
+            $history['status'] = $status;           // 在线状态
+            $history['customer_service'] = null;    // 如果在线,并且已经接入客服,当前客服信息
+            if ($status) {
+                // 在线,判断用户是否正在被客服接入
+                $client_ids = Gateway::getClientIdByUid(Online::getUId($history['session_id'], 'user'));
+                $client_id = current($client_ids);
+                $historySession = Gateway::getSession($client_id);
+                $customerService = $historySession['customer_service'] ? : null;
+                $history['customer_service'] = $customerService;
+            }
+            $history['status'] = $status;
+        }
+
+        return $histories;
+    }
+
+
+
+    /**
+     * 通过 session_id 获取连接的用户对应的 chatUser
+     *
+     * @param string $session_id
+     * @return object
+     */
+    public static function getChatUserBySessionId($session_id)
+    {
+        $chatUser = ChatUser::where('session_id', $session_id)->find();
+        return $chatUser;
+    }
+
+
+    /**
+     * 通过 user_id 获取连接的用户对应的 chatUser
+     *
+     * @param string $user_id
+     * @return object
+     */
+    public static function getChatUserByUserId($user_id)
+    {
+        $chatUser = ChatUser::where('user_id', $user_id)->find();
+        return $chatUser;
+    }
+}

+ 136 - 0
addons/shopro/library/chat/traits/SenderTrait.php

@@ -0,0 +1,136 @@
+<?php
+
+namespace addons\shopro\library\chat\traits;
+
+use GatewayWorker\Lib\Gateway;
+use addons\shopro\library\chat\Online;
+
+/**
+ * 通知基础方法
+ */
+trait SenderTrait
+{
+    /**
+     * 可以同时给多个 uid 发送,支持 u_id 是数组
+     */
+    public static function successById($u_id, array $content)
+    {
+        $result = [
+            'code' => 1,
+            'msg' => '',
+            'type' => '',
+            'data' => null
+        ];
+
+        $result = array_merge($result, $content);
+
+        Gateway::sendToUid($u_id, json_encode($result));
+
+        return $result;
+    }
+
+
+    public static function successByCustomerServiceId($customer_service_id, array $content)
+    {
+        return self::successById(Online::getUId($customer_service_id, 'customer_service'), $content);
+    }
+
+
+    public static function successBySessionId($session_id, array $content)
+    {
+        return self::successById(Online::getUId($session_id, 'user'), $content);
+    }
+
+
+    /**
+     * 给一个 client_id 发送消息
+     */
+    public static function success($client_id, array $content)
+    {
+        $result = [
+            'code' => 1,
+            'msg' => '',
+            'type' => '',
+            'data' => null
+        ];
+
+        $result = array_merge($result, $content);
+        Gateway::sendToClient($client_id, json_encode($result));
+
+        return $result;
+    }
+
+    /**
+     * 给所有 client_id 或指定 clientIds 发送
+     */
+    public static function successAll(array $content, $clientIds = [])
+    {
+        $result = [
+            'code' => 1,
+            'msg' => '',
+            'type' => '',
+            'data' => null
+        ];
+
+        $result = array_merge($result, $content);
+        Gateway::sendToAll(json_encode($result), $clientIds);
+
+        return $result;
+    }
+
+
+
+    public static function errorById($u_id, array $content)
+    {
+        $result = [
+            'code' => 0,
+            'msg' => '',
+            'type' => '',
+            'data' => null
+        ];
+
+        $result = array_merge($result, $content);
+        Gateway::sendToUid($u_id, json_encode($result));
+
+        return $result;
+    }
+
+
+    public static function error($client_id, array $content)
+    {
+        $result = [
+            'code' => 0,
+            'msg' => '',
+            'type' => '',
+            'data' => null
+        ];
+
+        $result = array_merge($result, $content);
+        Gateway::sendToClient($client_id, json_encode($result));
+
+        return $result;
+    }
+
+
+    public static function __callStatic($name, $arguments)
+    {
+        // 需要存储数据库的消息,先存储数据库,再发送
+        if (strpos($name, 'message') !== false) {
+            // 存库
+            $customerServiceLog = Online::addMessage($name, $arguments);
+
+            // 将 message 追加到 content 里面
+            $content = $arguments[1] ?? [];
+            $content['data'] = $content['data'] ?? [];
+            $content['data']['message'] = $customerServiceLog->toArray();
+            $arguments[1] = $content;
+
+            // 重载方法名
+            $currentName = str_replace('message', 'success', $name);
+        }
+
+        return self::$currentName(...$arguments);
+    }
+}
+
+

+ 17 - 0
addons/shopro/library/notify/Notifiable.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace addons\shopro\library\notify;
+
+use addons\shopro\exception\Exception;
+use think\queue\ShouldQueue;
+/**
+ * 消息通知 trait
+ */
+
+trait Notifiable
+{
+    public function notify ($notification) {
+        return \addons\shopro\library\notify\Notify::send([$this], $notification);
+    }
+    
+}

+ 68 - 0
addons/shopro/library/notify/Notify.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace addons\shopro\library\notify;
+
+use addons\shopro\exception\Exception;
+use think\queue\ShouldQueue;
+
+class Notify
+{
+    
+    public function sendNotify($notifiables, $notification) {
+        if ($notification instanceof ShouldQueue) {
+            // 队列执行
+            return $this->sendQueueNotify($notifiables, $notification, $notification->delay);
+        } 
+
+        return $this->sendNowNotify($notifiables, $notification);
+    }
+
+
+
+    /**
+     * 立即发送
+     */
+    public function sendNowNotify($notifiables, $notification) {
+        foreach ($notifiables as $key => $notifiable) {
+            $channels = $notification->via($notifiable);
+
+            if (empty($channels)) {
+                continue;
+            }
+
+            foreach ($channels as $k => $channel) {
+                (new $channel)->send($notifiable, $notification);
+            }
+        }
+    }
+
+
+    /**
+     * 队列发送
+     * delay 延迟时间
+     */
+    public function sendQueueNotify($notifiables, $notification, $delay) {
+        if ($delay > 0) {
+            // 异步延迟发送
+            \think\Queue::later($delay, '\addons\shopro\job\Notification@send', [
+                'notifiables' => $notifiables, 
+                'notification' => $notification,
+                'notification_name' => get_class($notification)
+            ], 'shopro');
+        } else {
+            // 异步立即发送
+            \think\Queue::push('\addons\shopro\job\Notification@send', [
+                'notifiables' => $notifiables,
+                'notification' => $notification,
+                'notification_name' => get_class($notification)
+            ], 'shopro');
+        }
+    }
+
+
+
+    public static function __callStatic($name, $arguments)
+    {
+        return (new self)->{$name . 'Notify'}(...$arguments);
+    }
+}

+ 41 - 0
addons/shopro/library/notify/channel/Database.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace addons\shopro\library\notify\channel;
+
+use addons\shopro\notifications\Notification;
+use addons\shopro\model\Notification as NotificationModel;
+
+class Database
+{
+
+    public function __construct()
+    {
+    }
+
+
+    /**
+     * 发送 模板消息
+     *
+     * @param  mixed  $notifiable       // 通知用户
+     * @param  通知内容
+     * @return void
+     */
+    public function send($notifiable, Notification $notification)
+    {
+        $data = [];
+
+        if (method_exists($notification, 'toDatabase')) {
+            $data = $notification->toDatabase($notifiable);
+
+            $notificationModel = new NotificationModel();
+            $notificationModel->type = $notification->event;
+            $notificationModel->notifiable_id = $notifiable['id'];
+            $notificationModel->notifiable_type = $notification->notifiableType;
+            $notificationModel->data = json_encode($data);
+
+            $notificationModel->save();
+        }
+        
+        return true;
+    }
+}

+ 55 - 0
addons/shopro/library/notify/channel/Email.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace addons\shopro\library\notify\channel;
+
+use addons\shopro\notifications\Notification;
+use think\Validate;
+use app\common\library\Email as SendEmail;
+
+class Email
+{
+
+    public function __construct()
+    {
+    }
+
+
+    /**
+     * 发送 微信模板消息
+     *
+     * @param  mixed  $notifiable       // 通知用户
+     * @param  通知内容
+     * @return void
+     */
+    public function send($notifiable, Notification $notification)
+    {
+        $data = [];
+
+        if (method_exists($notification, 'toEmail')) {
+            $data = $notification->toEmail($notifiable);
+
+            if ($data && isset($notifiable['email']) && Validate::is($notifiable['email'], "email")) {
+                $email = new SendEmail;
+                $result = $email
+                    ->to($notifiable['email'], $notifiable['nickname'])
+                    ->subject(($data['data'] ? $data['data']['template'] : '邮件通知'))
+                    ->message('<div style="min-height:550px; padding: 50px 20px 100px;">' . $data['content'] . '</div>')
+                    ->send();
+                if ($result) {
+                    // 发送成功
+                    $notification->sendOk('email');
+                } else {
+                    // 邮件发送失败
+                    \think\Log::write('邮件消息发送失败:用户:' . $notifiable['id'] . ';类型:' . get_class($notification) . ";发送类型:" . $notification->event . ";错误信息:" . json_encode($email->getError()));
+                }
+
+                return true;
+            }
+
+            // 没有openid
+            \think\Log::write('邮件消息发送失败,没有 email,或 email 格式不正确:用户:' . $notifiable['id'] . ';类型:' . get_class($notification) . ";发送类型:" . $notification->event);
+        }
+
+        return true;
+    }
+}

+ 57 - 0
addons/shopro/library/notify/channel/Sms.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace addons\shopro\library\notify\channel;
+
+use addons\shopro\notifications\Notification;
+use app\common\library\Sms as Smslib;
+
+class Sms
+{
+
+    public function __construct()
+    {
+    }
+
+
+    /**
+     * 发送 模板消息
+     *
+     * @param  mixed  $notifiable       // 通知用户
+     * @param  通知内容
+     * @return void
+     */
+    public function send($notifiable, Notification $notification)
+    {
+        $data = [];
+
+        if (method_exists($notification, 'toSms')) {
+            $data = $notification->toSms($notifiable);
+
+            if ($data && $data['phone'] && isset($data['template_id'])) {
+                $mobile = $data['phone'];
+                $sendData = $data['data'] ?? [];
+
+                $params = [
+                    'mobile'   => $mobile,
+                    'msg'      => $sendData,
+                    'template' => $data['template_id']
+                ];
+                $result = \think\Hook::listen('sms_notice', $params, null, true);
+
+                if (!$result) {
+                    // 短信发送失败
+                    \think\Log::write('短信发送失败:用户:'. $notifiable['id'] . ';类型:' . get_class($notification) . ";发送类型:" . $notification->event);
+                } else {
+                    // 发送成功
+                    $notification->sendOk('sms');
+                }
+
+                return true;
+            }
+            // 没有手机号
+            \think\Log::write('短信发送失败,没有手机号:用户:' . $notifiable['id'] . ';类型:' . get_class($notification) . ";发送类型:" . $notification->event);
+        }
+
+        return true;
+    }
+}

+ 53 - 0
addons/shopro/library/notify/channel/WxMiniProgram.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace addons\shopro\library\notify\channel;
+
+use addons\shopro\notifications\Notification;
+
+class WxMiniProgram
+{
+
+    public function __construct()
+    {
+    }
+
+
+    /**
+     * 发送 微信模板消息
+     *
+     * @param  mixed  $notifiable       // 通知用户
+     * @param  通知内容
+     * @return void
+     */
+    public function send($notifiable, Notification $notification)
+    {
+        $data = [];
+
+        if (method_exists($notification, 'toWxMiniProgram')) {
+            $data = $notification->toWxMiniProgram($notifiable);
+
+            if ($data && isset($data['openid']) && isset($data['template_id'])) {
+                $data['touser'] = $data['openid'];
+                unset($data['openid']);
+
+                // 发送模板消息
+                $result = (new \addons\shopro\library\Wechat('wxMiniProgram'))->getApp()->subscribe_message->send($data);
+
+                if ($result['errcode'] != 0) {
+                    // 短信发送失败
+                    \think\Log::write('小程序模板消息发送失败:用户:'. $notifiable['id'] . ';类型:' . get_class($notification) . ";发送类型:" . $notification->event . ";错误信息:" . json_encode($result));
+                } else {
+                    // 发送成功
+                    $notification->sendOk('wxMiniProgram');
+                }
+
+                return true;
+            }
+
+            // 没有openid
+            \think\Log::write('小程序模板消息发送失败,没有 openid:用户:' . $notifiable['id'] . ';类型:' . get_class($notification) . ";发送类型:" . $notification->event);
+        }
+
+        return true;
+    }
+}

+ 53 - 0
addons/shopro/library/notify/channel/WxOfficeAccount.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace addons\shopro\library\notify\channel;
+
+use addons\shopro\notifications\Notification;
+
+class WxOfficeAccount
+{
+
+    public function __construct()
+    {
+    }
+
+
+    /**
+     * 发送 微信模板消息
+     *
+     * @param  mixed  $notifiable       // 通知用户
+     * @param  通知内容
+     * @return void
+     */
+    public function send($notifiable, Notification $notification)
+    {
+        $data = [];
+
+        if (method_exists($notification, 'toWxOfficeAccount')) {
+            $data = $notification->toWxOfficeAccount($notifiable);
+
+            if ($data && isset($data['openid']) && isset($data['template_id'])) {
+                $data['touser'] = $data['openid'];
+                unset($data['openid']);
+
+                // 发送模板消息
+                $result = (new \addons\shopro\library\Wechat('wxOfficialAccount'))->getApp()->template_message->send($data);
+
+                if ($result['errcode'] != 0) {
+                    // 短信发送失败
+                    \think\Log::write('公众号模板消息发送失败:用户:' . $notifiable['id'] . ';类型:' . get_class($notification) . ";发送类型:" . $notification->event . ";错误信息:" . json_encode($result));
+                } else {
+                    // 发送成功
+                    $notification->sendOk('wxOfficialAccount');
+                }
+
+                return true;
+            }
+
+            // 没有openid
+            \think\Log::write('公众号模板消息发送失败,没有 openid:用户:' . $notifiable['id'] . ';类型:' . get_class($notification) . ";发送类型:" . $notification->event);
+        }
+
+        return true;
+    }
+}

+ 53 - 0
addons/shopro/library/notify/channel/WxOfficeAccountBizsend.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace addons\shopro\library\notify\channel;
+
+use addons\shopro\notifications\Notification;
+
+class WxOfficeAccountBizsend
+{
+
+    public function __construct()
+    {
+    }
+
+
+    /**
+     * 发送 微信公众号订阅消息(新)
+     *
+     * @param  mixed  $notifiable       // 通知用户
+     * @param  通知内容
+     * @return void
+     */
+    public function send($notifiable, Notification $notification)
+    {
+        $data = [];
+
+        if (method_exists($notification, 'toWxOfficeAccount')) {
+            $data = $notification->toWxOfficeAccount($notifiable, 'wxOfficialAccountBizsend');
+
+            if ($data && isset($data['openid']) && isset($data['template_id'])) {
+                $data['touser'] = $data['openid'];
+                unset($data['openid']);
+
+                // 发送模板消息
+                $result = (new \addons\shopro\library\Wechat('wxOfficialAccount'))->bizsendSubscribeMessage($data);
+
+                if ($result['errcode'] != 0) {
+                    // 短信发送失败
+                    \think\Log::write('公众号订阅消息发送失败:用户:' . $notifiable['id'] . ';类型:' . get_class($notification) . ";发送类型:" . $notification->event . ";错误信息:" . json_encode($result));
+                } else {
+                    // 发送成功
+                    $notification->sendOk('wxOfficialAccountBizsend');
+                }
+
+                return true;
+            }
+
+            // 没有openid
+            \think\Log::write('公众号订阅消息发送失败,没有 openid:用户:' . $notifiable['id'] . ';类型:' . get_class($notification) . ";发送类型:" . $notification->event);
+        }
+
+        return true;
+    }
+}

+ 660 - 0
addons/shopro/library/traits/ActivityCache.php

@@ -0,0 +1,660 @@
+<?php
+
+namespace addons\shopro\library\traits;
+
+use addons\shopro\exception\Exception;
+use addons\shopro\library\Redis;
+use addons\shopro\model\Activity;
+use addons\shopro\model\ActivityGoodsSkuPrice;
+use addons\shopro\model\Goods;
+use addons\shopro\model\GoodsSkuPrice;
+use addons\shopro\model\OrderItem;
+use addons\shopro\model\ScoreGoodsSkuPrice;
+
+/**
+ * 活动 redis 缓存
+ */
+trait ActivityCache
+{
+    protected $zsetKey = 'zset-activity';
+    protected $hashPrefix = 'hash-activity:';
+    protected $hashGoodsPrefix = 'goods-';
+    protected $hashGrouponPrefix = 'groupon-';
+
+
+    public function hasRedis($is_interrupt = false) {
+        $error_msg = '';
+        try {
+            $redis = $this->getRedis();
+
+            // 检测连接是否正常
+            $redis->ping();
+        } catch (\BadFunctionCallException $e) {
+            // 缺少扩展
+            $error_msg = $e->getMessage() ? $e->getMessage() : "缺少 redis 扩展";
+        } catch (\RedisException $e) {
+            // 连接拒绝
+            \think\Log::write('redis connection redisException fail: ' . $e->getMessage());
+            $error_msg = $e->getMessage() ? $e->getMessage() : "redis 连接失败";
+        } catch (\Exception $e) {
+            // 异常
+            \think\Log::write('redis connection fail: ' . $e->getMessage());
+            $error_msg = $e->getMessage() ? $e->getMessage() : "redis 连接异常";
+        }
+
+        if ($error_msg) {
+            if ($is_interrupt) {
+                throw new \Exception($error_msg);
+            } else {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+    public function getRedis() {
+        if (!isset($GLOBALS['SPREDIS'])) {
+            $GLOBALS['SPREDIS'] = (new Redis())->getRedis();
+        }
+
+        return $GLOBALS['SPREDIS'];
+    }
+
+
+    /**
+     * 将活动设置到 redis 中
+     *
+     * @param [type] $activity
+     * @param array $goodsList
+     * @return void
+     */
+    public function setActivity($activity, $goodsList = []) {
+        $redis = $this->getRedis();
+
+        // hash 键值
+        $hashKey = $this->getHashKey($activity['id'], $activity['type']);
+
+        // 删除旧的可变数据,需要排除销量 key 
+        if ($redis->EXISTS($hashKey)) {
+            // 如果 hashKey 存在,删除规格
+            $hashs = $redis->HGETALL($hashKey);
+
+            foreach ($hashs as $hashField => $hashValue) {
+                // 是商品规格,并且不是销量
+                if (strpos($hashField, $this->hashGoodsPrefix) !== false && strpos($hashField, '-sale') === false) {
+                    // 商品规格信息,删掉
+                    $redis->HDEL($hashKey, $hashField);
+                }
+            }
+        }
+
+        $redis->HMSET($hashKey, [
+                            'id' => $activity['id'],
+                            'title' => $activity['title'],
+                            'type' => $activity['type'],
+                            'richtext_id' => $activity['richtext_id'],
+                            'richtext_title' => $activity['richtext_title'],
+                            'starttime' => $activity['starttime'],
+                            'endtime' => $activity['endtime'],
+                            'rules' => is_array($activity['rules']) ? json_encode($activity['rules']) : $activity['rules'],
+                            'goods_ids' => $activity['goods_ids']
+                        ]
+                    );
+
+        if (in_array($activity['type'], ['groupon', 'seckill'])) {
+            // 拼团或者秒杀,记录商品规格信息 (里面包含活动库存,价格等信息)
+            foreach ($goodsList as $goods) {
+                unset($goods['sales']);     // 规格销量单独字段保存 goods-id-id-sale key
+                $goods_sku_key = $this->getHashGoodsKey($goods['goods_id'], $goods['sku_price_id']);
+                // 获取当前规格的销量,修改库存的时候,需要把 stock 加上这部分销量
+                $cacheSale = $redis->HGET($hashKey, $goods_sku_key . '-sale');
+                $goods['stock'] = $goods['stock'] + $cacheSale;
+                $redis->HSET($hashKey, $this->getHashGoodsKey($goods['goods_id'], $goods['sku_price_id']), json_encode($goods));
+            }
+        }
+
+        // 将 hash 键值存入 有序集合,score 为 id
+        $redis->ZADD($this->zsetKey, $activity['starttime'], $hashKey);
+    }
+
+
+    /**
+     * 获取所有活动(前端:秒杀商品列表,拼团商品列表)
+     *
+     * @param array $activityTypes 为空将查询所有类型的活动
+     * @param string $status
+     * @param string $format_type       // 格式化类型,默认clear,清理多余的字段,比如拼团的 团信息
+     * @return void
+     */
+    public function getActivityList($activityTypes = [], $status = 'all', $format_type = 'normal') {
+        $redis = $this->getRedis();
+
+        // 获取对应的活动类型的集合
+        $activityHashList = $this->getActivityHashKeysByType($activityTypes);
+        
+        $activityList = [];
+        if (!$activityHashList) {       // 没有获取到,返回空数组
+            return $activityList;
+        }
+
+        foreach ($activityHashList as $activityHashKey) {
+            // 查询活动状态
+            if ($status != 'all') {
+                $activity_status = $this->getActivityStatusByHashKey($activityHashKey);
+                
+                if ($status != $activity_status) {
+                    continue;
+                }
+            }
+
+            // 格式化活动
+            $activity = $this->formatActivityByType($activityHashKey, $format_type);
+            if ($activity) {
+                $activityList[] = $activity;
+            }
+        }
+
+        return $activityList;
+    }
+
+
+    /**
+     * 查询商品列表,详情时,获取这个商品对应的秒杀拼团等活动
+     *
+     * @param [type] $goods_id
+     * @param Array $activityTypes
+     * @param integer $activity_id
+     * @return void
+     */
+    public function getGoodsActivity($goods_id, $activityTypes = [], $activity_id = 0) {
+        // 获取商品第一条活动的 hash key
+        $activityHashKey = $this->getActivityHashKeyByGoods($goods_id, $activityTypes, 'first', $activity_id);
+
+        // 如果存在活动
+        if ($activityHashKey) {
+            // 获取活动并且按照商品的要求格式化
+            return $this->formatActivityByType($activityHashKey, 'goods', ['goods_id', $goods_id]);
+        }
+
+        return null;
+    }
+
+
+    /**
+     * 查询商品列表,详情时,获取这个商品对应的满减,满折等活动
+     *
+     * @param int $goods_id 特定商品 id
+     * @param Array $activityTypes  要查询的活动数组
+     * @param string $type  查单条,还是全部 all|first
+     * @param int $activity_id
+     * @return void
+     */
+    public function getGoodsActivityDiscount($goods_id, $activityTypes = [], $type = 'all', $activity_id = 0) {
+        // 获取活动的 hash key
+        $activityHashKey = $this->getActivityHashKeyByGoods($goods_id, $activityTypes, $type, $activity_id);
+
+        // 如果存在活动
+        if ($activityHashKey) {
+            if (is_array($activityHashKey)) {
+                $activities = [];
+                foreach ($activityHashKey as $key => $hashKey) {
+                    $activity = $this->formatActivityByType($hashKey, 'discount');
+                    if ($activity) {
+                        $activities[] = $activity;
+                    }
+                }
+
+                return $activities;
+            } else {
+                // 获取活动所有信息
+                return $activity = $this->formatActivityByType($activityHashKey, 'discount');
+            }
+        }
+
+        return $type == 'all' ? [] : null;
+    }
+
+
+    /**
+     * 通过活动的键值,获取活动完整信息
+     *
+     * @param [type] $activityHashKey
+     * @return array
+     */
+    public function getActivityByHashKey($activityHashKey)
+    {
+        $redis = $this->getRedis();
+
+        // 取出整条 hash 记录
+        $activityHash = $redis->HGETALL($activityHashKey);
+
+        return $activityHash;
+    }
+
+
+    // 删除活动缓存
+    public function delActivity($activity) {
+        $redis = $this->getRedis();
+
+        $hashKey = $this->getHashKey($activity['id'], $activity['type']);
+
+        // 删除 hash
+        $redis->DEL($hashKey);
+
+        // 删除集合
+        $redis->ZREM($this->zsetKey, $hashKey);
+    }
+
+
+    /**
+     * 通过商品获取该商品参与的活动的hash key
+     *
+     * @param [type] $goods_id
+     * @param Array $activityType
+     * @param string $type      全部还是第一条
+     * @param integer $activity_id
+     * @return void
+     */
+    private function getActivityHashKeyByGoods($goods_id, $activityType = [], $type = 'first', $activity_id = 0) {
+        $redis = $this->getRedis();
+
+        // 获取对应类型的活动集合
+        $activityHashList = $this->getActivityHashKeysByType($activityType, $activity_id);
+
+        $activityHashKeys = [];
+        if (!$activityHashList) {       // 没有获取到,返回空数组
+            return $activityHashKeys;
+        }
+
+        foreach ($activityHashList as $activityHashKey) {
+            if (strpos($activityHashKey, 'seckill') === false && strpos($activityHashKey, 'groupon') === false) {
+                // 不是拼团,秒杀,要校验活动时间,如果不在活动时间,跳过
+                // 获取活动状态
+                $activity_status = $this->getActivityStatusByHashKey($activityHashKey);
+                if ($activity_status != 'ing') {
+                    continue;
+                }
+            }
+
+            // 判断这条活动是否包含该商品
+            $goods_ids = array_filter(explode(',', $redis->HGET($activityHashKey, 'goods_ids')));
+            if (in_array($goods_id, $goods_ids) || empty($goods_ids)) {
+                $activityHashKeys[] = $activityHashKey;
+
+                if ($type == 'first') {     // 只取第一条
+                    break;
+                }
+            }
+        }
+
+        if ($activity_id && !$activityHashKeys) {
+            // 查询特定活动,没找到,抛出异常, 活动不存在
+            new Exception('活动不存在');
+        }
+
+        return $type == 'first' ? ($activityHashKeys[0] ?? '') : $activityHashKeys;
+    }
+
+
+
+    /**
+     * 获取活动的状态
+     */
+    private function getActivityStatusByHashKey($activityHashKey) {
+        $redis = $this->getRedis();
+
+        $starttime = $redis->HGET($activityHashKey, 'starttime');
+        $endtime = $redis->HGET($activityHashKey, 'endtime');
+
+        if ($starttime < time() && $endtime > time()) {
+            $status = 'ing';
+        }else if ($starttime > time()) {
+            $status = 'nostart';
+        }else if ($endtime < time()) {
+            $status = 'ended';
+        }
+
+        return $status;
+    }
+
+
+    /**
+     * 获取活动类型数组的所有活动hashkeys
+     *
+     * @param array|string $activityTypes
+     * @return array
+     */
+    private function getActivityHashKeysByType($activityTypes = [], $activity_id = 0) {
+        $redis = $this->getRedis();
+
+        $activityTypes = is_array($activityTypes) ? $activityTypes : [$activityTypes];
+        $activityTypes = array_values(array_filter($activityTypes));  // 过滤空值
+        
+        // 获取活动集合
+        $hashList = $redis->ZRANGE($this->zsetKey, 0, 999999999);
+
+        // 优先判断 activity_id,可以唯一确定 活动key, 不需要判断 activityTypes
+        if ($activity_id) {
+            $activityHashKeys = [];
+            foreach ($hashList as $hashKey) {
+                $suffix = ':' . $activity_id;
+                // 判断是否是要找的活动id, 截取 hashKey 后面几位,是否为当前要查找的活动 id
+                if (substr($hashKey, (strlen($hashKey) - strlen($suffix))) == $suffix) {
+                    $activityHashKeys[] = $hashKey;
+                    break;
+                }
+            }
+
+            return $activityHashKeys;
+        }
+
+        // 判断是否传入了 需要的活动类型,默认取全部活动
+        if ($activityTypes) {
+            // 获取对应的活动类型的集合
+            $activityHashKeys = [];
+
+            foreach ($hashList as $hashKey) {
+                // 循环要查找的活动类型数组
+                foreach ($activityTypes as $type) {
+                    if (strpos($hashKey, $type) !== false) {        // 是要查找的类型
+                        $activityHashKeys[] = $hashKey;
+                        break;
+                    }
+                }
+            }
+        } else {
+            // 全部活动
+            $activityHashKeys = $hashList;
+        }
+
+        return $activityHashKeys;
+    }
+
+
+    // ------------------------格式化活动---------------------
+
+    /**
+     * 格式化活动
+     *
+     * @param string array $activityHash 活动 key 或者活动完整信息
+     * @param string $type  格式化方式
+     * @param array $data  额外参数
+     * @return void
+     */
+    public function formatActivityByType($activityHash, $type = 'normal', $data = []) {
+        switch($type) {
+            case 'normal' :
+                // 正常模式,只移除销量,团信息,保留全部商品规格数据
+                $activity = $this->getActivityFormatNormal($activityHash, $data);
+                break;
+            case 'clear' :
+                // 简洁模式,只保留活动表基本信息
+                $activity = $this->getActivityFormatClear($activityHash, $data);
+                break;
+            case 'goods' :
+                // 按照前端商品方式格式化
+                $activity = $this->getActivityFormatGoods($activityHash, $data);
+                break;
+            case 'discount' :
+                $activity = $this->getActivityFormatDiscount($activityHash, $data);
+                break;
+            default :
+                $activity = $this->getActivityFormatNormal($activityHash, $data);
+                break;
+        }
+
+        return $activity;
+    }
+
+
+    /**
+     * 正常模式,只移除销量, 团信息,保留全部商品规格数据
+     *
+     * @param string $activityHashKey
+     * @param array $data  额外数据,商品 id
+     * @return void
+     */
+    private function getActivityFormatNormal($activityHashKey, $data = []) {
+        // 传入的是活动的key
+        $activityHash = $this->getActivityByHashKey($activityHashKey);
+
+        $activity = [];
+
+        foreach ($activityHash as $key => $value) {
+            // 包含 -sale 全部跳过
+            if (strpos($key, '-sale') !== false) {
+                continue;
+            } else if (strpos($key, $this->hashGrouponPrefix) !== false) {
+                // 拼团的参团人数,团用户,移除
+                continue;
+            } else if ($key == 'rules') {
+                $activity[$key] = json_decode($value, true);
+            } else {
+                // 普通键值
+                $activity[$key] = $value;
+            }
+        }
+
+        if ($activity) {
+            // 处理活动状态
+            $activity['status_code'] = Activity::getStatusCode($activity);
+        }
+
+        return $activity ?: null;
+    }
+
+
+    /**
+     * 简洁模式,只保留活动表基本信息
+     *
+     * @param string $activityHashKey
+     * @param array $data  额外数据,商品 id
+     * @return void
+     */
+    private function getActivityFormatClear($activityHashKey, $data = []) {
+        $activityHash = $this->getActivityByHashKey($activityHashKey);
+
+        $activity = [];
+
+        foreach ($activityHash as $key => $value) {
+            // 包含 -sale 全部跳过
+            if (strpos($key, $this->hashGoodsPrefix) !== false) {
+                continue;
+            } else if (strpos($key, $this->hashGrouponPrefix) !== false) {
+                // 拼团的参团人数,团用户,移除
+                continue;
+            } else if ($key == 'rules') {
+                $activity[$key] = json_decode($value, true);
+            } else {
+                // 普通键值
+                $activity[$key] = $value;
+            }
+        }
+
+        if ($activity) {
+            // 处理活动状态
+            $activity['status_code'] = Activity::getStatusCode($activity);
+        }
+
+        return $activity ?: null;
+    }
+
+
+    /**
+     * 获取并按照商品展示格式化活动数据
+     *
+     * @param string $activityHashKey hash key
+     * @param array $data  额外数据,商品 id
+     * @return array
+     */
+    private function getActivityFormatGoods($activityHashKey, $data = [])
+    {
+        $goods_id = $data['goods_id'] ?? 0;
+        // 传入的是活动的key
+        $activityHash = $this->getActivityByHashKey($activityHashKey);
+
+        $activity = [];
+
+        // 商品前缀
+        $goodsPrefix = $this->hashGoodsPrefix . ($goods_id ? $goods_id . '-' : '');
+
+        foreach ($activityHash as $key => $value) {
+            // 包含 -sale 全部跳过
+            if (strpos($key, '-sale') !== false) {
+                continue;
+            } else if (strpos($key, $goodsPrefix) !== false) {
+                // 商品规格信息,或者特定商品规格信息
+                $goods = json_decode($value, true);
+
+                // 计算销量库存数据
+                $goods = $this->calcGoods($goods, $activityHashKey);
+
+                // 商品规格项
+                $activity['activity_goods_sku_price'][] = $goods;
+            } else if ($goods_id && strpos($key, $this->hashGoodsPrefix) !== false) {
+                // 需要特定商品时,移除别的非当前商品的数据
+                continue;
+            } else if (strpos($key, $this->hashGrouponPrefix) !== false) {
+                // 拼团的参团人数,团用户,移除
+                continue;
+            } else if ($key == 'rules') {
+                $activity[$key] = json_decode($value, true);
+            } else {
+                // 普通键值
+                $activity[$key] = $value;
+            }
+        }
+
+        if ($activity) {
+            // 处理活动状态
+            $activity['status_code'] = Activity::getStatusCode($activity);
+        }
+
+        return $activity ?: null;
+    }
+
+
+    /**
+     * 获取并按照折扣格式展示格式化活动数据
+     *
+     * @param string $activityHashKey hash key
+     * @param array $data  额外数据
+     * @return void
+     */
+    private function getActivityFormatDiscount($activityHashKey, $data = [])
+    {
+        $activityHash = $this->getActivityByHashKey($activityHashKey);
+
+        $activity = [];
+        foreach ($activityHash as $key => $value) {
+            if ($key == 'rules') {
+                $rules = json_decode($value, true);
+
+                // 存在折扣
+                if (isset($rules['discounts']) && $rules['discounts']) {
+                    // 处理展示优惠,full 从小到大
+                    $discounts = $rules['discounts'] ?? [];
+
+                    $discountsKeys = array_column($discounts, null, 'full');
+                    ksort($discountsKeys);
+                    $rules['discounts'] = array_values($discountsKeys);        // 优惠按照 full 从小到大排序
+                }
+
+                $activity[$key] = $rules;
+            } else {
+                // 普通键值
+                $activity[$key] = $value;
+            }
+        }
+
+        if ($activity) {
+            // 处理活动状态
+            $activity['status_code'] = Activity::getStatusCode($activity);
+        }
+
+        return $activity ?: null;
+    }
+
+
+    /**
+     * 计算每个规格的真实库存、销量
+     *
+     * @param [type] $goods
+     * @param [type] $activityHashKey
+     * @return void
+     */
+    private function calcGoods($goods, $activityHashKey)
+    {
+        $redis = $this->getRedis();
+
+        // 销量 key 
+        $saleKey = $this->getHashGoodsKey($goods['goods_id'], $goods['sku_price_id'], true);
+
+        // 缓存中的销量
+        $cacheSale = $redis->HGET($activityHashKey, $saleKey);
+
+        $stock = $goods['stock'] - $cacheSale;
+        $goods['stock'] = $stock > 0 ? $stock : 0;
+        $goods['sales'] = $cacheSale;
+
+        return $goods;
+    }
+
+
+
+    // 拼接 hash key
+    private function getHashKey($activity_id, $activity_type) {
+        // 示例 hash-activity:groupon:25
+        return $this->hashPrefix . $activity_type . ':' . $activity_id;
+    }
+
+
+    // 拼接 hash 表中 goods 的 key
+    private function getHashGoodsKey($goods_id, $sku_price_id, $is_sale = false)
+    {
+        // 示例 商品规格:goods-25-30 or 商品规格销量:goods-25-30-sale
+        return $this->hashGoodsPrefix . $goods_id . '-' . $sku_price_id . ($is_sale ? '-sale' : '');
+    }
+
+
+
+    // 拼接 hash 表中 groupon 的 key
+    private function getHashGrouponKey($groupon_id, $goods_id, $type = '')
+    {
+        return $this->hashGrouponPrefix . $groupon_id . '-' . $goods_id . ($type ? '-' . $type : '');
+    }
+
+
+    // 获取 key 集合
+    public function getKeys($detail, $activity)
+    {
+        // 获取 hash key
+        $activityHashKey = $this->getHashKey($activity['activity_id'], $activity['activity_type']);
+
+        $goodsSkuPriceKey = '';
+        $saleKey = '';
+        if (isset($detail['goods_sku_price_id']) && $detail['goods_sku_price_id']) {
+            // 获取 hash 表中商品 sku 的 key
+            $goodsSkuPriceKey = $this->getHashGoodsKey($detail['goods_id'], $detail['goods_sku_price_id']);
+            // 获取 hash 表中商品 sku 的 销量的 key
+            $saleKey = $this->getHashGoodsKey($detail['goods_id'], $detail['goods_sku_price_id'], true);
+        }
+
+        // 需要拼团的字段
+        $grouponKey = '';
+        $grouponNumKey = '';
+        $grouponUserlistKey = '';
+        if (isset($detail['groupon_id']) && $detail['groupon_id']) {
+            // 获取 hash 表中团 key
+            $grouponKey = $this->getHashGrouponKey($detail['groupon_id'], $detail['goods_id']);
+            // 获取 hash 表中团当前人数 key
+            $grouponNumKey = $this->getHashGrouponKey($detail['groupon_id'], $detail['goods_id'], 'num');
+            // 获取 hash 表中团当前人员列表 key
+            $grouponUserlistKey = $this->getHashGrouponKey($detail['groupon_id'], $detail['goods_id'], 'userlist');
+        }
+
+        return compact('activityHashKey', 'goodsSkuPriceKey', 'saleKey', 'grouponKey', 'grouponNumKey', 'grouponUserlistKey');
+    }
+}

+ 418 - 0
addons/shopro/library/traits/Groupon.php

@@ -0,0 +1,418 @@
+<?php
+
+namespace addons\shopro\library\traits;
+
+use addons\shopro\exception\Exception;
+use addons\shopro\model\Activity;
+use addons\shopro\model\ActivityGroupon;
+use addons\shopro\model\ActivityGrouponLog;
+use addons\shopro\model\Order;
+use addons\shopro\model\OrderItem;
+use addons\shopro\model\UserFake;
+
+/**
+ * 拼团
+ */
+trait Groupon
+{
+    /**
+     * *、redis 没有存团完整信息,只存了团当前人数,团成员(当前人数,团成员均没有存虚拟用户)
+     * *、redis userList 没有存这个人的购买状态
+     * *、团 解散,成团,虚拟成团,没有修改 redis 团信息(因为直接修改了数据库,参团判断,先判断的数据库后判断的 redis)
+     */
+
+
+
+    /**
+     * 增加拼团预成员人数
+     */
+    protected function grouponCacheForwardNum($activityGroupon, $activity, $user, $payed = 'nopay')
+    {
+        if (!$this->hasRedis()) {
+            return true;
+        }
+
+        $keys = $this->getKeys([
+            'groupon_id' => $activityGroupon['id'],
+            'goods_id' => $activityGroupon['goods_id'],
+        ], [
+            'activity_id' => $activity['id'],
+            'activity_type' => $activity['type'],
+        ]);
+
+        extract($keys);
+
+        $redis = $this->getRedis();
+
+        // 将拼团团信息存入 redis 没有用,还得维护团状态,先不存
+        // $redis->HSET($activityHashKey, $grouponKey, json_encode($activityGroupon));
+
+        // 当前团人数 grouponNumKey 如果不存在,自动创建
+        $current_num = $redis->HINCRBY($activityHashKey, $grouponNumKey, 1);
+
+        if ($current_num > $activityGroupon['num']) {
+            // 再把刚加上的减回来
+            $current_num = $redis->HINCRBY($activityHashKey, $grouponNumKey, -1);
+
+            new Exception('该团已满,请参与其它团或自己开团');
+        }
+
+        // 将用户加入拼团缓存,用来判断同一个人在一个团,多次下单,取消订单删除
+        $userList = $redis->HGET($activityHashKey, $grouponUserlistKey);
+        $userList = json_decode($userList, true);
+        $userList = $userList ? : [];
+        $userList[] = [
+            'user_id' => $user['id'],
+            // 'status' => $payed       // 太复杂,先不做
+        ];
+        $redis->HSET($activityHashKey, $grouponUserlistKey, json_encode($userList));
+    }
+
+
+
+    // 拼团团成员预成员退回
+    protected function grouponCacheBackNum($order)
+    {
+        $items = OrderItem::where('order_id', $order['id'])->select();
+
+        foreach ($items as $key => $item) {
+            // 不是拼团,或者 没有配置 redis
+            if (strpos($item['activity_type'], 'groupon') === false || !$this->hasRedis()) {
+                continue;
+            }
+
+            // 扩展字段
+            $order_ext = $order['ext_arr'];
+            // 团 id
+            $groupon_id = $order_ext['groupon_id'] ?? 0;
+
+            if (!$groupon_id) {
+                continue;       // 商品独立购买,未参团,或者开新团
+            }
+
+            // 实例化 redis
+            $redis = $this->getRedis();
+
+            $keys = $this->getKeys([
+                'groupon_id' => $groupon_id,
+                'goods_id' => $item['goods_id'],
+                'goods_sku_price_id' => $item['goods_sku_price_id'],
+            ], [
+                'activity_id' => $item['activity_id'],
+                'activity_type' => $item['activity_type'],
+            ]);
+
+            extract($keys);
+
+            // 扣除预参团成员
+            if ($redis->EXISTS($activityHashKey) && $redis->HEXISTS($activityHashKey, $grouponNumKey)) {
+                $sale = $redis->HINCRBY($activityHashKey, $grouponNumKey, -1);
+            }
+
+            $userList = $redis->HGET($activityHashKey, $grouponUserlistKey);
+            $userList = json_decode($userList, true);
+            $userList = $userList ?: [];
+            foreach($userList as $key => $user) {
+                if ($user['user_id'] == $item['user_id']) {
+                    unset($userList[$key]);
+                }
+            }
+            $redis->HSET($activityHashKey, $grouponUserlistKey, json_encode($userList));
+        }
+    }
+
+
+    /**
+     * 判断加入旧拼团
+     */
+    protected function checkJoinGroupon($goods_info, $user, $groupon_id)
+    {
+        $goods = $goods_info['detail'];
+        $activity = $goods['activity'];
+        $rules = $activity['rules'];
+
+        // 获取团信息
+        $activityGroupon = ActivityGroupon::with('activity')->where('id', $groupon_id)->find();
+        if (!$activityGroupon) {
+            new Exception('要参与的团不存在');
+        }
+        // 判断团所属活动是否正常
+        if (!$activityGroupon->activity || $activityGroupon->activity['id'] != $activity['id']) {      // 修复,后台手动将活动删除,然后又立即给这个商品创建新的拼团活动,导致参与新活动的旧团错乱问题
+            new Exception('要参与的活动已结束');
+        }
+        if ($activityGroupon['status'] != 'ing') {
+            new Exception('要参与的团已成团,请选择其它团或自己开团');
+        }
+
+        if ($activityGroupon['current_num'] >= $activityGroupon['num']) {
+            new Exception('该团已满,请参与其它团或自己开团');
+        }
+        
+        if (!$this->hasRedis()) {
+            // 没有 redis 直接判断数据库团信息,因为 current_num 支付成功才会累加,故无法保证超员,
+            // 该团可加入
+            return $activityGroupon;
+        }
+
+        $keys = $this->getKeys([
+            'groupon_id' => $activityGroupon['id'],
+            'goods_id' => $activityGroupon['goods_id'],
+        ], [
+            'activity_id' => $activity['id'],
+            'activity_type' => $activity['type'],
+        ]);
+
+        extract($keys);
+
+        $redis = $this->getRedis();
+
+        $current_num = $redis->HGET($activityHashKey, $grouponNumKey);
+        if ($current_num >= $activityGroupon['num']) {
+            new Exception('该团已满,请参与其它团或自己开团');
+        }
+
+        // 将用户加入拼团缓存,用来判断同一个人在一个团,多次下单,订单失效删除
+        $userList = $redis->HGET($activityHashKey, $grouponUserlistKey);
+        $userList = json_decode($userList, true);
+        $userIds = array_column($userList, 'user_id');
+        if (in_array($user['id'], $userIds)) {
+            new Exception('您已参与该团,请不要重复参团');
+        }
+
+        return $activityGroupon;
+    }
+
+
+
+    /**
+     * 支付成功真实加入团
+     */
+    protected function joinGroupon($order, $user) {
+        $item = $order->item;
+        $goods_item = $item[0];      // 拼团只能单独购买
+
+        // 扩展字段
+        $order_ext = $order['ext_arr'];
+        // 团 id
+        $groupon_id = $order_ext['groupon_id'] ?? 0;
+        $buy_type = $order_ext['buy_type'] ?? 0;
+
+        // 不是拼团购买,比如拼团单独购买
+        if ($buy_type != 'groupon') {
+            return true;
+        }
+
+        if ($groupon_id) {
+            // 加入旧团,查询团
+            $activityGroupon = ActivityGroupon::where('id', $groupon_id)->find();
+        } else {
+            // 加入新团,创建团
+            $activityGroupon = $this->joinNewGroupon($order, $user);
+        }
+        // 添加参团记录
+        $activityGrouponLog = $this->addGrouponLog($order, $user, $activityGroupon);
+
+        return $this->checkGrouponStatus($activityGroupon);
+    }
+
+
+    /**
+     * 支付成功开启新拼团
+     */
+    protected function joinNewGroupon($order, $user)
+    {
+        $item = $order->item;
+        $goodsItem = $item[0];      // 拼团只能单独购买
+
+        // 获取活动
+        $activity = Activity::where('id', $goodsItem['activity_id'])->find();
+        $rules = $activity['rules'];
+
+        // 小于 0 不限结束时间单位小时
+        $expiretime = 0;
+        if (isset($rules['valid_time']) && $rules['valid_time'] > 0) {
+            // 转为 秒
+            $expiretime = $rules['valid_time'] * 3600;
+        }
+
+        // 开团
+        $activityGroupon = new ActivityGroupon();
+        $activityGroupon->user_id = $user['id'];
+        $activityGroupon->goods_id = $goodsItem['goods_id'];
+        $activityGroupon->activity_id = $goodsItem['activity_id'];
+        $activityGroupon->num = $rules['team_num'] ?? 1;        // 避免活动找不到
+        $activityGroupon->current_num = 0;              // 真实团成员等支付完成之后再增加
+        $activityGroupon->status = 'ing';
+        $activityGroupon->expiretime = $expiretime > 0 ? (time() + $expiretime) : 0;
+        $activityGroupon->save();
+
+        // 记录团 id
+        $order->ext = json_encode($order->setExt($order, ['groupon_id' => $activityGroupon->id]));      // 团 id
+        $order->save();
+
+        // 将团信息存入缓存,增加缓存中当前团人数
+        $this->grouponCacheForwardNum($activityGroupon, $activity, $user, 'payed');
+
+        if ($expiretime > 0) {
+            // 增加自动关闭拼团队列(如果有虚拟成团,会判断虚拟成团)
+            \think\Queue::later($expiretime, '\addons\shopro\job\ActivityGrouponAutoOper@expire', [
+                'activity' => $activity,
+                'activity_groupon_id' => $activityGroupon->id
+            ], 'shopro');
+        }
+
+        return $activityGroupon;
+    }
+
+
+    /**
+     * 增加团成员记录
+     */
+    protected function addGrouponLog($order, $user, $activityGroupon) {
+        if (!$activityGroupon) {
+            \think\Log::write('groupon-notfund: order_id: ' . $order['id']);
+            return null;
+        }
+
+        $item = $order->item;
+        $goodsItem = $item[0];      // 拼团只能单独购买
+
+        // 增加团成员数量
+        $activityGroupon->setInc('current_num', 1);
+
+        // 增加参团记录
+        $activityGrouponLog = new ActivityGrouponLog();
+        $activityGrouponLog->user_id = $user['id'];
+        $activityGrouponLog->user_nickname = $user['nickname'];
+        $activityGrouponLog->user_avatar = $user['avatar'];
+        $activityGrouponLog->groupon_id = $activityGroupon['id'] ?? 0;
+        $activityGrouponLog->goods_id = $goodsItem['goods_id'];
+        $activityGrouponLog->goods_sku_price_id = $goodsItem['goods_sku_price_id'];
+        $activityGrouponLog->activity_id = $goodsItem['activity_id'];
+        $activityGrouponLog->is_leader = ($activityGroupon['user_id'] == $user['id']) ? 1 : 0;
+        $activityGrouponLog->is_fictitious = 0;
+        $activityGrouponLog->order_id = $order['id'];
+        $activityGrouponLog->save();
+
+        return $activityGrouponLog;
+    }
+
+
+    // 虚拟成团,增加虚拟成员,并判断是否完成,然后将团状态改为,虚拟成团成功
+    protected function finishFictitiousGroupon($activityGroupon, $num = 0, $users = []) {
+        // 拼团剩余人数
+        $surplus_num = $activityGroupon['num'] - $activityGroupon['current_num'];
+        
+        // 团已经满员
+        if ($surplus_num <= 0) {
+            if ($activityGroupon['status'] == 'ing') {
+                // 已满员但还是进行中状态,检测并完成团,起到纠正作用
+                return $this->checkGrouponStatus($activityGroupon);
+            }
+            return true;
+        }
+
+        // 本次虚拟人数, 如果传入 num 则使用 num 和 surplus_num 中最小值, 如果没有传入,默认剩余人数全部虚拟
+        $fictitious_num = $num ? ($num > $surplus_num ? $surplus_num : $num) : $surplus_num;
+
+        // 查询虚拟用户
+        $userFakes = UserFake::orderRaw('rand()')->limit($fictitious_num)->select();
+
+        if (count($userFakes) < $fictitious_num && $num == 0) {
+            // 虚拟用户不足,并且是自动虚拟成团进程,自动解散团
+            return $this->invalidRefundGroupon($activityGroupon);
+        }
+
+        // 增加团人数
+        $activityGroupon->setInc('current_num', $fictitious_num);
+        
+        for ($i = 0; $i < $fictitious_num; $i ++) {
+            // 先用传过来的
+            $avatar = isset($users[$i]['avatar']) ? $users[$i]['avatar'] : '';
+            $nickname = isset($users[$i]['nickname']) ? $users[$i]['nickname'] : '';
+
+            // 如果没有,用查的虚拟的
+            $avatar = $avatar ? : $userFakes[$i]['avatar'];
+            $nickname = $nickname ? : $userFakes[$i]['nickname'];
+
+            // 增加参团记录
+            $activityGrouponLog = new ActivityGrouponLog();
+            $activityGrouponLog->user_id = 0;
+            $activityGrouponLog->user_nickname = $nickname;
+            $activityGrouponLog->user_avatar = $avatar;
+            $activityGrouponLog->groupon_id = $activityGroupon['id'] ?? 0;
+            $activityGrouponLog->goods_id = $activityGroupon['goods_id'];
+            $activityGrouponLog->goods_sku_price_id = 0;        // 没有订单,所以也就没有 goods_sku_price_id
+            $activityGrouponLog->activity_id = $activityGroupon['activity_id'];
+            $activityGrouponLog->is_leader = 0;     // 不是团长
+            $activityGrouponLog->is_fictitious = 1; // 虚拟用户
+            $activityGrouponLog->order_id = 0;      // 虚拟成员没有订单
+            $activityGrouponLog->save();
+        }
+
+        return $this->checkGrouponStatus($activityGroupon);
+    }
+
+
+    /**
+     * 团过期退款,或者后台手动解散退款
+     */
+    protected function invalidRefundGroupon($activityGroupon, $user = null) {
+        $activityGroupon->status = 'invalid';       // 拼团失败
+        $activityGroupon->save();
+
+        // 查询参团真人
+        $logs = ActivityGrouponLog::with('order')->where('groupon_id', $activityGroupon['id'])->where('is_fictitious', 0)->select();
+
+        foreach ($logs as $key => $log) {
+            $order = $log['order'];
+            if ($order && $order['status'] > 0) {
+                // 退款,只能有一个 item
+                $item = $order['item'][0];
+                if ($item && in_array($item['refund_status'], [OrderItem::REFUND_STATUS_NOREFUND, OrderItem::REFUND_STATUS_ING])) {
+                    // 未申请退款,或者退款中,直接全额退款
+                    Order::startRefund($order, $order['item'][0], $order['pay_fee'], $user, '拼团失败退款');
+                }
+            }
+
+            // 修改 logs 为已退款
+            $log->is_refund = 1;
+            $log->save();
+        }
+
+        // 触发拼团失败行为
+        $data = ['groupon' => $activityGroupon];
+        \think\Hook::listen('activity_groupon_fail', $data);
+
+        return true;
+    }
+
+
+
+    /**
+     * 检查团状态
+     */
+    protected function checkGrouponStatus($activityGroupon) {
+        if (!$activityGroupon) {
+            return true;
+        }
+
+        // 重新获取团信息
+        $activityGroupon = ActivityGroupon::where('id', $activityGroupon['id'])->find();
+        if ($activityGroupon['current_num'] >= $activityGroupon['num'] && !in_array($activityGroupon['status'], ['finish', 'finish-fictitious'])) {
+            // 查询是否有虚拟团成员
+            $fictitiousCount = ActivityGrouponLog::where('groupon_id', $activityGroupon['id'])->where('is_fictitious', 1)->count();
+
+            // 将团设置为已完成
+            $activityGroupon->status = $fictitiousCount ? 'finish-fictitious' : 'finish';
+            $activityGroupon->finishtime = time();
+            $activityGroupon->save();
+
+            // 触发成团行为
+            $data = ['groupon' => $activityGroupon];
+            \think\Hook::listen('activity_groupon_finish', $data);
+        }
+
+        return true;
+    }
+}

+ 212 - 0
addons/shopro/library/traits/StockSale.php

@@ -0,0 +1,212 @@
+<?php
+
+namespace addons\shopro\library\traits;
+
+use addons\shopro\exception\Exception;
+use addons\shopro\model\ActivityGoodsSkuPrice;
+use addons\shopro\model\Goods;
+use addons\shopro\model\GoodsSkuPrice;
+use addons\shopro\model\OrderItem;
+use addons\shopro\model\ScoreGoodsSkuPrice;
+
+/**
+ * 库存销量
+ */
+trait StockSale
+{
+    use StockWarning;
+
+    // cache 正向加销量,添加订单之前拦截
+    public function cacheForwardSale($goods_list) {
+        try {
+            // 记录库存不足,中断的位置
+            $break_key = -1;
+            foreach ($goods_list as $key => $goods) {
+                $detail = $goods['detail'];
+                $activity = $detail['activity'];
+
+                // 没有活动,不是秒杀|拼团,或者没有 redis
+                if (!$activity || !in_array($activity['type'], ['seckill', 'groupon']) || !$this->hasRedis()) {
+                    continue;
+                }
+
+                // 实例化 redis
+                $redis = $this->getRedis();
+
+                $keys = $this->getKeys([
+                    'goods_id' => $detail['id'],
+                    'goods_sku_price_id' => $detail['current_sku_price']['id'],
+                ], [
+                    'activity_id' => $activity['id'],
+                    'activity_type' => $activity['type'],
+                ]);
+
+                extract($keys);
+                
+                // 活动商品规格
+                $goodsSkuPrice = $redis->HGET($activityHashKey, $goodsSkuPriceKey);
+                $goodsSkuPrice = json_decode($goodsSkuPrice, true);
+                // 活动商品库存
+                $stock = $goodsSkuPrice['stock'] ?? 0;
+
+                // 当前销量 + 购买数量 ,salekey 如果不存在,自动创建
+                $sale = $redis->HINCRBY($activityHashKey, $saleKey, $goods['goods_num']);
+
+                if ($sale > $stock) {
+                    // 记录中断的位置
+                    $break_key = $key;
+                    throw new \Exception('活动商品库存不足');
+                }
+            }
+        } catch (\Exception $e) {
+            // 将 缓存的 销量减掉
+            if ($break_key >= 0) {
+                foreach ($goods_list as $key => $goods) {
+                    if ($key > $break_key) {        // 上面库存不足中断的位置
+                        break;
+                    }
+                    $detail = $goods['detail'];
+                    $activity = $detail['activity'];
+
+                    // 没有活动,不是秒杀|拼团,或者没有 redis
+                    if (!$activity || !in_array($activity['type'], ['seckill', 'groupon']) || !$this->hasRedis()) {
+                        continue;
+                    }
+
+                    // 实例化 redis
+                    $redis = $this->getRedis();
+
+                    $keys = $this->getKeys([
+                        'goods_id' => $detail['id'],
+                        'goods_sku_price_id' => $detail['current_sku_price']['id'],
+                    ], [
+                        'activity_id' => $activity['id'],
+                        'activity_type' => $activity['type'],
+                    ]);
+
+                    extract($keys);
+
+                    if ($redis->EXISTS($activityHashKey) && $redis->HEXISTS($activityHashKey, $saleKey)) {
+                        $sale = $redis->HINCRBY($activityHashKey, $saleKey, -$goods['goods_num']);
+                    }
+                }
+    
+                new Exception('商品库存不足');
+            }
+
+            new Exception($e->getMessage());
+        }
+    }
+
+
+    // cache 反向减销量,取消订单/订单自动关闭 时候
+    public function cacheBackSale($order) {
+        $items = OrderItem::where('order_id', $order['id'])->select();
+
+        foreach ($items as $key => $item) {
+            $this->cacheBackSaleByItem($item);
+        }
+    }
+
+
+
+    // 真实正向 减库存加销量(支付成功扣库存,加销量)
+    public function realForwardStockSale($order) {
+        $items = OrderItem::where('order_id', $order['id'])->select();
+
+        foreach ($items as $key => $orderItem) {
+            // 增加商品销量
+            Goods::where('id', $orderItem->goods_id)->setInc('sales', $orderItem->goods_num);
+
+            $goodsSkuPrice = GoodsSkuPrice::where('id', $orderItem->goods_sku_price_id)->find();
+            if ($goodsSkuPrice) {
+                $goodsSkuPrice->setDec('stock', $orderItem->goods_num);         // 减少库存
+                $goodsSkuPrice->setInc('sales', $orderItem->goods_num);         // 增加销量
+
+                // 库存预警检测
+                $this->checkStockWarning($goodsSkuPrice);
+            }
+
+            if ($orderItem->item_goods_sku_price_id) {
+                if ($order['type'] == 'score') {
+                    // 积分商城商品,扣除积分规格库存
+                    $itemGoodsSkuPrice = ScoreGoodsSkuPrice::where('id', $orderItem->item_goods_sku_price_id)->find();
+                } else {
+                    // 扣除活动库存
+                    $itemGoodsSkuPrice = ActivityGoodsSkuPrice::where('id', $orderItem->item_goods_sku_price_id)->find();
+                }
+                
+                if ($itemGoodsSkuPrice) {
+                    $itemGoodsSkuPrice->setDec('stock', $orderItem->goods_num);     // 减少库存
+                    $itemGoodsSkuPrice->setInc('sales', $orderItem->goods_num);     // 增加销量
+                }
+            }
+
+            // 已经真实减库存 减掉预销量,库存都是在缓存中读取的, 真是减库存,没有减掉 缓存库存,所以不需要减掉预销量, 设置开始的活动不可编辑
+            // $this->cacheBackSaleByItem($orderItem);
+        }
+    }
+
+
+    // 真实反向 加库存减销量(支付过的现在没有返库存,暂时没用)
+    public function realBackStockSale($order)
+    {
+        $items = OrderItem::where('order_id', $order['id'])->select();
+
+        foreach ($items as $key => $orderItem) {
+            // 返还商品销量
+            Goods::where('id', $orderItem->goods_id)->setDec('sales', $orderItem->goods_num);
+
+            // 返还规格库存
+            $goodsSkuPrice = GoodsSkuPrice::where('id', $orderItem->goods_sku_price_id)->find();
+            if ($goodsSkuPrice) {
+                $goodsSkuPrice->setInc('stock', $orderItem->goods_num);
+                $goodsSkuPrice->setDec('sales', $orderItem->goods_num);
+            }
+
+            if ($orderItem->item_goods_sku_price_id) {
+                if ($order['type'] == 'score') {
+                    // 积分商城商品,扣除积分规格库存
+                    $itemGoodsSkuPrice = ScoreGoodsSkuPrice::where('id', $orderItem->item_goods_sku_price_id)->find();
+                } else {
+                    $itemGoodsSkuPrice = ActivityGoodsSkuPrice::where('id', $orderItem->item_goods_sku_price_id)->find();
+                }                   
+
+                if ($itemGoodsSkuPrice) {
+                    $itemGoodsSkuPrice->setInc('stock', $orderItem->goods_num);       // 增加库存
+                    $itemGoodsSkuPrice->setDec('sales', $orderItem->goods_num);       // 减少销量
+                }
+            }
+        }
+    }
+
+
+
+    // 通过 OrderItem 减预库存
+    private function cacheBackSaleByItem($item)
+    {
+        // 不是秒杀|拼团,或者 没有配置 redis
+        if ((strpos($item['activity_type'], 'groupon') === false && strpos($item['activity_type'], 'seckill') === false) || !$this->hasRedis()) {
+            return false;
+        }
+
+        // 实例化 redis
+        $redis = $this->getRedis();
+
+        $keys = $this->getKeys([
+            'goods_id' => $item['goods_id'],
+            'goods_sku_price_id' => $item['goods_sku_price_id'],
+        ], [
+            'activity_id' => $item['activity_id'],
+            'activity_type' => $item['activity_type'],
+        ]);
+
+        extract($keys);
+
+        if ($redis->EXISTS($activityHashKey) && $redis->HEXISTS($activityHashKey, $saleKey)) {
+            $sale = $redis->HINCRBY($activityHashKey, $saleKey, -$item['goods_num']);
+        }
+
+        return true;
+    }
+}

Some files were not shown because too many files changed in this diff