diff --git a/saiadmin-artd/src/api/system/admin_guide.ts b/saiadmin-artd/src/api/system/admin_guide.ts new file mode 100644 index 0000000..f11c9da --- /dev/null +++ b/saiadmin-artd/src/api/system/admin_guide.ts @@ -0,0 +1,26 @@ +import request from '@/utils/http' + +/** + * 后台操作指南 API + */ +export default { + /** + * 读取 Markdown 内容 + */ + read() { + return request.get({ + url: '/core/adminGuide/read' + }) + }, + + /** + * 保存 Markdown 内容 + */ + save(params: { content: string }) { + return request.post({ + url: '/core/adminGuide/save', + data: params, + showSuccessMessage: true + }) + } +} diff --git a/saiadmin-artd/src/locales/langs/en/system/admin_guide.json b/saiadmin-artd/src/locales/langs/en/system/admin_guide.json new file mode 100644 index 0000000..f1420d9 --- /dev/null +++ b/saiadmin-artd/src/locales/langs/en/system/admin_guide.json @@ -0,0 +1,20 @@ +{ + "title": "Admin Guide", + "toolbar": { + "edit": "Edit", + "save": "Save", + "cancel": "Cancel", + "refresh": "Refresh" + }, + "meta": { + "filePath": "File Path", + "updateTime": "Updated At" + }, + "message": { + "loadFailed": "Failed to load admin guide", + "saveSuccess": "Saved successfully", + "saveFailed": "Failed to save", + "cancelConfirm": "You have unsaved changes. Cancel editing?", + "editRequired": "Please click Edit before saving" + } +} diff --git a/saiadmin-artd/src/locales/langs/zh/system/admin_guide.json b/saiadmin-artd/src/locales/langs/zh/system/admin_guide.json new file mode 100644 index 0000000..256ab5b --- /dev/null +++ b/saiadmin-artd/src/locales/langs/zh/system/admin_guide.json @@ -0,0 +1,20 @@ +{ + "title": "后台操作指南", + "toolbar": { + "edit": "编辑", + "save": "保存", + "cancel": "取消", + "refresh": "刷新" + }, + "meta": { + "filePath": "文档路径", + "updateTime": "更新时间" + }, + "message": { + "loadFailed": "加载操作指南失败", + "saveSuccess": "保存成功", + "saveFailed": "保存失败", + "cancelConfirm": "当前有未保存的修改,确定取消编辑吗?", + "editRequired": "请先点击编辑后再保存" + } +} diff --git a/saiadmin-artd/src/utils/channelLayout.ts b/saiadmin-artd/src/utils/channelLayout.ts index 3da80e0..b12ad54 100644 --- a/saiadmin-artd/src/utils/channelLayout.ts +++ b/saiadmin-artd/src/utils/channelLayout.ts @@ -14,7 +14,8 @@ const NO_CHANNEL_LAYOUT_PATHS = [ '/safeguard/database', '/safeguard/server', '/safeguard/cache', - '/safeguard/email-log' + '/safeguard/email-log', + '/admin_guide' ] /** 日志页:左侧首项为「全部」,dept_id=0 表示不按渠道过滤 */ diff --git a/saiadmin-artd/src/views/system/admin_guide/index.vue b/saiadmin-artd/src/views/system/admin_guide/index.vue new file mode 100644 index 0000000..cb49ff8 --- /dev/null +++ b/saiadmin-artd/src/views/system/admin_guide/index.vue @@ -0,0 +1,211 @@ + + + + + diff --git a/server/db/run_system_admin_guide_menu.php b/server/db/run_system_admin_guide_menu.php new file mode 100644 index 0000000..ecbb1e2 --- /dev/null +++ b/server/db/run_system_admin_guide_menu.php @@ -0,0 +1,107 @@ +exec($statement); + $ok++; + } + echo "完成:执行 {$ok} 条语句\n"; +} + +function cliPdo(): PDO +{ + $host = getenv('DB_HOST') ?: '127.0.0.1'; + $port = getenv('DB_PORT') ?: '3306'; + $db = getenv('DB_NAME') ?: ''; + $user = getenv('DB_USER') ?: ''; + $pass = getenv('DB_PASSWORD') ?: ''; + $dsn = "mysql:host={$host};port={$port};dbname={$db};charset=utf8mb4"; + return new PDO($dsn, $user, $pass, [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + ]); +} + +echo "========== 后台操作指南菜单安装 ==========\n"; +echo '数据库: ' . (getenv('DB_NAME') ?: '') . '@' . (getenv('DB_HOST') ?: '') . "\n"; + +$pdo = cliPdo(); +runSqlFile($pdo, __DIR__ . '/system_admin_guide_menu.sql', '1. 菜单与按钮权限'); + +$menuId = (int) Db::name('sa_system_menu') + ->where('path', 'admin_guide') + ->where('component', '/system/admin_guide/index') + ->where('type', 2) + ->value('id'); + +if ($menuId <= 0) { + echo "错误:未找到后台操作指南菜单\n"; + exit(1); +} + +$buttonIds = Db::name('sa_system_menu') + ->where('parent_id', $menuId) + ->where('type', 3) + ->column('id'); + +$allMenuIds = array_values(array_unique(array_merge([$menuId], array_map('intval', $buttonIds ?: [])))); + +echo "\n=== 2. 授权超级管理员角色 ===\n"; +$adminRoleIds = Db::name('sa_system_role') + ->where('code', 'super_admin') + ->column('id'); + +if ($adminRoleIds === [] || $adminRoleIds === null) { + $adminRoleIds = Db::name('sa_system_role')->where('id', 1)->column('id'); +} + +$inserted = 0; +foreach ($adminRoleIds as $roleId) { + $roleId = (int) $roleId; + foreach ($allMenuIds as $mid) { + $exists = Db::name('sa_system_role_menu') + ->where('role_id', $roleId) + ->where('menu_id', $mid) + ->count(); + if ($exists > 0) { + continue; + } + Db::name('sa_system_role_menu')->insert([ + 'role_id' => $roleId, + 'menu_id' => $mid, + ]); + $inserted++; + } + echo " 角色 {$roleId}:新增授权 {$inserted} 条\n"; +} + +UserMenuCache::clearMenuCache(); +\plugin\saiadmin\app\cache\UserAuthCache::clear(); + +echo "\n菜单 ID: {$menuId}\n"; +echo "按钮权限: " . implode(',', $allMenuIds) . "\n"; +echo "已清除菜单缓存,请重新登录后台查看。\n"; +echo "========== 安装完成 ==========\n"; diff --git a/server/db/system_admin_guide_menu.sql b/server/db/system_admin_guide_menu.sql new file mode 100644 index 0000000..2c91b9d --- /dev/null +++ b/server/db/system_admin_guide_menu.sql @@ -0,0 +1,39 @@ +-- 后台操作指南顶级菜单与权限 +-- 说明:挂载到顶级菜单(parent_id=0),内容来源 server/docs/ADMIN_GUIDE.md + +SET @now = NOW(); + +-- 1) 创建后台操作指南顶级菜单(type=2,parent_id=0) +INSERT INTO `sa_system_menu` +(`parent_id`,`name`,`code`,`slug`,`type`,`path`,`component`,`method`,`icon`,`sort`,`is_iframe`,`is_keep_alive`,`is_hidden`,`is_fixed_tab`,`is_full_page`,`generate_id`,`generate_key`,`status`,`create_time`,`update_time`) +SELECT 0, '后台操作指南', 'AdminGuide', NULL, 2, 'admin_guide', '/system/admin_guide/index', NULL, 'ri:book-read-line', 5, 2, 2, 2, 2, 2, 0, NULL, 1, @now, @now +WHERE NOT EXISTS ( + SELECT 1 FROM `sa_system_menu` WHERE `path` = 'admin_guide' AND `component` = '/system/admin_guide/index' AND `type` = 2 +); + +SET @admin_guide_menu_id = ( + SELECT `id` FROM `sa_system_menu` + WHERE `path` = 'admin_guide' AND `component` = '/system/admin_guide/index' AND `type` = 2 + ORDER BY `id` ASC LIMIT 1 +); + +-- 2) 创建按钮权限 +INSERT INTO `sa_system_menu` +(`parent_id`,`name`,`code`,`slug`,`type`,`path`,`component`,`method`,`sort`,`is_iframe`,`is_keep_alive`,`is_hidden`,`is_fixed_tab`,`is_full_page`,`generate_id`,`generate_key`,`status`,`create_time`,`update_time`) +SELECT @admin_guide_menu_id, '数据列表', '', 'system:admin_guide:index:index', 3, '', '', '', 100, 2, 2, 2, 2, 2, 0, NULL, 1, @now, @now +WHERE NOT EXISTS (SELECT 1 FROM `sa_system_menu` WHERE `slug` = 'system:admin_guide:index:index' AND `type` = 3); + +INSERT INTO `sa_system_menu` +(`parent_id`,`name`,`code`,`slug`,`type`,`path`,`component`,`method`,`sort`,`is_iframe`,`is_keep_alive`,`is_hidden`,`is_fixed_tab`,`is_full_page`,`generate_id`,`generate_key`,`status`,`create_time`,`update_time`) +SELECT @admin_guide_menu_id, '读取', '', 'system:admin_guide:index:read', 3, '', '', '', 100, 2, 2, 2, 2, 2, 0, NULL, 1, @now, @now +WHERE NOT EXISTS (SELECT 1 FROM `sa_system_menu` WHERE `slug` = 'system:admin_guide:index:read' AND `type` = 3); + +INSERT INTO `sa_system_menu` +(`parent_id`,`name`,`code`,`slug`,`type`,`path`,`component`,`method`,`sort`,`is_iframe`,`is_keep_alive`,`is_hidden`,`is_fixed_tab`,`is_full_page`,`generate_id`,`generate_key`,`status`,`create_time`,`update_time`) +SELECT @admin_guide_menu_id, '编辑', '', 'system:admin_guide:index:edit', 3, '', '', '', 100, 2, 2, 2, 2, 2, 0, NULL, 1, @now, @now +WHERE NOT EXISTS (SELECT 1 FROM `sa_system_menu` WHERE `slug` = 'system:admin_guide:index:edit' AND `type` = 3); + +INSERT INTO `sa_system_menu` +(`parent_id`,`name`,`code`,`slug`,`type`,`path`,`component`,`method`,`sort`,`is_iframe`,`is_keep_alive`,`is_hidden`,`is_fixed_tab`,`is_full_page`,`generate_id`,`generate_key`,`status`,`create_time`,`update_time`) +SELECT @admin_guide_menu_id, '保存', '', 'system:admin_guide:index:save', 3, '', '', '', 100, 2, 2, 2, 2, 2, 0, NULL, 1, @now, @now +WHERE NOT EXISTS (SELECT 1 FROM `sa_system_menu` WHERE `slug` = 'system:admin_guide:index:save' AND `type` = 3); diff --git a/server/docs/ADMIN_GUIDE.md b/server/docs/ADMIN_GUIDE.md new file mode 100644 index 0000000..870c514 --- /dev/null +++ b/server/docs/ADMIN_GUIDE.md @@ -0,0 +1,128 @@ +# 大富翁-使用说明指南 + +## 菜单简单介绍 + +## 工作台/统计页面:统计数据 + +![image.png](/docs/picture/guide_01.png) + +## 角色管理:对角色的菜单权限设置 + +按等级设定,等级越低权限越少(不要出现上级角色没有的权限,子角色有) +避免方式:使用子角色创建下级角色,可以避免下级角色比上级角色操作权限更多的问题 + +![image.png](/docs/picture/guide_02.png) + +这里设置角色的菜单以及按钮权限 + +![image.png](/docs/picture/guide_03.png) + +## 彩金池配置:监听彩金池实时变化 + +可以实时监听彩金池累积金额的变化 + +![image.png](/docs/picture/guide_04.png) + +## 游戏配置:游戏规则和平台币转化比 + +游戏配置 + +![image.png](/docs/picture/guide_05.png) + +其中游戏玩法为进入游戏的弹窗,和规则介绍(无特殊需求不需要大改) + +![image.png](/docs/picture/guide_06.png) + +游戏平台币兑换币:为进入平台时平台比转化比,比如,当前设置的为1:1,如果从jk8平台转入100,那么获取的游戏币为100,如果设置1:2则获取的平台币为200 + +## 底注配置:方便玩家快速调整压注倍率 + +底注配置 + +![image.png](/docs/picture/guide_07.png) + +对应游戏中的,其中每次游玩对局基础消耗为1游戏币(无法修改),底注的设置只是方便玩家快速修改压注金额 + +![image.png](/docs/picture/guide_08.png) + +# 抽奖逻辑 + +## 判断抽奖档位 + +当前的抽奖逻辑时,按照抽奖档位(T1-T5)进行抽奖,在【玩家管理】菜单中的设置玩家具体的档位权重 + +![image.png](/docs/picture/guide_09.png) + +也可以在【彩金池配置】菜单中设置玩家正常的抽奖档位权重 + +- 其中正常的档位权重为注册玩家默认绑定的档位权重,并且只有在修改完后,创建的玩家才能绑定最新的正常档位权重 + +![image.png](/docs/picture/guide_10.png) + +- 其中free为杀分权重为如果当前彩金池(平台)盈利超过设置的安全线则制动走杀分的权重 + +![image.png](/docs/picture/guide_11.png) + +- 剩余的两个权重可以方便快速切换用户的档位抽奖权重 + +![image.png](/docs/picture/guide_12.png) + +![image.png](/docs/picture/guide_13.png) + +## 根据档位抽取中奖号码 + +### 设置中奖号码地图 + +在后台设置地图缩影 + +![image.png](/docs/picture/guide_14.png) + +地图的索引参看如下 + +![image.png](/docs/picture/guide_15.png) + +其中地图的索引可以按照需求点击图中的按规则生成 + +并且规则尽可能符合:结算金额 < 0 → T4;0 < 结算金额 < 100 → T3;100 < 结算金额 < 200 → T2;200 < 结算金额 → T1;T5「再来一次」结算金额=0 + +![image.png](/docs/picture/guide_16.png) + +![image.png](/docs/picture/guide_17.png) + +### 创建完地图索引后创建相应的奖励对照表 + +创建奖励对照表的原因是由于有每个号码的权重不一样,豹子号10,15,20,25有多重组合方式,所以需要设置奖励对照表中的权重配比 + +![image.png](/docs/picture/guide_18.png) + +![image.png](/docs/picture/guide_19.png) + +根据抽到的奖励档位,抽取号码(主要用于设置抽取豹子号的5,10,15,20,25,30的权重) + +![image.png](/docs/picture/guide_20.png) + +比如上图中如果不设置,色子点数5抽到的概率和其他点数的概率是一样的,可能抽7次T1奖励,就有1次中豹子号5的可能 + +由于抽到色子点数和为10,15,20,25的色子点数组合有多种,所以在抽该这四个点数时还需要单独配置相应的中大奖概率(其中豹子号5和30只有一种组合【1,1,1,1,1】和【6,6,6,6,6】,所以不需要配置),其中权重拉到最大10000,那么中奖概率为100%(只要摇到了相应的色子点数和则中奖概率为100%) + +![image.png](/docs/picture/guide_21.png) + +### 扩展 + +- 测试设置的中奖概率,根据如下设置可以测试当前设置权重的中奖概率,该测试数据不记录到真实数据系统中 + +![image.png](/docs/picture/guide_22.png) + +![image.png](/docs/picture/guide_23.png) + +能够准确的反馈抽中点数的统计 + +![image.png](/docs/picture/guide_24.png) + +如果当前中奖概率符合预期,或则测试多组数据选取一组符合预期的导入到当前的配置中 + +![image.png](/docs/picture/guide_25.png) + +这里可以详情查询到指定测试记录的详情, + +![image.png](/docs/picture/guide_26.png) diff --git a/server/plugin/saiadmin/app/controller/system/SystemAdminGuideController.php b/server/plugin/saiadmin/app/controller/system/SystemAdminGuideController.php new file mode 100644 index 0000000..7ab4b62 --- /dev/null +++ b/server/plugin/saiadmin/app/controller/system/SystemAdminGuideController.php @@ -0,0 +1,49 @@ +guideLogic = new SystemAdminGuideLogic(); + parent::__construct(); + } + + /** + * 读取后台操作指南 Markdown 内容 + */ + #[Permission('后台操作指南读取', 'system:admin_guide:index:read')] + public function read(Request $request): Response + { + $data = $this->guideLogic->read(); + return $this->success($data); + } + + /** + * 保存后台操作指南 Markdown 内容 + */ + #[Permission('后台操作指南保存', 'system:admin_guide:index:save')] + public function save(Request $request): Response + { + $content = $request->post('content', ''); + if (! is_string($content)) { + return $this->fail('invalid content'); + } + $data = $this->guideLogic->save($content); + return $this->success($data, 'save success'); + } +} diff --git a/server/plugin/saiadmin/app/logic/system/SystemAdminGuideLogic.php b/server/plugin/saiadmin/app/logic/system/SystemAdminGuideLogic.php new file mode 100644 index 0000000..2d3586e --- /dev/null +++ b/server/plugin/saiadmin/app/logic/system/SystemAdminGuideLogic.php @@ -0,0 +1,72 @@ +getFilePath(); + if (! is_file($filePath)) { + throw new ApiException('admin guide file not found'); + } + $content = file_get_contents($filePath); + if ($content === false) { + throw new ApiException('failed to read admin guide file'); + } + + return [ + 'content' => $content, + 'file_path' => 'docs/' . self::GUIDE_FILENAME, + 'update_time' => date('Y-m-d H:i:s', filemtime($filePath)), + ]; + } + + /** + * 保存指南内容到 Markdown 文件 + * @param string $content + * @return array{content: string, file_path: string, update_time: string} + */ + public function save(string $content): array + { + $filePath = $this->getFilePath(); + $dir = dirname($filePath); + if (! is_dir($dir) && ! mkdir($dir, 0755, true) && ! is_dir($dir)) { + throw new ApiException('failed to create docs directory'); + } + + $result = file_put_contents($filePath, $content, LOCK_EX); + if ($result === false) { + throw new ApiException('failed to save admin guide file'); + } + + clearstatcache(true, $filePath); + + return [ + 'content' => $content, + 'file_path' => 'docs/' . self::GUIDE_FILENAME, + 'update_time' => date('Y-m-d H:i:s', filemtime($filePath)), + ]; + } +} diff --git a/server/plugin/saiadmin/config/route.php b/server/plugin/saiadmin/config/route.php index 9e23e2b..72b72ec 100644 --- a/server/plugin/saiadmin/config/route.php +++ b/server/plugin/saiadmin/config/route.php @@ -81,6 +81,10 @@ Route::group('/core', function () { Route::delete("/logs/deleteOperLog", [\plugin\saiadmin\app\controller\system\SystemLogController::class, 'deleteOperLog']); fastRoute("email", \plugin\saiadmin\app\controller\system\SystemMailController::class); + // 后台操作指南 + Route::get("/adminGuide/read", [\plugin\saiadmin\app\controller\system\SystemAdminGuideController::class, 'read']); + Route::post("/adminGuide/save", [\plugin\saiadmin\app\controller\system\SystemAdminGuideController::class, 'save']); + // 服务管理 Route::get("/server/monitor", [\plugin\saiadmin\app\controller\system\SystemServerController::class, 'monitor']); Route::get("/server/cache", [\plugin\saiadmin\app\controller\system\SystemServerController::class, 'cache']); diff --git a/server/public/docs/picture/guide_01.png b/server/public/docs/picture/guide_01.png new file mode 100644 index 0000000..7edbb2b Binary files /dev/null and b/server/public/docs/picture/guide_01.png differ diff --git a/server/public/docs/picture/guide_02.png b/server/public/docs/picture/guide_02.png new file mode 100644 index 0000000..6cbc0e0 Binary files /dev/null and b/server/public/docs/picture/guide_02.png differ diff --git a/server/public/docs/picture/guide_03.png b/server/public/docs/picture/guide_03.png new file mode 100644 index 0000000..b4f47bc Binary files /dev/null and b/server/public/docs/picture/guide_03.png differ diff --git a/server/public/docs/picture/guide_04.png b/server/public/docs/picture/guide_04.png new file mode 100644 index 0000000..9e3df5c Binary files /dev/null and b/server/public/docs/picture/guide_04.png differ diff --git a/server/public/docs/picture/guide_05.png b/server/public/docs/picture/guide_05.png new file mode 100644 index 0000000..a9391f5 Binary files /dev/null and b/server/public/docs/picture/guide_05.png differ diff --git a/server/public/docs/picture/guide_06.png b/server/public/docs/picture/guide_06.png new file mode 100644 index 0000000..505f9d3 Binary files /dev/null and b/server/public/docs/picture/guide_06.png differ diff --git a/server/public/docs/picture/guide_07.png b/server/public/docs/picture/guide_07.png new file mode 100644 index 0000000..d2fe6d3 Binary files /dev/null and b/server/public/docs/picture/guide_07.png differ diff --git a/server/public/docs/picture/guide_08.png b/server/public/docs/picture/guide_08.png new file mode 100644 index 0000000..219744f Binary files /dev/null and b/server/public/docs/picture/guide_08.png differ diff --git a/server/public/docs/picture/guide_09.png b/server/public/docs/picture/guide_09.png new file mode 100644 index 0000000..59322a9 Binary files /dev/null and b/server/public/docs/picture/guide_09.png differ diff --git a/server/public/docs/picture/guide_10.png b/server/public/docs/picture/guide_10.png new file mode 100644 index 0000000..3ea9d2d Binary files /dev/null and b/server/public/docs/picture/guide_10.png differ diff --git a/server/public/docs/picture/guide_11.png b/server/public/docs/picture/guide_11.png new file mode 100644 index 0000000..5cc5182 Binary files /dev/null and b/server/public/docs/picture/guide_11.png differ diff --git a/server/public/docs/picture/guide_12.png b/server/public/docs/picture/guide_12.png new file mode 100644 index 0000000..cc0b07e Binary files /dev/null and b/server/public/docs/picture/guide_12.png differ diff --git a/server/public/docs/picture/guide_13.png b/server/public/docs/picture/guide_13.png new file mode 100644 index 0000000..09bc774 Binary files /dev/null and b/server/public/docs/picture/guide_13.png differ diff --git a/server/public/docs/picture/guide_14.png b/server/public/docs/picture/guide_14.png new file mode 100644 index 0000000..8f648de Binary files /dev/null and b/server/public/docs/picture/guide_14.png differ diff --git a/server/public/docs/picture/guide_15.png b/server/public/docs/picture/guide_15.png new file mode 100644 index 0000000..c6c9403 Binary files /dev/null and b/server/public/docs/picture/guide_15.png differ diff --git a/server/public/docs/picture/guide_16.png b/server/public/docs/picture/guide_16.png new file mode 100644 index 0000000..a527a34 Binary files /dev/null and b/server/public/docs/picture/guide_16.png differ diff --git a/server/public/docs/picture/guide_17.png b/server/public/docs/picture/guide_17.png new file mode 100644 index 0000000..063f11c Binary files /dev/null and b/server/public/docs/picture/guide_17.png differ diff --git a/server/public/docs/picture/guide_18.png b/server/public/docs/picture/guide_18.png new file mode 100644 index 0000000..5f2ba5f Binary files /dev/null and b/server/public/docs/picture/guide_18.png differ diff --git a/server/public/docs/picture/guide_19.png b/server/public/docs/picture/guide_19.png new file mode 100644 index 0000000..aaab46a Binary files /dev/null and b/server/public/docs/picture/guide_19.png differ diff --git a/server/public/docs/picture/guide_20.png b/server/public/docs/picture/guide_20.png new file mode 100644 index 0000000..2916302 Binary files /dev/null and b/server/public/docs/picture/guide_20.png differ diff --git a/server/public/docs/picture/guide_21.png b/server/public/docs/picture/guide_21.png new file mode 100644 index 0000000..eb8bdeb Binary files /dev/null and b/server/public/docs/picture/guide_21.png differ diff --git a/server/public/docs/picture/guide_22.png b/server/public/docs/picture/guide_22.png new file mode 100644 index 0000000..2531709 Binary files /dev/null and b/server/public/docs/picture/guide_22.png differ diff --git a/server/public/docs/picture/guide_23.png b/server/public/docs/picture/guide_23.png new file mode 100644 index 0000000..e17436a Binary files /dev/null and b/server/public/docs/picture/guide_23.png differ diff --git a/server/public/docs/picture/guide_24.png b/server/public/docs/picture/guide_24.png new file mode 100644 index 0000000..15b230c Binary files /dev/null and b/server/public/docs/picture/guide_24.png differ diff --git a/server/public/docs/picture/guide_25.png b/server/public/docs/picture/guide_25.png new file mode 100644 index 0000000..797fb03 Binary files /dev/null and b/server/public/docs/picture/guide_25.png differ diff --git a/server/public/docs/picture/guide_26.png b/server/public/docs/picture/guide_26.png new file mode 100644 index 0000000..aeda457 Binary files /dev/null and b/server/public/docs/picture/guide_26.png differ