Browse Source

优化大量UI,操作逻辑,使用体验更丝滑

tushan 11 months ago
parent
commit
33d78748d2
62 changed files with 1758 additions and 410 deletions
  1. 1 0
      .gitignore
  2. 2 2
      Dockerfile
  3. 16 36
      app/BaseController.php
  4. 3 35
      app/PluginsBase.php
  5. 51 0
      app/command/repair.php
  6. 45 0
      app/command/repass.php
  7. 26 0
      app/command/test.php
  8. 18 8
      app/controller/Admin.php
  9. 51 22
      app/controller/Api.php
  10. 4 1
      app/controller/Config.php
  11. 102 0
      app/controller/File.php
  12. 4 5
      app/controller/Index.php
  13. 41 2
      app/controller/Link.php
  14. 116 4
      app/controller/LinkStore.php
  15. 4 1
      app/controller/Tabbar.php
  16. 24 3
      app/controller/User.php
  17. 56 6
      app/controller/admin/Index.php
  18. 37 0
      app/model/FileModel.php
  19. 5 1
      app/model/LinkModel.php
  20. 5 0
      app/model/LinkStoreModel.php
  21. 37 0
      app/model/UserModel.php
  22. 3 1
      composer.json
  23. 3 0
      config/console.php
  24. 28 0
      defaultData.sql
  25. 5 0
      docker/install.sh
  26. 1 1
      docker/php.ini
  27. 6 1
      docker/start.sh
  28. 4 2
      extend/BrowserExtBuild.php
  29. 87 0
      extend/ImageBack.php
  30. 2 1
      extend/browserExt/manifest.json
  31. 358 136
      install.sql
  32. 1 1
      public/dist/index.html
  33. 2 2
      public/index.php
  34. 11 1
      public/install.php
  35. 0 0
      public/static/aliyun.svg
  36. 17 0
      public/static/bookmark.svg
  37. 0 0
      public/static/defLinkLogo/acfun.svg
  38. 1 0
      public/static/defLinkLogo/baiduyun.svg
  39. 0 0
      public/static/defLinkLogo/douyin.svg
  40. 1 0
      public/static/defLinkLogo/gitee.svg
  41. 0 0
      public/static/defLinkLogo/iqy.svg
  42. 0 0
      public/static/defLinkLogo/jingdongyun.svg
  43. 0 0
      public/static/defLinkLogo/kuaishou.svg
  44. 0 0
      public/static/defLinkLogo/leshi.svg
  45. 0 0
      public/static/defLinkLogo/mangguo.svg
  46. 0 0
      public/static/defLinkLogo/migu.svg
  47. 0 0
      public/static/defLinkLogo/qqmusic.svg
  48. 0 0
      public/static/defLinkLogo/wangyiyun.svg
  49. BIN
      public/static/defLinkLogo/webos.png
  50. BIN
      public/static/defLinkLogo/yisuyun.png
  51. 0 0
      public/static/defLinkLogo/youku.svg
  52. 1 0
      public/static/defLinkLogo/youtube.svg
  53. 574 138
      public/static/defaultTab.json
  54. 2 0
      public/static/jsdesign.svg
  55. 0 0
      public/static/pageGroup/chat.svg
  56. 1 0
      public/static/pageGroup/computer.svg
  57. 1 0
      public/static/pageGroup/faxian.svg
  58. 0 0
      public/static/pageGroup/geren.svg
  59. 1 0
      public/static/pageGroup/kongjian.svg
  60. 0 0
      public/static/pageGroup/work.svg
  61. 0 0
      public/static/pageGroup/xiuxian.svg
  62. BIN
      public/static/webTerm.svg

+ 1 - 0
.gitignore

@@ -14,3 +14,4 @@ public/installed.lock
 .user.ini
 /mtab
 mtab.zip
+/public/dist/

+ 2 - 2
Dockerfile

@@ -19,8 +19,8 @@ RUN chmod +x /install.sh && chmod +x /start.sh && /bin/sh /install.sh && rm /ins
 
 EXPOSE 80
 
-CMD ["./start.sh"]
+CMD ["/bin/bash","/start.sh"]
 
 #构建全平台 docker buildx create --name mybuilder --driver docker-container --use
-#构建全平台 docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6,linux/amd64/v3,linux/386 -t itushan/mtab --push .
+#构建全平台 docker buildx build --no-cache --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6,linux/amd64/v3 -t itushan/mtab --push .
 #构建本地镜像 docker build -t itushan/mtab .

+ 16 - 36
app/BaseController.php

@@ -17,6 +17,8 @@ use think\App;
 use think\db\exception\DataNotFoundException;
 use think\db\exception\DbException;
 use think\db\exception\ModelNotFoundException;
+use think\Exception;
+use think\facade\Config;
 use think\Model;
 
 /**
@@ -53,7 +55,6 @@ class BaseController
      * @access public
      * @param App $app 应用对象
      */
-    protected $user_temp = false;
     private $SettingConfig = false;
     public $auth = false;
 
@@ -69,13 +70,20 @@ class BaseController
     // 初始化
     protected function initialize()
     {
-        if ($this->Setting('authCode', env('authCode', false), true)) {
+        if ($this->systemSetting('authCode', env('authCode', false), true)) {
             $this->auth = true;
         }
+        if ($this->systemSetting("app_debug", '0') === '1') {
+            $this->app->debug(true);
+            Config::set([
+                'show_error_msg' => true,
+                'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl'
+            ], 'app');
+        }
     }
 
     //系统设置项
-    public function Setting($key = false, $def = false, $emptyReplace = false)
+    protected function systemSetting($key = false, $def = false, $emptyReplace = false)
     {
         if ($this->SettingConfig === false) {
             $this->SettingConfig = SettingModel::Config();
@@ -100,41 +108,13 @@ class BaseController
      * @throws DbException
      * @throws ModelNotFoundException
      */
-    public function getUser(bool $must = false)
+    protected function getUser(bool $must = false)
     {
-        $id = $this->request->header("Userid",'');
-        $token = $this->request->header("Token",'');
-        if (!$id) {
-            $id = $this->request->cookie('user_id', '');
-        }
-        if (!$token) {
-            $token = $this->request->cookie('token', '');
-        }
-        if ($id && $token) {
-            if ($this->user_temp) return $this->user_temp;
-            $user = TokenModel::where("user_id", $id)->where('token', $token)->field("user_id,token,create_time")->find();
-            if ($user) {
-                if (time() > ($user['create_time'] + 60 * 60 * 24 * 15)) {//如果创建时间大于15天则删除
-                    $user->delete();
-                } else {
-                    if ((time() - $user['create_time']) > (864000)) { //token定时15天清理一次,10-15天内如果使用了则重新计算时间
-                        $user->create_time = time();
-                        $user->save();
-                    }
-                    $this->user_temp = $user;
-                    return $user;
-                }
-            }
-        }
-        if ($must) {
-            $this->error("请登录后操作")->send();
-            exit();
-        }
-        return false;
+        return UserModel::getUser($must);
     }
 
     //admin认证
-    public function getAdmin()
+    protected function getAdmin()
     {
         $user = $this->getUser(true);
         $info = UserModel::where('id', $user['user_id'])->where("manager", 1)->find();
@@ -145,7 +125,7 @@ class BaseController
         exit();
     }
 
-    public function success($msg, $data = []): \think\response\Json
+    protected function success($msg, $data = []): \think\response\Json
     {
         if (is_array($msg)) {
             return json(['msg' => "", "code" => 1, "data" => $msg]);
@@ -153,7 +133,7 @@ class BaseController
         return json(['msg' => $msg, "code" => 1, "data" => $data]);
     }
 
-    public function error($msg, $data = []): \think\response\Json
+    protected function error($msg, $data = []): \think\response\Json
     {
         if (is_array($msg)) {
             return json(['msg' => "", "code" => 0, "data" => $msg]);

+ 3 - 35
app/PluginsBase.php

@@ -5,24 +5,18 @@ namespace app;
 use think\App;
 use think\View;
 
-class PluginsBase
+class PluginsBase extends BaseController
 {
     public ?View $view = null;
-    public ?\think\Request $request = null;
-    public ?App $app = null;
-
     function __construct(App $app)
     {
-        $this->request = $app->request;
-        // 视图对象
-        $this->view = new View($app);
-        $this->app = $app;
+        parent::__construct($app);
         $this->_initialize();
     }
 
     function _initialize()
     {
-
+        $this->view = new View($this->app);
     }
 
     function assign($key, $view)
@@ -36,30 +30,4 @@ class PluginsBase
         return $this->view->fetch($view, $opt);
     }
 
-    public function getAdmin()
-    {
-        $info = new BaseController($this->app);
-        return $info->getAdmin();
-    }
-    public function getUser(bool $must = false)
-    {
-        $info = new BaseController($this->app);
-        return $info->getUser($must);
-    }
-
-    public function success($msg, $data = []): \think\response\Json
-    {
-        if (is_array($msg)) {
-            return json(['msg' => '', 'code' => 1, 'data' => $msg]);
-        }
-        return json(['msg' => $msg, 'code' => 1, 'data' => $data]);
-    }
-
-    public function error($msg, $data = []): \think\response\Json
-    {
-        if (is_array($msg)) {
-            return json(['msg' => '', 'code' => 0, 'data' => $msg]);
-        }
-        return json(['msg' => $msg, 'code' => 0, 'data' => $data]);
-    }
 }

+ 51 - 0
app/command/repair.php

@@ -0,0 +1,51 @@
+<?php
+declare (strict_types=1);
+
+namespace app\command;
+
+use mysqli;
+use think\console\Command;
+use think\console\Input;
+
+use think\console\Output;
+
+class repair extends Command
+{
+    protected function configure()
+    {
+        // 指令配置
+        $this->setName('repair')
+            ->setDescription('修复数据库差异');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        self::repair();
+        print_r("\033[1;31m数据库差异信息修复完毕\033[0m\n\r\033[1;42m请尝试刷新网站检查是否正常\033[0m\n");
+    }
+
+    public static function repair()
+    {
+        //默认的一些基础数据
+        $sqlFile = joinPath(root_path(), 'install.sql');
+        $sql_file_content = file_get_contents($sqlFile);
+        // 解析SQL文件内容并执行
+        $sql_statements = explode(';', trim($sql_file_content));
+        try {
+            $conn = new mysqli(env('database.hostname'), env('database.username'), env('database.password'), env('database.database'), (int)env('database.hostport', 3306));
+        } catch (\Exception $exception) {
+            print_r("数据库连接失败咯,请正确配置数据库\n");
+            exit();
+        }
+        foreach ($sql_statements as $sql_statement) {
+            if (!empty($sql_statement)) {
+                try {
+                    $conn->query($sql_statement);
+                } catch (\Exception $exception) {
+                    //不用管
+                }
+            }
+        }
+    }
+
+}

+ 45 - 0
app/command/repass.php

@@ -0,0 +1,45 @@
+<?php
+declare (strict_types=1);
+namespace app\command;
+use app\model\UserModel;
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Option;
+use think\console\Output;
+
+class repass extends Command
+{
+    protected function configure()
+    {
+        // 指令配置
+        $this->setName('repass')
+            ->setDescription('修改管理员密码 -u 用户名 -p 密码')
+            ->addOption('user', '-u', Option::VALUE_REQUIRED, '管理员账户')
+            ->addOption('pass', '-p', Option::VALUE_REQUIRED, '新密码');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $this->repass($input);
+    }
+
+
+    private function repass($input)
+    {
+        $user = $input->getOption('user');
+        $pass = $input->getOption('pass');
+        if ($user && $pass) {
+            $info = UserModel::where('mail', $user)->find();
+            if ($info) {
+                $info->password = md5($pass);
+                $info->save();
+                print_r("\033[1;31m账户密码重置完毕\033[0m\n\r\033[1;42m请使用新的密码登录\033[0m\n");
+            } else {
+                print_r("\033[1;31m账户不存在\033[0m\n");
+            }
+            exit();
+        }
+        print_r("\033[1;31m缺少用户名或密码\033[0m\n");
+        exit();
+    }
+}

+ 26 - 0
app/command/test.php

@@ -0,0 +1,26 @@
+<?php
+declare (strict_types=1);
+
+namespace app\command;
+
+use app\controller\Api;
+use think\console\Command;
+use think\console\Input;
+
+use think\console\Output;
+
+class test extends Command
+{
+    protected function configure()
+    {
+        // 指令配置
+        $this->setName('test')
+            ->setDescription('脚本测试');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $res = new Api($this->app);
+        print_r($res->upload()->getData());
+    }
+}

+ 18 - 8
app/controller/Admin.php

@@ -3,7 +3,10 @@
 namespace app\controller;
 
 use app\BaseController;
+use app\command\repair;
+use app\command\util;
 use app\model\ConfigModel;
+use app\model\FileModel;
 use app\model\HistoryModel;
 use app\model\LinkModel;
 use app\model\LinkStoreModel;
@@ -16,7 +19,9 @@ use app\model\UserSearchEngineModel;
 use DateInterval;
 use DatePeriod;
 use DateTime;
+use mysqli;
 use think\facade\Cache;
+use think\facade\Db;
 
 class Admin extends BaseController
 {
@@ -27,7 +32,10 @@ class Admin extends BaseController
         $search = $this->request->post('search');
         $sql = [];
         if (isset($search['mail']) && mb_strlen($search['mail']) > 0) {
-            $sql['mail'] = $search['mail'];
+            $sql[] = ['mail', 'like', "%$search[mail]%"];
+        }
+        if (isset($search['nickname']) && mb_strlen($search['nickname']) > 0) {
+            $sql[] = ["nickname","like","%$search[nickname]%"];
         }
         $user = UserModel::where($sql)->withoutField('password')->order($this->request->post('sort.prop', 'id'), $this->request->post('sort.order', 'desc'))->paginate($limit);
         return $this->success('ok', $user);
@@ -126,13 +134,7 @@ class Admin extends BaseController
         $userNum = UserModel::count('id');
         $linkNum = LinkStoreModel::count('id');
         $redisNum = 0;
-        $fileNum = Cache::get('fileNum');
-        if (!$fileNum) {
-            if (is_dir(public_path() . 'images')) {
-                $fileNum = $this->countFilesInDirectory(public_path() . 'images');
-                Cache::set('fileNum', $fileNum, 300);
-            }
-        }
+        $fileNum = FileModel::field('id')->count("id");
         return $this->success('ok', ['userNum' => $userNum, 'linkNum' => $linkNum, 'redisNum' => $redisNum, 'fileNum' => $fileNum]);
     }
 
@@ -196,4 +198,12 @@ class Admin extends BaseController
         }
         return $this->success('', []);
     }
+
+    function repair(): \think\response\Json
+    {
+        $this->getAdmin();
+        is_demo_mode(true);
+        repair::repair();
+        return $this->success("修复完毕");
+    }
 }

+ 51 - 22
app/controller/Api.php

@@ -3,7 +3,7 @@
 namespace app\controller;
 
 use app\BaseController;
-use app\model\ConfigModel;
+use app\model\FileModel;
 use app\model\LinkModel;
 use app\model\SettingModel;
 use GuzzleHttp\Client;
@@ -19,14 +19,23 @@ class Api extends BaseController
     public function site(): \think\response\Json
     {
         return $this->success("ok", [
-            'email' => $this->Setting('email', ''),
-            'qqGroup' => $this->Setting("qqGroup", ''),
-            'beianMps' => $this->Setting("beianMps", ''),
-            'copyright' => $this->Setting("copyright", ''),
-            "recordNumber" => $this->Setting("recordNumber", ''),
+            'email' => $this->systemSetting('email', ''),
+            'qqGroup' => $this->systemSetting("qqGroup", ''),
+            'beianMps' => $this->systemSetting("beianMps", ''),
+            'copyright' => $this->systemSetting("copyright", ''),
+            "recordNumber" => $this->systemSetting("recordNumber", ''),
+            "mobileRecordNumber" => $this->systemSetting('mobileRecordNumber', '0'),
             "auth" => $this->auth,
-            "logo" => $this->Setting('logo', ''),
-            "qq_login" => $this->Setting('qq_login', '0')
+            "logo" => $this->systemSetting('logo', ''),
+            "qq_login" => $this->systemSetting('qq_login', '0'),
+            "loginCloseRecordNumber" => $this->systemSetting('loginCloseRecordNumber', '0'),
+            "is_push_link_store" => $this->auth ? $this->systemSetting('is_push_link_store', '0') : '0',
+            "is_push_link_store_tips" => $this->systemSetting('is_push_link_store_tips', '0'),
+            "is_push_link_status" => $this->systemSetting("is_push_link_status", '0'),
+            'google_ext_link' => $this->systemSetting("google_ext_link", ''),
+            'edge_ext_link' => $this->systemSetting("edge_ext_link", ''),
+            'local_ext_link' => $this->systemSetting("local_ext_link", ''),
+            "customAbout" => $this->systemSetting("customAbout", '')
         ]);
     }
 
@@ -36,9 +45,9 @@ class Api extends BaseController
     }
 
     //获取默认壁纸
-    function DefBg()
+    function DefBg(): \think\response\Json
     {
-        $config = $this->Setting('defaultTab', 'static/defaultTab.json', true);
+        $config = $this->systemSetting('defaultTab', 'static/defaultTab.json', true);
         if ($config) {
             $fp = public_path() . $config;
             if (file_exists($fp)) {
@@ -54,7 +63,7 @@ class Api extends BaseController
         return $this->success("ok", ['background' => "static/background.jpeg", "mime" => 0]);
     }
 
-    function globalNotify()
+    function globalNotify(): \think\response\Json
     {
         $info = SettingModel::Config("globalNotify", false);
         if ($info) {
@@ -94,7 +103,7 @@ class Api extends BaseController
                     Cache::set('code' . $mail, $code, 300);
                     return $this->success('发送成功');
                 }
-            }catch (\Exception $e){
+            } catch (\Exception $e) {
                 return $this->error($e->getMessage());
             }
 
@@ -158,13 +167,13 @@ class Api extends BaseController
     {
         $avatar = $this->request->post('avatar');
         if ($avatar) {
-            $remote_avatar = $this->Setting("remote_avatar", "https://avatar.mtab.cc/6.x/bottts/png?seed=", true);
+            $remote_avatar = $this->systemSetting("remote_avatar", "https://avatar.mtab.cc/6.x/bottts/png?seed=", true);
             $str = $this->downloadFile($remote_avatar . $avatar, md5($avatar) . '.png');
             return $this->success(['src' => $str]);
         }
         $url = $this->request->post('url', false);
         $icon = "";
-        $cdn = $this->Setting('assets_host', '');
+        $cdn = $this->systemSetting('assets_host', '');
         if ($url) {
             $realUrl = $this->addHttpProtocolRemovePath($url);
             $client = \Axios::http();
@@ -255,6 +264,7 @@ class Api extends BaseController
 
     private function downloadFile($url, $name)
     {
+        $user = $this->getUser();
         $client = \Axios::http();
         $path = '/images/' . date('Y/m/d/');
         $remotePath = public_path() . $path;
@@ -269,6 +279,7 @@ class Api extends BaseController
                     'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
                 ]
             ]);
+            FileModel::addFile($path . $name, $user['user_id'] ?? null);
             return $path . $name;
         } catch (RequestException $e) {
         }
@@ -279,7 +290,7 @@ class Api extends BaseController
     {
         $send = $this->request->get('seed');
         $client = new Client();
-        $remote_avatar = $this->Setting('remote_avatar', 'https://avatar.mtab.cc/6.x/bottts/png?seed=', true);
+        $remote_avatar = $this->systemSetting('remote_avatar', 'https://avatar.mtab.cc/6.x/bottts/png?seed=', true);
         $response = $client->get($remote_avatar . urlencode($send), [
             'stream' => true,
             'timeout' => 10,
@@ -291,17 +302,20 @@ class Api extends BaseController
     {
         $user = $this->getUser();
         if (!$user) {
-            if ($this->Setting('touristUpload') !== '1') {
+            if ($this->systemSetting('touristUpload') !== '1') {
                 //如果没有开启游客上传
                 return $this->error('管理员已关闭游客上传!请登录后使用');
             }
         }
+        $type = $this->request->header("Up-Type", '');
         $file = $this->request->file('file');
         if (empty($file)) {
             return $this->error('not File');
         }
-        if ($file->getSize() > 1024 * 1024 * 2) {
-            return $this->error('文件最大2MB,请压缩后再试');
+        $maxSize = (double)$this->systemSetting('upload_size', '2');
+        if ($file->getSize() > 1024 * 1024 * $maxSize) {
+            $limit = $maxSize < 1 ? ($maxSize * 1000) . 'KB' : ($maxSize) . 'MB';
+            return $this->error("文件最大$limit,请压缩后再试");
         }
         if (in_array(strtolower($file->getOriginalExtension()), ['png', 'jpg', 'jpeg', 'webp', 'ico', 'svg'])) {
             // 验证文件并保存
@@ -311,9 +325,23 @@ class Api extends BaseController
                 $hash = Str::random(32);
                 $fileName = $hash . '.' . $file->getOriginalExtension();
                 $filePath = Filesystem::disk('images')->putFileAs($savePath, $file, $fileName);
-                $cdn = $this->Setting('assets_host', '/', true);
-                return $this->success(['url' => $cdn . $filePath]);
+                $minPath = '';
+                if ($type == 'icon' || $type == 'avatar') {
+                    $fp = joinPath(public_path(), $filePath);
+                    $image = new \ImageBack($fp);
+                    $image->resize(120, 0)->save($fp);
+                } else if ($type == 'AdminBackground') {
+                    $minPath = joinPath($savePath, "/min_$fileName");
+                    $fp = joinPath(public_path(), $filePath);
+                    $image = new \ImageBack($fp);
+                    $image->resize(400, 0)->save(joinPath(public_path(), $minPath));
+                    FileModel::addFile($minPath, $user['user_id'] ?? null);
+                }
+                $cdn = $this->systemSetting('assets_host', '/', true);
+                FileModel::addFile($filePath, $user['user_id'] ?? null);
+                return $this->success(['url' => $cdn . $filePath, "minUrl" => joinPath($cdn, $minPath)]);
             } catch (\think\exception\ValidateException $e) {
+                return $this->error($e->getMessage());
                 // 验证失败,给出错误提示
                 // ...
             }
@@ -323,7 +351,7 @@ class Api extends BaseController
 
     function AdminUpload(): \think\response\Json
     {
-        $this->getAdmin();
+        $user = $this->getAdmin();
         $file = $this->request->file('file');
         if (empty($file)) {
             return $this->error('not File');
@@ -338,7 +366,8 @@ class Api extends BaseController
             $hash = Str::random(32);
             $fileName = $hash . '.' . $file->getOriginalExtension();
             $filePath = Filesystem::disk('images')->putFileAs($savePath, $file, $fileName);
-            $cdn = $this->Setting('assets_host', '/', true);
+            $cdn = $this->systemSetting('assets_host', '/', true);
+            FileModel::addFile($filePath, $user['user_id'] ?? null);
             return $this->success(['url' => $cdn . $filePath]);
         } catch (\think\exception\ValidateException $e) {
             // 验证失败,给出错误提示

+ 4 - 1
app/controller/Config.php

@@ -40,9 +40,12 @@ class Config extends BaseController
                 return $this->success("ok", $data['config']);
             }
         }
-        $config = $this->Setting('defaultTab', 'static/defaultTab.json', true);
+        $config = $this->systemSetting('defaultTab', 'static/defaultTab.json', true);
         if ($config) {
             $fp = public_path() . $config;
+            if (!file_exists($fp)) {
+                $fp = public_path() . 'static/defaultTab.json';
+            }
             if (file_exists($fp)) {
                 $file = file_get_contents($fp);
                 $json = json_decode($file, true);

+ 102 - 0
app/controller/File.php

@@ -0,0 +1,102 @@
+<?php
+
+namespace app\controller;
+ini_set('max_execution_time', 300);
+
+use app\BaseController;
+use app\model\FileModel;
+
+class File extends BaseController
+{
+    private $files = [];
+
+    public function list(): \think\response\Json
+    {
+        $this->getAdmin();
+        $limit = $this->request->post('limit', 15);
+        $name = $this->request->post('search.path', false);
+        $user_id = $this->request->post("search.user_id",false);
+        $sql = [];
+        if ($name) {
+            $sql[] = ['mime_type|path', 'like', '%' . $name . '%'];
+        }
+        if($user_id){
+            $sql["user_id"] = $user_id;
+        }
+        $list = FileModel::with("user")->where($sql);
+        $list = $list->order('id', 'desc')->paginate($limit);
+        return $this->success('ok', $list);
+    }
+
+    function del(): \think\response\Json
+    {
+        is_demo_mode(true);
+        $this->getAdmin();
+        $ids = $this->request->post('ids', []);
+        $res = FileModel::where('id', 'in', $ids)->select()->toArray();
+        foreach ($res as $k => $v) {
+            $p = joinPath(public_path(), $v['path']);
+            if (file_exists($p)) {
+                @unlink($p);
+            }
+            FileModel::where('id', $v['id'])->delete();
+        }
+        return $this->success('删除成功');
+    }
+
+    private function countFilesInDirectory($directory): int
+    {
+        $fileCount = 0;
+        // 获取目录中的文件和子目录
+        $files = scandir($directory);
+        foreach ($files as $file) {
+            // 排除"."和".."
+            if ($file != '.' && $file != '..') {
+                $filePath = $directory . '/' . $file;
+                // 如果是目录,则递归调用函数
+                if (is_dir($filePath)) {
+                    $fileCount += $this->countFilesInDirectory($filePath);
+                } else {
+                    // 如果是文件,则增加文件数量
+                    $this->files[] = joinPath("/", $filePath);
+                    $fileCount++;
+                }
+            }
+        }
+
+        return $fileCount;
+    }
+
+    function scanLocal(): \think\response\Json
+    {
+        is_demo_mode(true);
+        $this->getAdmin();
+        if (!is_dir(public_path("images"))) {
+            return $this->success('扫描完成');
+        }
+        $this->countFilesInDirectory("images");
+        $list = FileModel::limit(5000)->select()->toArray();
+        foreach ($list as $key => $v) {
+            $index = array_search(joinPath('/', $v['path']), $this->files);
+            if ($index >= 0) {
+                unset($this->files[$index]);
+            }
+        }
+        $all = [];
+        if (count($this->files) > 0) {
+            foreach ($this->files as $key => $v) {
+                $p = joinPath(public_path(), $v);
+                $info = [];
+                $info['path'] = $v;
+                $info['user_id'] = null;
+                $info['create_time'] = date('Y-m-d H:i:s');
+                $info['size'] = filesize($p) ?? 0;
+                $info['mime_type'] = mime_content_type($p) ?? 'null';
+                $all[] = $info;
+            }
+            $file = new FileModel();
+            $file->saveAll($all);
+        }
+        return $this->success("扫描完成");
+    }
+}

+ 4 - 5
app/controller/Index.php

@@ -24,7 +24,6 @@ class Index extends BaseController
         View::assign("favicon", SettingModel::Config('logo', '/favicon.ico'));
         return View::fetch("dist/index.html");
     }
-
     function all()
     {
         $app = app();
@@ -43,16 +42,16 @@ class Index extends BaseController
         return $this->success("ok", $dt);
     }
 
-    function privacy()
+    function privacy(): string
     {
-        $content = $this->Setting("privacy", "");
-        return View::fetch('/privacy', ['content' => $content,'title'=>$this->Setting("title",''), 'logo' => $this->Setting('logo', '')]);
+        $content = $this->systemSetting("privacy", "");
+        return View::fetch('/privacy', ['content' => $content,'title'=>$this->systemSetting("title",''), 'logo' => $this->systemSetting('logo', '')]);
     }
 
     function favicon()
     {
         //从配置中获取logo
-        $favicon = $this->Setting('logo');
+        $favicon = $this->systemSetting('logo');
         $file = public_path() . $favicon;
         if (file_exists($file) && is_file($file)) {
             return download($file)->mimeType(\PluginStaticSystem::mimeType($file))->force(false)->expire(60 * 60 * 24);

+ 41 - 2
app/controller/Link.php

@@ -20,13 +20,13 @@ class Link extends BaseController
             if ($link) {
                 $is = LinkModel::where("user_id", $user['user_id'])->find();
                 if ($is) {
+                    HistoryModel::create(['user_id' => $user['user_id'], 'link' => $is['link']]); //历史记录备份,用于用户误操作恢复用途
                     $is->link = $link;
                     $is->save();
                 } else {
                     LinkModel::create(["user_id" => $user['user_id'], "link" => $link]);
                 }
                 Cache::delete("Link.{$user['user_id']}");
-                HistoryModel::create(["user_id" => $user['user_id'], "link" => $link]); //历史记录备份,用于用户误操作恢复用途
                 return $this->success('ok');
             }
         }
@@ -49,9 +49,12 @@ class Link extends BaseController
                 return $this->success('ok', $c);
             }
         }
-        $config = $this->Setting("defaultTab", 'static/defaultTab.json', true);
+        $config = $this->systemSetting("defaultTab", 'static/defaultTab.json', true);
         if ($config) {
             $fp = public_path() . $config;
+            if (!file_exists($fp)) {
+                $fp = public_path() . "static/defaultTab.json";
+            }
             if (file_exists($fp)) {
                 $file = file_get_contents($fp);
                 $json = json_decode($file, true);
@@ -68,6 +71,42 @@ class Link extends BaseController
         return $this->success('刷新完毕');
     }
 
+    public function history(): \think\response\Json
+    {
+        $user = $this->getUser(true);
+        $history = HistoryModel::where("user_id", $user['user_id'])->whereNotNull("create_time")->field('id,user_id,create_time')->limit(100)->order("id", "desc")->select();
+        return $this->success('ok', $history);
+    }
+
+    public function delBack(): \think\response\Json
+    {
+        $user = $this->getUser(true);
+        $id = $this->request->post('id');
+        if ($id) {
+            $res = HistoryModel::where('id', $id)->where('user_id', $user['user_id'])->delete();
+            if ($res) {
+                return $this->success('ok');
+            }
+        }
+        return $this->error('备份节点不存在');
+    }
+
+    public function rollBack(): \think\response\Json
+    {
+        $user = $this->getUser(true);
+        $id = $this->request->post("id");
+        if ($id) {
+            $res = HistoryModel::where('id', $id)->where("user_id", $user['user_id'])->find();
+            if ($res) {
+                $link = $res['link'];
+                Cache::delete("Link.{$user['user_id']}");
+                LinkModel::update(["user_id" => $user['user_id'], "link" => $link]);
+                return $this->success('ok');
+            }
+        }
+        return $this->error("备份节点不存在");
+    }
+
     public function reset(): \think\response\Json
     {
         $user = $this->getUser();

+ 116 - 4
app/controller/LinkStore.php

@@ -4,6 +4,7 @@ namespace app\controller;
 
 use app\BaseController;
 use app\model\ConfigModel;
+use app\model\FileModel;
 use app\model\LinkFolderModel;
 use app\model\LinkStoreModel;
 use think\facade\Db;
@@ -20,7 +21,7 @@ class LinkStore extends BaseController
         if ($name) {
             $sql[] = ['name|tips', 'like', "%" . $name . "%"];
         }
-        $list = LinkStoreModel::where($sql);
+        $list = LinkStoreModel::where($sql)->where('status', 1)->order('hot', "desc")->withoutField('user_id');
         //area需要使用find_in_set来匹配
         if ($area && $area != 0) {
             $list = $list->whereRaw("find_in_set('$area',area)");
@@ -39,7 +40,7 @@ class LinkStore extends BaseController
         if ($name) {
             $sql[] = ['name|tips', 'like', '%' . $name . '%'];
         }
-        $list = LinkStoreModel::where($sql);
+        $list = LinkStoreModel::with(['userInfo'])->where($sql);
         //area需要使用find_in_set来匹配
         if ($area && $area != '全部') {
             $list = $list->whereRaw("find_in_set('$area',area)");
@@ -58,16 +59,106 @@ class LinkStore extends BaseController
         is_demo_mode(true);
         $admin = $this->getAdmin();
         $data = $this->request->post("form");
-        $info = LinkStoreModel::where("id", $data['id'])->update($data);
+        try {
+            unset($data['userInfo']);
+        } catch (\Exception $exception) {
+
+        }
+        $info = LinkStoreModel::where("id", $data['id'])->withoutField(['userInfo'])->update($data);
         return $this->success('修改成功', $info);
     }
 
+    function addPublic(): \think\response\Json
+    {
+        $user = $this->getAdmin();
+        $info = $this->request->post();
+        $info['create_time'] = date("Y-m-d H:i:s");
+        $info['domain'] = $this->getDomain($info['url']);
+        $info['src'] = $this->downloadLogo($info['src']);
+        FileModel::addFile($info['src'],$user['id']);
+        if (isset($info['id'])) {
+            unset($info['id']);
+        }
+        (new \app\model\LinkStoreModel)->allowField(["name", "src", "url", "domain", "create_time", "tips", "app"])->insert($info);
+        return $this->success('添加成功', $info);
+    }
+
+    private function downloadLogo($src): string
+    {
+        $f = file_get_contents($src);
+        $pathinfo = pathinfo($src);
+        try {
+            mkdir(public_path() . 'images/' . date("Y/m/d"), 0755, true);
+        } catch (\Throwable $th) {
+            //throw $th;
+        }
+        $filePath = '/images/' . date("Y/m/d") . '/' . md5($src) . '.' . $pathinfo['extension'];
+        file_put_contents(joinPath(public_path(), $filePath), $f);
+        return $filePath;
+    }
+
+    function push(): \think\response\Json
+    {
+        $user = $this->getUser(true);
+        $data = $this->request->post();
+        $info = [];
+        if ($data) {
+            if (isset($data['name'])) {
+                $info['name'] = $data['name'];
+            }
+            if (isset($data['src'])) {
+                $info['src'] = $data['src'];
+            }
+            if (isset($data['url']) && mb_strlen($data['url']) > 2) {
+                $info['url'] = $data['url'];
+            } else {
+                return $this->error('推送失败');
+            }
+            if (isset($data['bgColor'])) {
+                $info['bgColor'] = $data['bgColor'];
+            }
+            if (isset($data['app'])) {
+                $info['app'] = $data['app'];
+            }
+            if (isset($data['tips'])) {
+                $info['tips'] = $data['tips'];
+            }
+            $info['domain'] = $this->getDomain($info['url']);
+            $info['user_id'] = $user['user_id'];
+            $info['status'] = 0;
+            $info['create_time'] = date('Y-m-d H:i:s');
+            if (!LinkStoreModel::where("url", $info['url'])->find()) {
+                LinkStoreModel::create($info);
+                return $this->success('推送完毕');
+            }
+        }
+        return $this->error('推送失败');
+    }
+
+    private function getDomain($url)
+    {
+        $domain = $url;
+        $p = parse_url($domain);
+        if (isset($p['host'])) {
+            return $p['host'];
+        }
+        if (isset($p['path'])) {
+            return $p['path'];
+        }
+        return '';
+    }
+
     public function add(): \think\response\Json
     {
         $admin = $this->getAdmin();
         is_demo_mode(true);
-        $data = $this->request->post('form');
+        $data = $this->request->post('form', []);
         if ($data) {
+            try {
+                unset($data['userInfo']);
+            } catch (\Exception $exception) {
+
+            }
             if (isset($data['id']) && $data['id']) { //更新
                 return $this->update();
             } else {
@@ -167,4 +258,25 @@ class LinkStore extends BaseController
         LinkStoreModel::where("id", 'in', $ids)->delete();
         return $this->success('删除成功');
     }
+
+    function domains(): \think\response\Json
+    {
+        $domains = $this->request->post('domains', []);
+        $tmp = [];
+        foreach (LinkStoreModel::where('status', 1)->cursor() as $value) {
+            $d = $this->getDomain($value['url']);
+            if (in_array($d, $domains)) {
+                $tmp[$d] = ["domain" => $d, "name" => $value['name'], "src" => $value['src'], "bgColor" => $value['bgColor'],'tips'=>$value['tips']];
+            } else if ($value['domain']) {
+                $r = explode(",", $value['domain']);
+                foreach ($r as $v) {
+                    if (in_array($v, $domains)) {
+                        $tmp[$v] = ['domain' => $v, 'name' => $value['name'], 'src' => $value['src'], 'bgColor' => $value['bgColor'],'tips'=>$value['tips']];
+                        break;
+                    }
+                }
+            }
+        }
+        return $this->success('ok', $tmp);
+    }
 }

+ 4 - 1
app/controller/Tabbar.php

@@ -38,9 +38,12 @@ class Tabbar extends BaseController
                 return $this->success('ok', $data['tabs']);
             }
         }
-        $config = $this->Setting('defaultTab', '/static/defaultTab.json', true);
+        $config = $this->systemSetting('defaultTab', '/static/defaultTab.json', true);
         if ($config) {
             $fp = joinPath(public_path(), $config);
+            if (!file_exists($fp)) {
+                $fp = public_path() . 'static/defaultTab.json';
+            }
             if (file_exists($fp)) {
                 $file = file_get_contents($fp);
                 $json = json_decode($file, true);

+ 24 - 3
app/controller/User.php

@@ -22,7 +22,7 @@ class User extends BaseController
         $pass = $this->request->post('password', '0');
         $user = trim($user);
         $pass = trim($pass);
-        $info = UserModel::where('mail', $user)->field('id,mail,password,login_fail_count,login_ip,login_time')->find();
+        $info = UserModel::where('mail', $user)->find();
 
         if (Cache::get('login.' . $user)) {
             return $this->error('账号已被安全锁定,您可以修改密码然后登录');
@@ -41,6 +41,9 @@ class User extends BaseController
             $info->save();
             return $this->error('账号不存在或密码错误');
         }
+        if ($info['status'] === 1) {
+            return $this->error('账号已被冻结');
+        }
         $auth = $this->refreshToken($info);
         $info->login_ip = getRealIp();
         $info->login_time = date('Y-m-d H:i:s');
@@ -49,6 +52,7 @@ class User extends BaseController
         return $this->success('登录成功', $auth);
     }
 
+
     private function refreshToken($info): array
     {
         $token = renderToken($info['id']);
@@ -180,6 +184,20 @@ class User extends BaseController
         return $this->error('获取失败');
     }
 
+    public function unbindQQ(): \think\response\Json
+    {
+        $info = $this->getUser(true);
+        if ($info) {
+            $info = UserModel::field('id,mail,manager,nickname,avatar,qq_open_id')->find($info['user_id']);
+            if (empty($info->mail)) {
+                return $this->error("请先绑定邮箱后再解绑");
+            }
+            $info->qq_open_id = "";
+            $info->save();
+        }
+        return $this->success('解绑成功', $info);
+    }
+
     public function updateInfo(): \think\response\Json
     {
         $info = $this->getUser(true);
@@ -265,10 +283,10 @@ class User extends BaseController
                     //如果openid数据库不存在说明QQ没有被绑定过,可以绑定
                     $this->BindQQ($openid);//绑定后需要替换Token,不然之前的QQ登录会失效
                 }
-                $info = UserModel::where('qq_open_id', $openid)->field('id,mail,qq_open_id,password,login_fail_count,login_ip,login_time')->find();
+                $info = UserModel::where('qq_open_id', $openid)->find();
                 if (!$info) {//不存在就创建一个新用户,如果上一个步骤绑定成功的话,是不可能进入此步骤的
                     UserModel::insert(['mail' => '', 'password' => md5(time()), 'create_time' => date('Y-m-d H:i:s'), 'register_ip' => getRealIp(), 'qq_open_id' => $openid]);
-                    $info = UserModel::where('qq_open_id', $openid)->field('id,mail,qq_open_id,password,login_fail_count,login_ip,login_time')->find();
+                    $info = UserModel::where('qq_open_id', $openid)->find();
                     $this->getUserOpenInfo($access_token, $openid);//获取一些用户的默认信息
                 }
                 if ($info) {//如果用户存在
@@ -278,6 +296,9 @@ class User extends BaseController
                     $info->save();
                     $info['access_token'] = $access_token;
                     $auth = $this->refreshToken($info);
+                    if ($info['status'] === 1) {
+                        return View::fetch('/qq_login_error');
+                    }
                     return View::fetch('/qq_login', ['info' => $auth]);
                 }
             }

+ 56 - 6
app/controller/admin/Index.php

@@ -4,6 +4,7 @@ namespace app\controller\admin;
 
 use app\BaseController;
 use app\model\CardModel;
+use app\model\LinkStoreModel;
 use app\model\SettingModel;
 use think\facade\Cache;
 use think\facade\Db;
@@ -28,12 +29,12 @@ class Index extends BaseController
 
     private function initAuth()
     {
-        $authCode = $this->Setting('authCode', '', true);
+        $authCode = $this->systemSetting('authCode', '', true);
         if (strlen($authCode) == 0) {
             $authCode = env('authCode', '');
         }
         $this->authCode = $authCode;
-        $this->authService = $this->Setting('authServer', 'https://auth.mtab.cc', true);
+        $this->authService = $this->systemSetting('authServer', 'https://auth.mtab.cc', true);
     }
 
 
@@ -55,7 +56,7 @@ class Index extends BaseController
                 $f = "";
                 $upGrade = null;
                 if (!empty($json['info']['update_php'])) {
-                    try {//用远程脚本更新,一般用不到,除非上一个版本发生一些问题需要额外脚本处理
+                    try { //用远程脚本更新,一般用不到,除非上一个版本发生一些问题需要额外脚本处理
                         $f = file_get_contents($json['info']['update_php']);
                         file_put_contents(runtime_path() . 'update.php', $f);
                         require_once $upgradePhp;
@@ -74,7 +75,7 @@ class Index extends BaseController
                     $upGrade->update_sql_url = $json['info']['update_sql'];
                 }
                 try {
-                    $upGrade->run();//启动任务
+                    $upGrade->run(); //启动任务
                     if (file_exists($upgradePhp)) {
                         unlink($upgradePhp);
                     }
@@ -212,7 +213,6 @@ class Index extends BaseController
             } catch (\Exception $e) {
                 return $this->error($e->getMessage());
             }
-
         }
         return $this->error("没有需要安装的卡片插件!");
     }
@@ -315,4 +315,54 @@ class Index extends BaseController
         }
         return $this->success('打包失败');
     }
-}
+
+
+    function folders(): \think\response\Json
+    {
+        $this->getAdmin();
+        $this->initAuth();
+        $result = \Axios::http()->post($this->authService . '/client/folders', [
+            'timeout' => 15,
+            'form_params' => [
+                'authorization_code' => $this->authCode
+            ]
+        ]);
+        $json = $result->getBody()->getContents();
+        $json = json_decode($json, true);
+        if ($json['code'] === 1) {
+            return $this->success('ok', $json['data']);
+        }
+        return $this->success('获取失败');
+    }
+
+    function links(): \think\response\Json
+    {
+        $this->getAdmin();
+        $this->initAuth();
+        $folders = $this->request->get("folders");
+        $page = $this->request->get("page", 1);
+        $limit = $this->request->get("limit", 18);
+        $result = \Axios::http()->post($this->authService . '/client/links', [
+            'timeout' => 15,
+            'form_params' => [
+                'folders' => $folders,
+                'limit' => $limit,
+                'page' => $page,
+                'authorization_code' => $this->authCode
+            ]
+        ]);
+        $json = $result->getBody()->getContents();
+        $json = json_decode($json, true);
+        if ($json['code'] === 1) {
+            $arrName = [];
+            $arrUrl = [];
+            foreach ($json['data']['data'] as $key => $value) {
+                $arrName[] = $value['name'];
+                $arrUrl[] = $value['url'];
+            }
+            $res = LinkStoreModel::whereOr([["name",'in', $arrName],['url','in',$arrUrl]])->select();
+            return json(['code'=>1,'msg'=>'ok','data'=>$json['data'],'local'=>$res]);
+        }
+        return $this->success('获取失败');
+    }
+}

+ 37 - 0
app/model/FileModel.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace app\model;
+
+use think\Model;
+
+class FileModel extends Model
+{
+    protected $name = "file";
+    protected $pk = "id";
+
+    function getPathAttr($value)
+    {
+        return joinPath("/", $value);
+    }
+
+    public static function addFile($file, $user_id = null)
+    {
+        $originPath = joinPath(public_path(), $file);
+        if (file_exists($originPath)) {
+            $info = [];
+            $info["path"] = $file;
+            $info["user_id"] = $user_id;
+            $info['create_time'] = date("Y-m-d H:i:s");
+            $info['size'] = filesize($originPath);
+            $info["mime_type"] = mime_content_type($originPath);
+            self::insert($info);
+            return $info;
+        }
+        return false;
+    }
+
+    function user(): \think\model\relation\HasOne
+    {
+        return $this->hasOne(UserModel::class, "id", "user_id")->field("id,nickname,mail");
+    }
+}

+ 5 - 1
app/model/LinkModel.php

@@ -35,9 +35,13 @@ class LinkModel extends Model
     {
         foreach ($value as $k => &$v) {
             if (isset($v['app']) && $v['app'] == 1) {
-                if (isset($v['origin_id']) && $v['origin_id'] > 0) {
+                if (isset($v['origin_id']) && $v['origin_id'] > 0 && $v['type'] === 'icon') {
                     if (isset($this->WebApp[(int)$v['origin_id']])) {
                         $v['custom'] = $this->WebApp[(int)$v['origin_id']]['custom'];
+                        $v['url'] = $this->WebApp[(int)$v['origin_id']]['url'];
+                        $v['src'] = $this->WebApp[(int)$v['origin_id']]['src'];
+                        $v['name'] = $this->WebApp[(int)$v['origin_id']]['name'];
+                        $v['bgColor'] = $this->WebApp[(int)$v['origin_id']]['bgColor'];
                     }
                 }
             }

+ 5 - 0
app/model/LinkStoreModel.php

@@ -16,4 +16,9 @@ class LinkStoreModel extends Model
     protected $pk = "id";
     protected $jsonAssoc = true;
     protected $json = ['custom'];
+
+    function userInfo(): \think\model\relation\HasOne
+    {
+        return $this->hasOne(UserModel::class, 'id', 'user_id')->field('id,nickname');
+    }
 }

+ 37 - 0
app/model/UserModel.php

@@ -10,4 +10,41 @@ class UserModel extends Model
 {
     protected $name = "user";
     protected $pk = "id";
+    protected static $user_temp = null;
+
+    public static function getUser(bool $must = false)
+    {
+        $id = request()->header('Userid', '');
+        $token = request()->header('Token', '');
+        if (!$id) {
+            $id = request()->cookie('user_id', '');
+        }
+        if (!$token) {
+            $token = request()->cookie('token', '');
+        }
+        if ($id && $token) {
+            if (self::$user_temp) return self::$user_temp;
+            $user = TokenModel::where('user_id', $id)->where('token', $token)->field('user_id,token,create_time')->find();
+            if ($user) {
+                $status = UserModel::where('id', $user['user_id'])->find();
+                if ($status && $status['status'] === 0) {
+                    if (time() > ($user['create_time'] + 60 * 60 * 24 * 15)) {//如果创建时间大于15天则删除
+                        $user->delete();
+                    } else {
+                        if ((time() - $user['create_time']) > (864000)) { //token定时15天清理一次,10-15天内如果使用了则重新计算时间
+                            $user->create_time = time();
+                            $user->save();
+                        }
+                        self::$user_temp = $user;
+                        return $user;
+                    }
+                }
+            }
+        }
+        if ($must) {
+            json(['code' => 0, 'msg' => '请登录后操作'])->send();
+            exit();
+        }
+        return false;
+    }
 }

+ 3 - 1
composer.json

@@ -37,7 +37,9 @@
     "ext-zip": "*",
     "ext-posix": "*",
     "ext-dom": "*",
-    "ext-mbstring": "*"
+    "ext-mbstring": "*",
+    "ext-bcmath": "*",
+    "ext-gd": "*"
   },
   "require-dev": {
     "symfony/var-dumper": "^4.2",

+ 3 - 0
config/console.php

@@ -5,5 +5,8 @@
 return [
     // 指令定义
     'commands' => [
+        'repair' => 'app\command\repair',
+        'repass' => 'app\command\repass',
+        'test' => 'app\command\test',
     ],
 ];

+ 28 - 0
defaultData.sql

@@ -0,0 +1,28 @@
+INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('Bilibili', '/static/bilibili.png', 'https://bilibili.com', 'icon', '1x1', '2022-11-07 21:51:42', 0, 'Bilibili弹幕视频网站Acg网站', 'bilibili.com,www.bilibili.com', 0, 0);
+INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('蓝易云', '/static/tsy.png', 'https://www.tsyvps.com/aff/IRYIGFMX', 'icon', '1x1', '2022-11-07 22:02:41', 0, '蓝易云-持证高性价比服务器', 'www.tsyvps.com,tsyvps.com', 0, 0);
+INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('ImgUrl', '/static/imgurl.png', 'https://imgurl.ink', 'icon', '1x1', '2022-11-07 22:05:46', 0, 'ImgUrl图床,图片外链', 'imgurl.ink,www.imgurl.ink', 0, 0);
+INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('微博', '/static/weibo.png', 'http://weibo.com/', 'icon', '1x1', '2022-11-07 23:37:22', 1, '微博-随时随地发现新鲜事', 'weibo.com,www.weibo.com', 0, 0);
+INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('火山翻译', '/static/huoshanfanyi.png', 'https://translate.volcengine.com/translate', 'icon', '1x1', '2022-11-07 23:42:49', 1, '火山翻译-字节跳动旗下机器翻译品牌', 'translate.volcengine.com', 1, 1);
+INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('腾讯云', '/static/tencentcloud.png', 'https://cloud.tencent.com/', 'icon', '1x1', '2022-11-10 16:25:51', 1, '腾讯云', 'cloud.tencent.com', 0, 0);
+INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('阿里云', '/static/aliyun.svg', 'https://www.aliyun.com/', 'icon', '1x1', '2022-11-10 17:30:17', 1, '阿里云', 'www.aliyun.com,aliyun.com', 0, 0);
+INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('腾讯视频', '/static/txsp.png', 'https://v.qq.com/channel/choice?channel_2022=1', 'icon', '1x1', '2022-12-19 19:34:45', 0, '腾讯视频', 'v.qq.com', 0, 0);
+INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('记事本', '/static/note.png', '/noteApp', 'icon', '1x1', '2023-06-14 21:13:15', 1,'记事本App', '/noteApp', 1, 3);
+INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('WebTerm', '/static/webTerm.svg', 'https://ssh.mtab.cc', 'icon', '1x1', '2023-06-14 21:13:15', 1,'在线SSH终端', 'ssh.mtab.cc', 1, 3);
+
+
+INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (1, '百度', '/static/searchEngine/baidu.svg', 'https://www.baidu.com/s?wd={1}', 0, '2024-01-14 22:12:18', 1, '中国领先的搜索引擎和互联网公司,提供全球最大的中文搜索引擎服务,同时涵盖在线地图、贴吧、知道等多个互');
+INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (3, '必应', '/static/searchEngine/bing.svg', 'https://www.bing.com/search?q={1}', 99, '2024-01-14 23:20:03', 1, '微软推出的搜索引擎,以直观的界面和优质搜索结果而闻名,提供全球范围内的多语言搜索服务');
+INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (4, 'Google', '/static/searchEngine/google.svg', 'https://www.google.com/search?q={1}', 98, '2024-01-14 23:20:21', 1, 'Google:全球最大的搜索引擎,以卓越的搜索算法、广告服务和多样化的产品而著称,成为互联网信息检索');
+INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (5, '搜狗', '/static/searchEngine/sougou.svg', 'https://www.sogou.com/web?query={1}', 0, '2024-01-14 23:20:46', 1, '中国领先的搜索引擎,致力于提供智能搜索和语音输入技术,以及多元化的互联网服务,深受用户喜爱');
+INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (6, '360', '/static/searchEngine/360.svg', 'https://www.so.com/s?q={1}', 0, '2024-01-14 23:21:07', 1, '中国知名搜索引擎,注重用户隐私安全,提供全面的搜索服务,涵盖网页、图片、新闻等多个领域,致力于用户友');
+INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (7, '开发者搜索', '/static/searchEngine/baidudev.png', 'https://kaifa.baidu.com/searchPage?module=SEARCH&wd={1}', 0, '2024-01-14 23:21:45', 1, '专注于技术文档、API 和开发者资源的搜索引擎,为开发者提供快速准确的技术信息检索服务,支持多种编程');
+INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (8, 'B站', '/static/searchEngine/bilibiliico.png', 'https://search.bilibili.com/all?vt=21160573&keyword={1}', 0, '2024-01-14 23:21:57', 1, '中国弹幕视频平台,以二次元文化为特色,提供丰富的动画、游戏、音乐等内容,用户可通过弹幕互动分享观感。');
+INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (9, '微博', '/static/searchEngine/weiboico.png', 'https://s.weibo.com/weibo?q={1}', 0, '2024-01-14 23:22:12', 1, '中国社交媒体平台,用户可以发布短文、图片和视频,关注他人并互动评论,是实时新闻、话题讨论和社交分享的');
+INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (10, 'DuckDuckGo', '/static/searchEngine/DuckDuckGo.svg', 'https://duckduckgo.com/?t=h_&q={1}&ia=web', 96, '2024-01-15 21:37:44', 1, '注重隐私保护的搜索引擎,致力于不追踪用户个人信息,提供匿名、安全的搜索服务,受到关注的隐私倡导者青睐');
+
+INSERT INTO wallpaper (id, type, folder, mime, url, cover, create_time, name, sort) VALUES (1, 1, null, 0, null, null, '2024-02-22 12:29:21', '默认壁纸', 999);
+INSERT INTO wallpaper (id, type, folder, mime, url, cover, create_time, name, sort) VALUES (2, 0, 1, 0, '/static/wallpaper/wallpaper-1.jpeg', '/static/wallpaper/m_wallpaper-1.jpeg', '2024-02-22 12:35:59', null, 999);
+INSERT INTO wallpaper (id, type, folder, mime, url, cover, create_time, name, sort) VALUES (3, 0, 1, 0, '/static/wallpaper/wallpaper-2.jpeg', '/static/wallpaper/m_wallpaper-2.jpeg', '2024-02-22 12:36:27', null, 999);
+INSERT INTO wallpaper (id, type, folder, mime, url, cover, create_time, name, sort) VALUES (4, 0, 1, 0, '/static/wallpaper/wallpaper-3.jpeg', '/static/wallpaper/m_wallpaper-3.jpeg', '2024-02-22 12:36:43', null, 999);
+INSERT INTO wallpaper (id, type, folder, mime, url, cover, create_time, name, sort) VALUES (5, 0, 1, 0, '/static/wallpaper/wallpaper-4.jpeg', '/static/wallpaper/m_wallpaper-4.jpeg', '2024-02-22 12:36:52', null, 999);
+INSERT INTO wallpaper (id, type, folder, mime, url, cover, create_time, name, sort) VALUES (6, 0, 1, 0, '/static/wallpaper/wallpaper-5.jpeg', '/static/wallpaper/m_wallpaper-5.jpeg', '2024-02-22 12:37:03', null, 999);

+ 5 - 0
docker/install.sh

@@ -4,15 +4,20 @@ apk add php7 php7-pdo_mysql php7-xml php7-xmlrpc php7-openssl php7-posix php7-pc
 
 apk add php7-simplexml
 
+apk add php7-bcmath
+
 apk add php7-opcache
 
 apk add nginx
 
+apk add bash
+
 apk add redis
 
 apk add rsync
 
 apk add --no-cache tzdata
+
 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
 
 #创建nginx启动需要的目录

+ 1 - 1
docker/php.ini

@@ -691,7 +691,7 @@ auto_globals_jit = On
 ; Its value may be 0 to disable the limit. It is ignored if POST data reading
 ; is disabled through enable_post_data_reading.
 ; http://php.net/post-max-size
-post_max_size = 8M
+post_max_size = 20M
 
 ; Automatically add files before PHP document.
 ; http://php.net/auto-prepend-file

+ 6 - 1
docker/start.sh

@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
 php-fpm7
 
@@ -27,6 +27,11 @@ if [ ! -e "$lock_file" ]; then
     rm -rf "$source_dir";
 fi
 
+if [ -e "/app/public/installed.lock" ]; then
+    # 如果锁文件存在,执行以下更新数据库操作
+    echo "检查数据库更新...";
+    php "$destination_dir/think" repair
+fi
 
 echo "php-fpm7,redis and nginx started";
 

+ 4 - 2
extend/BrowserExtBuild.php

@@ -27,7 +27,9 @@ class BrowserExtBuild
         ),
         'permissions' => array(
             'background',
-            'cookies'
+            'cookies',
+            'bookmarks',
+            'favicon'
         ),
         'action' => array(
             'default_icon' => 'icon/64.png',
@@ -102,7 +104,7 @@ class BrowserExtBuild
         $this->manifest['description'] = $this->info['ext_description'];
         $this->manifest['action']['default_title'] = $this->info['ext_name'];
         $this->manifest['externally_connectable']['matches'] = ["*://{$host}/*"];
-        $this->manifest['host_permissions'] = ["*://{$host}/*"];
+        $this->manifest['host_permissions'] = ["*://{$host}/*", '*://*.baidu.com/*'];
         file_put_contents(joinPath($this->buildDir, "manifest.json"), json_encode($this->manifest, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
     }
 

+ 87 - 0
extend/ImageBack.php

@@ -0,0 +1,87 @@
+<?php
+
+class ImageBack
+{
+    protected $filename;
+    protected $fileExt = "";
+    protected $croppedWidth = 0;
+    protected $croppedHeight = 0;
+    protected $width = 0;
+    protected $height = 0;
+    protected $croppedX = 0;
+    protected $croppedY = 0;
+    protected $source;
+    protected $cropped;
+    protected $process = true;
+    protected $funName = "jpeg";
+
+    function __construct($filename)
+    {
+        $this->filename = $filename;
+        $fileExt = pathinfo($filename, PATHINFO_EXTENSION);
+        $this->fileExt = $fileExt;
+        switch ($this->fileExt) {
+            case 'jpg':
+            case 'jpeg':
+                $this->funName = "jpeg";
+                break;
+            case 'png':
+                $this->funName = 'png';
+                break;
+            case 'webp':
+                $this->funName = 'webp';
+                break;
+            default:
+                $this->process = false;
+        }
+        if ($this->process) {
+            $fun = 'imagecreatefrom' . $this->funName;
+            $this->source = $fun($filename);
+            $this->width = imagesx($this->source);
+            $this->height = imagesy($this->source);
+        }
+    }
+
+    public function resize($croppedWidth, $croppedHeight = 0, $croppedX = 0, $croppedY = 0): ImageBack
+    {
+        if ($this->process) {
+            $this->croppedHeight = $croppedHeight;
+            $this->croppedWidth = $croppedWidth;
+            $this->croppedX = $croppedX;
+            $this->croppedY = $croppedY;
+            if ($croppedWidth >= $this->width) {
+                $this->croppedWidth = $this->width;
+            }
+            if ($croppedHeight == 0) {
+                $this->croppedHeight = (int)($this->height / ($this->width / $this->croppedWidth));
+            } else if ($croppedHeight >= $this->height) {
+                $this->croppedHeight = $this->height;
+            }
+            $this->cropped = imagecreatetruecolor($this->croppedWidth, $this->croppedHeight);
+            if ($this->funName == 'png') {
+                // 将图像设置为支持 alpha 通道的模式
+                imagealphablending($this->cropped, false);
+                imagesavealpha($this->cropped, true);
+                $transparentColor = imagecolorallocatealpha($this->cropped, 0, 0, 0, 127);
+                imagefill($this->cropped, 0, 0, $transparentColor);
+            }
+        }
+        return $this;
+    }
+
+    public function save($savePath)
+    {
+        if ($this->process) {
+            try {
+                imagecopyresampled($this->cropped, $this->source, 0, 0, 0, 0, $this->croppedWidth, $this->croppedHeight, $this->width, $this->height);
+                $fun = 'image' . $this->funName;
+                $fun($this->cropped, $savePath);
+                imagedestroy($this->source);
+                return true;
+            } catch (Exception $exception) {
+                return $exception->getMessage();
+            }
+        }
+        return false;
+    }
+}

+ 2 - 1
extend/browserExt/manifest.json

@@ -27,7 +27,8 @@
     "default_title": "浏览器扩展样板"
   },
   "host_permissions": [
-    "*://go.mtab.cc/*"
+    "*://go.mtab.cc/*",
+    "*://*.baidu.com/*"
   ],
   "chrome_url_overrides": {
     "newtab": "dist/index.html"

+ 358 - 136
install.sql

@@ -1,212 +1,434 @@
-create table card
+# 创建Card数据表
+
+create table if not exists card
 (
-    id          int auto_increment
-        primary key,
-    name        varchar(200)  null,
-    name_en     varchar(200)  null,
-    status      int default 0 null,
-    version     int default 0 null,
-    tips        varchar(255)  null comment '说明',
-    create_time datetime      null comment '添加时间',
-    src         text          null comment 'logo',
-    url         varchar(255)  null comment '卡片地址',
-    `window`    varchar(255)  null comment '窗口地址',
-    update_time datetime      null,
-    install_num int default 0 null,
-    setting     varchar(200)  null comment '设置页面的url',
-    dict_option longtext      null comment '配置的参数'
-)
-    comment '卡片数据表';
+    id int auto_increment
+        primary key
+) comment '卡片数据表';
+
+
+alter table card
+    add name varchar(200) null;
+
+alter table card
+    add name_en varchar(200) null;
+
+alter table card
+    add status int default 0 null;
+
+alter table card
+    add version int default 0 null;
+
+alter table card
+    add tips varchar(255) null comment '说明';
+
+alter table card
+    add create_time datetime null comment '添加时间';
+
+alter table card
+    add src text null comment 'logo';
+
+alter table card
+    add url varchar(255) null comment '卡片地址';
+
+alter table card
+    add `window` varchar(255) null comment '窗口地址';
+
+alter table card
+    add update_time datetime null;
+
+alter table card
+    add install_num int default 0 null;
+
+alter table card
+    add setting varchar(200) null comment '设置页面的url';
 
-create table config
+alter table card
+    add dict_option longtext null comment '配置的参数';
+
+
+#创建config数据表
+
+create table if not exists config
 (
-    user_id int  null,
-    config  json null
-);
+    user_id int null
+) comment '用户配置数据表';
 
 create index config_user_id_index
     on config (user_id);
 
-create table history
+alter table config
+    add config longtext null;
+
+# 创建file数据表
+
+create table if not exists file
+(
+    id bigint auto_increment
+        primary key
+)
+    comment '文件';
+
+alter table file
+    add path varchar(255) null;
+
+alter table file
+    add user_id int null;
+
+alter table file
+    add create_time datetime null;
+
+alter table file
+    add size double default 0 null comment '尺寸';
+
+alter table file
+    add mime_type varchar(100) null comment '文件类型';
+
+
+#创建history数据表
+
+create table if not exists history
 (
-    id      bigint auto_increment
+    id bigint auto_increment
         primary key,
-    user_id int  null,
-    link    json null,
+
     constraint history_id_uindex
         unique (id)
 )
     comment 'link历史数据';
 
-create table link
+alter table history
+    add user_id int null;
+
+alter table history
+    add link longtext null;
+
+alter table history
+    add create_time datetime null comment '创建时间';
+
+
+#创建link数据表
+
+create table if not exists link
 (
-    user_id     int      null,
-    update_time datetime null comment '更新时间',
-    link        longtext null
+    user_id int null
 );
 
-create table link_folder
+create index link_user_id_index
+    on link (user_id);
+
+
+alter table link
+    add update_time datetime null comment '更新时间';
+
+alter table link
+    add link longtext null;
+
+
+#创建link_folder数据表
+
+create table if not exists link_folder
 (
-    id   int auto_increment comment 'id'
-        primary key,
-    name varchar(50)   null comment '分类名称',
-    sort int default 0 null
+    id int auto_increment comment 'id'
+        primary key
 )
     comment '标签链接分类';
 
-create table linkstore
+alter table link_folder
+    add name varchar(50) null comment '分类名称';
+
+alter table link_folder
+    add sort int default 0 null;
+
+
+#创建link_store数据表
+
+create table if not exists linkstore
 (
-    id          int auto_increment
+    id int auto_increment
         primary key,
-    name        varchar(255)               null,
-    src         varchar(255)               null,
-    url         varchar(255)               null,
-    type        varchar(20) default 'icon' null,
-    size        varchar(20) default '1x1'  null,
-    create_time datetime                   null,
-    hot         bigint      default 0      null,
-    area        varchar(20) default ''     null comment '专区',
-    tips        varchar(255)               null comment '介绍',
-    domain      varchar(255)               null,
-    app         int         default 0      null comment '是否app',
-    install_num int         default 0      null comment '安装量',
-    bgColor     varchar(30)                null comment '背景颜色',
-    vip         int         default 0      null comment '是否会员可见 0所有人 1=会员',
-    custom      text                       null comment '自定义配置',
     constraint linkStore_id_uindex
         unique (id)
 );
 
-create table note
+alter table linkstore
+    add name varchar(255) null;
+
+alter table linkstore
+    add src varchar(255) null;
+
+alter table linkstore
+    add url varchar(255) null;
+
+alter table linkstore
+    add type varchar(20) default 'icon' null;
+
+alter table linkstore
+    add size varchar(20) default '1x1' null;
+
+alter table linkstore
+    add create_time datetime null;
+
+alter table linkstore
+    add hot bigint default 0 null;
+
+alter table linkstore
+    add area varchar(20) default '' null comment '专区';
+
+alter table linkstore
+    add tips varchar(255) null comment '介绍';
+
+alter table linkstore
+    add domain varchar(255) null;
+
+alter table linkstore
+    add app int default 0 null comment '是否app';
+
+alter table linkstore
+    add install_num int default 0 null comment '安装量';
+
+alter table linkstore
+    add bgColor varchar(30) null comment '背景颜色';
+
+alter table linkstore
+    add vip int default 0 null comment '是否会员可见 0所有人 1=会员';
+
+alter table linkstore
+    add custom text null comment '自定义配置';
+
+alter table linkstore
+    add user_id int null comment '用户id';
+
+alter table linkstore
+    add status int default 1 null comment '状态 1=展示 0=待审核';
+
+
+#创建note数据表
+
+create table if not exists note
 (
-    id          bigint auto_increment
+    id bigint auto_increment
         primary key,
-    user_id     bigint        null,
-    title       varchar(50)   null,
-    text        text          null,
-    create_time datetime      null,
-    update_time datetime      null,
-    weight      int default 0 null,
     constraint note_id_uindex
         unique (id)
 );
 
+alter table note
+    add user_id bigint null;
+
+alter table note
+    add title varchar(50) null;
+
+alter table note
+    add text text null;
+
+alter table note
+    add create_time datetime null;
+
+alter table note
+    add update_time datetime null;
+
+alter table note
+    add weight int default 0 null;
+
 create index note_user_id_index
     on note (user_id);
 
-create table search_engine
+#创建search_engine数据表
+
+create table if not exists search_engine
 (
-    id          int auto_increment
-        primary key,
-    name        varchar(50)   null comment '名称',
-    icon        varchar(255)  null comment '图标 128x128',
-    url         varchar(255)  null comment '跳转url',
-    sort        int default 0 null comment '排序',
-    create_time datetime      null comment '添加时间',
-    status      int default 0 null comment '状态 0=关闭 1=启用',
-    tips        varchar(250)  null comment '搜索引擎介绍'
+    id int auto_increment
+        primary key
 )
     comment '搜索引擎';
 
-create table setting
+alter table search_engine
+    add name varchar(50) null comment '名称';
+
+alter table search_engine
+    add icon varchar(255) null comment '图标 128x128';
+
+alter table search_engine
+    add url varchar(255) null comment '跳转url';
+
+alter table search_engine
+    add sort int default 0 null comment '排序';
+
+alter table search_engine
+    add create_time datetime null comment '添加时间';
+
+alter table search_engine
+    add status int default 0 null comment '状态 0=关闭 1=启用';
+
+alter table search_engine
+    add tips varchar(250) null comment '搜索引擎介绍';
+
+
+#创建setting表
+
+create table if not exists setting
 (
     `keys` varchar(200) not null
-        primary key,
-    value  text         null
+        primary key
 );
 
-create table tabbar
+alter table setting
+    add value text null;
+
+#创建tabbar数据表
+
+create table if not exists tabbar
 (
-    user_id     int      null,
-    tabs        json     null,
-    update_time datetime null
+    user_id int null
 )
     comment '用户页脚信息';
 
-create table token
+alter table tabbar
+    add tabs longtext null;
+
+alter table tabbar
+    add update_time datetime null;
+
+#创建token表
+
+create table if not exists token
 (
-    id           bigint auto_increment
+    id bigint auto_increment
         primary key,
-    user_id      int          null,
-    token        tinytext     null,
-    create_time  int          null,
-    ip           tinytext     null,
-    user_agent   tinytext     null,
-    access_token varchar(200) null comment 'qq的令牌',
     constraint token_id_uindex
         unique (id)
 );
 
-create table user
+alter table token
+    add user_id int null;
+
+alter table token
+    add token tinytext null;
+
+alter table token
+    add create_time int null;
+
+alter table token
+    add ip tinytext null;
+
+alter table token
+    add user_agent tinytext null;
+
+alter table token
+    add access_token varchar(200) null comment 'qq的令牌';
+
+
+#创建user表
+
+create table if not exists user
 (
-    id               int auto_increment
+    id int auto_increment
         primary key,
-    avatar           varchar(255)  null comment '头像',
-    mail             varchar(50)   null,
-    password         tinytext      null,
-    create_time      datetime      null,
-    login_ip         varchar(100)  null comment '登录IP',
-    register_ip      varchar(100)  null comment '注册IP',
-    manager          int default 0 null,
-    login_fail_count int default 0 null,
-    login_time       datetime      null comment '登录时间',
-    qq_open_id       varchar(200)  null comment 'qq开放平台Id',
-    nickname         varchar(200)  null comment '昵称',
     constraint user_id_uindex
         unique (id)
 );
 
-create table user_search_engine
+alter table user
+    add avatar varchar(255) null comment '头像';
+
+alter table user
+    add mail varchar(50) null;
+
+alter table user
+    add password tinytext null;
+
+alter table user
+    add create_time datetime null;
+
+alter table user
+    add login_ip varchar(100) null comment '登录IP';
+
+alter table user
+    add register_ip varchar(100) null comment '注册IP';
+
+alter table user
+    add manager int default 0 null;
+
+alter table user
+    add login_fail_count int default 0 null;
+
+alter table user
+    add login_time datetime null comment '登录时间';
+
+alter table user
+    add qq_open_id varchar(200) null comment 'qq开放平台Id';
+
+alter table user
+    add nickname varchar(200) null comment '昵称';
+
+alter table user
+    add status int default 0 null comment '用户账号状态 0正常 1冻结';
+
+#创建user_search_engine表
+
+create table if not exists user_search_engine
 (
-    user_id int  not null
+    user_id int not null
         primary key,
-    list    json null,
     constraint user_search_engine_pk
         unique (user_id)
 )
     comment '用户搜索引擎同步表';
 
-create table wallpaper
+alter table user_search_engine
+    add list longtext null;
+
+
+#创建wallpaper表
+
+create table if not exists wallpaper
 (
-    id          int auto_increment
-        primary key,
-    type        int             null comment '1=folder;0=assets',
-    folder      int             null comment '0',
-    mime        int default 0   null comment '文件类型0=images,1=video',
-    url         text            null comment '图片地址',
-    cover       text            null comment '封面',
-    create_time datetime        null,
-    name        varchar(200)    null comment '标题',
-    sort        int default 999 null
+    id int auto_increment
+        primary key
 );
 
+alter table wallpaper
+    add type int null comment '1=folder;0=assets';
+
+alter table wallpaper
+    add folder int null comment '0';
+
+alter table wallpaper
+    add mime int default 0 null comment '文件类型0=images,1=video';
+
+alter table wallpaper
+    add url text null comment '图片地址';
+
+alter table wallpaper
+    add cover text null comment '封面';
+
+alter table wallpaper
+    add create_time datetime null;
+
+alter table wallpaper
+    add name varchar(200) null comment '标题';
+
+alter table wallpaper
+    add sort int default 999 null;
+
+##创建结束
+
+#补充内容 针对<5.7数据库使用longtext
 
+alter table history
+    modify link longtext null;
 
+alter table link
+    modify link longtext null;
 
-INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('Bilibili', '/static/bilibili.png', 'https://bilibili.com', 'icon', '1x1', '2022-11-07 21:51:42', 0, 'Bilibili弹幕视频网站Acg网站', 'bilibili.com,www.bilibili.com', 0, 0);
-INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('蓝易云', '/static/tsy.png', 'https://www.tsyvps.com/aff/IRYIGFMX', 'icon', '1x1', '2022-11-07 22:02:41', 0, '蓝易云-持证高性价比服务器', 'www.tsyvps.com,tsyvps.com', 0, 0);
-INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('ImgUrl', '/static/imgurl.png', 'https://imgurl.ink', 'icon', '1x1', '2022-11-07 22:05:46', 0, 'ImgUrl图床,图片外链', 'imgurl.ink,www.imgurl.ink', 0, 0);
-INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('微博', '/static/weibo.png', 'http://weibo.com/', 'icon', '1x1', '2022-11-07 23:37:22', 1, '微博-随时随地发现新鲜事', 'weibo.com,www.weibo.com', 0, 0);
-INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('火山翻译', '/static/huoshanfanyi.png', 'https://translate.volcengine.com/translate', 'icon', '1x1', '2022-11-07 23:42:49', 1, '火山翻译-字节跳动旗下机器翻译品牌', 'translate.volcengine.com', 1, 1);
-INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('腾讯云', '/static/tencentcloud.png', 'https://cloud.tencent.com/', 'icon', '1x1', '2022-11-10 16:25:51', 1, '腾讯云', 'cloud.tencent.com', 0, 0);
-INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('阿里云', '/static/aliyun.png', 'https://www.aliyun.com/', 'icon', '1x1', '2022-11-10 17:30:17', 1, '阿里云', 'www.aliyun.com,aliyun.com', 0, 0);
-INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('腾讯视频', '/static/txsp.png', 'https://v.qq.com/channel/choice?channel_2022=1', 'icon', '1x1', '2022-12-19 19:34:45', 0, '腾讯视频', 'v.qq.com', 0, 0);
-INSERT INTO linkstore (name, src, url, type, size, create_time, hot, tips, domain, app, install_num) VALUES ('记事本', '/static/note.png', '/noteApp', 'icon', '1x1', '2023-06-14 21:13:15', 1,'记事本App', '/noteApp', 1, 3);
+alter table config
+    modify config longtext null;
 
+alter table tabbar
+    modify tabs longtext null;
 
-INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (1, '百度', '/static/searchEngine/baidu.svg', 'https://www.baidu.com/s?wd={1}', 0, '2024-01-14 22:12:18', 1, '中国领先的搜索引擎和互联网公司,提供全球最大的中文搜索引擎服务,同时涵盖在线地图、贴吧、知道等多个互');
-INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (3, '必应', '/static/searchEngine/bing.svg', 'https://www.bing.com/search?q={1}', 99, '2024-01-14 23:20:03', 1, '微软推出的搜索引擎,以直观的界面和优质搜索结果而闻名,提供全球范围内的多语言搜索服务');
-INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (4, 'Google', '/static/searchEngine/google.svg', 'https://www.google.com/search?q={1}', 98, '2024-01-14 23:20:21', 1, 'Google:全球最大的搜索引擎,以卓越的搜索算法、广告服务和多样化的产品而著称,成为互联网信息检索');
-INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (5, '搜狗', '/static/searchEngine/sougou.svg', 'https://www.sogou.com/web?query={1}', 0, '2024-01-14 23:20:46', 1, '中国领先的搜索引擎,致力于提供智能搜索和语音输入技术,以及多元化的互联网服务,深受用户喜爱');
-INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (6, '360', '/static/searchEngine/360.svg', 'https://www.so.com/s?q={1}', 0, '2024-01-14 23:21:07', 1, '中国知名搜索引擎,注重用户隐私安全,提供全面的搜索服务,涵盖网页、图片、新闻等多个领域,致力于用户友');
-INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (7, '开发者搜索', '/static/searchEngine/baidudev.png', 'https://kaifa.baidu.com/searchPage?module=SEARCH&wd={1}', 0, '2024-01-14 23:21:45', 1, '专注于技术文档、API 和开发者资源的搜索引擎,为开发者提供快速准确的技术信息检索服务,支持多种编程');
-INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (8, 'B站', '/static/searchEngine/bilibiliico.png', 'https://search.bilibili.com/all?vt=21160573&keyword={1}', 0, '2024-01-14 23:21:57', 1, '中国弹幕视频平台,以二次元文化为特色,提供丰富的动画、游戏、音乐等内容,用户可通过弹幕互动分享观感。');
-INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (9, '微博', '/static/searchEngine/weiboico.png', 'https://s.weibo.com/weibo?q={1}', 0, '2024-01-14 23:22:12', 1, '中国社交媒体平台,用户可以发布短文、图片和视频,关注他人并互动评论,是实时新闻、话题讨论和社交分享的');
-INSERT INTO search_engine (id, name, icon, url, sort, create_time, status, tips) VALUES (10, 'DuckDuckGo', '/static/searchEngine/DuckDuckGo.svg', 'https://duckduckgo.com/?t=h_&q={1}&ia=web', 96, '2024-01-15 21:37:44', 1, '注重隐私保护的搜索引擎,致力于不追踪用户个人信息,提供匿名、安全的搜索服务,受到关注的隐私倡导者青睐');
+alter table user_search_engine
+    modify list longtext null;
 
-INSERT INTO wallpaper (id, type, folder, mime, url, cover, create_time, name, sort) VALUES (1, 1, null, 0, null, null, '2024-02-22 12:29:21', '默认壁纸', 999);
-INSERT INTO wallpaper (id, type, folder, mime, url, cover, create_time, name, sort) VALUES (2, 0, 1, 0, '/static/wallpaper/wallpaper-1.jpeg', '/static/wallpaper/m_wallpaper-1.jpeg', '2024-02-22 12:35:59', null, 999);
-INSERT INTO wallpaper (id, type, folder, mime, url, cover, create_time, name, sort) VALUES (3, 0, 1, 0, '/static/wallpaper/wallpaper-2.jpeg', '/static/wallpaper/m_wallpaper-2.jpeg', '2024-02-22 12:36:27', null, 999);
-INSERT INTO wallpaper (id, type, folder, mime, url, cover, create_time, name, sort) VALUES (4, 0, 1, 0, '/static/wallpaper/wallpaper-3.jpeg', '/static/wallpaper/m_wallpaper-3.jpeg', '2024-02-22 12:36:43', null, 999);
-INSERT INTO wallpaper (id, type, folder, mime, url, cover, create_time, name, sort) VALUES (5, 0, 1, 0, '/static/wallpaper/wallpaper-4.jpeg', '/static/wallpaper/m_wallpaper-4.jpeg', '2024-02-22 12:36:52', null, 999);
-INSERT INTO wallpaper (id, type, folder, mime, url, cover, create_time, name, sort) VALUES (6, 0, 1, 0, '/static/wallpaper/wallpaper-5.jpeg', '/static/wallpaper/m_wallpaper-5.jpeg', '2024-02-22 12:37:03', null, 999);
+#补充结束

+ 1 - 1
public/dist/index.html

@@ -1 +1 @@
-<!doctype html><html lang="zh"><head><meta charset="UTF-8"/><link href="{$favicon}" rel="icon"/><meta name="version" content="{$version}"><meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"><title>{$title}</title>{$customHead|raw}<meta content="{$keywords}" name="keywords"/><meta content="{$description}" name="description"/><script type="module" crossorigin src="/dist/assets/index.1713442796762.js"></script><link rel="stylesheet" href="/dist/assets/index.17134427967625.css"></head><body style="background-color:#fff"><div id="app"></div></body></html>
+<!doctype html><html lang="zh"><head><meta charset="UTF-8"/><link href="{$favicon}" rel="icon"/><meta name="version" content="{$version}"><meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"><title>{$title}</title>{$customHead|raw}<meta content="{$keywords}" name="keywords"/><meta content="{$description}" name="description"/><script type="module" crossorigin src="/dist/assets/index.1716208563220.js"></script><link rel="stylesheet" href="/dist/assets/index.17162085632204.css"></head><body style="background-color:#fff"><div id="app"></div></body></html>

+ 2 - 2
public/index.php

@@ -1,8 +1,8 @@
 <?php
 
 namespace think;
-define('app_version', '1.8.1');
-define('app_version_code', 82);
+define('app_version', '2.0.1');
+define('app_version_code', 201);
 require __DIR__ . '/../vendor/autoload.php';
 
 // 执行HTTP应用并响应

+ 11 - 1
public/install.php

@@ -88,6 +88,7 @@ if ($db_username && $php_version && $fileinfo_ext && $curl_ext && $zip_ext) {
                 $error = '数据表创建失败';
             }
             $conn = new mysqli($db_host, $db_username, $db_password, $table_name, $db_port);
+            //数据库的格式内容数据
             $sql_file_content = file_get_contents('../install.sql');
             // 解析SQL文件内容并执行
             $sql_statements = explode(';', trim($sql_file_content));
@@ -96,6 +97,15 @@ if ($db_username && $php_version && $fileinfo_ext && $curl_ext && $zip_ext) {
                     $conn->query($sql_statement);
                 }
             }
+            //默认的一些基础数据
+            $sql_file_content = file_get_contents('../defaultData.sql');
+            // 解析SQL文件内容并执行
+            $sql_statements = explode(';', trim($sql_file_content));
+            foreach ($sql_statements as $sql_statement) {
+                if (!empty($sql_statement)) {
+                    $conn->query($sql_statement);
+                }
+            }
             $admin_password = md5($admin_password);
             //添加默认管理员
             $AdminSql = ("
@@ -407,7 +417,7 @@ EOF;
             <a class='btn' href='/'>进入首页</a>
         </div>
         <p>后台进入方式,需要用管理员账户登录客户端<br/></p>
-        <p> <b>鼠标在桌面右击打开菜单->点击设置->个人中心->登录管理员的账号</b><br/>
+        <p><b>鼠标在桌面右击打开菜单->点击设置->个人中心->登录管理员的账号</b><br/>
             <b>
                 ->再次进入个人中心即可看到->管理后台->进入即可</b></p>
         <p>这是一个多用户的书签导航程序,用户之间数据是隔离的不受干扰</p>

File diff suppressed because it is too large
+ 0 - 0
public/static/aliyun.svg


+ 17 - 0
public/static/bookmark.svg

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="50px" height="50px" viewBox="0 0 50 50" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>书签</title>
+    <g id="书签" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <rect fill="#FA636E" x="0" y="0" width="50" height="50"></rect>
+        <g id="MBE风格多色图标-书签" transform="translate(7.000000, 9.000000)" fill-rule="nonzero">
+            <path d="M11.263164,12.074106 C11.147004,11.957946 11.2167,11.748858 11.379324,11.702394 L12.889404,11.493306 L12.889404,10.122618 C12.889404,8.961018 13.818684,8.008506 14.980284,8.008506 L23.4135,8.008506 L23.4135,7.47417 C23.4135,6.31257 22.460988,5.360058 21.299388,5.360058 L10.75206,5.360058 C9.59046,5.360058 8.66118,6.31257 8.66118,7.47417 L8.66118,24.31737 L12.866172,22.505274 L12.866172,13.607418 L11.263164,12.074106 Z" id="路径" fill-opacity="0.477136145" fill="#FFFFFF"></path>
+            <path d="M20.74182,11.748858 L20.416572,11.098362 C20.346876,10.935738 20.114556,10.935738 20.04486,11.098362 L19.81254,11.586234 L20.695356,11.702394 L20.74182,11.748858 Z M20.85798,11.981178 C20.85798,12.027642 20.834748,12.050874 20.788284,12.074106 L18.558012,14.257914 L19.092348,17.324538 C19.11558,17.487162 18.929724,17.626554 18.790332,17.556858 L17.698428,16.976058 L17.187324,19.972986 C17.164092,20.13561 17.349948,20.275002 17.48934,20.205306 L20.253948,18.764922 L23.018556,20.205306 C23.18118,20.298234 23.367036,20.158842 23.320572,19.972986 L22.786236,16.906362 L23.4135,16.30233 L23.4135,14.141754 L21.833724,13.909434 L20.85798,11.981178 L20.85798,11.981178 Z" id="形状" fill-opacity="0.477136145" fill="#FFFFFF"></path>
+            <path d="M20.74182,11.748858 L20.8799785,11.981178 C20.9076102,11.88825 20.8523468,11.795322 20.74182,11.748858 Z" id="路径" fill="#FFBA00"></path>
+            <path d="M25.50438,8.031738 L14.980284,8.031738 C13.818684,8.031738 12.889404,8.98425 12.889404,10.14585 L12.889404,27.012282 L20.253948,23.85273 L27.618492,27.012282 L27.618492,10.122618 C27.618492,8.961018 26.66598,8.031738 25.50438,8.031738 Z M25.016508,14.699322 L23.390268,16.279098 L22.763004,16.88313 L23.29734,19.949754 C23.320572,20.112378 23.134716,20.25177 22.995324,20.182074 L20.230716,18.74169 L17.466108,20.182074 C17.303484,20.275002 17.117628,20.13561 17.164092,19.949754 L17.675196,16.952826 L17.698428,16.859898 L15.468156,14.67609 C15.351996,14.55993 15.421692,14.350842 15.584316,14.304378 L18.674172,13.86297 L19.81254,11.563002 L20.04486,11.07513 C20.114556,10.912506 20.346876,10.912506 20.416572,11.07513 L20.74182,11.725626 C20.834748,11.77209 20.881212,11.865018 20.85798,11.957946 L21.810492,13.886202 L23.390268,14.118522 L24.877116,14.32761 C25.062972,14.374074 25.132668,14.583162 25.016508,14.699322 L25.016508,14.699322 Z" id="形状" fill="#FFFFFF"></path>
+            <path d="M5.780412,24.340602 L4.432956,24.340602 L4.432956,22.993146 C4.432956,22.69113 4.200636,22.45881 3.89862,22.45881 C3.596604,22.45881 3.364284,22.69113 3.364284,22.993146 L3.364284,24.340602 L2.04006,24.340602 C1.738044,24.340602 1.505724,24.572922 1.505724,24.874938 C1.505724,25.176954 1.738044,25.409274 2.04006,25.409274 L3.387516,25.409274 L3.387516,26.75673 C3.387516,27.058746 3.619836,27.291066 3.921852,27.291066 C4.223868,27.291066 4.456188,27.058746 4.456188,26.75673 L4.456188,25.409274 L5.803644,25.409274 C6.10566,25.409274 6.33798,25.176954 6.33798,24.874938 C6.314748,24.572922 6.082428,24.340602 5.780412,24.340602 Z" id="路径" fill="#FFFFFF"></path>
+            <path d="M10.17126,3.17625 C9.24198,3.17625 8.77734,2.432826 8.42886,1.875258 C8.08038,1.31769 7.917756,1.08537 7.592508,1.08537 C7.290492,1.08537 7.104636,1.31769 6.756156,1.875258 C6.430908,2.432826 5.966268,3.17625 5.013756,3.17625 C4.084476,3.17625 3.619836,2.432826 3.271356,1.875258 C2.922876,1.31769 2.760252,1.08537 2.435004,1.08537 C2.132988,1.08537 1.900668,0.85305 1.900668,0.551034 C1.900668,0.249018 2.132988,0.016698 2.435004,0.016698 C3.364284,0.016698 3.828924,0.760122 4.177404,1.31769 C4.525884,1.875258 4.688508,2.107578 5.013756,2.107578 C5.315772,2.107578 5.501628,1.875258 5.850108,1.31769 C6.175356,0.760122 6.639996,0.016698 7.592508,0.016698 C8.521788,0.016698 8.986428,0.760122 9.334908,1.31769 C9.683388,1.875258 9.846012,2.107578 10.17126,2.107578 C10.496508,2.107578 10.659132,1.852026 11.007612,1.31769 C11.33286,0.760122 11.7975,0.016698 12.750012,0.016698 C13.052028,0.016698 13.284348,0.249018 13.284348,0.551034 C13.284348,0.85305 13.052028,1.08537 12.750012,1.08537 C12.424764,1.08537 12.26214,1.31769 11.91366,1.875258 C11.56518,2.432826 11.10054,3.17625 10.17126,3.17625 Z M7.60342704,30.0582295 L9.70615536,27.9557335 L11.8088837,30.0582295 L9.70638768,32.1607255 L7.60342704,30.0582295 Z M33.589116,19.345722 L35.168892,17.765946 L32.00934,17.765946 L33.589116,19.345722 Z" id="形状" fill="#FFFFFF"></path>
+            <path d="M0.042108,17.58009 C0.042108,18.4012535 0.707792524,19.066938 1.528956,19.066938 C2.35011948,19.066938 3.015804,18.4012535 3.015804,17.58009 C3.015804,16.7589265 2.35011948,16.093242 1.528956,16.093242 C0.707792524,16.093242 0.042108,16.7589265 0.042108,17.58009 Z" id="路径" fill="#FFFFFF"></path>
+            <path d="M33.333564,6.149946 L31.08006,3.896442 C30.917436,3.733818 30.661884,3.733818 30.49926,3.896442 L28.245756,6.149946 C28.083132,6.31257 28.083132,6.568122 28.245756,6.730746 L30.49926,8.98425 C30.661884,9.146874 30.917436,9.146874 31.08006,8.98425 L33.333564,6.730746 C33.496188,6.568122 33.496188,6.31257 33.333564,6.149946 Z M30.778044,8.124666 L29.10534,6.451962 L30.778044,4.779258 L32.450748,6.451962 L30.778044,8.124666 Z" id="形状" fill="#FFFFFF"></path>
+        </g>
+    </g>
+</svg>

File diff suppressed because it is too large
+ 0 - 0
public/static/defLinkLogo/acfun.svg


+ 1 - 0
public/static/defLinkLogo/baiduyun.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="120" height="120" viewBox="0 0 120 120"><g><g><rect x="0" y="0" width="120" height="120" rx="0" fill="#FFFFFF" fill-opacity="1"/></g><g><path d="M34.8639,74.15639999999999L34.8639,55.4413C34.8639,51.787,33.0372,48.3638,29.8247,46.53352L17,39L17,84.4323C17,85.5754,17.686588,86.7123,18.59994,87.1746L58,110L58,95.16409999999999C58,91.5098,56.167,88.0866,52.9608,86.25630000000001L36.4701,76.905C35.5505,76.2178,34.8639,75.3058,34.8639,74.15639999999999Z" fill="#008DD5" fill-opacity="1"/></g><g><path d="M84.53620000000001,76.7758L68.03918,86.33330000000001C64.833,88.1515,63,91.5635,63,95.206L63,110L102.40010000000001,87.2424C103.38730000000001,86.6805,103.9969,85.6413,104,84.5152L104,39L91.1753,46.28493C87.9691,48.10304,86.1361,51.515100000000004,86.1361,55.1576L86.1361,73.81819999999999C86.1361,75.188,85.4495,76.0909,84.53620000000001,76.7758Z" fill="#EE3306" fill-opacity="1"/></g><g><path d="M79.37,20.977719999999998L63.0804,11.344147C62.0737,10.885284,60.92,10.885284,59.9134,11.344147L21,34.2827L33.6683,41.6256C36.8416,43.4581,40.6807,43.4581,43.6238,41.6256L59.9133,31.9857C60.1436,31.7598,60.3676,31.7598,60.5978,31.7598C61.4234,31.4908,62.3219,31.5724,63.0866,31.9857L79.37,41.619299999999996C82.5433,43.4581,86.3886,43.4581,89.3255,41.619299999999996L102,34.276399999999995L79.37,20.977719999999998Z" fill="#5AB200" fill-opacity="1"/></g></g></svg>

File diff suppressed because it is too large
+ 0 - 0
public/static/defLinkLogo/douyin.svg


+ 1 - 0
public/static/defLinkLogo/gitee.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="128" height="128" viewBox="0 0 128 128"><defs><clipPath id="master_svg0_52_161"><rect x="0" y="0" width="128" height="128" rx="0"/></clipPath></defs><g><g clip-path="url(#master_svg0_52_161)"><rect x="0" y="0" width="128" height="128" rx="0" fill="#C71D23" fill-opacity="1"/><g><rect x="29" y="29" width="72" height="69" rx="0" fill="#FFFFFF" fill-opacity="1"/></g><g><path d="M64,120C33.0721,120,8,94.9279,8,64C8,33.0721,33.0721,8,64,8C94.9279,8,120,33.0721,120,64C120,94.9279,94.9279,120,64,120ZM92.344,57.776L60.544,57.776C59.0153,57.776,57.776,59.0153,57.776,60.544L57.776,67.456C57.776,68.98400000000001,59.016,70.22399999999999,60.536,70.22399999999999L79.896,70.22399999999999C81.432,70.22399999999999,82.664,71.464,82.664,72.984L82.664,74.368C82.664,78.952,78.952,82.664,74.368,82.664L48.096,82.664C46.5735,82.6596,45.3404,81.4265,45.336,79.904L45.336,53.632C45.336,49.048,49.048,45.336,53.624,45.336L92.344,45.336C93.864,45.336,95.104,44.096,95.104,42.568L95.104,35.656C95.104,34.1304,93.8696,32.892399999999995,92.344,32.888000000000005L53.624,32.888000000000005C42.1687,32.888000000000005,32.8836,42.1767,32.888000000000005,53.632L32.888000000000005,92.344C32.888000000000005,93.872,34.128,95.112,35.656,95.112L76.44,95.112C86.751,95.1164,95.112,86.759,95.112,76.448L95.112,60.544C95.112,59.0153,93.8727,57.776,92.344,57.776Z" fill="#C71D23" fill-opacity="1"/></g></g></g></svg>

File diff suppressed because it is too large
+ 0 - 0
public/static/defLinkLogo/iqy.svg


File diff suppressed because it is too large
+ 0 - 0
public/static/defLinkLogo/jingdongyun.svg


File diff suppressed because it is too large
+ 0 - 0
public/static/defLinkLogo/kuaishou.svg


File diff suppressed because it is too large
+ 0 - 0
public/static/defLinkLogo/leshi.svg


File diff suppressed because it is too large
+ 0 - 0
public/static/defLinkLogo/mangguo.svg


File diff suppressed because it is too large
+ 0 - 0
public/static/defLinkLogo/migu.svg


File diff suppressed because it is too large
+ 0 - 0
public/static/defLinkLogo/qqmusic.svg


File diff suppressed because it is too large
+ 0 - 0
public/static/defLinkLogo/wangyiyun.svg


BIN
public/static/defLinkLogo/webos.png


BIN
public/static/defLinkLogo/yisuyun.png


File diff suppressed because it is too large
+ 0 - 0
public/static/defLinkLogo/youku.svg


+ 1 - 0
public/static/defLinkLogo/youtube.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="128" height="128" viewBox="0 0 128 128"><defs><clipPath id="master_svg0_43_629"><rect x="0" y="0" width="128" height="128" rx="0"/></clipPath></defs><g><g clip-path="url(#master_svg0_43_629)"><rect x="0" y="0" width="128" height="128" rx="0" fill="#FFFFFF" fill-opacity="1"/><g><path d="M55,78.6471L55,47.352900000000005L82,63.0536L55,78.6471ZM116.92,41.393699999999995Q115.863,33.95012,112.627,30.66871C108.5185,26.36353,103.915,26.34565,101.8045,26.0953Q86.6935,25,64.02250000000001,25L63.9775,25Q41.3065,25,26.1955,26.09529C24.0805,26.34565,19.4815,26.36353,15.368500000000001,30.66871Q12.133,33.95012,11.08,41.3981Q10,50.1336,10,58.8736L10,67.0772Q10,75.82169999999999,11.08,84.5661Q12.133,92.0097,15.368500000000001,95.2911C19.4815,99.5962,24.877000000000002,99.4576,27.28,99.9092Q35.92,100.7452,64,101Q86.6935,100.9642,101.8045,99.8734C103.9195,99.6186,108.5185,99.6007,112.627,95.2955Q115.867,92.0141,116.92,84.5661Q118,75.8261,118,67.08160000000001L118,58.8826Q118,50.1381,116.92,41.393699999999995Z" fill="#FF0000" fill-opacity="1"/></g></g></g></svg>

+ 574 - 138
public/static/defaultTab.json

@@ -1,180 +1,197 @@
 {
   "link": [
     {
-      "sort": 0,
       "id": "EA3D2091-3C2E-4F6B-83BE-0609B5F16024",
+      "app": 0,
+      "pid": null,
+      "src": "/static/aliyun.svg",
+      "url": "https://www.aliyun.com/",
       "name": "阿里云",
       "size": "1x1",
-      "src": "/static/aliyun.png",
-      "url": "https://www.aliyun.com/",
+      "sort": 26,
       "type": "icon",
-      "app": 0,
-      "pid": "72246EC7-57BD-49FA-8E2B-AD6C3981A297"
+      "bgColor": "rgba(255, 106, 0, 1)",
+      "pageGroup": "",
+      "form": "link"
     },
     {
       "id": "45154338-89c4-41b1-ae9f-4508078f4c7b",
-      "name": "Mtab书签",
+      "app": 0,
+      "pid": null,
       "src": "/static/mtab.png",
       "url": "https://mtab.cc",
+      "form": "link",
+      "name": "Mtab书签",
       "size": "1x1",
+      "sort": 1,
       "type": "icon",
-      "sort": 0,
-      "app": 0,
-      "pid": null
+      "bgColor": "#fff",
+      "pageGroup": ""
     },
     {
       "id": "f730b603-6514-414a-8165-7d5a679e12db",
+      "app": 0,
       "pid": null,
       "src": "/static/mcecy.png",
       "url": "https://blog.mcecy.com/",
-      "name": "IT博客",
+      "form": "link",
+      "name": "小涂博客",
       "size": "1x1",
-      "sort": 1,
-      "type": "icon"
+      "sort": 0,
+      "type": "icon",
+      "bgColor": "#fff",
+      "pageGroup": ""
     },
     {
-      "sort": 1,
       "id": "D3AB9DDF-EB1A-47AD-B9B5-824A367C7A61",
-      "name": "华为云",
-      "size": "1x1",
+      "app": 0,
+      "pid": null,
       "src": "/static/huawei.png",
       "url": "https://www.huaweicloud.com/",
+      "name": "华为云",
+      "size": "1x1",
+      "sort": 22,
       "type": "icon",
-      "app": 0,
-      "pid": "72246EC7-57BD-49FA-8E2B-AD6C3981A297"
+      "bgColor": "#fff",
+      "pageGroup": "",
+      "form": "link"
     },
     {
-      "sort": 2,
       "id": "5C3099FE-4A6E-4DA9-85B2-F20E1205347C",
-      "name": "GitHub",
-      "size": "1x1",
+      "app": 0,
+      "pid": null,
       "src": "/static/github.png",
       "url": "https://github.com/",
+      "name": "GitHub",
+      "size": "1x1",
+      "sort": 11,
       "type": "icon",
-      "app": 0,
-      "pid": null
+      "bgColor": "rgba(0, 0, 0, 1)",
+      "pageGroup": ""
     },
     {
-      "sort": 3,
       "id": "C4E35210-C3CB-44DB-9D32-96FDA9116EB1",
-      "name": "微博",
-      "size": "1x1",
+      "app": 0,
+      "pid": null,
       "src": "/static/weibo.png",
       "url": "http://weibo.com/",
+      "form": "link",
+      "name": "微博",
+      "size": "1x1",
+      "sort": 6,
       "type": "icon",
-      "app": 0,
-      "pid": null
+      "bgColor": "#fff",
+      "pageGroup": ""
     },
     {
-      "sort": 3,
       "id": "E97A6A65-6744-40F5-B097-44BBCB68FA86",
-      "name": "腾讯云",
-      "size": "1x1",
+      "app": 0,
+      "pid": null,
       "src": "/static/tencentcloud.png",
       "url": "https://cloud.tencent.com/",
+      "name": "腾讯云",
+      "size": "1x1",
+      "sort": 27,
       "type": "icon",
-      "app": 0,
-      "pid": "72246EC7-57BD-49FA-8E2B-AD6C3981A297"
+      "bgColor": "rgba(43, 48, 59, 1)",
+      "pageGroup": "",
+      "form": "link"
     },
     {
-      "sort": 4,
       "id": "679EFDC3-1A8F-473C-94B1-DE94C3C4C561",
-      "name": "腾讯视频",
-      "size": "1x1",
+      "app": 0,
+      "pid": null,
       "src": "/static/txsp.png",
       "url": "https://v.qq.com/channel/choice?channel_2022=1",
+      "form": "link",
+      "name": "腾讯视频",
+      "size": "1x2",
+      "sort": 14,
       "type": "icon",
-      "app": 0,
-      "pid": null
+      "bgColor": "#fff",
+      "pageGroup": ""
     },
     {
-      "sort": 5,
       "id": "E0F115F4-B6E4-46A2-92CE-FF49329EF0E1",
-      "name": "蓝易云",
-      "size": "1x1",
+      "app": 0,
+      "pid": null,
       "src": "/static/tsy.png",
       "url": "https://www.tsyvps.com/aff/IRYIGFMX",
-      "type": "icon",
-      "app": 0,
-      "pid": null
-    },
-    {
-      "id": "72246EC7-57BD-49FA-8E2B-AD6C3981A297",
+      "form": "link",
+      "name": "蓝易云",
       "size": "1x1",
-      "component": "iconGroup",
-      "name": "云服务器",
-      "type": "component",
-      "url": "iconGroup",
-      "children": [],
-      "sort": 6,
-      "pid": null
+      "sort": 21,
+      "type": "icon",
+      "bgColor": "#fff",
+      "pageGroup": ""
     },
     {
-      "sort": 7,
       "id": "983BA64F-D710-46B5-B3B9-8AC1C37C3A5E",
-      "name": "Bilibili",
-      "size": "1x1",
+      "app": 0,
+      "pid": null,
       "src": "/static/bilibili.png",
       "url": "https://bilibili.com",
+      "form": "link",
+      "name": "Bilibili",
+      "size": "1x2",
+      "sort": 16,
       "type": "icon",
-      "app": 0,
-      "pid": null
+      "bgColor": "#fff",
+      "pageGroup": ""
     },
     {
-      "sort": 9,
       "id": "F743D0A2-49BE-42BF-8CC1-EE98FFD20B48",
-      "name": "ImgUrl图床",
-      "size": "1x1",
+      "app": 0,
+      "pid": null,
       "src": "/static/imgurl.png",
       "url": "https://imgurl.ink",
+      "form": "link",
+      "name": "ImgUrl图床",
+      "size": "1x1",
+      "sort": 4,
       "type": "icon",
-      "app": 0,
-      "pid": null
+      "pageGroup": ""
     },
     {
-      "sort": 10,
       "id": "4F9137E3-5701-4F6F-A8F4-C3F131FD9429",
-      "name": "火山翻译",
-      "size": "1x1",
+      "app": 1,
+      "pid": null,
       "src": "/static/huoshanfanyi.png",
       "url": "https://translate.volcengine.com/translate",
+      "form": "link",
+      "name": "火山翻译",
+      "size": "1x1",
+      "sort": 31,
       "type": "icon",
-      "app": 1,
-      "pid": null
+      "bgColor": "#fff",
+      "pageGroup": ""
     },
     {
-      "sort": 11,
       "id": "9589E037-8EE3-4B1C-95E8-F419E9187357",
-      "name": "记事本",
-      "size": "1x1",
+      "app": 1,
+      "pid": null,
       "src": "/static/note.png",
       "url": "/noteApp",
+      "name": "记事本",
+      "size": "1x1",
+      "sort": 33,
       "type": "icon",
-      "app": 1,
-      "bgColor":"rgba(0,0,0,0)",
-      "pid": null
+      "bgColor": "rgba(252, 141, 0, 1)",
+      "pageGroup": "",
+      "form": "link"
     },
     {
-      "id": "C6057D42-2BAA-402D-8508-C8E2B9454DB0",
+      "id": "9F256401-0FF9-4DCE-980E-082F1C4DA118",
       "app": 0,
       "pid": null,
-      "src": "/static/editAll.png",
-      "url": "tab://editAll",
-      "name": "批量编辑",
-      "size": "1x1",
-      "sort": 12,
-      "type": "icon"
-    },
-    {
-      "sort": 13,
-      "id": "9F256401-0FF9-4DCE-980E-082F1C4DA118",
-      "name": "添加标签",
-      "size": "1x1",
       "src": "/static/addIco.png",
       "url": "tab://addicon",
+      "name": "添加标签",
+      "size": "1x1",
+      "sort": 29,
       "type": "icon",
-      "app": 0,
-      "pid": null
+      "bgColor": "rgba(255, 255, 255, 1)",
+      "pageGroup": ""
     },
     {
       "id": "033E9038-B97C-4894-83D2-6E030FAB83C6",
@@ -182,90 +199,494 @@
       "pid": null,
       "src": "/static/setting.png",
       "url": "tab://setting",
+      "form": "link",
       "name": "设置",
       "size": "1x1",
-      "sort": 14,
+      "sort": 34,
       "type": "icon",
-      "bgColor":"rgba(0,0,0,0)"
-    }
-  ],
-  "tabbar": [
+      "bgColor": "rgba(149, 168, 184, 1)",
+      "pageGroup": ""
+    },
     {
-      "id": "45154338-89c4-41b1-ae9f-4508078f4c7b",
-      "name": "Mtab书签",
-      "src": "/static/mtab.png",
-      "url": "https://mtab.cc",
+      "id": "4A7E7020-690E-4955-86F4-2D9B35CFAF8B",
+      "app": 1,
+      "pid": null,
+      "src": "/static/webTerm.svg",
+      "url": "https://ssh.mtab.cc",
+      "form": "link",
+      "name": "WebTerm",
       "size": "1x1",
+      "sort": 32,
+      "tips": "WebTerm",
       "type": "icon",
-      "sort": 0,
+      "custom": {
+        "immersion": 0,
+        "width": 1200,
+        "height": 700,
+        "controllerColor": "#FFFFFF",
+        "maximize": 1,
+        "minimization": 1
+      },
+      "bgColor": "rgba(0, 0, 0, 0.79)",
+      "origin_id": 114,
+      "pageGroup": ""
+    },
+    {
+      "id": "5D022341-A5B4-43F5-BF1E-0783F4778676",
       "app": 0,
-      "pid": null
+      "pid": null,
+      "src": "/static/jsdesign.svg",
+      "url": "https://js.design/",
+      "form": "link",
+      "name": "即时设计",
+      "size": "1x1",
+      "sort": 8,
+      "tips": "即时设计 - 可实时协作的专业 UI 设计工具",
+      "type": "icon",
+      "custom": null,
+      "bgColor": "rgba(244, 71, 71, 1)",
+      "origin_id": 93,
+      "pageGroup": ""
+    },
+    {
+      "id": "835c280d-be17-460d-b45d-b8d0a4d832db",
+      "app": 0,
+      "src": "/static/defLinkLogo/yisuyun.png",
+      "url": "https://www.yisu.com/",
+      "name": "亿速云",
+      "size": "1x1",
+      "sort": 25,
+      "type": "icon",
+      "bgColor": "#fff",
+      "pageGroup": "",
+      "pid": null,
+      "form": "link"
     },
     {
+      "id": "5d179bcc-55cb-4e39-9d14-ae9ee5758370",
+      "app": 0,
+      "pid": "AD879898-8CEA-4980-9798-F799A9A4AF7F",
+      "src": "https://download.mtab.cc/friendLinkLogo/sayai-logo.png",
+      "url": "https://sayai.cc",
+      "form": "link",
+      "name": "SayAi",
+      "size": "1x1",
       "sort": 4,
-      "id": "4F9137E3-5701-4F6F-A8F4-C3F131FD9429",
-      "name": "火山翻译",
+      "type": "icon",
+      "bgColor": "#fff",
+      "pageGroup": ""
+    },
+    {
+      "id": "666f1878-e285-41f6-9bf1-d0893a1b0cba",
+      "app": 0,
+      "src": "/static/defLinkLogo/baiduyun.svg",
+      "url": "https://cloud.baidu.com/",
+      "name": "百度智能云",
       "size": "1x1",
-      "src": "/static/huoshanfanyi.png",
-      "url": "https://translate.volcengine.com/translate",
+      "sort": 24,
       "type": "icon",
-      "app": 1,
-      "pid": null
+      "bgColor": "#fff",
+      "pageGroup": "",
+      "pid": null,
+      "form": "link"
+    },
+    {
+      "id": "3768e010-c2eb-4bf6-9fd6-2e221b0dd1e3",
+      "app": 0,
+      "src": "/static/defLinkLogo/jingdongyun.svg",
+      "url": "https://www.jdcloud.com/",
+      "name": "京东云",
+      "size": "1x1",
+      "sort": 23,
+      "type": "icon",
+      "bgColor": "#fff",
+      "pageGroup": "",
+      "pid": null,
+      "form": "link"
     },
     {
+      "id": "51a6914b-d310-4b35-b911-5d2bc203a714",
+      "app": 0,
+      "pid": "AD879898-8CEA-4980-9798-F799A9A4AF7F",
+      "src": "https://download.mtab.cc/friendLinkLogo/el9.png",
+      "url": "https://blog.el9.cn",
+      "form": "link",
+      "name": "布兰德",
+      "size": "1x1",
       "sort": 5,
-      "id": "9589E037-8EE3-4B1C-95E8-F419E9187357",
-      "name": "记事本",
+      "type": "icon",
+      "bgColor": "#fff",
+      "pageGroup": ""
+    },
+    {
+      "id": "6ee9674c-4a8b-4d23-bb4d-d7eefec2c792",
+      "app": 0,
+      "pid": null,
+      "src": "/static/defLinkLogo/iqy.svg",
+      "url": "https://www.iqiyi.com/",
+      "form": "link",
+      "name": "爱奇艺",
+      "size": "1x2",
+      "sort": 17,
+      "type": "icon",
+      "bgColor": "rgba(66, 189, 86, 1)",
+      "pageGroup": ""
+    },
+    {
+      "id": "caeec76a-250e-4ce1-b69f-51a843c79c58",
+      "app": 0,
+      "pid": null,
+      "src": "/static/defLinkLogo/youku.svg",
+      "url": "https://www.youku.com/",
+      "form": "link",
+      "name": "优酷视频",
+      "size": "1x2",
+      "sort": 19,
+      "type": "icon",
+      "bgColor": "#fff",
+      "pageGroup": ""
+    },
+    {
+      "id": "de5c2249-1413-4abb-802a-c3f680698979",
+      "app": 0,
+      "pid": null,
+      "src": "/static/defLinkLogo/mangguo.svg",
+      "url": "https://www.mgtv.com/",
+      "name": "芒果TV",
       "size": "1x1",
-      "src": "/static/note.png",
-      "url": "/noteApp",
+      "sort": 5,
       "type": "icon",
-      "app": 1,
+      "bgColor": "#fff",
+      "pageGroup": "",
+      "form": "link"
+    },
+    {
+      "id": "f9b77d71-2db2-4d38-b72f-84c7b08b1afa",
+      "app": 0,
+      "pid": null,
+      "src": "/static/defLinkLogo/migu.svg",
+      "url": "https://www.miguvideo.com/",
+      "name": "咪咕视频",
+      "size": "1x1",
+      "sort": 2,
+      "type": "icon",
+      "bgColor": "#fff",
+      "pageGroup": "",
+      "form": "link"
+    },
+    {
+      "id": "d7207735-83c9-4060-8ae5-539d52c810e9",
+      "app": 0,
+      "pid": null,
+      "src": "/static/defLinkLogo/leshi.svg",
+      "url": "https://www.le.com/",
+      "name": "乐视视频",
+      "size": "1x1",
+      "sort": 12,
+      "type": "icon",
+      "bgColor": "#fff",
+      "pageGroup": "",
+      "form": "link"
+    },
+    {
+      "id": "86ae5293-32d7-40de-98a2-9e195f15ca2b",
+      "app": 0,
+      "pid": null,
+      "src": "/static/defLinkLogo/webos.png",
+      "url": "https://os.tenfell.cn/",
+      "name": "Web os",
+      "size": "1x1",
+      "sort": 9,
+      "type": "icon",
+      "bgColor": null,
+      "pageGroup": "",
+      "form": "link"
+    },
+    {
+      "id": "3e6d48dd-8b31-41d9-8487-a123407c5aae",
+      "app": 0,
+      "pid": null,
+      "src": "/static/defLinkLogo/acfun.svg",
+      "url": "https://www.acfun.cn/",
+      "form": "link",
+      "name": "AcFun",
+      "size": "1x2",
+      "sort": 15,
+      "type": "icon",
+      "bgColor": "rgba(250, 99, 110, 1)",
+      "pageGroup": ""
+    },
+    {
+      "id": "007d6c7d-06e3-46ad-8257-48ae63b830f8",
+      "name": "抖音",
+      "src": "/static/defLinkLogo/douyin.svg",
+      "url": "https://www.douyin.com/",
+      "size": "1x2",
+      "type": "icon",
+      "sort": 18,
+      "app": 0,
+      "bgColor": "rgba(17, 17, 17, 1)",
+      "pageGroup": "",
+      "form": "link",
       "pid": null
     },
     {
+      "id": "994e5a5f-5ea2-4af6-8e63-86867a1422ad",
+      "name": "快手",
+      "src": "/static/defLinkLogo/kuaishou.svg",
+      "url": "https://www.kuaishou.com/new-reco",
+      "size": "1x2",
+      "type": "icon",
+      "sort": 20,
+      "app": 0,
+      "bgColor": "rgba(255, 74, 8, 1)",
+      "pageGroup": "",
+      "pid": null,
+      "form": "link"
+    },
+    {
+      "id": "fd9c04a9-e499-44af-add3-a7b63356cd81",
+      "name": "QQ音乐",
+      "src": "/static/defLinkLogo/qqmusic.svg",
+      "url": "https://y.qq.com/",
+      "size": "1x1",
+      "type": "icon",
+      "sort": 3,
+      "app": 0,
+      "bgColor": "#fff",
+      "pageGroup": "",
+      "pid": null,
+      "form": "link"
+    },
+    {
+      "id": "431fb677-da74-442a-8fa3-98738402b604",
+      "name": "网易云音乐",
+      "src": "/static/defLinkLogo/wangyiyun.svg",
+      "url": "https://music.163.com/",
+      "size": "1x1",
+      "type": "icon",
+      "sort": 13,
+      "app": 0,
+      "bgColor": "rgba(234, 62, 60, 1)",
+      "pageGroup": "",
+      "pid": null,
+      "form": "link"
+    },
+    {
+      "id": "73866702-487c-475b-b56b-8da63f067c56",
+      "name": "Youtube",
+      "src": "/static/defLinkLogo/youtube.svg",
+      "url": "https://www.youtube.com/",
+      "size": "1x1",
+      "type": "icon",
+      "sort": 7,
+      "app": 0,
+      "bgColor": "#fff",
+      "pageGroup": "",
+      "pid": null,
+      "form": "link"
+    },
+    {
+      "sort": 30,
+      "id": "3C7C4FB1-5D91-4B44-93A2-3FC06A27DAEE",
+      "name": "壁纸",
+      "size": "1x1",
+      "src": "/static/backgroundIco.png",
+      "url": "tab://background",
+      "type": "icon",
+      "app": 0,
+      "tips": "设置自己的个性首页背景",
+      "bgColor": "rgba(255,255,255,1)",
+      "pageGroup": "",
+      "pid": null,
+      "form": "link"
+    },
+    {
+      "id": "08798f97-0e68-40fb-8440-83540efacfc9",
+      "name": "子幽博客",
+      "src": "https://download.mtab.cc/friendLinkLogo/liukuai.png",
+      "url": "https://blog.liukuan.cc/",
+      "size": "1x1",
+      "type": "icon",
+      "sort": 3,
+      "app": 0,
+      "bgColor": "#fff",
+      "pageGroup": "",
+      "form": "link",
+      "pid": "AD879898-8CEA-4980-9798-F799A9A4AF7F"
+    },
+    {
+      "id": "a5b425d1-4c2f-4979-aeaf-68531e052a4e",
+      "name": "学习时间-综合性学习服务平台",
+      "src": "https://download.mtab.cc/friendLinkLogo/learningtimes.png",
+      "url": "https://learningtimes.cn",
+      "size": "1x1",
+      "type": "icon",
       "sort": 1,
-      "id": "D3AB9DDF-EB1A-47AD-B9B5-824A367C7A61",
-      "name": "华为云",
+      "app": 0,
+      "bgColor": null,
+      "pageGroup": "",
+      "pid": "AD879898-8CEA-4980-9798-F799A9A4AF7F",
+      "form": "link"
+    },
+    {
+      "id": "93024f66-0561-4d85-a527-c10897cde7f4",
+      "name": "大师兄导航",
+      "src": "https://download.mtab.cc/friendLinkLogo/dsx.png",
+      "url": "https://dsxdh.com/",
+      "size": "1x1",
+      "type": "icon",
+      "sort": 0,
+      "app": 0,
+      "bgColor": "rgba(0,0,0,0)",
+      "pageGroup": "",
+      "pid": "AD879898-8CEA-4980-9798-F799A9A4AF7F",
+      "form": "link"
+    },
+    {
+      "id": "8b70f87f-65ce-4533-9ca1-1ed815943bb4",
+      "name": "码云Gitee",
+      "src": "/static/defLinkLogo/gitee.svg",
+      "url": "https://gitee.com",
       "size": "1x1",
-      "src": "/static/huawei.png",
-      "url": "https://www.huaweicloud.com/",
       "type": "icon",
+      "sort": 10,
       "app": 0,
+      "bgColor": "rgba(199, 29, 35, 1)",
+      "pageGroup": "",
+      "form": "link",
       "pid": null
     },
     {
-      "id": "72246EC7-57BD-49FA-8E2B-AD6C3981A297",
+      "id": "3497447a-bd77-4d4e-a9a6-99452a93f99c",
+      "name": "旅者Bin",
+      "src": "https://download.mtab.cc/friendLinkLogo/101jc.png",
+      "url": "https://blog.101jc.com/archives",
+      "size": "1x1",
+      "type": "icon",
+      "sort": 2,
+      "app": 0,
+      "bgColor": "#fff",
+      "pageGroup": "",
+      "form": "link",
+      "pid": "AD879898-8CEA-4980-9798-F799A9A4AF7F"
+    },
+    {
+      "id": "AD879898-8CEA-4980-9798-F799A9A4AF7F",
       "size": "1x1",
       "component": "iconGroup",
-      "name": "云服务器",
+      "name": "友情推荐",
       "type": "component",
       "url": "iconGroup",
+      "pageGroup": "",
       "children": [],
+      "pid": null,
+      "sort": 28
+    },
+    {
+      "id": "0c706332-0417-4512-a1c7-02813106b4d5",
+      "name": "王先生",
+      "src": "https://download.mtab.cc/friendLinkLogo/wangxiansheng.jpg",
+      "url": "https://www.wangxiansheng.com",
+      "size": "1x1",
+      "type": "icon",
+      "sort": 6,
+      "app": 0,
+      "bgColor": null,
+      "pageGroup": "",
+      "pid": "AD879898-8CEA-4980-9798-F799A9A4AF7F"
+    }
+  ],
+  "tabbar": [
+    {
+      "id": "45154338-89c4-41b1-ae9f-4508078f4c7b",
+      "app": 0,
+      "pid": null,
+      "src": "/static/mtab.png",
+      "url": "https://mtab.cc",
+      "name": "Mtab书签",
+      "size": "1x1",
+      "sort": 0,
+      "type": "icon"
+    },
+    {
+      "id": "4F9137E3-5701-4F6F-A8F4-C3F131FD9429",
+      "app": 1,
+      "pid": null,
+      "src": "/static/huoshanfanyi.png",
+      "url": "https://translate.volcengine.com/translate",
+      "name": "火山翻译",
+      "size": "1x1",
       "sort": 4,
-      "pid": null
+      "type": "icon"
     },
     {
-      "sort": 2,
-      "id": "5C3099FE-4A6E-4DA9-85B2-F20E1205347C",
-      "name": "GitHub",
+      "id": "9589E037-8EE3-4B1C-95E8-F419E9187357",
+      "app": 1,
+      "pid": null,
+      "src": "/static/note.png",
+      "url": "/noteApp",
+      "name": "记事本",
       "size": "1x1",
+      "sort": 5,
+      "type": "icon"
+    },
+    {
+      "id": "D3AB9DDF-EB1A-47AD-B9B5-824A367C7A61",
+      "app": 0,
+      "pid": null,
+      "src": "/static/huawei.png",
+      "url": "https://www.huaweicloud.com/",
+      "name": "华为云",
+      "size": "1x1",
+      "sort": 1,
+      "type": "icon"
+    },
+    {
+      "id": "5C3099FE-4A6E-4DA9-85B2-F20E1205347C",
+      "app": 0,
+      "pid": null,
       "src": "/static/github.png",
       "url": "https://github.com/",
-      "type": "icon",
-      "app": 0,
-      "pid": null
+      "name": "GitHub",
+      "size": "1x1",
+      "sort": 2,
+      "type": "icon"
     },
     {
-      "sort": 3,
       "id": "C4E35210-C3CB-44DB-9D32-96FDA9116EB1",
-      "name": "微博",
-      "size": "1x1",
+      "app": 0,
+      "pid": null,
       "src": "/static/weibo.png",
       "url": "http://weibo.com/",
+      "name": "微博",
+      "size": "1x1",
+      "sort": 3,
+      "type": "icon"
+    },
+    {
+      "id": "4A7E7020-690E-4955-86F4-2D9B35CFAF8B",
+      "app": 1,
+      "pid": null,
+      "src": "/static/webTerm.svg",
+      "url": "https://ssh.mtab.cc",
+      "form": "tabbar",
+      "name": "WebTerm",
+      "size": "1x2",
+      "sort": 10,
+      "tips": "WebTerm",
       "type": "icon",
-      "app": 0,
-      "pid": null
+      "custom": {
+        "width": 1200,
+        "height": 700,
+        "maximize": 1,
+        "immersion": 0,
+        "minimization": 1,
+        "controllerColor": "#000000"
+      },
+      "bgColor": "rgba(0, 0, 0, 0.79)",
+      "origin_id": 114,
+      "pageGroup": ""
     },
     {
       "id": "033E9038-B97C-4894-83D2-6E030FAB83C6",
@@ -277,6 +698,20 @@
       "size": "1x1",
       "sort": 8,
       "type": "icon"
+    },
+    {
+      "id": "f730b603-6514-414a-8165-7d5a679e12db",
+      "app": 0,
+      "pid": null,
+      "src": "/static/mcecy.png",
+      "url": "https://blog.mcecy.com/",
+      "form": "link",
+      "name": "IT博客",
+      "size": "1x1",
+      "sort": 0,
+      "type": "icon",
+      "bgColor": "#fff",
+      "pageGroup": ""
     }
   ],
   "config": {
@@ -294,23 +729,24 @@
       "blur": 0,
       "timeColor": "#fff",
       "tabbar": true,
-      "iconWidth": 70,
+      "iconWidth": 60,
       "iconBg": false,
       "LinkTitle": false,
       "iconRadius": 10,
       "CompactMode": false,
       "nameColor": "#fff",
-      "opacity": 0.10,
+      "opacity": 0.1,
       "colsGap": 35,
       "pageGroup": true,
       "pageGroupStatus": false,
-      "timeView":true,
-      "timeWeek":true,
-      "timeGanZhi":true,
-      "timeSecond":true,
-      "timeMonthDay":true,
-      "timeLunar":true,
-      "time24":true
+      "timeView": true,
+      "timeWeek": true,
+      "timeGanZhi": true,
+      "timeSecond": true,
+      "timeMonthDay": true,
+      "timeLunar": true,
+      "time24": true,
+      "maxColumn":14
     }
   }
 }

File diff suppressed because it is too large
+ 2 - 0
public/static/jsdesign.svg


File diff suppressed because it is too large
+ 0 - 0
public/static/pageGroup/chat.svg


+ 1 - 0
public/static/pageGroup/computer.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="32" height="32" viewBox="0 0 32 32"><defs><clipPath id="master_svg0_81_2114"><rect x="0" y="0" width="32" height="32" rx="0"/></clipPath></defs><g clip-path="url(#master_svg0_81_2114)"><g><path d="M25.9412,4.00000060536C27.6305,4,29,5.45507,29,7.25L29,21.0625C29,22.8574,27.6305,24.3125,25.9412,24.3125L17.147100000000002,24.3125L17.147100000000002,27.5625L20.5882,27.5625C21.2217,27.5625,21.7353,28.1082,21.7353,28.7813C21.7353,29.4543,21.2217,30,20.5882,30L11.41177,30C10.77826,30,10.264710000000001,29.4543,10.264710000000001,28.7813C10.264710000000001,28.1082,10.77826,27.5625,11.41177,27.5625L14.8529,27.5625L14.8529,24.3125L6.05882,24.3125C4.36948,24.3125,3,22.8574,3,21.0625L3,7.25C2.99999943025,5.45507,4.36948,4,6.05882,4L25.9412,4.00000060536ZM26.7059,18.8281L5.2941199999999995,18.8281L5.2941199999999995,21.0625C5.2941199999999995,21.5112,5.63649,21.875,6.05882,21.875L25.9412,21.875C26.3635,21.875,26.7059,21.5112,26.7059,21.0625L26.7059,18.8281ZM25.9412,6.4375L6.05882,6.4375C5.63649,6.4375,5.2941199999999995,6.801270000000001,5.2941199999999995,7.25L5.2941199999999995,16.3906L26.7059,16.3906L26.7059,7.25C26.7059,6.801270000000001,26.3635,6.4375,25.9412,6.4375Z" fill="#FFFFFF" fill-opacity="1"/></g></g></svg>

+ 1 - 0
public/static/pageGroup/faxian.svg

@@ -0,0 +1 @@
+<svg t="1714921340017" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1106" width="32" height="32"><path d="M383.36 524.842667L332.8 387.584a42.666667 42.666667 0 0 1 54.784-54.826667l137.301333 50.602667a42.666667 42.666667 0 0 1 15.445334 70.186667l-86.741334 86.698666a42.666667 42.666667 0 0 1-70.186666-15.36z" fill="#ffffff" p-id="1107"></path><path d="M483.754667 570.453333l86.698666-86.698666a42.666667 42.666667 0 0 1 70.186667 15.402666l50.602667 137.301334a42.666667 42.666667 0 0 1-54.784 54.784l-137.301334-50.602667a42.666667 42.666667 0 0 1-15.402666-70.186667z" fill="#ffffff" p-id="1108"></path><path d="M981.333333 512c0 259.2-210.133333 469.333333-469.333333 469.333333S42.666667 771.2 42.666667 512 252.8 42.666667 512 42.666667s469.333333 210.133333 469.333333 469.333333z m-85.333333 0a384 384 0 1 0-768 0 384 384 0 0 0 768 0z" fill="#ffffff" p-id="1109"></path></svg>

File diff suppressed because it is too large
+ 0 - 0
public/static/pageGroup/geren.svg


+ 1 - 0
public/static/pageGroup/kongjian.svg

@@ -0,0 +1 @@
+<svg t="1714890067328" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2265" width="32" height="32"><path d="M512 35.84L99.4816 273.8176v476.16L512 988.16l412.5184-238.1824v-476.16z m325.2736 258.56L512 476.672 191.8464 291.4304 512 106.5984z m-676.352 50.1248L481.28 529.7152v369.92l-320.3584-184.9344zM542.72 899.6352v-369.664l320.3584-179.6096v364.288z" p-id="2266" fill="#ffffff"></path></svg>

File diff suppressed because it is too large
+ 0 - 0
public/static/pageGroup/work.svg


File diff suppressed because it is too large
+ 0 - 0
public/static/pageGroup/xiuxian.svg


BIN
public/static/webTerm.svg


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