mirror of
https://github.com/cedar2025/Xboard.git
synced 2025-02-01 23:18:13 -05:00
fix: frontend styling and bug fixes, update deployment docs
- Fix class styling issues and adjust UI components - Fix various minor bugs across the application - Update deployment documentation with improved instructions
This commit is contained in:
parent
07eaddcb83
commit
4728784d1f
@ -1,5 +0,0 @@
|
||||
FROM redis:7-alpine
|
||||
|
||||
RUN mkdir -p /run/redis-socket && chmod 777 /run/redis-socket
|
||||
COPY ./redis.conf /etc/redis.conf
|
||||
CMD ["redis-server", "/etc/redis.conf"]
|
@ -1,7 +0,0 @@
|
||||
unixsocket /run/redis-socket/redis.sock
|
||||
unixsocketperm 777
|
||||
port 0
|
||||
|
||||
save 900 1
|
||||
save 300 10
|
||||
save 60 10000
|
5
.github/workflows/docker-publish.yml
vendored
5
.github/workflows/docker-publish.yml
vendored
@ -7,9 +7,8 @@ name: Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "dev" ]
|
||||
branches: [ "new" ]
|
||||
# Publish semver tags as releases.
|
||||
tags: [ 'v*.*.*' ]
|
||||
workflow_dispatch: # Enable manual trigger
|
||||
|
||||
env:
|
||||
@ -73,7 +72,7 @@ jobs:
|
||||
context: .
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
tags: ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:latest,${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard,${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:${{ steps.get_version.outputs.version }}
|
||||
tags: ${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:new,${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard,${{ env.REGISTRY }}/${{ github.repository_owner }}/xboard:${{ steps.get_version.outputs.version }}
|
||||
# Sign the resulting Docker image digest except on PRs.
|
||||
# This will only write to the public Rekor transparency log when the Docker
|
||||
# repository is public to avoid leaking data. If you would like to publish
|
||||
|
@ -14,4 +14,10 @@ RUN composer install --optimize-autoloader --no-cache --no-dev \
|
||||
&& chown -R www:www /www \
|
||||
&& chmod -R 775 /www
|
||||
|
||||
CMD php artisan octane:start --server="swoole" --port=7010
|
||||
CMD php artisan octane:start \
|
||||
--server="swoole" \
|
||||
--host=0.0.0.0 \
|
||||
--port=${OCTANE_PORT:-7001} \
|
||||
--workers=${OCTANE_WORKERS:-auto} \
|
||||
--task-workers=${OCTANE_TASK_WORKERS:-auto} \
|
||||
--max-requests=${OCTANE_MAX_REQUESTS:-500}
|
52
README.md
52
README.md
@ -1,26 +1,19 @@
|
||||
# 关于Xboard
|
||||
Xboard是基于V2board二次开发,在性能上和功能上都有大部分增强的**面板
|
||||
Xboard New是基于Xboard二次开发,重写后台管理并优化系统架构的**面板,提升可维护性
|
||||
|
||||
# 免责声明
|
||||
本项目只是本人个人学习开发并维护,本人不保证任何可用性,也不对使用本软件造成的任何后果负责。
|
||||
|
||||
# Xboard 特点
|
||||
基于V2board 二次开发,增加了以下特性
|
||||
- 升级Laravel10
|
||||
- 适配Laravels (提升至10+倍并发)
|
||||
- 适配Webman (比laravels快50%左右)
|
||||
- 修改配置从数据库中获取
|
||||
- 支持Docker部署、分布式部署
|
||||
- 支持根据用户IP归属地来下发订阅
|
||||
- 增加Hy2支持
|
||||
- 增加sing-box下发
|
||||
- 支持直接从cloudflare获取访问者真实IP
|
||||
- 支持根据客户端版本自动下发新协议
|
||||
- 支持线路筛选(订阅地址后面增加 &filter=香港|美国)
|
||||
- 支持Sqlite安装(代替Mysql,自用用户福音)
|
||||
# Xboard New 特点
|
||||
基于Xboard 二次开发,增加了以下特性
|
||||
- 增加Octane支持
|
||||
- 使用React + Shadcn UI + TailwindCSS重构后台管理
|
||||
- 使用Vue3 + TypeScript + NaiveUI + Unocss + Pinia重构用户前端
|
||||
- 修复大量BUG
|
||||
|
||||
- 使用Docker Compose作为容器化部署工具
|
||||
- 使用Docker作为容器化部署工具
|
||||
- 重构主题管理,增加主题上传,并且只暴露激活主题
|
||||
- 使用Octane Cache作为设置的缓存
|
||||
- 优化系统架构,提升可维护性
|
||||
# **系统架构**
|
||||
|
||||
- PHP8.1+
|
||||
@ -28,15 +21,26 @@ Xboard是基于V2board二次开发,在性能上和功能上都有大部分增
|
||||
- MySQL5.7+
|
||||
- Redis
|
||||
- Laravel
|
||||
- Octane
|
||||
|
||||
## 性能对比 [查看详情](./docs/性能对比.md)
|
||||
> xboard 无论前端还是后端性能都有巨大的提升
|
||||
## 快速体验
|
||||
|
||||
|场景 | php-fpm(传统) | php-fpm(传统开启opcache) | laravels | webman(docker)|
|
||||
|---- | ---- |---- |----| ---|
|
||||
|首页 | 6请求/秒 | 157请求/秒 | 477请求/秒 | 803请求/秒 |
|
||||
|用户订阅 | 6请求/秒 | 196请求/秒 | 586请求/秒 | 1064请求/秒 |
|
||||
|用户首页延迟| 308ms | 110ms | 101ms | 98ms |
|
||||
使用以下命令快速部署并体验 Xboard(基于 Docker + SQLite):
|
||||
|
||||
```bash
|
||||
git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard && \
|
||||
cd Xboard && \
|
||||
docker compose run -it --rm \
|
||||
-e enable_sqlite=true \
|
||||
-e enable_redis=true \
|
||||
-e admin_account=admin@demo.com \
|
||||
web php artisan xboard:install && \
|
||||
docker compose up -d
|
||||
|
||||
# 安装完成后访问 http://服务器IP:7001
|
||||
```
|
||||
|
||||
> 提示:安装过程中会显示管理员账号密码,请务必保存。
|
||||
|
||||
## 页面展示
|
||||
![示例图片](./docs/images/dashboard.png)
|
||||
|
@ -3,12 +3,9 @@
|
||||
namespace App\Http\Controllers\V2\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\PlanSort;
|
||||
use App\Models\Order;
|
||||
use App\Models\Plan;
|
||||
use App\Models\ServerGroup;
|
||||
use App\Models\User;
|
||||
use App\Services\PlanService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
|
@ -17,6 +17,7 @@ class ServerSave extends FormRequest
|
||||
$protocolRules = [
|
||||
'type' => 'required|in:shadowsocks,vmess,trojan,hysteria,vless',
|
||||
'spectific_key' => 'nullable|string',
|
||||
'code' => 'nullable|string',
|
||||
'show' => '',
|
||||
'name' => 'required|string',
|
||||
'group_ids' => 'nullable|array',
|
||||
|
@ -66,7 +66,7 @@ class BTCPay implements PaymentInterface
|
||||
];
|
||||
}
|
||||
|
||||
public function notify(): array|bool
|
||||
public function notify($params): array|bool
|
||||
{
|
||||
$payload = trim(get_request_content());
|
||||
|
||||
|
@ -1,125 +1,88 @@
|
||||
当然可以。以下是增强了步骤性的部署教程:
|
||||
## 1Panel 快速部署指南
|
||||
|
||||
# 1panel 部署教程
|
||||
本指南介绍如何使用 1Panel 部署 Xboard。
|
||||
|
||||
本文将介绍如何使用 1panel 快速部署 Xboard。
|
||||
|
||||
## 安装部署
|
||||
|
||||
### 步骤 1:安装 1panel
|
||||
|
||||
1. 执行以下命令安装 1panel:
|
||||
|
||||
```
|
||||
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
|
||||
```
|
||||
|
||||
2. 安装完成后,登录 1panel 进行环境的安装。
|
||||
|
||||
### 步骤 2:安装应用
|
||||
|
||||
1. 打开应用商店,安装以下应用:
|
||||
|
||||
- ☑️ OpenResty 任意版本 (<span style="color:yellow">安装时需要勾选 "端口外部访问" 来打开防火墙</span>>
|
||||
- ☑️ MySQL 5.7.\* (arm 架构可以选择 mariadb 进行代替)
|
||||
|
||||
<span style="color:yellow">⚠️ :安装过程中配置默认即可。</span>
|
||||
|
||||
### 步骤 3:添加站点
|
||||
|
||||
1. 在 1panel 面板中,选择“网站”并点击“创建网站”,然后选择“反向代理”。
|
||||
2. 在 “主域名” 中填写你指向服务器的域名,
|
||||
3. 在 “代号” 中填写 `xboard`
|
||||
4. 在 “在代理地址” 中填写 `127.0.0.1:7001`,
|
||||
5. 最后点击“创建”按钮。
|
||||
6. 点击刚创建的网站的 "配置" > "反向代理" > "源文" 修改反向代理规则为以下内容:
|
||||
|
||||
```
|
||||
location ^~ / {
|
||||
proxy_pass http://127.0.0.1:7001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Real-PORT $remote_port;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Scheme $scheme;
|
||||
proxy_set_header Server-Protocol $server_protocol;
|
||||
proxy_set_header Server-Name $server_name;
|
||||
proxy_set_header Server-Addr $server_addr;
|
||||
proxy_set_header Server-Port $server_port;
|
||||
proxy_cache off;
|
||||
}
|
||||
```
|
||||
|
||||
### 步骤 4:创建数据库
|
||||
|
||||
1. 在 1panel 面板中,选择“数据库”并点击“创建数据库”。
|
||||
2. 在“名称”中填写 `xboard`。
|
||||
3. 在“用户”中填写 `xboard`。
|
||||
4. 在“权限”中选择“所有人(%)”。
|
||||
5. 最后点击“创建”按钮。
|
||||
6. 记住数据库账号密码进行下一步
|
||||
|
||||
### 步骤 5:安装 Xboard
|
||||
|
||||
1. 通过 SSH 登录到服务器后,访问站点路径如:`/opt/1panel/apps/openresty/openresty/www/sites/xboard/index`。
|
||||
2. 如果系统没有安装 git,请执行以下命令安装 git:
|
||||
|
||||
- Ubuntu/Debian:
|
||||
|
||||
```
|
||||
apt update
|
||||
apt install -y git
|
||||
```
|
||||
|
||||
- CentOS/RHEL:
|
||||
|
||||
```
|
||||
yum update
|
||||
yum install -y git
|
||||
```
|
||||
|
||||
3. 在站点目录中执行以下命令从 Github 克隆到当前目录:
|
||||
|
||||
```
|
||||
git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard ./
|
||||
```
|
||||
|
||||
4. 执行以下命令安装 Xboard:
|
||||
|
||||
```
|
||||
docker compose run -it --rm xboard php artisan xboard:install
|
||||
```
|
||||
|
||||
5. 根据提示输入上述创建的数据库账号密码,选择使用内置 redis 完成安装。
|
||||
执行这条命令之后,会返回你的后台地址和管理员账号密码(你需要记录下来)。
|
||||
你需要执行下面的“启动 Xboard”步骤之后才能访问后台。
|
||||
|
||||
### 步骤 6:启动 Xboard
|
||||
|
||||
在站点目录中执行以下命令:
|
||||
### 1. 环境准备
|
||||
|
||||
安装 1Panel:
|
||||
```bash
|
||||
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && \
|
||||
sudo bash quick_start.sh
|
||||
```
|
||||
|
||||
### 2. 环境配置
|
||||
|
||||
1. 在应用商店安装:
|
||||
- OpenResty(任意版本)
|
||||
- ⚠️ 安装时需要勾选"端口外部访问"以开放防火墙
|
||||
- MySQL 5.7(ARM 架构可使用 MariaDB)
|
||||
|
||||
2. 创建数据库:
|
||||
- 数据库名:`xboard`
|
||||
- 用户名:`xboard`
|
||||
- 访问权限:所有人(%)
|
||||
- 记录数据库密码,后续安装需要使用
|
||||
|
||||
### 3. 部署步骤
|
||||
|
||||
1. 添加站点:
|
||||
- 选择"网站" > "创建网站" > "反向代理"
|
||||
- 主域名:填写你的域名
|
||||
- 代号:`xboard`
|
||||
- 代理地址:`127.0.0.1:7001`
|
||||
|
||||
2. 配置反向代理:
|
||||
```nginx
|
||||
location ^~ / {
|
||||
proxy_pass http://127.0.0.1:7001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Real-PORT $remote_port;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Scheme $scheme;
|
||||
proxy_set_header Server-Protocol $server_protocol;
|
||||
proxy_set_header Server-Name $server_name;
|
||||
proxy_set_header Server-Addr $server_addr;
|
||||
proxy_set_header Server-Port $server_port;
|
||||
proxy_cache off;
|
||||
}
|
||||
```
|
||||
|
||||
3. 安装 Xboard:
|
||||
```bash
|
||||
# 进入站点目录
|
||||
cd /opt/1panel/apps/openresty/openresty/www/sites/xboard/index
|
||||
|
||||
# 安装 Git(如未安装)
|
||||
# Ubuntu/Debian
|
||||
apt update && apt install -y git
|
||||
# CentOS/RHEL
|
||||
yum update && yum install -y git
|
||||
|
||||
# 克隆代码
|
||||
git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard ./
|
||||
|
||||
# 安装依赖并初始化
|
||||
docker compose run -it --rm web php artisan xboard:install
|
||||
```
|
||||
> 安装时选择使用内置 Redis,并输入之前创建的数据库信息
|
||||
> 安装完成后请保存返回的后台地址和管理员账号密码
|
||||
|
||||
4. 启动服务:
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
🎉: 到这里,你已经可以通过域名访问你的站点了。
|
||||
### 4. 版本更新
|
||||
|
||||
⚠️: 请务必开启防火墙防止7001端口暴露到公网当中。
|
||||
```bash
|
||||
docker compose pull && docker compose up -d
|
||||
```
|
||||
|
||||
## 更新
|
||||
### 注意事项
|
||||
|
||||
1. 通过 SSH 登录到服务器后,访问站点路径如:`/opt/1panel/apps/openresty/openresty/www/sites/xboard/index`,然后在站点目录中执行以下命令:
|
||||
|
||||
```
|
||||
docker compose down xboard
|
||||
docker compose pull
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
🎉: 在此,你已完成 Xboard 的更新。
|
||||
|
||||
## 注意
|
||||
|
||||
- 启用 webman 后做的任何代码修改都需要重启生效。
|
||||
- ⚠️ 请确保防火墙已开启,避免 7001 端口暴露到公网
|
||||
- 代码修改后需要重启服务才能生效
|
||||
- 建议配置 SSL 证书以确保安全访问
|
||||
|
@ -1,68 +1,67 @@
|
||||
## Docker-Compose 部署教程
|
||||
本文教你如何在命令行使用aapanel + docker-compose来快速Xboard
|
||||
## aaPanel + Docker 快速部署指南
|
||||
|
||||
### 部署
|
||||
1. 安装aaPanel + 和docker
|
||||
```
|
||||
# 安装Docker
|
||||
本指南介绍如何使用 aaPanel + Docker Compose 部署 Xboard。
|
||||
|
||||
### 1. 环境准备
|
||||
|
||||
1. 安装 Docker:
|
||||
```bash
|
||||
# 安装 Docker
|
||||
curl -sSL https://get.docker.com | bash
|
||||
# Centos系统可能还需要执行下面命令来启动Docker
|
||||
|
||||
# CentOS 系统需要执行:
|
||||
systemctl enable docker
|
||||
systemctl start docker
|
||||
```
|
||||
```
|
||||
# 安装宝塔
|
||||
URL=https://www.aapanel.com/script/install_6.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_6.0_en.sh "$URL";fi;bash install_6.0_en.sh aapanel
|
||||
|
||||
2. 安装 aaPanel:
|
||||
```bash
|
||||
curl -sSL https://www.aapanel.com/script/install_6.0_en.sh -o install_6.0_en.sh && \
|
||||
bash install_6.0_en.sh aapanel
|
||||
```
|
||||
|
||||
安装完成后我们登陆 aaPanel 进行环境的安装。
|
||||
2. 选择使用LNMP的环境安装方式勾选如下信息
|
||||
☑️ Nginx 任意版本
|
||||
☑️ MySQL 5.7
|
||||
选择 Fast 快速编译后进行安装。
|
||||
### 2. 环境配置
|
||||
|
||||
<span style="color:yellow">⚠️ :无需安装php 与 redis</span>
|
||||
在 aaPanel 中安装 LNMP:
|
||||
- Nginx(任意版本)
|
||||
- MySQL 5.7
|
||||
- ⚠️ 无需安装 PHP 和 Redis
|
||||
|
||||
3. 添加站点
|
||||
>aaPanel 面板 > Website > Add site。
|
||||
>>在 Domain 填入你指向服务器的域名
|
||||
>>在 Database 选择MySQL
|
||||
>>在 PHP Verison 选择纯静态
|
||||
### 3. 部署步骤
|
||||
|
||||
4. 安装 Xborad
|
||||
>通过SSH登录到服务器后访问站点路径如:/www/wwwroot/你的站点域名。
|
||||
>以下命令都需要在站点目录进行执行。
|
||||
```
|
||||
# 删除目录下文件
|
||||
1. 添加站点:
|
||||
- 进入 aaPanel > Website > Add site
|
||||
- 域名:填写你的域名
|
||||
- 数据库:选择 MySQL
|
||||
- PHP 版本:选择纯静态
|
||||
|
||||
2. 安装 Xboard:
|
||||
```bash
|
||||
# 进入站点目录
|
||||
cd /www/wwwroot/你的域名
|
||||
|
||||
# 清理目录
|
||||
chattr -i .user.ini
|
||||
rm -rf .htaccess 404.html 502.html index.html .user.ini
|
||||
```
|
||||
> 执行命令从 Github 克隆到当前目录。
|
||||
```
|
||||
git clone https://github.com/cedar2025/Xboard.git ./
|
||||
```
|
||||
> 复制一份docker-compose.yaml文件
|
||||
```
|
||||
cp docker-compose.sample.yaml docker-compose.yaml
|
||||
```
|
||||
> 执行命令安装依赖包以及Xboard
|
||||
```
|
||||
docker compose run -it --rm xboard sh init.sh
|
||||
```
|
||||
> 根据提示完成安装
|
||||
> 执行这条命令之后,会返回你的后台地址和管理员账号密码(你需要记录下来)
|
||||
> 你需要执行下面的 **启动xborad** 步骤之后才能访问后台
|
||||
|
||||
5. 启动xboard
|
||||
# 克隆代码
|
||||
git clone https://github.com/cedar2025/Xboard.git ./
|
||||
|
||||
# 准备配置文件
|
||||
cp compose.sample.yaml compose.yaml
|
||||
|
||||
# 安装依赖并初始化
|
||||
docker compose run -it --rm web sh init.sh
|
||||
```
|
||||
> 安装完成后请保存返回的后台地址和管理员账号密码
|
||||
|
||||
3. 启动服务:
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
6. 设置反向代理
|
||||
> 站点设置 > 反向代理 > 添加反向代理
|
||||
>> 在 **代理名称** 填入 Xboard
|
||||
>> 在 **目标URL** 填入 ```http://127.0.0.1:7001```
|
||||
>> 修改反向代理规则为:
|
||||
```
|
||||
|
||||
4. 配置反向代理:
|
||||
```nginx
|
||||
location ^~ / {
|
||||
proxy_pass http://127.0.0.1:7001;
|
||||
proxy_http_version 1.1;
|
||||
@ -80,23 +79,14 @@ location ^~ / {
|
||||
}
|
||||
```
|
||||
|
||||
🎉: 到这里,你可以已经可以通过域名访问你的站点了
|
||||
### 4. 版本更新
|
||||
|
||||
⚠️: 请务必开启防火墙防止7001端口暴露到公网当中。
|
||||
```bash
|
||||
docker compose pull && docker compose up -d
|
||||
```
|
||||
|
||||
### 更新
|
||||
1. 更新代码
|
||||
>通过SSH登录到服务器后访问站点路径如:/www/wwwroot/你的站点域名。
|
||||
>以下命令都需要在站点目录进行执行。
|
||||
```
|
||||
docker compose pull
|
||||
docker compose run -it --rm xboard sh update.sh
|
||||
```
|
||||
2. 重启Xboard
|
||||
```
|
||||
docker compose restart
|
||||
```
|
||||
🎉: 在此你已完成Xboard的更新
|
||||
### 注意事项
|
||||
|
||||
### 注意
|
||||
启用webman后做的任何代码修改都需要重启生效
|
||||
- ⚠️ 请确保防火墙已开启,避免 7001 端口暴露到公网
|
||||
- 代码修改后需要重启服务才能生效
|
||||
- 建议配置 SSL 证书以确保安全访问
|
||||
|
@ -1,64 +1,66 @@
|
||||
## aapanel部署指南
|
||||
> 本文将教你如何使用aapanel进行部署
|
||||
## aaPanel 快速部署指南
|
||||
|
||||
<span style="color:red">⚠️:Centos7有部分反馈部署失败,请尽量避免使用Centos7进行部署</span>
|
||||
### 安装
|
||||
1. 安装aaPanel
|
||||
本指南介绍如何使用 aaPanel 部署 Xboard。
|
||||
|
||||
```
|
||||
URL=https://www.aapanel.com/script/install_6.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_6.0_en.sh "$URL";fi;bash install_6.0_en.sh aapanel
|
||||
⚠️ 不建议在 CentOS 7 上部署,可能会遇到兼容性问题。
|
||||
|
||||
### 1. 环境准备
|
||||
|
||||
安装 aaPanel:
|
||||
```bash
|
||||
URL=https://www.aapanel.com/script/install_6.0_en.sh && \
|
||||
if [ -f /usr/bin/curl ];then curl -ksSO "$URL" ;else wget --no-check-certificate -O install_6.0_en.sh "$URL";fi && \
|
||||
bash install_6.0_en.sh aapanel
|
||||
```
|
||||
|
||||
安装完成后我们登陆 aaPanel 进行环境的安装。
|
||||
2. 选择使用LNMP的环境安装方式勾选如下信息
|
||||
☑️ Nginx 任意版本
|
||||
☑️ MySQL 5.7
|
||||
☑️ PHP 8.1 (如果没看到8.1先不选,去App Store安装)
|
||||
选择 Fast 快速编译后进行安装。
|
||||
### 2. 环境配置
|
||||
|
||||
3. 安装扩展
|
||||
> aaPanel 面板 > App Store > 找到PHP 8.1点击Setting > Install extentions选择以下扩展进行安装
|
||||
- redis
|
||||
- fileinfo
|
||||
- swoole4
|
||||
- readline
|
||||
- event
|
||||
- inotify (可选,热重载依赖)
|
||||
1. 在 aaPanel 中安装 LNMP:
|
||||
- Nginx(任意版本)
|
||||
- MySQL 5.7
|
||||
- PHP 8.1
|
||||
|
||||
4. 解除被禁止函数
|
||||
> aaPanel 面板 > App Store > 找到PHP 8.1点击Setting > Disabled functions 将以下函数从列表中删除
|
||||
- putenv
|
||||
- proc_open
|
||||
- pcntl_alarm
|
||||
- pcntl_signal
|
||||
2. 安装 PHP 扩展:
|
||||
- redis
|
||||
- fileinfo
|
||||
- swoole4
|
||||
- readline
|
||||
- event
|
||||
|
||||
5. 添加站点
|
||||
>aaPanel 面板 > Website > Add site。
|
||||
>>在 Domain 填入你指向服务器的域名
|
||||
>>在 Database 选择MySQL
|
||||
>>在 PHP Verison 选择PHP-81
|
||||
3. 解除 PHP 禁用函数:
|
||||
- putenv
|
||||
- proc_open
|
||||
- pcntl_alarm
|
||||
- pcntl_signal
|
||||
|
||||
6. 安装 Xborad
|
||||
>通过SSH登录到服务器后访问站点路径如:/www/wwwroot/你的站点域名。
|
||||
>以下命令都需要在站点目录进行执行。
|
||||
```
|
||||
# 删除目录下文件
|
||||
### 3. 部署步骤
|
||||
|
||||
1. 添加站点:
|
||||
- 进入 aaPanel > Website > Add site
|
||||
- 填写域名
|
||||
- 数据库选择 MySQL
|
||||
- PHP 版本选择 8.1
|
||||
|
||||
2. 安装 Xboard:
|
||||
```bash
|
||||
# 进入站点目录
|
||||
cd /www/wwwroot/你的域名
|
||||
|
||||
# 清理目录
|
||||
chattr -i .user.ini
|
||||
rm -rf .htaccess 404.html 502.html index.html .user.ini
|
||||
```
|
||||
> 执行命令从 Github 克隆到当前目录。
|
||||
```
|
||||
git clone https://github.com/cedar2025/Xboard.git ./
|
||||
```
|
||||
> 执行命令安装依赖包以及V2board
|
||||
```
|
||||
|
||||
# 克隆代码
|
||||
git clone -b new https://github.com/cedar2025/Xboard.git ./
|
||||
|
||||
# 安装依赖
|
||||
sh init.sh
|
||||
```
|
||||
> 根据提示完成安装
|
||||
7. 配置站点目录及伪静态
|
||||
> 添加完成后编辑添加的站点 > Site directory > Running directory 选择 /public 保存。
|
||||
> 添加完成后编辑添加的站点 > URL rewrite 填入伪静态信息。
|
||||
```
|
||||
|
||||
3. 配置站点:
|
||||
- 设置运行目录为 `/public`
|
||||
- 配置伪静态规则:
|
||||
```nginx
|
||||
location /downloads {
|
||||
}
|
||||
|
||||
@ -73,82 +75,70 @@ location ~ .*\.(js|css)?$
|
||||
access_log /dev/null;
|
||||
}
|
||||
```
|
||||
8. 配置守护进程
|
||||
>Xboard的系统强依赖队列服务,正常使用XBoard必须启动队列服务。下面以aaPanel中supervisor服务来守护队列服务作为演示。
|
||||
- 1️⃣. aaPanel 面板 > App Store > Tools
|
||||
- 2️⃣. 找到Supervisor进行安装,安装完成后点击设置 > Add Daemon按照如下填写
|
||||
- - 在 Name 填写 `Xboard`
|
||||
- - 在 Run User 选择 www
|
||||
- - 在 Run Dir 选择 站点目录 在 Start Command 填写 `php artisan horizon` 在 Processes 填写 1
|
||||
|
||||
>填写后点击Confirm添加即可运行。
|
||||
4. 配置守护进程:
|
||||
- 安装 Supervisor
|
||||
- 添加队列守护进程:
|
||||
- 名称:`Xboard`
|
||||
- 运行用户:`www`
|
||||
- 运行目录:站点目录
|
||||
- 启动命令:`php artisan horizon`
|
||||
- 进程数:1
|
||||
|
||||
9. 配置定时任务#
|
||||
aaPanel 面板 > Cron。
|
||||
- 在 Type of Task 选择 Shell Script
|
||||
- 在 Name of Task 填写 v2board
|
||||
- 在 Period 选择 N Minutes 1 Minute
|
||||
- 在 Script content 填写 `php /www/wwwroot/路径/artisan schedule:run`
|
||||
5. 添加计划任务:
|
||||
- 类型:Shell Script
|
||||
- 任务名:v2board
|
||||
- 周期:1分钟
|
||||
- 脚本内容:`php /www/wwwroot/站点目录/artisan schedule:run`
|
||||
|
||||
根据上述信息添加每1分钟执行一次的定时任务。
|
||||
### 4. 开启 Octane(可选)
|
||||
|
||||
|
||||
### 开启webman
|
||||
> 在上述安装的基础上开启webman提高性能
|
||||
|
||||
1. 配置php.ini
|
||||
> 通过SSH登录到服务器后访问站点路径如:/www/wwwroot/你的站点域名。
|
||||
```
|
||||
1. 配置 PHP:
|
||||
```bash
|
||||
cp /www/server/php/81/etc/php.ini cli-php.ini
|
||||
|
||||
sed -i 's/^disable_functions[[:space:]]*=[[:space:]]*.*/disable_functions=header,header_remove,headers_sent,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,set_time_limit/g' cli-php.ini
|
||||
|
||||
```
|
||||
2. 添加守护进程
|
||||
>下面以aaPanel中supervisor服务来守护队列服务作为演示。
|
||||
- 1️⃣. aaPanel 面板 > App Store > Tools
|
||||
- 2️⃣. 找到Supervisor进行安装,安装完成后点击设置 > Add Daemon按照如下填写
|
||||
- - 在 Name 填写 webman
|
||||
- - 在 Run User 选择 www
|
||||
- - 在 Run Dir 选择 站点目录 在 Start Command 填写 ```/www/server/php/81/bin/php -c cli-php.ini webman.php start``` 在 Processes 填写 1
|
||||
>填写后点击Confirm添加即可运行。
|
||||
|
||||
3. 修改伪静态
|
||||
> 站点设置 > URL Rewrite(伪静态) 填入一下内容<span style="color:red">(覆盖前伪静态配置)</span>
|
||||
2. 添加 Octane 守护进程:
|
||||
- 名称:Octane
|
||||
- 运行用户:www
|
||||
- 运行目录:站点目录
|
||||
- 启动命令:`/www/server/php/81/bin/php artisan octane:start --port 7010`
|
||||
- 进程数:1
|
||||
|
||||
```
|
||||
3. 更新伪静态规则:
|
||||
```nginx
|
||||
location ~* \.(jpg|jpeg|png|gif|js|css|svg|woff2|woff|ttf|eot|wasm|json|ico)$ {
|
||||
|
||||
}
|
||||
|
||||
location ~ .* {
|
||||
proxy_pass http://127.0.0.1:7010;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Real-PORT $remote_port;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Scheme $scheme;
|
||||
proxy_set_header Server-Protocol $server_protocol;
|
||||
proxy_set_header Server-Name $server_name;
|
||||
proxy_set_header Server-Addr $server_addr;
|
||||
proxy_set_header Server-Port $server_port;
|
||||
}
|
||||
proxy_pass http://127.0.0.1:7010;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Real-PORT $remote_port;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header Scheme $scheme;
|
||||
proxy_set_header Server-Protocol $server_protocol;
|
||||
proxy_set_header Server-Name $server_name;
|
||||
proxy_set_header Server-Addr $server_addr;
|
||||
proxy_set_header Server-Port $server_port;
|
||||
}
|
||||
```
|
||||
|
||||
> 在此你的webman已经成功部署了
|
||||
### 5. 版本更新
|
||||
|
||||
### 更新
|
||||
|
||||
1. 更新代码
|
||||
> 通过SSH登录到服务器后访问站点路径如:/www/wwwroot/你的站点域名。
|
||||
```
|
||||
```bash
|
||||
# 更新代码
|
||||
cd /www/wwwroot/你的域名
|
||||
sh update.sh
|
||||
|
||||
# 如果启用了 Octane,需要重启守护进程
|
||||
# aaPanel > App Store > Tools > Supervisor > 重启 Octane
|
||||
```
|
||||
2. 重启webman 守护进程(如果启用了webman)
|
||||
- 1️⃣. aaPanel 面板 > App Store > Tools
|
||||
- 2️⃣. 找到Supervisor点击设置,找到名为webman的守护进程点击重启即可
|
||||
|
||||
### 注意事项
|
||||
|
||||
### 注意
|
||||
启用webman后做的任何代码修改都需要重启生效
|
||||
- 修改后台路径需要重启服务才能生效
|
||||
- 启用 octane 后的任何代码修改都需要重启才能生效
|
||||
|
@ -1,36 +1,54 @@
|
||||
#### config/v2board.php 迁移
|
||||
> xboard将配置储存到数据库了, 不再使用file进行储存,你需要对配置文件进行迁移。
|
||||
#### docker-compose 环境
|
||||
1. 在xboard 目录下创建 config文件夹
|
||||
2. 复制旧项目的 v2board.php 到config目录
|
||||
3. 修改docker-compose.yaml 取消下面代码的注释(删除 "#")
|
||||
```
|
||||
# - ./config/v2board.php:/www/config/v2board.php
|
||||
```
|
||||
4. 执行下面的命令即可完成迁移
|
||||
```
|
||||
docker compose down
|
||||
docker compose run -it --rm xboard php artisan migrateFromV2b config
|
||||
docker compose up -d
|
||||
```
|
||||
#### aapanel 环境
|
||||
1. 将旧的 ```config/v2board.php``` 文件复制到 xboard的 ```config/v2board.php``` 下
|
||||
2. 执行下面的命令,即可完成迁移
|
||||
```
|
||||
php artisan migrateFromV2b config
|
||||
```
|
||||
### aapanel + docker 环境
|
||||
1. 将旧的 ```config/v2board.php``` 文件复制到 xboard的 ```config/v2board.php``` 下
|
||||
2. 执行下面的命令,即可完成迁移
|
||||
```
|
||||
docker compose down
|
||||
docker compose run -it --rm xboard php artisan migrateFromV2b config
|
||||
docker compose up -d
|
||||
## 配置迁移指南
|
||||
|
||||
本指南介绍如何将 v2board 的配置文件迁移到 Xboard。Xboard 使用数据库存储配置,不再使用文件存储。
|
||||
|
||||
### 1. Docker Compose 环境
|
||||
|
||||
1. 准备配置文件:
|
||||
```bash
|
||||
# 创建配置目录
|
||||
mkdir config
|
||||
|
||||
# 复制旧配置文件
|
||||
cp 旧项目路径/config/v2board.php config/
|
||||
```
|
||||
|
||||
## 注意
|
||||
> 修改后台路径需要重启才能生效
|
||||
2. 修改 `docker-compose.yaml`,取消以下行的注释:
|
||||
```yaml
|
||||
- ./config/v2board.php:/www/config/v2board.php
|
||||
```
|
||||
docker compose restart
|
||||
|
||||
3. 执行迁移:
|
||||
```bash
|
||||
docker compose run -it --rm web php artisan migrateFromV2b config
|
||||
```
|
||||
> 如果是是aapanel安装则需要重启 webman守护进程
|
||||
|
||||
### 2. aaPanel 环境
|
||||
|
||||
1. 复制配置文件:
|
||||
```bash
|
||||
cp 旧项目路径/config/v2board.php config/v2board.php
|
||||
```
|
||||
|
||||
2. 执行迁移:
|
||||
```bash
|
||||
php artisan migrateFromV2b config
|
||||
```
|
||||
|
||||
### 3. aaPanel + Docker 环境
|
||||
|
||||
1. 复制配置文件:
|
||||
```bash
|
||||
cp 旧项目路径/config/v2board.php config/v2board.php
|
||||
```
|
||||
|
||||
2. 执行迁移:
|
||||
```bash
|
||||
docker compose run -it --rm web php artisan migrateFromV2b config
|
||||
```
|
||||
|
||||
### 注意事项
|
||||
|
||||
- 修改后台路径后需要重启服务:
|
||||
- Docker 环境:`docker compose restart`
|
||||
- aaPanel 环境:重启 Octane 守护进程
|
||||
|
@ -1,77 +1,66 @@
|
||||
## Docker-Compose 部署教程
|
||||
本文教你如何在命令行使用docker-compose + sqlite来快速部署Xboard
|
||||
如果你需要使用Mysql,你需要自行处理好Mysql的安装。
|
||||
### 部署 (使用docker-compose 2分钟部署)
|
||||
> 在此提供Xboard安装、快速体验Xboard的步骤。
|
||||
使用docker compose + sqlite 快速部署站点(**无需安装Mysql以及redis**)
|
||||
1. 安装docker
|
||||
```
|
||||
## Docker Compose 快速部署指南
|
||||
|
||||
本指南介绍如何使用 Docker Compose 快速部署 Xboard。默认使用 SQLite 数据库,无需额外安装 MySQL。
|
||||
|
||||
### 1. 环境准备
|
||||
|
||||
安装 Docker:
|
||||
```bash
|
||||
curl -sSL https://get.docker.com | bash
|
||||
```
|
||||
Centos系统可能需要执行下面命令来启动Docker。
|
||||
```
|
||||
|
||||
# CentOS 系统需要执行:
|
||||
systemctl enable docker
|
||||
systemctl start docker
|
||||
```
|
||||
2. 获取Docker compose 文件
|
||||
```
|
||||
git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard
|
||||
|
||||
### 2. 部署步骤
|
||||
|
||||
1. 获取项目文件:
|
||||
```bash
|
||||
git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard
|
||||
cd Xboard
|
||||
```
|
||||
3. 执行数据库安装命令
|
||||
> 选择 **启用sqlite** 和 **Docker内置的Redis**
|
||||
```
|
||||
docker compose run -it --rm -e enable_sqlite=true -e enable_redis=true -e admin_account=your_admin_email@example.com xboard php artisan xboard:install
|
||||
```
|
||||
> 或者根据自己的需要在运行时选择
|
||||
```
|
||||
docker compose run -it --rm xboard php artisan xboard:install
|
||||
```
|
||||
> 执行这条命令之后,会返回你的后台地址和管理员账号密码(你需要记录下来)
|
||||
> 你需要执行下面的 **启动xborad** 步骤之后才能访问后台
|
||||
|
||||
4. 启动Xboard
|
||||
2. 安装数据库:
|
||||
```bash
|
||||
# 快速安装(推荐新手使用)
|
||||
docker compose run -it --rm \
|
||||
-e enable_sqlite=true \
|
||||
-e enable_redis=true \
|
||||
-e admin_account=admin@demo.com \
|
||||
web php artisan xboard:install
|
||||
|
||||
# 自定义配置安装(高级用户)
|
||||
docker compose run -it --rm web php artisan xboard:install
|
||||
```
|
||||
> 安装完成后请保存返回的后台地址和管理员账号密码
|
||||
|
||||
3. 启动服务:
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
> 安装完成之后即可访问你的站点
|
||||
5. 访问站点
|
||||
> 启动之后网站端口默认为7001, 你可以配置nginx反向代理使用80端口
|
||||
|
||||
网站地址: http://你的IP:7001/
|
||||
在此你已经成功部署了, 你可以访问网址体验Xboard的完整功能,
|
||||
4. 访问站点:
|
||||
- 默认端口:7001
|
||||
- 网站地址:http://服务器IP:7001
|
||||
|
||||
> 如果你需要使用mysql,请自行安装Mysql后重新部署
|
||||
### 3. 版本更新
|
||||
|
||||
### **更新**
|
||||
1. 修改版本
|
||||
```
|
||||
```bash
|
||||
cd Xboard
|
||||
vi docker-compose.yaml
|
||||
```
|
||||
> 修改docker-compose.yaml 当中image后面的版本号为你需要的版本
|
||||
> 如果为版本为latest 则可以忽略这一步,直接进行第二步
|
||||
|
||||
2. 更新数据库(可以执行多次都是安全的)
|
||||
```
|
||||
docker compose pull
|
||||
docker compose down
|
||||
docker compose run -it --rm xboard php artisan xboard:update
|
||||
docker compose up -d
|
||||
```
|
||||
> 即可更新成功
|
||||
|
||||
### **回滚**
|
||||
> 此回滚不回滚数据库,是否回滚数据库请查看相关文档
|
||||
1. 回退版本
|
||||
```
|
||||
vi docker-compose.yaml
|
||||
```
|
||||
> 修改docker-compose.yaml 当中image后面的版本号为更新前的版本号
|
||||
2. 启动
|
||||
```
|
||||
docker compose run -it --rm web php artisan xboard:update
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 注意
|
||||
启用webman后做的任何代码修改都需要重启生效
|
||||
### 4. 版本回滚
|
||||
|
||||
1. 修改 `docker-compose.yaml` 中的版本号为需要回滚的版本
|
||||
2. 执行:`docker compose up -d`
|
||||
|
||||
### 注意事项
|
||||
|
||||
- 如需使用 MySQL,请自行安装并重新部署
|
||||
- 代码修改后需要重启服务才能生效
|
||||
- 可以配置 Nginx 反向代理使用 80 端口
|
||||
|
@ -1,59 +1,63 @@
|
||||
## V2borad 1.7.3版本迁移指南
|
||||
## V2board 1.7.3 迁移指南
|
||||
|
||||
### 迁移脚本会对你的数据库做以下更改
|
||||
- v2_stat_order 更名为 v2_stat
|
||||
- 字段 `order_amount` 修改为 `order_total`
|
||||
- 字段 `commission_amount` 修改为 `commission_total`
|
||||
- 添加 `paid_count` 字段 类型 integer nullable
|
||||
- 添加 `paid_total` 字段 类型 integer nullable
|
||||
- 添加 `register_count` 字段 类型 integer nullable
|
||||
- 添加 `invite_count` 字段 类型 integer nullable
|
||||
- 添加 `transfer_used_total` 字段 类型 string 长度 32 nullable
|
||||
本指南介绍如何将 V2board 1.7.3 版本迁移到 Xboard。
|
||||
|
||||
- 添加 v2_log 数据表
|
||||
- 添加 v2_server_hysteria 数据表
|
||||
- 添加 v2_server_vless 数据表
|
||||
### 1. 数据库变更说明
|
||||
|
||||
## 迁移之前
|
||||
迁移之前你需要执行正常安装步骤(记得不可选择Sqlite)
|
||||
> sqlite迁移请自行学习相关知识
|
||||
- [Docker Compose 纯命令行快速部署](./docs/docker-compose安装指南.md)
|
||||
- [aapanel + Docker Compose](./docs/aapanel+docker安装指南.md)
|
||||
- [aapanel 部署](./docs/)
|
||||
- `v2_stat_order` 表更名为 `v2_stat`:
|
||||
- `order_amount` → `order_total`
|
||||
- `commission_amount` → `commission_total`
|
||||
- 新增字段:
|
||||
- `paid_count` (integer, nullable)
|
||||
- `paid_total` (integer, nullable)
|
||||
- `register_count` (integer, nullable)
|
||||
- `invite_count` (integer, nullable)
|
||||
- `transfer_used_total` (string(32), nullable)
|
||||
|
||||
## 开始迁移
|
||||
> 针对docker与非docker用户提供不同的迁移步骤,你根据你的安装环境选择其一即可。
|
||||
- 新增数据表:
|
||||
- `v2_log`
|
||||
- `v2_server_hysteria`
|
||||
- `v2_server_vless`
|
||||
|
||||
### docker 环境
|
||||
> 以下命令需要你打开SSH进入到项目目录进行执行
|
||||
1. 停止Xboard
|
||||
```
|
||||
### 2. 准备工作
|
||||
|
||||
⚠️ 请先完成 Xboard 基础安装(不支持 SQLite):
|
||||
- [Docker Compose 部署](./docker-compose安装指南.md)
|
||||
- [aaPanel + Docker 部署](./aapanel+docker安装指南.md)
|
||||
- [aaPanel 部署](./aapanel安装指南.md)
|
||||
|
||||
### 3. 迁移步骤
|
||||
|
||||
#### Docker 环境
|
||||
|
||||
```bash
|
||||
# 1. 停止服务
|
||||
docker compose down
|
||||
```
|
||||
2. 清空数据库
|
||||
```
|
||||
docker compose run -it --rm xboard php artisan db:wipe
|
||||
```
|
||||
3. 导入旧数据库<span style="color:red">(重要)</span>
|
||||
>导入你1.7.3 v2board的数据库到当前数据库当中
|
||||
|
||||
4. 执行迁移命令
|
||||
```
|
||||
docker compose run -it --rm xboard php artisan migratefromv2b 1.7.3
|
||||
```
|
||||
## aapanel 环境
|
||||
1. 清空数据库
|
||||
# 2. 清空数据库
|
||||
docker compose run -it --rm web php artisan db:wipe
|
||||
|
||||
# 3. 导入旧数据库(重要)
|
||||
# 请手动导入 V2board 1.7.3 的数据库
|
||||
|
||||
# 4. 执行迁移
|
||||
docker compose run -it --rm web php artisan migratefromv2b 1.7.3
|
||||
```
|
||||
|
||||
#### aaPanel 环境
|
||||
|
||||
```bash
|
||||
# 1. 清空数据库
|
||||
php artisan db:wipe
|
||||
```
|
||||
2. 导入导入旧数据库<span style="color:red">(重要)</span>数据库
|
||||
>导入你1.7.3 v2board的数据库到当前数据库当中
|
||||
|
||||
3. 执行迁移命令
|
||||
```
|
||||
# 2. 导入旧数据库(重要)
|
||||
# 请手动导入 V2board 1.7.3 的数据库
|
||||
|
||||
# 3. 执行迁移
|
||||
php artisan migratefromv2b 1.7.3
|
||||
```
|
||||
|
||||
> 上述迁移完成之后你需要进行 配置文件迁移
|
||||
## config/v2board.php 配置文件迁移 [点击查看步骤](./config迁移指南.md)
|
||||
> xboard将配置储存到数据库, 不再使用file进行储存,你需要对配置文件进行迁移。
|
||||
### 4. 配置迁移
|
||||
|
||||
完成数据迁移后,还需要迁移配置文件:
|
||||
- [配置迁移指南](./config迁移指南.md)
|
||||
|
@ -1,48 +1,51 @@
|
||||
## V2borad 1.7.4版本迁移指南
|
||||
## V2board 1.7.4 迁移指南
|
||||
|
||||
### 迁移脚本会对你的数据库做以下更改
|
||||
- 添加 v2_server_vless 数据表
|
||||
本指南介绍如何将 V2board 1.7.4 版本迁移到 Xboard。
|
||||
|
||||
## 迁移之前
|
||||
迁移之前你需要执行正常安装步骤(记得不可选择Sqlite)
|
||||
> sqlite迁移请自行学习相关知识
|
||||
- [Docker Compose 纯命令行快速部署](./docs/docker-compose安装指南.md)
|
||||
- [aapanel + Docker Compose](./docs/aapanel+docker安装指南.md)
|
||||
- [aapanel 部署](./docs/)
|
||||
### 1. 数据库变更说明
|
||||
|
||||
## 开始迁移
|
||||
> 针对docker与非docker用户提供不同的迁移步骤,你根据你的安装环境选择其一即可。
|
||||
- 新增数据表:
|
||||
- `v2_server_vless`
|
||||
|
||||
### docker 环境
|
||||
> 以下命令需要你打开SSH进入到项目目录进行执行
|
||||
1. 停止Xboard
|
||||
```
|
||||
### 2. 准备工作
|
||||
|
||||
⚠️ 请先完成 Xboard 基础安装(不支持 SQLite):
|
||||
- [Docker Compose 部署](./docker-compose安装指南.md)
|
||||
- [aaPanel + Docker 部署](./aapanel+docker安装指南.md)
|
||||
- [aaPanel 部署](./aapanel安装指南.md)
|
||||
|
||||
### 3. 迁移步骤
|
||||
|
||||
#### Docker 环境
|
||||
|
||||
```bash
|
||||
# 1. 停止服务
|
||||
docker compose down
|
||||
```
|
||||
2. 清空数据库
|
||||
```
|
||||
docker compose run -it --rm xboard php artisan db:wipe
|
||||
```
|
||||
3. 导入旧数据库<span style="color:red">(重要)</span>
|
||||
>导入你1.7.4 v2board的数据库到当前项目数据库当中
|
||||
|
||||
4. 执行迁移命令
|
||||
```
|
||||
docker compose run -it --rm xboard php artisan migratefromv2b 1.7.4
|
||||
```
|
||||
## aapanel 环境
|
||||
1. 清空数据库
|
||||
# 2. 清空数据库
|
||||
docker compose run -it --rm web php artisan db:wipe
|
||||
|
||||
# 3. 导入旧数据库(重要)
|
||||
# 请手动导入 V2board 1.7.4 的数据库
|
||||
|
||||
# 4. 执行迁移
|
||||
docker compose run -it --rm web php artisan migratefromv2b 1.7.4
|
||||
```
|
||||
|
||||
#### aaPanel 环境
|
||||
|
||||
```bash
|
||||
# 1. 清空数据库
|
||||
php artisan db:wipe
|
||||
```
|
||||
2. 导入旧数据库<span style="color:red">(重要)</span>数据库
|
||||
>导入你1.7.4 v2board的数据库到当前项目数据库当中
|
||||
|
||||
3. 执行迁移命令
|
||||
```
|
||||
# 2. 导入旧数据库(重要)
|
||||
# 请手动导入 V2board 1.7.4 的数据库
|
||||
|
||||
# 3. 执行迁移
|
||||
php artisan migratefromv2b 1.7.4
|
||||
```
|
||||
|
||||
> 上述迁移完成之后你需要进行 配置文件迁移
|
||||
## config/v2board.php 配置文件迁移 [点击查看步骤](./config迁移指南.md)
|
||||
> xboard将配置储存到数据库, 不再使用file进行储存,你需要对配置文件进行迁移。
|
||||
### 4. 配置迁移
|
||||
|
||||
完成数据迁移后,还需要迁移配置文件:
|
||||
- [配置迁移指南](./config迁移指南.md)
|
@ -1,56 +1,61 @@
|
||||
## V2borad Dev版本迁移指南
|
||||
> 请先按照官方升级指导升级到 2023/10/27的版本后再执行迁移操作
|
||||
## V2board Dev 迁移指南
|
||||
|
||||
### 迁移脚本会对你的数据库做以下更改
|
||||
- v2_order
|
||||
- 添加 `surplus_order_ids` 字段 类型 text nullable 折抵订单
|
||||
- v2_plan(影响功能:周期价值、 流量价值)
|
||||
- 删除 `daily_unit_price` 字段
|
||||
- 删除 `transfer_unit_price` 字段
|
||||
- v2_server_hysteria (影响:Ignore Client Bandwidth 配置和混淆类型配置)
|
||||
- 删除 `ignore_client_bandwidth` 字段
|
||||
- 删除 `obfs_type` 字段
|
||||
本指南介绍如何将 V2board Dev(2023/10/27)版本迁移到 Xboard。
|
||||
|
||||
## 迁移之前
|
||||
迁移之前你需要执行正常安装步骤(记得不可选择Sqlite)
|
||||
> sqlite迁移请自行学习相关知识
|
||||
- [Docker Compose 纯命令行快速部署](./docs/docker-compose安装指南.md)
|
||||
- [aapanel + Docker Compose](./docs/aapanel+docker安装指南.md)
|
||||
- [aapanel 部署](./docs/)
|
||||
⚠️ 请先按照官方指南升级到 2023/10/27 版本后再执行迁移。
|
||||
|
||||
## 开始迁移
|
||||
> 针对docker与非docker用户提供不同的迁移步骤,你根据你的安装环境选择其一即可。
|
||||
### 1. 数据库变更说明
|
||||
|
||||
### docker 环境
|
||||
> 以下命令需要你打开SSH进入到项目目录进行执行
|
||||
1. 停止Xboard
|
||||
```
|
||||
- `v2_order` 表:
|
||||
- 新增 `surplus_order_ids` (text, nullable) - 折抵订单
|
||||
|
||||
- `v2_plan` 表:
|
||||
- 删除 `daily_unit_price` - 影响周期价值
|
||||
- 删除 `transfer_unit_price` - 影响流量价值
|
||||
|
||||
- `v2_server_hysteria` 表:
|
||||
- 删除 `ignore_client_bandwidth` - 影响带宽配置
|
||||
- 删除 `obfs_type` - 影响混淆类型配置
|
||||
|
||||
### 2. 准备工作
|
||||
|
||||
⚠️ 请先完成 Xboard 基础安装(不支持 SQLite):
|
||||
- [Docker Compose 部署](./docker-compose安装指南.md)
|
||||
- [aaPanel + Docker 部署](./aapanel+docker安装指南.md)
|
||||
- [aaPanel 部署](./aapanel安装指南.md)
|
||||
|
||||
### 3. 迁移步骤
|
||||
|
||||
#### Docker 环境
|
||||
|
||||
```bash
|
||||
# 1. 停止服务
|
||||
docker compose down
|
||||
```
|
||||
2. 清空数据库
|
||||
```
|
||||
docker compose run -it --rm xboard php artisan db:wipe
|
||||
```
|
||||
3. 导入旧数据库<span style="color:red">(重要)</span>数据库
|
||||
>导入你dev v2board的数据库到当前数据库当中
|
||||
|
||||
4. 执行迁移命令
|
||||
```
|
||||
docker compose run -it --rm xboard php artisan migratefromv2b dev231027
|
||||
```
|
||||
## aapanel 环境
|
||||
1. 清空数据库
|
||||
# 2. 清空数据库
|
||||
docker compose run -it --rm web php artisan db:wipe
|
||||
|
||||
# 3. 导入旧数据库(重要)
|
||||
# 请手动导入 V2board Dev 的数据库
|
||||
|
||||
# 4. 执行迁移
|
||||
docker compose run -it --rm web php artisan migratefromv2b dev231027
|
||||
```
|
||||
|
||||
#### aaPanel 环境
|
||||
|
||||
```bash
|
||||
# 1. 清空数据库
|
||||
php artisan db:wipe
|
||||
```
|
||||
2. 导入旧数据库<span style="color:red">(重要)</span>数据库
|
||||
>导入你dev v2board的数据库到当前数据库当中
|
||||
|
||||
3. 执行迁移命令
|
||||
```
|
||||
# 2. 导入旧数据库(重要)
|
||||
# 请手动导入 V2board Dev 的数据库
|
||||
|
||||
# 3. 执行迁移
|
||||
php artisan migratefromv2b dev231027
|
||||
```
|
||||
|
||||
> 上述迁移完成之后你需要进行 配置文件迁移
|
||||
## config/v2board.php 配置文件迁移 [点击查看步骤](./config迁移指南.md)
|
||||
> xboard将配置储存到数据库, 不再使用file进行储存,你需要对配置文件进行迁移。
|
||||
### 4. 配置迁移
|
||||
|
||||
完成数据迁移后,还需要迁移配置文件:
|
||||
- [配置迁移指南](./config迁移指南.md)
|
@ -1,62 +1,68 @@
|
||||
## V2borad wyx2685版本迁移指南
|
||||
> 此迁移指南写于 2023/11/17 , 其他时间的版本可能会迁移失败
|
||||
- wyx2685 添加了设备限制的功能,如果你迁移过来你会失去这个功能
|
||||
- 你会失去wyx2685佬添加的 trojan的 **(我也不知道) 功能
|
||||
- 你的hysteria2 线路需要重新配置
|
||||
## V2board wyx2685 迁移指南
|
||||
|
||||
### 迁移脚本会对你的数据库做以下更改
|
||||
- v2_plan
|
||||
- 删除字段 `device_limit` nullable
|
||||
- v2_server_hysteria
|
||||
- 删除字段 `version`
|
||||
- 删除字段 `obfs`
|
||||
- 删除字段 `obfs_password`
|
||||
- v2_server_trojan
|
||||
- 删除字段 `network`
|
||||
- 删除字段 `network_settings`
|
||||
- v2_user
|
||||
- 删除字段 `device_limit`
|
||||
本指南介绍如何将 V2board wyx2685(2023/11/17)版本迁移到 Xboard。
|
||||
|
||||
## 迁移之前
|
||||
迁移之前你需要执行正常安装步骤(记得不可选择Sqlite)
|
||||
> sqlite迁移请自行学习相关知识
|
||||
- [Docker Compose 纯命令行快速部署](./docs/docker-compose安装指南.md)
|
||||
- [aapanel + Docker Compose](./docs/aapanel+docker安装指南.md)
|
||||
- [aapanel 部署](./docs/)
|
||||
⚠️ 迁移注意事项:
|
||||
- 将失去设备限制功能
|
||||
- 将失去 Trojan 的特殊功能
|
||||
- Hysteria2 线路需要重新配置
|
||||
|
||||
## 开始迁移
|
||||
> 针对docker与非docker用户提供不同的迁移步骤,你根据你的安装环境选择其一即可。
|
||||
### 1. 数据库变更说明
|
||||
|
||||
### docker 环境
|
||||
> 以下命令需要你打开SSH进入到项目目录进行执行
|
||||
1. 停止Xboard
|
||||
```
|
||||
- `v2_plan` 表:
|
||||
- 删除 `device_limit` (nullable)
|
||||
|
||||
- `v2_server_hysteria` 表:
|
||||
- 删除 `version`
|
||||
- 删除 `obfs`
|
||||
- 删除 `obfs_password`
|
||||
|
||||
- `v2_server_trojan` 表:
|
||||
- 删除 `network`
|
||||
- 删除 `network_settings`
|
||||
|
||||
- `v2_user` 表:
|
||||
- 删除 `device_limit`
|
||||
|
||||
### 2. 准备工作
|
||||
|
||||
⚠️ 请先完成 Xboard 基础安装(不支持 SQLite):
|
||||
- [Docker Compose 部署](./docker-compose安装指南.md)
|
||||
- [aaPanel + Docker 部署](./aapanel+docker安装指南.md)
|
||||
- [aaPanel 部署](./aapanel安装指南.md)
|
||||
|
||||
### 3. 迁移步骤
|
||||
|
||||
#### Docker 环境
|
||||
|
||||
```bash
|
||||
# 1. 停止服务
|
||||
docker compose down
|
||||
```
|
||||
2. 清空数据库
|
||||
```
|
||||
docker compose run -it --rm xboard php artisan db:wipe
|
||||
```
|
||||
3. 导入旧数据库<span style="color:red">(重要)</span>数据库
|
||||
>导入你wyx2685 v2board的数据库到当前数据库当中
|
||||
|
||||
4. 执行迁移命令
|
||||
```
|
||||
docker compose run -it --rm xboard php artisan migratefromv2b wyx2685
|
||||
```
|
||||
## aapanel 环境
|
||||
1. 清空数据库
|
||||
# 2. 清空数据库
|
||||
docker compose run -it --rm web php artisan db:wipe
|
||||
|
||||
# 3. 导入旧数据库(重要)
|
||||
# 请手动导入 V2board wyx2685 的数据库
|
||||
|
||||
# 4. 执行迁移
|
||||
docker compose run -it --rm web php artisan migratefromv2b wyx2685
|
||||
```
|
||||
|
||||
#### aaPanel 环境
|
||||
|
||||
```bash
|
||||
# 1. 清空数据库
|
||||
php artisan db:wipe
|
||||
```
|
||||
2. 导入旧数据库<span style="color:red">(重要)</span>数据库
|
||||
>导入你wyx2685 v2board的数据库到当前数据库当中
|
||||
|
||||
3. 执行迁移命令
|
||||
```
|
||||
# 2. 导入旧数据库(重要)
|
||||
# 请手动导入 V2board wyx2685 的数据库
|
||||
|
||||
# 3. 执行迁移
|
||||
php artisan migratefromv2b wyx2685
|
||||
```
|
||||
|
||||
> 上述迁移完成之后你需要进行 配置文件迁移
|
||||
## config/v2board.php 配置文件迁移 [点击查看步骤](./config迁移指南.md)
|
||||
> xboard将配置储存到数据库, 不再使用file进行储存,你需要对配置文件进行迁移。
|
||||
### 4. 配置迁移
|
||||
|
||||
完成数据迁移后,还需要迁移配置文件:
|
||||
- [配置迁移指南](./config迁移指南.md)
|
@ -1 +0,0 @@
|
||||
import{j as a,a as s}from"./index-ra1jmRmU.js";import{h as l}from"./button-BkBuHKqj.js";import{I as n}from"./input-BJSapCFH.js";import{T as p}from"./textarea-C2MOf6wm.js";const x=(e,r)=>{let t=null;switch(e.field_type){case"input":t=a.jsx(n,{placeholder:e.placeholder,...r});break;case"textarea":t=a.jsx(p,{placeholder:e.placeholder,...r});break;case"select":t=a.jsx("select",{className:s(l({variant:"outline"}),"w-full appearance-none font-normal"),...r,children:e.select_options&&Object.keys(e.select_options).map(o=>a.jsx("option",{value:o,children:e.select_options?.[o]},o))});break;default:t=null;break}return t};export{x as D};
|
@ -1 +0,0 @@
|
||||
import{c as a}from"./index-ra1jmRmU.js";var e=a("adjustments","IconAdjustments",[["path",{d:"M4 10a2 2 0 1 0 4 0a2 2 0 0 0 -4 0",key:"svg-0"}],["path",{d:"M6 4v4",key:"svg-1"}],["path",{d:"M6 12v8",key:"svg-2"}],["path",{d:"M10 16a2 2 0 1 0 4 0a2 2 0 0 0 -4 0",key:"svg-3"}],["path",{d:"M12 4v10",key:"svg-4"}],["path",{d:"M12 18v2",key:"svg-5"}],["path",{d:"M16 7a2 2 0 1 0 4 0a2 2 0 0 0 -4 0",key:"svg-6"}],["path",{d:"M18 4v1",key:"svg-7"}],["path",{d:"M18 9v11",key:"svg-8"}]]),t=a("lock","IconLock",[["path",{d:"M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6z",key:"svg-0"}],["path",{d:"M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0",key:"svg-1"}],["path",{d:"M8 11v-4a4 4 0 1 1 8 0v4",key:"svg-2"}]]),s=a("server","IconServer",[["path",{d:"M3 4m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z",key:"svg-0"}],["path",{d:"M3 12m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v2a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z",key:"svg-1"}],["path",{d:"M7 8l0 .01",key:"svg-2"}],["path",{d:"M7 16l0 .01",key:"svg-3"}]]),h=a("ticket","IconTicket",[["path",{d:"M15 5l0 2",key:"svg-0"}],["path",{d:"M15 11l0 2",key:"svg-1"}],["path",{d:"M15 17l0 2",key:"svg-2"}],["path",{d:"M5 5h14a2 2 0 0 1 2 2v3a2 2 0 0 0 0 4v3a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-3a2 2 0 0 0 0 -4v-3a2 2 0 0 1 2 -2",key:"svg-3"}]]);export{t as I,h as a,s as b,e as c};
|
File diff suppressed because one or more lines are too long
11
public/assets/admin/assets/arrow-up-Cu4ezgY6.js
vendored
11
public/assets/admin/assets/arrow-up-Cu4ezgY6.js
vendored
@ -1,11 +0,0 @@
|
||||
import{c as r}from"./user-nav-Ch7kI57y.js";/**
|
||||
* @license lucide-react v0.399.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
* See the LICENSE file in the root directory of this source tree.
|
||||
*/const a=r("ArrowDown",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);/**
|
||||
* @license lucide-react v0.399.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
* See the LICENSE file in the root directory of this source tree.
|
||||
*/const e=r("ArrowUp",[["path",{d:"m5 12 7-7 7 7",key:"hav0vg"}],["path",{d:"M12 19V5",key:"x0mq9r"}]]);export{e as A,a};
|
@ -1,5 +0,0 @@
|
||||
import{r as i,v as y,j as n,z as _,a as f,x as Z}from"./index-ra1jmRmU.js";import{c as J,a as p,e as Q,u as X}from"./index-OwEZQf1t.js";import{P as b,R as ee,h as te,a as oe,F as ae,D as ne,u as h,b as se}from"./index-CmmzV1O3.js";import{P as m}from"./index-QSXu8nGm.js";import{a as re}from"./react-icons.esm-BRv52UVg.js";var N="Dialog",[E,Ie]=J(N),[ie,d]=E(N),w=e=>{const{__scopeDialog:t,children:o,open:s,defaultOpen:r,onOpenChange:a,modal:l=!0}=e,c=i.useRef(null),g=i.useRef(null),[v=!1,D]=X({prop:s,defaultProp:r,onChange:a});return n.jsx(ie,{scope:t,triggerRef:c,contentRef:g,contentId:h(),titleId:h(),descriptionId:h(),open:v,onOpenChange:D,onOpenToggle:i.useCallback(()=>D(Y=>!Y),[D]),modal:l,children:o})};w.displayName=N;var P="DialogTrigger",O=i.forwardRef((e,t)=>{const{__scopeDialog:o,...s}=e,r=d(P,o),a=y(t,r.triggerRef);return n.jsx(m.button,{type:"button","aria-haspopup":"dialog","aria-expanded":r.open,"aria-controls":r.contentId,"data-state":j(r.open),...s,ref:a,onClick:p(e.onClick,r.onOpenToggle)})});O.displayName=P;var C="DialogPortal",[le,I]=E(C,{forceMount:void 0}),T=e=>{const{__scopeDialog:t,forceMount:o,children:s,container:r}=e,a=d(C,t);return n.jsx(le,{scope:t,forceMount:o,children:i.Children.map(s,l=>n.jsx(b,{present:o||a.open,children:n.jsx(se,{asChild:!0,container:r,children:l})}))})};T.displayName=C;var x="DialogOverlay",A=i.forwardRef((e,t)=>{const o=I(x,e.__scopeDialog),{forceMount:s=o.forceMount,...r}=e,a=d(x,e.__scopeDialog);return a.modal?n.jsx(b,{present:s||a.open,children:n.jsx(ce,{...r,ref:t})}):null});A.displayName=x;var ce=i.forwardRef((e,t)=>{const{__scopeDialog:o,...s}=e,r=d(x,o);return n.jsx(ee,{as:_,allowPinchZoom:!0,shards:[r.contentRef],children:n.jsx(m.div,{"data-state":j(r.open),...s,ref:t,style:{pointerEvents:"auto",...s.style}})})}),u="DialogContent",M=i.forwardRef((e,t)=>{const o=I(u,e.__scopeDialog),{forceMount:s=o.forceMount,...r}=e,a=d(u,e.__scopeDialog);return n.jsx(b,{present:s||a.open,children:a.modal?n.jsx(de,{...r,ref:t}):n.jsx(ue,{...r,ref:t})})});M.displayName=u;var de=i.forwardRef((e,t)=>{const o=d(u,e.__scopeDialog),s=i.useRef(null),r=y(t,o.contentRef,s);return i.useEffect(()=>{const a=s.current;if(a)return te(a)},[]),n.jsx(F,{...e,ref:r,trapFocus:o.open,disableOutsidePointerEvents:!0,onCloseAutoFocus:p(e.onCloseAutoFocus,a=>{a.preventDefault(),o.triggerRef.current?.focus()}),onPointerDownOutside:p(e.onPointerDownOutside,a=>{const l=a.detail.originalEvent,c=l.button===0&&l.ctrlKey===!0;(l.button===2||c)&&a.preventDefault()}),onFocusOutside:p(e.onFocusOutside,a=>a.preventDefault())})}),ue=i.forwardRef((e,t)=>{const o=d(u,e.__scopeDialog),s=i.useRef(!1),r=i.useRef(!1);return n.jsx(F,{...e,ref:t,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:a=>{e.onCloseAutoFocus?.(a),a.defaultPrevented||(s.current||o.triggerRef.current?.focus(),a.preventDefault()),s.current=!1,r.current=!1},onInteractOutside:a=>{e.onInteractOutside?.(a),a.defaultPrevented||(s.current=!0,a.detail.originalEvent.type==="pointerdown"&&(r.current=!0));const l=a.target;o.triggerRef.current?.contains(l)&&a.preventDefault(),a.detail.originalEvent.type==="focusin"&&r.current&&a.preventDefault()}})}),F=i.forwardRef((e,t)=>{const{__scopeDialog:o,trapFocus:s,onOpenAutoFocus:r,onCloseAutoFocus:a,...l}=e,c=d(u,o),g=i.useRef(null),v=y(t,g);return oe(),n.jsxs(n.Fragment,{children:[n.jsx(ae,{asChild:!0,loop:!0,trapped:s,onMountAutoFocus:r,onUnmountAutoFocus:a,children:n.jsx(ne,{role:"dialog",id:c.contentId,"aria-describedby":c.descriptionId,"aria-labelledby":c.titleId,"data-state":j(c.open),...l,ref:v,onDismiss:()=>c.onOpenChange(!1)})}),n.jsxs(n.Fragment,{children:[n.jsx(fe,{titleId:c.titleId}),n.jsx(pe,{contentRef:g,descriptionId:c.descriptionId})]})]})}),R="DialogTitle",S=i.forwardRef((e,t)=>{const{__scopeDialog:o,...s}=e,r=d(R,o);return n.jsx(m.h2,{id:r.titleId,...s,ref:t})});S.displayName=R;var k="DialogDescription",$=i.forwardRef((e,t)=>{const{__scopeDialog:o,...s}=e,r=d(k,o);return n.jsx(m.p,{id:r.descriptionId,...s,ref:t})});$.displayName=k;var W="DialogClose",G=i.forwardRef((e,t)=>{const{__scopeDialog:o,...s}=e,r=d(W,o);return n.jsx(m.button,{type:"button",...s,ref:t,onClick:p(e.onClick,()=>r.onOpenChange(!1))})});G.displayName=W;function j(e){return e?"open":"closed"}var L="DialogTitleWarning",[Te,z]=Q(L,{contentName:u,titleName:R,docsSlug:"dialog"}),fe=({titleId:e})=>{const t=z(L),o=`\`${t.contentName}\` requires a \`${t.titleName}\` for the component to be accessible for screen reader users.
|
||||
|
||||
If you want to hide the \`${t.titleName}\`, you can wrap it with our VisuallyHidden component.
|
||||
|
||||
For more information, see https://radix-ui.com/primitives/docs/components/${t.docsSlug}`;return i.useEffect(()=>{e&&(document.getElementById(e)||console.error(o))},[o,e]),null},ge="DialogDescriptionWarning",pe=({contentRef:e,descriptionId:t})=>{const s=`Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${z(ge).contentName}}.`;return i.useEffect(()=>{const r=e.current?.getAttribute("aria-describedby");t&&r&&(document.getElementById(t)||console.warn(s))},[s,e,t]),null},me=w,xe=O,ve=T,B=A,H=M,V=S,q=$,K=G;const Ae=me,Me=xe,De=ve,Fe=K,U=i.forwardRef(({className:e,...t},o)=>n.jsx(B,{ref:o,className:f("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",e),...t}));U.displayName=B.displayName;const he=i.forwardRef(({className:e,children:t,...o},s)=>n.jsxs(De,{children:[n.jsx(U,{}),n.jsxs(H,{ref:s,className:f("max-h-[95%] overflow-auto fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",e),...o,children:[t,n.jsxs(K,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",children:[n.jsx(re,{className:"h-4 w-4"}),n.jsx("span",{className:"sr-only",children:"Close"})]})]})]}));he.displayName=H.displayName;const ye=({className:e,...t})=>n.jsx("div",{className:f("flex flex-col space-y-1.5 text-center sm:text-left",e),...t});ye.displayName="DialogHeader";const be=({className:e,...t})=>n.jsx("div",{className:f("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",e),...t});be.displayName="DialogFooter";const Ne=i.forwardRef(({className:e,...t},o)=>n.jsx(V,{ref:o,className:f("text-lg font-semibold leading-none tracking-tight",e),...t}));Ne.displayName=V.displayName;const Ce=i.forwardRef(({className:e,...t},o)=>n.jsx(q,{ref:o,className:f("text-sm text-muted-foreground",e),...t}));Ce.displayName=q.displayName;const Re=Z("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",{variants:{variant:{default:"bg-primary text-primary-foreground shadow hover:bg-primary/90",destructive:"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",outline:"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",secondary:"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-9 px-4 py-2",sm:"h-8 rounded-md px-3 text-xs",lg:"h-10 rounded-md px-8",icon:"h-9 w-9"}},defaultVariants:{variant:"default",size:"default"}}),je=i.forwardRef(({className:e,variant:t,size:o,asChild:s=!1,...r},a)=>{const l=s?_:"button";return n.jsx(l,{className:f(Re({variant:t,size:o,className:e})),ref:a,...r})});je.displayName="Button";export{je as B,H as C,Ae as D,B as O,ve as P,me as R,xe as T,Te as W,he as a,ye as b,Ne as c,Ce as d,Me as e,be as f,Fe as g,Re as h,Ie as i,V as j,q as k,K as l};
|
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/card-m9i8rs49.js
vendored
1
public/assets/admin/assets/card-m9i8rs49.js
vendored
@ -1 +0,0 @@
|
||||
import{r as s,j as d,a as t}from"./index-ra1jmRmU.js";const o=s.forwardRef(({className:a,...e},r)=>d.jsx("div",{ref:r,className:t("rounded-xl border bg-card text-card-foreground shadow",a),...e}));o.displayName="Card";const c=s.forwardRef(({className:a,...e},r)=>d.jsx("div",{ref:r,className:t("flex flex-col space-y-1.5 p-6",a),...e}));c.displayName="CardHeader";const i=s.forwardRef(({className:a,...e},r)=>d.jsx("h3",{ref:r,className:t("font-semibold leading-none tracking-tight",a),...e}));i.displayName="CardTitle";const n=s.forwardRef(({className:a,...e},r)=>d.jsx("p",{ref:r,className:t("text-sm text-muted-foreground",a),...e}));n.displayName="CardDescription";const l=s.forwardRef(({className:a,...e},r)=>d.jsx("div",{ref:r,className:t("p-6 pt-0",a),...e}));l.displayName="CardContent";const f=s.forwardRef(({className:a,...e},r)=>d.jsx("div",{ref:r,className:t("flex items-center p-6 pt-0",a),...e}));f.displayName="CardFooter";export{o as C,c as a,i as b,l as c,n as d};
|
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
import{r as n,j as c,v as O}from"./index-ra1jmRmU.js";import{c as T,u as S,a as D,b as M}from"./index-OwEZQf1t.js";import{P as m}from"./index-QSXu8nGm.js";import{u as $,P as L}from"./index-CmmzV1O3.js";var v="Collapsible",[k,K]=T(v),[F,g]=k(v),j=n.forwardRef((e,a)=>{const{__scopeCollapsible:r,open:s,defaultOpen:t,disabled:l,onOpenChange:i,...f}=e,[p=!1,d]=S({prop:s,defaultProp:t,onChange:i});return c.jsx(F,{scope:r,disabled:l,contentId:$(),open:p,onOpenToggle:n.useCallback(()=>d(C=>!C),[d]),children:c.jsx(m.div,{"data-state":R(p),"data-disabled":l?"":void 0,...f,ref:a})})});j.displayName=v;var w="CollapsibleTrigger",A=n.forwardRef((e,a)=>{const{__scopeCollapsible:r,...s}=e,t=g(w,r);return c.jsx(m.button,{type:"button","aria-controls":t.contentId,"aria-expanded":t.open||!1,"data-state":R(t.open),"data-disabled":t.disabled?"":void 0,disabled:t.disabled,...s,ref:a,onClick:D(e.onClick,t.onOpenToggle)})});A.displayName=w;var x="CollapsibleContent",I=n.forwardRef((e,a)=>{const{forceMount:r,...s}=e,t=g(x,e.__scopeCollapsible);return c.jsx(L,{present:r||t.open,children:({present:l})=>c.jsx(B,{...s,ref:a,present:l})})});I.displayName=x;var B=n.forwardRef((e,a)=>{const{__scopeCollapsible:r,present:s,children:t,...l}=e,i=g(x,r),[f,p]=n.useState(s),d=n.useRef(null),C=O(a,d),h=n.useRef(0),P=h.current,y=n.useRef(0),N=y.current,b=i.open||f,E=n.useRef(b),u=n.useRef(void 0);return n.useEffect(()=>{const o=requestAnimationFrame(()=>E.current=!1);return()=>cancelAnimationFrame(o)},[]),M(()=>{const o=d.current;if(o){u.current=u.current||{transitionDuration:o.style.transitionDuration,animationName:o.style.animationName},o.style.transitionDuration="0s",o.style.animationName="none";const _=o.getBoundingClientRect();h.current=_.height,y.current=_.width,E.current||(o.style.transitionDuration=u.current.transitionDuration,o.style.animationName=u.current.animationName),p(s)}},[i.open,s]),c.jsx(m.div,{"data-state":R(i.open),"data-disabled":i.disabled?"":void 0,id:i.contentId,hidden:!b,...l,ref:C,style:{"--radix-collapsible-content-height":P?`${P}px`:void 0,"--radix-collapsible-content-width":N?`${N}px`:void 0,...e.style},children:b&&t})});function R(e){return e?"open":"closed"}var G=j;const Q=G,U=A,V=I;export{Q as C,U as a,V as b};
|
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
import{d as f,C as l}from"./clipboard-Bl2zvJsv.js";import{t as s}from"./index-ra1jmRmU.js";const a=r=>r;function u(r=void 0,o="YYYY-MM-DD HH:mm:ss"){return r==null?"":(Math.floor(r).toString().length===10&&(r=r*1e3),f(r).format(o))}function b(r=void 0,o="YYYY-MM-DD"){return u(r,o)}function e(r){const o=typeof r=="string"?parseFloat(r):r;return isNaN(o)?"0.00":o.toFixed(2)}function p(r){const o=typeof r=="string"?parseFloat(r):r;return isNaN(o)?"0.00":(o/100).toFixed(2)}function D(r){navigator.clipboard?navigator.clipboard.writeText(r).then(()=>{s.success(a("复制成功"))}).catch(o=>{console.error("复制到剪贴板时出错:",o),i(r)}):i(r)}function i(r){const o=document.createElement("button"),t=new l(o,{text:()=>r});t.on("success",()=>{s.success(a("复制成功")),t.destroy()}),t.on("error",()=>{s.error(a("复制失败")),t.destroy()}),o.click()}function T(r){const o=r/1024,t=o/1024,n=t/1024,c=n/1024;return c>=1?e(c)+" TB":n>=1?e(n)+" GB":t>=1?e(t)+" MB":e(o)+" KB"}export{u as a,T as b,D as c,e as d,b as e,p as f};
|
@ -1 +0,0 @@
|
||||
import{c as s,j as e}from"./index-ra1jmRmU.js";import{I as i,a as t,b as a,c as r}from"./IconTicket-s_6DwrCY.js";var c=s("brand-telegram","IconBrandTelegram",[["path",{d:"M15 10l-4 4l6 6l4 -16l-18 7l4 2l2 6l3 -4",key:"svg-0"}]]),n=s("building","IconBuilding",[["path",{d:"M3 21l18 0",key:"svg-0"}],["path",{d:"M9 8l1 0",key:"svg-1"}],["path",{d:"M9 12l1 0",key:"svg-2"}],["path",{d:"M9 16l1 0",key:"svg-3"}],["path",{d:"M14 8l1 0",key:"svg-4"}],["path",{d:"M14 12l1 0",key:"svg-5"}],["path",{d:"M14 16l1 0",key:"svg-6"}],["path",{d:"M5 21v-16a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v16",key:"svg-7"}]]),o=s("mail","IconMail",[["path",{d:"M3 7a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-10z",key:"svg-0"}],["path",{d:"M3 7l9 6l9 -6",key:"svg-1"}]]),l=s("user-circle","IconUserCircle",[["path",{d:"M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0",key:"svg-0"}],["path",{d:"M12 10m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0",key:"svg-1"}],["path",{d:"M6.168 18.849a4 4 0 0 1 3.832 -2.849h4a4 4 0 0 1 3.834 2.855",key:"svg-2"}]]);const y=[{title:"站点设置",key:"site",icon:e.jsx(n,{size:18}),href:"/config/system",description:"配置站点基本信息,包括站点名称、描述、货币单位等核心设置。"},{title:"安全设置",key:"safe",icon:e.jsx(i,{size:18}),href:"/config/system/safe",description:"配置系统安全相关选项,包括登录验证、密码策略、API访问等安全设置。"},{title:"订阅设置",key:"subscribe",icon:e.jsx(t,{size:18}),href:"/config/system/subscribe",description:"管理用户订阅相关配置,包括订阅链接格式、更新频率、流量统计等设置。"},{title:"邀请&佣金",key:"invite",icon:e.jsx(l,{size:18}),href:"/config/system/invite",description:"管理用户邀请和佣金系统,配置邀请奖励、分销规则等。"},{title:"节点配置",key:"server",icon:e.jsx(a,{size:18}),href:"/config/system/server",description:"配置节点通信和同步设置,包括通信密钥、轮询间隔、负载均衡等高级选项。"},{title:"邮件设置",key:"email",icon:e.jsx(o,{size:18}),href:"/config/system/email",description:"配置系统邮件服务,用于发送验证码、密码重置、通知等邮件,支持多种SMTP服务商。"},{title:"Telegram设置",key:"telegram",icon:e.jsx(c,{size:18}),href:"/config/system/telegram",description:"配置Telegram机器人功能,实现用户通知、账户绑定、指令交互等自动化服务。"},{title:"APP设置",key:"app",icon:e.jsx(r,{size:18}),href:"/config/system/app",description:"管理移动应用程序相关配置,包括API接口、版本控制、推送通知等功能设置。"}];export{y as S};
|
@ -1,7 +0,0 @@
|
||||
import{r as l,j as o,v as A,y as q,a as i,B as u}from"./index-ra1jmRmU.js";import{c as J,a as K}from"./index-OwEZQf1t.js";import{i as x,T as Q,O as U,W as X,C as Z,j as ee,k as ae,l as D,R as te,P as oe,h as v}from"./button-BkBuHKqj.js";var N="AlertDialog",[re,ye]=J(N,[x]),n=x(),y=e=>{const{__scopeAlertDialog:a,...t}=e,r=n(a);return o.jsx(te,{...r,...t,modal:!0})};y.displayName=N;var se="AlertDialogTrigger",j=l.forwardRef((e,a)=>{const{__scopeAlertDialog:t,...r}=e,s=n(t);return o.jsx(Q,{...s,...r,ref:a})});j.displayName=se;var le="AlertDialogPortal",h=e=>{const{__scopeAlertDialog:a,...t}=e,r=n(a);return o.jsx(oe,{...r,...t})};h.displayName=le;var ie="AlertDialogOverlay",R=l.forwardRef((e,a)=>{const{__scopeAlertDialog:t,...r}=e,s=n(t);return o.jsx(U,{...s,...r,ref:a})});R.displayName=ie;var d="AlertDialogContent",[ne,ce]=re(d),C=l.forwardRef((e,a)=>{const{__scopeAlertDialog:t,children:r,...s}=e,p=n(t),c=l.useRef(null),m=A(a,c),f=l.useRef(null);return o.jsx(X,{contentName:d,titleName:_,docsSlug:"alert-dialog",children:o.jsx(ne,{scope:t,cancelRef:f,children:o.jsxs(Z,{role:"alertdialog",...p,...s,ref:m,onOpenAutoFocus:K(s.onOpenAutoFocus,g=>{g.preventDefault(),f.current?.focus({preventScroll:!0})}),onPointerDownOutside:g=>g.preventDefault(),onInteractOutside:g=>g.preventDefault(),children:[o.jsx(q,{children:r}),o.jsx(pe,{contentRef:c})]})})})});C.displayName=d;var _="AlertDialogTitle",w=l.forwardRef((e,a)=>{const{__scopeAlertDialog:t,...r}=e,s=n(t);return o.jsx(ee,{...s,...r,ref:a})});w.displayName=_;var E="AlertDialogDescription",b=l.forwardRef((e,a)=>{const{__scopeAlertDialog:t,...r}=e,s=n(t);return o.jsx(ae,{...s,...r,ref:a})});b.displayName=E;var de="AlertDialogAction",P=l.forwardRef((e,a)=>{const{__scopeAlertDialog:t,...r}=e,s=n(t);return o.jsx(D,{...s,...r,ref:a})});P.displayName=de;var T="AlertDialogCancel",S=l.forwardRef((e,a)=>{const{__scopeAlertDialog:t,...r}=e,{cancelRef:s}=ce(T,t),p=n(t),c=A(a,s);return o.jsx(D,{...p,...r,ref:c})});S.displayName=T;var pe=({contentRef:e})=>{const a=`\`${d}\` requires a description for the component to be accessible for screen reader users.
|
||||
|
||||
You can add a description to the \`${d}\` by passing a \`${E}\` component as a child, which also benefits sighted users by adding visible context to the dialog.
|
||||
|
||||
Alternatively, you can use your own component as a description by assigning it an \`id\` and passing the same value to the \`aria-describedby\` prop in \`${d}\`. If the description is confusing or duplicative for sighted users, you can use the \`@radix-ui/react-visually-hidden\` primitive as a wrapper around your description component.
|
||||
|
||||
For more information, see https://radix-ui.com/primitives/docs/components/alert-dialog`;return l.useEffect(()=>{document.getElementById(e.current?.getAttribute("aria-describedby"))||console.warn(a)},[a,e]),null},ge=y,me=j,fe=h,O=R,$=C,M=P,I=S,F=w,k=b;const ue=ge,Ae=me,xe=fe,z=l.forwardRef(({className:e,...a},t)=>o.jsx(O,{className:i("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",e),...a,ref:t}));z.displayName=O.displayName;const L=l.forwardRef(({className:e,...a},t)=>o.jsxs(xe,{children:[o.jsx(z,{}),o.jsx($,{ref:t,className:i("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",e),...a})]}));L.displayName=$.displayName;const B=({className:e,...a})=>o.jsx("div",{className:i("flex flex-col space-y-2 text-center sm:text-left",e),...a});B.displayName="AlertDialogHeader";const G=({className:e,...a})=>o.jsx("div",{className:i("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",e),...a});G.displayName="AlertDialogFooter";const H=l.forwardRef(({className:e,...a},t)=>o.jsx(F,{ref:t,className:i("text-lg font-semibold",e),...a}));H.displayName=F.displayName;const W=l.forwardRef(({className:e,...a},t)=>o.jsx(k,{ref:t,className:i("text-sm text-muted-foreground",e),...a}));W.displayName=k.displayName;const V=l.forwardRef(({className:e,...a},t)=>o.jsx(M,{ref:t,className:i(v(),e),...a}));V.displayName=M.displayName;const Y=l.forwardRef(({className:e,...a},t)=>o.jsx(I,{ref:t,className:i(v({variant:"outline"}),"mt-2 sm:mt-0",e),...a}));Y.displayName=I.displayName;function je({onConfirm:e,children:a,title:t="确认操作",description:r="确定要执行此操作吗?",cancelText:s="取消",confirmText:p="确认",variant:c="default",className:m}){return o.jsxs(ue,{children:[o.jsx(Ae,{asChild:!0,children:a}),o.jsxs(L,{className:i("sm:max-w-[425px]",m),children:[o.jsxs(B,{children:[o.jsx(H,{children:t}),o.jsx(W,{children:r})]}),o.jsxs(G,{children:[o.jsx(Y,{asChild:!0,children:o.jsx(u,{variant:"outline",children:s})}),o.jsx(V,{asChild:!0,children:o.jsx(u,{variant:c,onClick:e,children:p})})]})]})]})}export{je as C};
|
@ -1,6 +0,0 @@
|
||||
import{c}from"./user-nav-Ch7kI57y.js";/**
|
||||
* @license lucide-react v0.399.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
* See the LICENSE file in the root directory of this source tree.
|
||||
*/const e=c("Ellipsis",[["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}],["circle",{cx:"19",cy:"12",r:"1",key:"1wjl8i"}],["circle",{cx:"5",cy:"12",r:"1",key:"1pcz8c"}]]);export{e as E};
|
1
public/assets/admin/assets/form-BdPgCkkB.js
vendored
1
public/assets/admin/assets/form-BdPgCkkB.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-BDkIR942.js
vendored
1
public/assets/admin/assets/index-BDkIR942.js
vendored
File diff suppressed because one or more lines are too long
14
public/assets/admin/assets/index-BJkinkSk.js
vendored
14
public/assets/admin/assets/index-BJkinkSk.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-BLDQqHaS.js
vendored
1
public/assets/admin/assets/index-BLDQqHaS.js
vendored
@ -1 +0,0 @@
|
||||
import{e as d,u as m,r as h,j as e,a as r,L as p,g as f,O as j}from"./index-ra1jmRmU.js";import{S as u,T as g,U as N}from"./user-nav-Ch7kI57y.js";import{S as v}from"./separator-Ckt7QEUw.js";import{L as S,f as y,g as b}from"./sidelinks-B70MVRK0.js";import{S as w,a as L,b as T,c as k,d as E}from"./select-ar7QGfF7.js";import{S as V}from"./config-BH6RmWlb.js";import"./react-icons.esm-BRv52UVg.js";import"./index-CmmzV1O3.js";import"./index-OwEZQf1t.js";import"./index-QSXu8nGm.js";import"./button-BkBuHKqj.js";import"./index-NvRyusV4.js";import"./IconTicket-s_6DwrCY.js";import"./index-DGqrqZGX.js";import"./index-DBonxKbv.js";function H({className:t,items:a,...c}){const{pathname:l}=d(),i=m(),[n,o]=h.useState(l??"/settings"),x=s=>{o(s),i(s)};return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"p-1 md:hidden",children:e.jsxs(w,{value:n,onValueChange:x,children:[e.jsx(L,{className:"h-12 sm:w-48",children:e.jsx(T,{placeholder:"Theme"})}),e.jsx(k,{children:a.map(s=>e.jsx(E,{value:s.href,children:e.jsxs("div",{className:"flex gap-x-4 px-2 py-1",children:[e.jsx("span",{className:"scale-125",children:s.icon}),e.jsx("span",{className:"text-md",children:s.title})]})},s.href))})]})}),e.jsx("div",{className:"hidden w-full overflow-x-auto bg-background px-1 py-2 md:block",children:e.jsx("nav",{className:r("flex space-x-2 lg:flex-col lg:space-x-0 lg:space-y-1",t),...c,children:a.map(s=>e.jsxs(p,{to:s.href,className:r(f({variant:"ghost"}),l===s.href?"bg-muted hover:bg-muted":"hover:bg-transparent hover:underline","justify-start"),children:[e.jsx("span",{className:"mr-2",children:s.icon}),s.title]},s.href))})})]})}function J(){return e.jsxs(S,{fadedBelow:!0,fixedHeight:!0,children:[e.jsxs(y,{children:[e.jsx(u,{}),e.jsxs("div",{className:"ml-auto flex items-center space-x-4",children:[e.jsx(g,{}),e.jsx(N,{})]})]}),e.jsxs(b,{className:"flex flex-col",fixedHeight:!0,children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx("h1",{className:"text-2xl font-bold tracking-tight md:text-3xl",children:"系统设置"}),e.jsx("p",{className:"text-muted-foreground",children:"管理系统核心配置,包括站点、安全、订阅、邀请佣金、节点、邮件和通知等设置"})]}),e.jsx(v,{className:"my-6"}),e.jsxs("div",{className:"flex flex-1 flex-col space-y-8 overflow-auto lg:flex-row lg:space-x-12 lg:space-y-0",children:[e.jsx("aside",{className:"sticky top-0 lg:w-1/5",children:e.jsx(H,{items:V})}),e.jsx("div",{className:"w-full p-1 pr-4 lg:max-w-xl",children:e.jsx("div",{className:"pb-16",children:e.jsx(j,{})})})]})]})]})}export{J as default};
|
1
public/assets/admin/assets/index-BO6ULa-X.js
vendored
1
public/assets/admin/assets/index-BO6ULa-X.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-BSLwkSgR.js
vendored
1
public/assets/admin/assets/index-BSLwkSgR.js
vendored
File diff suppressed because one or more lines are too long
16
public/assets/admin/assets/index-BcCyiqia.js
vendored
16
public/assets/admin/assets/index-BcCyiqia.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-Bn7vc-ec.js
vendored
1
public/assets/admin/assets/index-Bn7vc-ec.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-C1dBp5Nw.js
vendored
1
public/assets/admin/assets/index-C1dBp5Nw.js
vendored
@ -1 +0,0 @@
|
||||
import{r as j,j as e,a as f,g as p,B as b,t as _}from"./index-ra1jmRmU.js";import{S as g}from"./separator-Ckt7QEUw.js";import{z as s,t as v}from"./zod-DftZp2aV.js";import{C as F}from"./react-icons.esm-BRv52UVg.js";import{u as N,F as S,a as t,b as o,c as a,f as l,d as c,e as m}from"./form-BdPgCkkB.js";import{I as y}from"./input-BJSapCFH.js";import{S as h}from"./switch-koO8JJ-3.js";import{u as C}from"./useQuery-BPONQpNy.js";import{e as k,s as w}from"./index-vL3ySUIK.js";import"./index-QSXu8nGm.js";import"./index-OwEZQf1t.js";import"./index-DGqrqZGX.js";import"./index-NvRyusV4.js";import"./clipboard-Bl2zvJsv.js";const E=s.object({frontend_theme:s.string().nullable(),frontend_theme_sidebar:s.string().nullable(),frontend_theme_header:s.string().nullable(),frontend_theme_color:s.string().nullable(),frontend_background_url:s.string().url().nullable()}),I={frontend_theme:"",frontend_theme_sidebar:"",frontend_theme_header:"",frontend_theme_color:"",frontend_background_url:""};function V(){const{data:d}=C({queryKey:["settings","frontend"],queryFn:()=>k("frontend")}),r=N({resolver:v(E),defaultValues:I,mode:"onChange"});j.useEffect(()=>{if(d?.data?.frontend){const n=d?.data?.frontend;Object.entries(n).forEach(([i,u])=>{r.setValue(i,u)})}},[d]);function x(n){w(n).then(({data:i})=>{i&&_.success("更新成功")})}return e.jsx(S,{...r,children:e.jsxs("form",{onSubmit:r.handleSubmit(x),className:"space-y-8",children:[e.jsx(t,{control:r.control,name:"frontend_theme_sidebar",render:({field:n})=>e.jsxs(o,{children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(a,{className:"text-base",children:"边栏风格"}),e.jsx(l,{children:"边栏风格"})]}),e.jsx(c,{children:e.jsx(h,{checked:n.value,onCheckedChange:n.onChange})})]})}),e.jsx(t,{control:r.control,name:"frontend_theme_header",render:({field:n})=>e.jsxs(o,{children:[e.jsxs("div",{className:"space-y-0.5",children:[e.jsx(a,{className:"text-base",children:"头部风格"}),e.jsx(l,{children:"边栏风格"})]}),e.jsx(c,{children:e.jsx(h,{checked:n.value,onCheckedChange:n.onChange})})]})}),e.jsx(t,{control:r.control,name:"frontend_theme_color",render:({field:n})=>e.jsxs(o,{children:[e.jsx(a,{children:"主题色"}),e.jsxs("div",{className:"relative w-max",children:[e.jsx(c,{children:e.jsxs("select",{className:f(p({variant:"outline"}),"w-[200px] appearance-none font-normal"),...n,children:[e.jsx("option",{value:"default",children:"默认"}),e.jsx("option",{value:"black",children:"黑色"}),e.jsx("option",{value:"blackblue",children:"暗蓝色"}),e.jsx("option",{value:"green",children:"奶绿色"})]})}),e.jsx(F,{className:"absolute right-3 top-2.5 h-4 w-4 opacity-50"})]}),e.jsx(l,{children:"主题色"}),e.jsx(m,{})]})}),e.jsx(t,{control:r.control,name:"frontend_background_url",render:({field:n})=>e.jsxs(o,{children:[e.jsx(a,{children:"背景"}),e.jsx(c,{children:e.jsx(y,{placeholder:"请输入图片地址",...n})}),e.jsx(l,{children:"将会在后台登录页面进行展示。"}),e.jsx(m,{})]})}),e.jsx(b,{type:"submit",children:"保存设置"})]})})}function P(){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-medium",children:"个性化设置"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"自定义系统界面外观,包括主题风格、布局、颜色方案、背景图等个性化选项。"})]}),e.jsx(g,{}),e.jsx(V,{})]})}export{P as default};
|
4
public/assets/admin/assets/index-C3nYxwSD.js
vendored
4
public/assets/admin/assets/index-C3nYxwSD.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-C7jqFNYI.js
vendored
1
public/assets/admin/assets/index-C7jqFNYI.js
vendored
@ -1 +0,0 @@
|
||||
import{r as k,j as e,B as d,t as g}from"./index-ra1jmRmU.js";import{S as F}from"./separator-Ckt7QEUw.js";import{z as o,t as S}from"./zod-DftZp2aV.js";import{u as v,F as y,a as x,b as a,c as n,d as c,f as l,e as m}from"./form-BdPgCkkB.js";import{I as h}from"./input-BJSapCFH.js";import{S as T}from"./switch-koO8JJ-3.js";import{u as C}from"./useQuery-BPONQpNy.js";import{u}from"./useMutation-CAQi7k46.js";import{e as E,s as W,j as B}from"./index-vL3ySUIK.js";import"./index-QSXu8nGm.js";import"./index-OwEZQf1t.js";import"./index-DGqrqZGX.js";import"./index-NvRyusV4.js";import"./clipboard-Bl2zvJsv.js";const I=o.object({telegram_bot_enable:o.boolean().nullable(),telegram_bot_token:o.string().nullable(),telegram_discuss_link:o.string().nullable()}),K={telegram_bot_enable:!1,telegram_bot_token:"",telegram_discuss_link:""};function N(){const s=v({resolver:S(I),defaultValues:K,mode:"onChange"}),{data:i}=C({queryKey:["settings","telegram"],queryFn:()=>E("telegram")});k.useEffect(()=>{if(i?.data.telegram){const t=i.data.telegram;Object.entries(t).forEach(([r,_])=>{s.setValue(r,_)})}},[i]);const{mutate:j,status:p}=u({mutationFn:t=>W(t).then(({data:r})=>r&&g.success("保存成功")),mutationKey:["settings","telegram"]}),{mutate:b,status:f}=u({mutationFn:t=>B().then(({data:r})=>r&&g.success("保存成功")),mutationKey:["settings","settelegramWebhook"]});return e.jsxs(y,{...s,children:[e.jsx(x,{control:s.control,name:"telegram_bot_token",render:({field:t})=>e.jsxs(a,{children:[e.jsx(n,{children:"机器人Token"}),e.jsx(c,{children:e.jsx(h,{placeholder:"0000000000:xxxxxxxxx_xxxxxxxxxxxxxxx",...t})}),e.jsx(l,{children:"请输入由Botfather提供的token。"}),e.jsx(m,{})]})}),s.watch("telegram_bot_token")&&e.jsxs(a,{children:[e.jsx(n,{children:"设置Webhook"}),e.jsx("div",{children:e.jsx(d,{loading:f=="pending",onClick:()=>{b()},children:"一键设置"})}),e.jsx(l,{children:"对机器人进行Webhook设置,不设置将无法收到Telegram通知。"}),e.jsx(m,{})]}),e.jsx(x,{control:s.control,name:"telegram_bot_enable",render:({field:t})=>e.jsxs(a,{children:[e.jsx(n,{children:"开启机器人通知"}),e.jsx(l,{children:"开启后bot将会对绑定了telegram的管理员和用户进行基础通知。"}),e.jsx(c,{children:e.jsx(T,{checked:t.value,onCheckedChange:t.onChange})}),e.jsx(m,{})]})}),e.jsx(x,{control:s.control,name:"telegram_discuss_link",render:({field:t})=>e.jsxs(a,{children:[e.jsx(n,{children:"群组地址"}),e.jsx(c,{children:e.jsx(h,{placeholder:"https://t.me/xxxxxx",...t})}),e.jsx(l,{children:"填写后将会在用户端展示,或者被用于需要的地方。"}),e.jsx(m,{})]})}),e.jsx(d,{type:"submit",loading:p==="pending",onClick:()=>{s.handleSubmit(t=>{console.log(t),j(t)})()},children:"保存设置"})]})}function P(){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-medium",children:"Telegram设置"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"配置Telegram机器人功能,实现用户通知、账户绑定、指令交互等自动化服务。"})]}),e.jsx(F,{}),e.jsx(N,{})]})}export{P as default};
|
1
public/assets/admin/assets/index-CP9YUybY.js
vendored
1
public/assets/admin/assets/index-CP9YUybY.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-CVkq03hO.js
vendored
1
public/assets/admin/assets/index-CVkq03hO.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-CfrSGnrO.js
vendored
1
public/assets/admin/assets/index-CfrSGnrO.js
vendored
@ -1 +0,0 @@
|
||||
import{r as h,j as e,B as p,t as v}from"./index-ra1jmRmU.js";import{S as f}from"./separator-Ckt7QEUw.js";import{z as t,t as _}from"./zod-DftZp2aV.js";import{u as b,F,a,b as l,c,d as i,f as m,e as d}from"./form-BdPgCkkB.js";import{I as u}from"./input-BJSapCFH.js";import{u as g}from"./useQuery-BPONQpNy.js";import{e as S,s as y}from"./index-vL3ySUIK.js";import"./index-QSXu8nGm.js";import"./clipboard-Bl2zvJsv.js";const E=t.object({server_pull_interval:t.coerce.number().nullable(),server_push_interval:t.coerce.number().nullable(),server_token:t.string().nullable()}),N={server_pull_interval:0,server_push_interval:0,server_token:""};function k(){const s=b({resolver:_(E),defaultValues:N,mode:"onChange"}),{data:n}=g({queryKey:["settings","server"],queryFn:()=>S("server")});h.useEffect(()=>{if(n?.data.server){const r=n.data.server;Object.entries(r).forEach(([o,j])=>{s.setValue(o,j)})}},[n]);function x(r){y(r).then(({data:o})=>{o&&v.success("保存成功")})}return e.jsx(F,{...s,children:e.jsxs("form",{onSubmit:s.handleSubmit(x),className:"space-y-8",children:[e.jsx(a,{control:s.control,name:"server_token",render:({field:r})=>e.jsxs(l,{children:[e.jsx(c,{children:"通讯密钥"}),e.jsx(i,{children:e.jsx(u,{placeholder:"请输入",...r})}),e.jsx(m,{children:"Xboard与节点通讯的密钥,以便数据不会被他人获取。"}),e.jsx(d,{})]})}),e.jsx(a,{control:s.control,name:"server_pull_interval",render:({field:r})=>e.jsxs(l,{children:[e.jsx(c,{children:"节点拉取动作轮询间隔"}),e.jsx(i,{children:e.jsx(u,{placeholder:"请输入",...r})}),e.jsx(m,{children:"节点从面板获取数据的间隔频率。"}),e.jsx(d,{})]})}),e.jsx(a,{control:s.control,name:"server_push_interval",render:({field:r})=>e.jsxs(l,{children:[e.jsx(c,{children:"节点推送动作轮询间隔"}),e.jsx(i,{children:e.jsx(u,{placeholder:"请输入",...r})}),e.jsx(m,{children:"节点推送数据到面板的间隔频率。"}),e.jsx(d,{})]})}),e.jsx(p,{type:"submit",children:"保存设置"})]})})}function M(){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-medium",children:"节点配置"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"配置节点通信和同步设置,包括通信密钥、轮询间隔、负载均衡等高级选项。"})]}),e.jsx(f,{}),e.jsx(k,{})]})}export{M as default};
|
6
public/assets/admin/assets/index-CixzCB63.js
vendored
6
public/assets/admin/assets/index-CixzCB63.js
vendored
File diff suppressed because one or more lines are too long
41
public/assets/admin/assets/index-CmmzV1O3.js
vendored
41
public/assets/admin/assets/index-CmmzV1O3.js
vendored
File diff suppressed because one or more lines are too long
5
public/assets/admin/assets/index-CtUqtdJN.js
vendored
5
public/assets/admin/assets/index-CtUqtdJN.js
vendored
File diff suppressed because one or more lines are too long
140
public/assets/admin/assets/index-CtWZZ_6n.js
vendored
140
public/assets/admin/assets/index-CtWZZ_6n.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-D1AQYL1e.js
vendored
1
public/assets/admin/assets/index-D1AQYL1e.js
vendored
@ -1 +0,0 @@
|
||||
import{i as d}from"./index-ra1jmRmU.js";var m={exports:{}};(function(w){var g=Object.prototype.hasOwnProperty,u="~";function h(){}Object.create&&(h.prototype=Object.create(null),new h().__proto__||(u=!1));function E(s,t,n){this.fn=s,this.context=t,this.once=n||!1}function x(s,t,n,r,l){if(typeof n!="function")throw new TypeError("The listener must be a function");var c=new E(n,r||s,l),o=u?u+t:t;return s._events[o]?s._events[o].fn?s._events[o]=[s._events[o],c]:s._events[o].push(c):(s._events[o]=c,s._eventsCount++),s}function y(s,t){--s._eventsCount===0?s._events=new h:delete s._events[t]}function f(){this._events=new h,this._eventsCount=0}f.prototype.eventNames=function(){var t=[],n,r;if(this._eventsCount===0)return t;for(r in n=this._events)g.call(n,r)&&t.push(u?r.slice(1):r);return Object.getOwnPropertySymbols?t.concat(Object.getOwnPropertySymbols(n)):t},f.prototype.listeners=function(t){var n=u?u+t:t,r=this._events[n];if(!r)return[];if(r.fn)return[r.fn];for(var l=0,c=r.length,o=new Array(c);l<c;l++)o[l]=r[l].fn;return o},f.prototype.listenerCount=function(t){var n=u?u+t:t,r=this._events[n];return r?r.fn?1:r.length:0},f.prototype.emit=function(t,n,r,l,c,o){var a=u?u+t:t;if(!this._events[a])return!1;var e=this._events[a],p=arguments.length,v,i;if(e.fn){switch(e.once&&this.removeListener(t,e.fn,void 0,!0),p){case 1:return e.fn.call(e.context),!0;case 2:return e.fn.call(e.context,n),!0;case 3:return e.fn.call(e.context,n,r),!0;case 4:return e.fn.call(e.context,n,r,l),!0;case 5:return e.fn.call(e.context,n,r,l,c),!0;case 6:return e.fn.call(e.context,n,r,l,c,o),!0}for(i=1,v=new Array(p-1);i<p;i++)v[i-1]=arguments[i];e.fn.apply(e.context,v)}else{var b=e.length,_;for(i=0;i<b;i++)switch(e[i].once&&this.removeListener(t,e[i].fn,void 0,!0),p){case 1:e[i].fn.call(e[i].context);break;case 2:e[i].fn.call(e[i].context,n);break;case 3:e[i].fn.call(e[i].context,n,r);break;case 4:e[i].fn.call(e[i].context,n,r,l);break;default:if(!v)for(_=1,v=new Array(p-1);_<p;_++)v[_-1]=arguments[_];e[i].fn.apply(e[i].context,v)}}return!0},f.prototype.on=function(t,n,r){return x(this,t,n,r,!1)},f.prototype.once=function(t,n,r){return x(this,t,n,r,!0)},f.prototype.removeListener=function(t,n,r,l){var c=u?u+t:t;if(!this._events[c])return this;if(!n)return y(this,c),this;var o=this._events[c];if(o.fn)o.fn===n&&(!l||o.once)&&(!r||o.context===r)&&y(this,c);else{for(var a=0,e=[],p=o.length;a<p;a++)(o[a].fn!==n||l&&!o[a].once||r&&o[a].context!==r)&&e.push(o[a]);e.length?this._events[c]=e.length===1?e[0]:e:y(this,c)}return this},f.prototype.removeAllListeners=function(t){var n;return t?(n=u?u+t:t,this._events[n]&&y(this,n)):(this._events=new h,this._eventsCount=0),this},f.prototype.off=f.prototype.removeListener,f.prototype.addListener=f.prototype.on,f.prefixed=u,f.EventEmitter=f,w.exports=f})(m);var L=m.exports;const O=d(L);export{O as E,L as e};
|
6
public/assets/admin/assets/index-D8S9pxYD.js
vendored
6
public/assets/admin/assets/index-D8S9pxYD.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-DBonxKbv.js
vendored
1
public/assets/admin/assets/index-DBonxKbv.js
vendored
@ -1 +0,0 @@
|
||||
import{r as i,j as o}from"./index-ra1jmRmU.js";import{P as t}from"./index-QSXu8nGm.js";var s="VisuallyHidden",a=i.forwardRef((r,e)=>o.jsx(t.span,{...r,ref:e,style:{position:"absolute",border:0,width:1,height:1,padding:0,margin:-1,overflow:"hidden",clip:"rect(0, 0, 0, 0)",whiteSpace:"nowrap",wordWrap:"normal",...r.style}}));a.displayName=s;var n=a;export{n as R,a as V};
|
1
public/assets/admin/assets/index-DGqrqZGX.js
vendored
1
public/assets/admin/assets/index-DGqrqZGX.js
vendored
@ -1 +0,0 @@
|
||||
import{r as u}from"./index-ra1jmRmU.js";function o(r){const e=u.useRef({value:r,previous:r});return u.useMemo(()=>(e.current.value!==r&&(e.current.previous=e.current.value,e.current.value=r),e.current.previous),[r])}export{o as u};
|
6
public/assets/admin/assets/index-DNOg6s17.js
vendored
6
public/assets/admin/assets/index-DNOg6s17.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-DimQiza1.js
vendored
1
public/assets/admin/assets/index-DimQiza1.js
vendored
@ -1 +0,0 @@
|
||||
import{r as j,j as e,B as h,t as p}from"./index-ra1jmRmU.js";import{S as v}from"./separator-Ckt7QEUw.js";import{z as n,t as _}from"./zod-DftZp2aV.js";import{u as w,F as f,a as o,b as d,d as a,e as t}from"./form-BdPgCkkB.js";import{I as l}from"./input-BJSapCFH.js";import{u as g}from"./useQuery-BPONQpNy.js";import{u as b}from"./useMutation-CAQi7k46.js";import{e as F,s as N}from"./index-vL3ySUIK.js";import"./index-QSXu8nGm.js";import"./clipboard-Bl2zvJsv.js";const S=n.object({windows_version:n.string().nullable(),windows_download_url:n.string().nullable(),macos_version:n.string().nullable(),macos_download_url:n.string().nullable(),android_version:n.string().nullable(),android_download_url:n.string().nullable()}),y={windows_version:"",windows_download_url:"",macos_version:"",macos_download_url:"",android_version:"",android_download_url:""};function A(){const r=w({resolver:_(S),defaultValues:y,mode:"onChange"}),{data:i}=g({queryKey:["settings","app"],queryFn:()=>F("app")});j.useEffect(()=>{if(i?.data.app){const s=i.data.app;Object.entries(s).forEach(([c,u])=>{r.setValue(c,u)})}},[i]);const{mutate:x,status:m}=b({mutationFn:s=>N(s).then(({data:c})=>c&&p.success("保存成功")),mutationKey:["settings","app","update"]});return e.jsxs(f,{...r,children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",children:"Windows"}),e.jsx("div",{className:"text-[0.8rem] text-muted-foreground",children:"Windows端版本号及下载地址"}),e.jsxs("div",{children:[e.jsx("div",{className:"mb-1",children:e.jsx(o,{control:r.control,name:"windows_version",render:({field:s})=>e.jsxs(d,{children:[e.jsx(a,{children:e.jsx(l,{placeholder:"1.0.0",...s})}),e.jsx(t,{})]})})}),e.jsx("div",{children:e.jsx(o,{control:r.control,name:"windows_download_url",render:({field:s})=>e.jsxs(d,{children:[e.jsx(a,{children:e.jsx(l,{placeholder:"https://xxx.com/xxx.exe",...s})}),e.jsx(t,{})]})})})]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",children:"macOS"}),e.jsx("div",{className:"text-[0.8rem] text-muted-foreground",children:"macOS端版本号及下载地址"}),e.jsxs("div",{children:[e.jsx("div",{className:"mb-1",children:e.jsx(o,{control:r.control,name:"mac_version",render:({field:s})=>e.jsxs(d,{children:[e.jsx(a,{children:e.jsx(l,{placeholder:"1.0.0",...s})}),e.jsx(t,{})]})})}),e.jsx("div",{children:e.jsx(o,{control:r.control,name:"mac_download_url",render:({field:s})=>e.jsxs(d,{children:[e.jsx(a,{children:e.jsx(l,{placeholder:"https://xxx.com/xxx.dmg",...s})}),e.jsx(t,{})]})})})]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",children:"Android"}),e.jsx("div",{className:"text-[0.8rem] text-muted-foreground",children:"Android端版本号及下载地址"}),e.jsxs("div",{children:[e.jsx("div",{className:"mb-1",children:e.jsx(o,{control:r.control,name:"android_version",render:({field:s})=>e.jsxs(d,{children:[e.jsx(a,{children:e.jsx(l,{placeholder:"1.0.0",...s})}),e.jsx(t,{})]})})}),e.jsx("div",{children:e.jsx(o,{control:r.control,name:"android_download_url",render:({field:s})=>e.jsxs(d,{children:[e.jsx(a,{children:e.jsx(l,{placeholder:"https://xxx.com/xxx.apk",...s})}),e.jsx(t,{})]})})})]})]}),e.jsx(h,{type:"submit",loading:m=="pending",onClick:()=>{r.handleSubmit(s=>{x(s)})()},children:"保存设置"})]})}function V(){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-medium",children:"APP设置"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"管理移动应用程序相关配置,包括API接口、版本控制、推送通知等功能设置。"})]}),e.jsx(v,{}),e.jsx(A,{})]})}export{V as default};
|
1
public/assets/admin/assets/index-Dkqleggl.js
vendored
1
public/assets/admin/assets/index-Dkqleggl.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-NvRyusV4.js
vendored
1
public/assets/admin/assets/index-NvRyusV4.js
vendored
@ -1 +0,0 @@
|
||||
import{r as u}from"./index-ra1jmRmU.js";import{b as z}from"./index-OwEZQf1t.js";function c(r){const[h,e]=u.useState(void 0);return z(()=>{if(r){e({width:r.offsetWidth,height:r.offsetHeight});const f=new ResizeObserver(i=>{if(!Array.isArray(i)||!i.length)return;const b=i[0];let o,t;if("borderBoxSize"in b){const s=b.borderBoxSize,d=Array.isArray(s)?s[0]:s;o=d.inlineSize,t=d.blockSize}else o=r.offsetWidth,t=r.offsetHeight;e({width:o,height:t})});return f.observe(r,{box:"border-box"}),()=>f.unobserve(r)}else e(void 0)},[r]),h}export{c as u};
|
1
public/assets/admin/assets/index-OwEZQf1t.js
vendored
1
public/assets/admin/assets/index-OwEZQf1t.js
vendored
@ -1 +0,0 @@
|
||||
import{r as c,j as C}from"./index-ra1jmRmU.js";function $(e,o,{checkForDefaultPrevented:t=!0}={}){return function(n){if(e?.(n),t===!1||!n.defaultPrevented)return o?.(n)}}function j(e,o){const t=c.createContext(o),u=s=>{const{children:r,...a}=s,i=c.useMemo(()=>a,Object.values(a));return C.jsx(t.Provider,{value:i,children:r})};u.displayName=e+"Provider";function n(s){const r=c.useContext(t);if(r)return r;if(o!==void 0)return o;throw new Error(`\`${s}\` must be used within \`${e}\``)}return[u,n]}function w(e,o=[]){let t=[];function u(s,r){const a=c.createContext(r),i=t.length;t=[...t,r];const f=l=>{const{scope:p,children:v,...d}=l,h=p?.[e]?.[i]||a,S=c.useMemo(()=>d,Object.values(d));return C.jsx(h.Provider,{value:S,children:v})};f.displayName=s+"Provider";function x(l,p){const v=p?.[e]?.[i]||a,d=c.useContext(v);if(d)return d;if(r!==void 0)return r;throw new Error(`\`${l}\` must be used within \`${s}\``)}return[f,x]}const n=()=>{const s=t.map(r=>c.createContext(r));return function(a){const i=a?.[e]||s;return c.useMemo(()=>({[`__scope${e}`]:{...a,[e]:i}}),[a,i])}};return n.scopeName=e,[u,P(n,...o)]}function P(...e){const o=e[0];if(e.length===1)return o;const t=()=>{const u=e.map(n=>({useScope:n(),scopeName:n.scopeName}));return function(s){const r=u.reduce((a,{useScope:i,scopeName:f})=>{const l=i(s)[`__scope${f}`];return{...a,...l}},{});return c.useMemo(()=>({[`__scope${o.scopeName}`]:r}),[r])}};return t.scopeName=o.scopeName,t}function m(e){const o=c.useRef(e);return c.useEffect(()=>{o.current=e}),c.useMemo(()=>(...t)=>o.current?.(...t),[])}function R({prop:e,defaultProp:o,onChange:t=()=>{}}){const[u,n]=b({defaultProp:o,onChange:t}),s=e!==void 0,r=s?e:u,a=m(t),i=c.useCallback(f=>{if(s){const l=typeof f=="function"?f(e):f;l!==e&&a(l)}else n(f)},[s,e,n,a]);return[r,i]}function b({defaultProp:e,onChange:o}){const t=c.useState(e),[u]=t,n=c.useRef(u),s=m(o);return c.useEffect(()=>{n.current!==u&&(s(u),n.current=u)},[u,n,s]),t}var _=globalThis?.document?c.useLayoutEffect:()=>{};export{$ as a,_ as b,w as c,m as d,j as e,R as u};
|
1
public/assets/admin/assets/index-QSXu8nGm.js
vendored
1
public/assets/admin/assets/index-QSXu8nGm.js
vendored
@ -1 +0,0 @@
|
||||
import{r as p,j as m,z as u,M as d}from"./index-ra1jmRmU.js";var f=["a","button","div","form","h2","h3","img","input","label","li","nav","ol","p","span","svg","ul"],l=f.reduce((r,i)=>{const t=p.forwardRef((s,o)=>{const{asChild:e,...a}=s,n=e?u:i;return typeof window<"u"&&(window[Symbol.for("radix-ui")]=!0),m.jsx(n,{...a,ref:o})});return t.displayName=`Primitive.${i}`,{...r,[i]:t}},{});function v(r,i){r&&d.flushSync(()=>r.dispatchEvent(i))}export{l as P,v as d};
|
1
public/assets/admin/assets/index-d9rU2FsX.js
vendored
1
public/assets/admin/assets/index-d9rU2FsX.js
vendored
@ -1 +0,0 @@
|
||||
import{r as b,j as e,a as y,g as S,B as h,t as p}from"./index-ra1jmRmU.js";import{S as F}from"./separator-Ckt7QEUw.js";import{z as l,t as T}from"./zod-DftZp2aV.js";import{C as v}from"./react-icons.esm-BRv52UVg.js";import{u as M,F as w,a as n,b as i,c as t,d as o,f as c,e as m}from"./form-BdPgCkkB.js";import{I as d}from"./input-BJSapCFH.js";import{u as j}from"./useQuery-BPONQpNy.js";import{s as E,e as N,h as q,i as C}from"./index-vL3ySUIK.js";import"./index-QSXu8nGm.js";import"./clipboard-Bl2zvJsv.js";const P=l.object({email_template:l.string().nullable(),email_host:l.string().nullable(),email_port:l.string().regex(/^\d+$/).nullable(),email_username:l.string().nullable(),email_password:l.string().nullable(),email_encryption:l.string().nullable(),email_from_address:l.string().email().nullable()}),I={email_template:"classic",email_host:"",email_port:"465",email_username:"",email_password:"",email_encryption:"",email_from_address:""};function L(){const r=M({resolver:T(P),defaultValues:I,mode:"onChange"}),{data:x}=j({queryKey:["settings","email"],queryFn:()=>N("email")}),{data:u}=j({queryKey:["emailTemplate"],queryFn:()=>q()});b.useEffect(()=>{if(x?.data.email){const s=x.data.email;Object.entries(s).forEach(([a,_])=>{r.setValue(a,_)})}},[x]);const{isLoading:f,refetch:g}=j({queryKey:["sendTestMail"],queryFn:()=>C().then(()=>p.success("发送成功")),enabled:!1});return e.jsxs(w,{...r,children:[e.jsx(n,{control:r.control,name:"email_host",render:({field:s})=>e.jsxs(i,{children:[e.jsx(t,{children:"SMTP服务器地址"}),e.jsx(o,{children:e.jsx(d,{placeholder:"请输入",...s})}),e.jsx(c,{children:"由邮件服务商提供的服务地址"}),e.jsx(m,{})]})}),e.jsx(n,{control:r.control,name:"email_port",render:({field:s})=>e.jsxs(i,{children:[e.jsx(t,{children:"SMTP服务端口"}),e.jsx(o,{children:e.jsx(d,{placeholder:"请输入",...s})}),e.jsx(c,{children:"常见的端口有25, 465, 587"}),e.jsx(m,{})]})}),e.jsx(n,{control:r.control,name:"email_encryption",render:({field:s})=>e.jsxs(i,{children:[e.jsx(t,{children:"SMTP加密方式"}),e.jsx(o,{children:e.jsx(d,{placeholder:"请输入",...s})}),e.jsx(c,{children:"465端口加密方式一般为SSL,587端口加密方式一般为TLS"}),e.jsx(m,{})]})}),e.jsx(n,{control:r.control,name:"email_username",render:({field:s})=>e.jsxs(i,{children:[e.jsx(t,{children:"SMTP账号"}),e.jsx(o,{children:e.jsx(d,{placeholder:"请输入",...s})}),e.jsx(c,{children:"由邮件服务商提供的账号"}),e.jsx(m,{})]})}),e.jsx(n,{control:r.control,name:"email_password",render:({field:s})=>e.jsxs(i,{children:[e.jsx(t,{children:"SMTP密码"}),e.jsx(o,{children:e.jsx(d,{placeholder:"请输入",...s})}),e.jsx(c,{children:"由邮件服务商提供的密码"}),e.jsx(m,{})]})}),e.jsx(n,{control:r.control,name:"email_from_address",render:({field:s})=>e.jsxs(i,{children:[e.jsx(t,{children:"发件地址"}),e.jsx(o,{children:e.jsx(d,{placeholder:"请输入",...s})}),e.jsx(c,{children:"由邮件服务商提供的发件地址"}),e.jsx(m,{})]})}),e.jsx(n,{control:r.control,name:"email_template",render:({field:s})=>e.jsxs(i,{children:[e.jsx(t,{children:"邮件模板"}),e.jsxs("div",{className:"relative w-max",children:[e.jsx(o,{children:e.jsx("select",{className:y(S({variant:"outline"}),"w-[200px] appearance-none font-normal"),...s,children:u?.data?.map(a=>e.jsx("option",{value:a,children:a},a))})}),e.jsx(v,{className:"absolute right-3 top-2.5 h-4 w-4 opacity-50"})]}),e.jsx(c,{children:"你可以在文档查看如何自定义邮件模板"}),e.jsx(m,{})]})}),e.jsxs("div",{className:"flex justify-between",children:[e.jsx(h,{type:"submit",onClick:()=>{r.handleSubmit(s=>{console.log(s),E(s).then(({data:a})=>{a&&p.success("保存成功")})})()},children:"保存设置"}),e.jsx(h,{loading:f,onClick:()=>{g()},children:"发送测试邮件"})]})]})}function A(){return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-medium",children:"邮件设置"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"配置系统邮件服务,用于发送验证码、密码重置、通知等邮件,支持多种SMTP服务商。"})]}),e.jsx(F,{}),e.jsx(L,{})]})}export{A as default};
|
1
public/assets/admin/assets/index-ngg4RcvF.js
vendored
1
public/assets/admin/assets/index-ngg4RcvF.js
vendored
@ -1 +0,0 @@
|
||||
var E=(a=>(a[a.PENDING=0]="PENDING",a[a.PROCESSING=1]="PROCESSING",a[a.CANCELLED=2]="CANCELLED",a[a.COMPLETED=3]="COMPLETED",a[a.DISCOUNTED=4]="DISCOUNTED",a))(E||{});const c={0:"待支付",1:"开通中",2:"已取消",3:"已完成",4:"已折抵"},p={0:"yellow-500",1:"blue-500",2:"red-500",3:"green-500",4:"green-500"},N={1:"新购",2:"续费",3:"升级",5:"流量重置"};var e=(a=>(a[a.PENDING=0]="PENDING",a[a.PROCESSING=1]="PROCESSING",a[a.VALID=2]="VALID",a[a.INVALID=3]="INVALID",a))(e||{});const t={0:"待确认",1:"发放中",2:"有效",3:"无效"},n={0:"yellow-500",1:"blue-500",2:"green-500",3:"red-500"};var s=(a=>(a.MONTH_PRICE="month_price",a.QUARTER_PRICE="quarter_price",a.HALF_YEAR_PRICE="half_year_price",a.YEAR_PRICE="year_price",a.TWO_YEAR_PRICE="two_year_price",a.THREE_YEAR_PRICE="three_year_price",a.ONETIME_PRICE="onetime_price",a.RESET_PRICE="reset_price",a))(s||{});const l={month_price:"月付",quarter_price:"季付",half_year_price:"半年付",year_price:"年付",two_year_price:"两年付",three_year_price:"三年付",onetime_price:"一次性",reset_price:"流量重置包"};var r=(a=>(a.Shadowsocks="shadowsocks",a.Vmess="vmess",a.Trojan="trojan",a.Hysteria="hysteria",a.Vless="vless",a))(r||{});const C=[{type:"shadowsocks",label:"Shadowsocks"},{type:"vmess",label:"VMess"},{type:"trojan",label:"Trojan"},{type:"hysteria",label:"Hysteria"},{type:"vless",label:"VLess"}],D={shadowsocks:"#489851",vmess:"#CB3180",trojan:"#EBB749",hysteria:"#5684e6",vless:"#1a1a1a"};var o=(a=>(a[a.AMOUNT=1]="AMOUNT",a[a.PERCENTAGE=2]="PERCENTAGE",a))(o||{});const R={1:"按金额优惠",2:"按比例优惠"},M={0:"正常",1:"锁定"};var _=(a=>(a[a.OPENING=0]="OPENING",a[a.CLOSED=1]="CLOSED",a))(_||{});const A={0:"开启",1:"已关闭"};var I=(a=>(a[a.LOW=0]="LOW",a[a.MIDDLE=1]="MIDDLE",a[a.HIGH=2]="HIGH",a))(I||{});const P={0:"低",1:"中",2:"高"};export{e as C,E as O,r as S,I as T,D as a,p as b,t as c,n as d,l as e,N as f,o as g,s as h,R as i,_ as j,A as k,c as o,C as p,P as t,M as u};
|
11
public/assets/admin/assets/index-oNJQadwM.js
vendored
11
public/assets/admin/assets/index-oNJQadwM.js
vendored
File diff suppressed because one or more lines are too long
47
public/assets/admin/assets/index-qcmcBeKk.js
vendored
47
public/assets/admin/assets/index-qcmcBeKk.js
vendored
File diff suppressed because one or more lines are too long
83
public/assets/admin/assets/index-ra1jmRmU.js
vendored
83
public/assets/admin/assets/index-ra1jmRmU.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index-vL3ySUIK.js
vendored
1
public/assets/admin/assets/index-vL3ySUIK.js
vendored
@ -1 +0,0 @@
|
||||
import"./clipboard-Bl2zvJsv.js";import{b as e}from"./index-ra1jmRmU.js";const s=window?.settings?.secure_path,a=()=>e.get(s+"/stat/getOrder"),p=()=>e.get(s+"/stat/getStats"),c=t=>e.get(s+"/stat/getTrafficRank",{params:t}),u=()=>e.get(s+"/theme/getThemes"),g=t=>e.post(s+"/theme/getThemeConfig",{name:t}),d=(t,r)=>e.post(s+"/theme/saveThemeConfig",{name:t,config:r}),i=t=>{const r=new FormData;return r.append("file",t),e.post(s+"/theme/upload",r,{headers:{"Content-Type":"multipart/form-data"}})},m=t=>e.post(s+"/theme/delete",{name:t}),l=t=>e.post(s+"/config/save",t),h=()=>e.get(s+"/server/manage/getNodes"),f=t=>e.post(s+"/server/manage/save",t),v=t=>e.post(s+"/server/manage/drop",t),y=t=>e.post(s+"/server/manage/copy",t),k=t=>e.post(s+"/server/manage/update",t),T=t=>e.post(s+"/server/manage/sort",t),w=()=>e.get(s+"/server/group/fetch"),S=t=>e.post(s+"/server/group/save",t),P=t=>e.post(s+"/server/group/drop",t),L=()=>e.get(s+"/server/route/fetch"),N=t=>e.post(s+"/server/route/save",t),C=t=>e.post(s+"/server/route/drop",t),M=()=>e.get(s+"/payment/fetch"),O=()=>e.get(s+"/payment/getPaymentMethods"),G=t=>e.post(s+"/payment/getPaymentForm",t),K=t=>e.post(s+"/payment/save",t),U=t=>e.post(s+"/payment/drop",t),I=t=>e.post(s+"/payment/show",t),b=t=>e.post(s+"/payment/sort",t),D=()=>e.get(s+"/notice/fetch"),R=t=>e.post(s+"/notice/save",t),F=t=>e.post(s+"/notice/drop",t),x=t=>e.post(s+"/notice/show",t),E=()=>e.get(s+"/knowledge/fetch"),W=t=>e.get(s+"/knowledge/fetch?id="+t),q=t=>e.post(s+"/knowledge/save",t),_=t=>e.post(s+"/knowledge/drop",t),j=t=>e.post(s+"/knowledge/show",t),z=t=>e.post(s+"/knowledge/sort",t),A=()=>e.get(s+"/plan/fetch"),B=t=>e.post(s+"/plan/save",t),H=t=>e.post(s+"/plan/update",t),J=t=>e.post(s+"/plan/drop",t),Q=t=>e.post(s+"/plan/sort",{ids:t}),V=async t=>e.post(s+"/order/fetch",t),X=t=>e.post(s+"/order/detail",t),Y=t=>e.post(s+"/order/paid",t),Z=t=>e.post(s+"/order/cancel",t),$=t=>e.post(s+"/order/update",t),tt=t=>e.post(s+"/order/assign",t),et=t=>e.post(s+"/coupon/fetch",t),st=t=>e.post(s+"/coupon/generate",t),rt=t=>e.post(s+"/coupon/drop",t),ot=t=>e.post(s+"/coupon/update",t),nt=t=>e.post(s+"/user/fetch",t),at=t=>e.post(s+"/user/update",t),pt=t=>e.post(s+"/user/resetSecret",t),ct=t=>e.post(s+"/user/generate",t),ut=t=>e.post(s+"/stat/getStatUser",t),gt=t=>e.post(s+"/ticket/fetch",t),dt=t=>e.get(s+"/ticket/fetch?id= "+t),it=t=>e.post(s+"/ticket/reply",t),mt=t=>e.post(s+"/ticket/close",{id:t}),lt=(t="")=>e.get(s+"/config/fetch?key="+t),ht=t=>e.post(s+"/config/save",t),ft=()=>e.get(s+"/config/getEmailTemplate"),vt=()=>e.post(s+"/config/testSendMail"),yt=()=>e.post(s+"/config/setTelegramWebhook");export{$,F as A,D as B,W as C,q as D,j as E,_ as F,E as G,z as H,w as I,L as J,h as K,f as L,k as M,y as N,v as O,T as P,P as Q,N as R,C as S,B as T,H as U,J as V,Q as W,S as X,X as Y,Y as Z,Z as _,gt as a,st as a0,ot as a1,rt as a2,et as a3,ct as a4,pt as a5,nt as a6,tt as a7,dt as a8,it as a9,mt as aa,at as ab,ut as ac,V as b,p as c,c as d,lt as e,A as f,a as g,ft as h,vt as i,yt as j,O as k,G as l,K as m,U as n,M as o,b as p,g as q,d as r,ht as s,m as t,I as u,l as v,i as w,u as x,R as y,x as z};
|
1
public/assets/admin/assets/index-y_qnpziV.js
vendored
1
public/assets/admin/assets/index-y_qnpziV.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/index.css
vendored
Normal file
1
public/assets/admin/assets/index.css
vendored
Normal file
File diff suppressed because one or more lines are too long
21
public/assets/admin/assets/index.js
vendored
Normal file
21
public/assets/admin/assets/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/input-BJSapCFH.js
vendored
1
public/assets/admin/assets/input-BJSapCFH.js
vendored
@ -1 +0,0 @@
|
||||
import{r as o,j as i,a as n}from"./index-ra1jmRmU.js";const a=o.forwardRef(({className:e,type:r,...s},t)=>i.jsx("input",{type:r,className:n("flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",e),ref:t,...s}));a.displayName="Input";export{a as I};
|
@ -1,6 +0,0 @@
|
||||
import{c as e}from"./user-nav-Ch7kI57y.js";/**
|
||||
* @license lucide-react v0.399.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
* See the LICENSE file in the root directory of this source tree.
|
||||
*/const r=e("LoaderCircle",[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]]);export{r as L};
|
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
import{r as d,j as e,B as h,t as O}from"./index-ra1jmRmU.js";import{D as I,e as _,a as T,b as V,c as L,d as P,f as k}from"./button-BkBuHKqj.js";import{z as n,t as y}from"./zod-DftZp2aV.js";import{u as E,F as N,a as o,b as l,c as t,d as i,e as w}from"./form-BdPgCkkB.js";import{I as j}from"./input-BJSapCFH.js";import{b as z}from"./react-icons.esm-BRv52UVg.js";import{f as A,a7 as B}from"./index-vL3ySUIK.js";import{S as u,a as p,b as g,c as f,d as C}from"./select-ar7QGfF7.js";import{e as F}from"./index-ngg4RcvF.js";const M=n.object({email:n.string().min(1),plan_id:n.number(),period:n.string(),total_amount:n.number()}),H={email:"",plan_id:0,total_amount:0,period:""};function Y({refetch:x,trigger:v,defaultValues:b}){const[c,m]=d.useState(!1),a=E({resolver:y(M),defaultValues:{...H,...b},mode:"onChange"}),[S,D]=d.useState([]);return d.useEffect(()=>{c&&A().then(({data:s})=>{D(s)})},[c]),e.jsxs(I,{open:c,onOpenChange:m,children:[e.jsx(_,{asChild:!0,children:v||e.jsxs(h,{variant:"outline",size:"sm",className:"ml-auto hidden h-8 lg:flex",children:[e.jsx(z,{className:"mr-2 h-4 w-4"}),"添加订单"]})}),e.jsxs(T,{className:"sm:max-w-[425px]",children:[e.jsxs(V,{children:[e.jsx(L,{children:"订单分配"}),e.jsx(P,{})]}),e.jsxs(N,{...a,children:[e.jsx(o,{control:a.control,name:"email",render:({field:s})=>e.jsxs(l,{children:[e.jsx(t,{children:"用户邮箱"}),e.jsx(i,{children:e.jsx(j,{placeholder:"请输入用户邮箱",...s})})]})}),e.jsx(o,{control:a.control,name:"plan_id",render:({field:s})=>e.jsxs(l,{children:[e.jsx(t,{children:"订阅计划"}),e.jsx(i,{children:e.jsxs(u,{value:s.value?s.value?.toString():void 0,onValueChange:r=>s.onChange(parseInt(r)),children:[e.jsx(p,{children:e.jsx(g,{placeholder:"请选择订阅计划"})}),e.jsx(f,{children:S.map(r=>e.jsx(C,{value:r.id.toString(),children:r.name},r.id))})]})})]})}),e.jsx(o,{control:a.control,name:"period",render:({field:s})=>e.jsxs(l,{children:[e.jsx(t,{children:"订阅时长"}),e.jsx(i,{children:e.jsxs(u,{value:s.value,onValueChange:s.onChange,children:[e.jsx(p,{children:e.jsx(g,{placeholder:"请选择购买时长"})}),e.jsx(f,{children:Object.keys(F).map(r=>e.jsx(C,{value:r,children:F[r]},r))})]})})]})}),e.jsx(o,{control:a.control,name:"total_amount",render:({field:s})=>e.jsxs(l,{children:[e.jsx(t,{children:"支付金额"}),e.jsx(i,{children:e.jsx(j,{type:"number",placeholder:"请输入需要支付的金额",value:s.value/100,onChange:r=>s.onChange(parseFloat(r.currentTarget.value)*100)})}),e.jsx(w,{})]})}),e.jsxs(k,{children:[e.jsx(h,{variant:"outline",onClick:()=>m(!1),children:"取消"}),e.jsx(h,{type:"submit",onClick:()=>{a.handleSubmit(s=>{B(s).then(({data:r})=>{r&&(x&&x(),a.reset(),m(!1),O.success("添加成功"))})})()},children:"确定"})]})]})]})]})}export{Y as O};
|
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
import{j as a}from"./index-ra1jmRmU.js";const s=e=>a.jsx("svg",{className:"inline-block",viewBox:"0 0 24 24",width:"1.2em",height:"1.2em",...e,children:a.jsx("path",{fill:"currentColor",d:"M11.29 15.29a2 2 0 0 0-.12.15a.8.8 0 0 0-.09.18a.6.6 0 0 0-.06.18a1.4 1.4 0 0 0 0 .2a.84.84 0 0 0 .08.38a.9.9 0 0 0 .54.54a.94.94 0 0 0 .76 0a.9.9 0 0 0 .54-.54A1 1 0 0 0 13 16a1 1 0 0 0-.29-.71a1 1 0 0 0-1.42 0M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2m0 18a8 8 0 1 1 8-8a8 8 0 0 1-8 8m0-13a3 3 0 0 0-2.6 1.5a1 1 0 1 0 1.73 1A1 1 0 0 1 12 9a1 1 0 0 1 0 2a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-.18A3 3 0 0 0 12 7"})});export{s as u};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
import{r as s,j as l,a as m}from"./index-ra1jmRmU.js";import{P as v}from"./index-QSXu8nGm.js";var f="Separator",n="horizontal",N=["horizontal","vertical"],p=s.forwardRef((r,a)=>{const{decorative:t,orientation:o=n,...i}=r,e=u(o)?o:n,d=t?{role:"none"}:{"aria-orientation":e==="vertical"?e:void 0,role:"separator"};return l.jsx(v.div,{"data-orientation":e,...d,...i,ref:a})});p.displayName=f;function u(r){return N.includes(r)}var c=p;const x=s.forwardRef(({className:r,orientation:a="horizontal",decorative:t=!0,...o},i)=>l.jsx(c,{ref:i,decorative:t,orientation:a,className:m("shrink-0 bg-border",a==="horizontal"?"h-[1px] w-full":"h-full w-[1px]",r),...o}));x.displayName=c.displayName;export{x as S};
|
@ -1,6 +0,0 @@
|
||||
import{c as e}from"./user-nav-Ch7kI57y.js";/**
|
||||
* @license lucide-react v0.399.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
* See the LICENSE file in the root directory of this source tree.
|
||||
*/const y=e("Server",[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]]);export{y as S};
|
@ -1 +0,0 @@
|
||||
import{r as d,j as s,B as o,t as x}from"./index-ra1jmRmU.js";import{D as f,e as g,a as b,b as F,c as S,d as D,f as C,g as v}from"./button-BkBuHKqj.js";import{u as N,F as I,a as w,b as y,c as z,d as G,f as L,e as B}from"./form-BdPgCkkB.js";import{I as E}from"./input-BJSapCFH.js";import{z as i,t as O}from"./zod-DftZp2aV.js";import{I as T}from"./iconify-DJqeKjVQ.js";import{X as A}from"./index-vL3ySUIK.js";import{L as H}from"./loader-circle-DZwZUkW0.js";const M=i.object({id:i.number().optional(),name:i.string().min(2,"组名至少需要2个字符").max(50,"组名不能超过50个字符").regex(/^[a-zA-Z0-9\u4e00-\u9fa5_-]+$/,"组名只能包含字母、数字、中文、下划线和连字符")});function J({refetch:t,dialogTrigger:u,defaultValues:h={name:""},type:a="add"}){const e=N({resolver:O(M),defaultValues:h,mode:"onChange"}),[p,n]=d.useState(!1),[l,m]=d.useState(!1),j=async r=>{try{m(!0);const{data:c}=await A(r);c&&(x.success(a==="edit"?"更新成功":"创建成功"),t&&t(),e.reset(),n(!1))}catch{x.error("操作失败,请重试")}finally{m(!1)}};return s.jsxs(f,{open:p,onOpenChange:n,children:[s.jsx(g,{asChild:!0,children:u||s.jsxs(o,{variant:"outline",size:"sm",className:"space-x-2",children:[s.jsx(T,{icon:"ion:add",className:"h-4 w-4"}),s.jsx("span",{children:"添加权限组"})]})}),s.jsxs(b,{className:"sm:max-w-[425px]",children:[s.jsxs(F,{children:[s.jsx(S,{children:a==="edit"?"编辑权限组":"创建权限组"}),s.jsx(D,{children:a==="edit"?"修改权限组信息,更新后会立即生效。":"创建新的权限组,可以为不同的用户分配不同的权限。"})]}),s.jsx(I,{...e,children:s.jsxs("form",{onSubmit:e.handleSubmit(j),className:"space-y-4",children:[s.jsx(w,{control:e.control,name:"name",render:({field:r})=>s.jsxs(y,{children:[s.jsx(z,{children:"组名称"}),s.jsx(G,{children:s.jsx(E,{placeholder:"请输入权限组名称",...r,className:"w-full"})}),s.jsx(L,{children:"权限组名称用于标识不同的用户组,建议使用有意义的名称。"}),s.jsx(B,{})]})}),s.jsxs(C,{className:"gap-2",children:[s.jsx(v,{asChild:!0,children:s.jsx(o,{type:"button",variant:"outline",children:"取消"})}),s.jsxs(o,{type:"submit",disabled:l||!e.formState.isValid,children:[l&&s.jsx(H,{className:"mr-2 h-4 w-4 animate-spin"}),a==="edit"?"更新":"创建"]})]})]})})]})]})}export{J as S};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
import{j as r,a as s}from"./index-ra1jmRmU.js";function t({className:a,...e}){return r.jsx("div",{className:s("animate-pulse rounded-md bg-primary/10",a),...e})}export{t as S};
|
@ -1 +0,0 @@
|
||||
import{r as s,v as _,j as r,a as S}from"./index-ra1jmRmU.js";import{c as H,u as I,a as M}from"./index-OwEZQf1t.js";import{u as B}from"./index-DGqrqZGX.js";import{u as q}from"./index-NvRyusV4.js";import{P as g}from"./index-QSXu8nGm.js";var v="Switch",[z,J]=H(v),[A,O]=z(v),x=s.forwardRef((e,o)=>{const{__scopeSwitch:t,name:a,checked:n,defaultChecked:l,required:i,disabled:c,value:d="on",onCheckedChange:b,form:m,...p}=e,[u,E]=s.useState(null),R=_(o,f=>E(f)),k=s.useRef(!1),w=u?m||!!u.closest("form"):!0,[h=!1,N]=I({prop:n,defaultProp:l,onChange:b});return r.jsxs(A,{scope:t,checked:h,disabled:c,children:[r.jsx(g.button,{type:"button",role:"switch","aria-checked":h,"aria-required":i,"data-state":P(h),"data-disabled":c?"":void 0,disabled:c,value:d,...p,ref:R,onClick:M(e.onClick,f=>{N(T=>!T),w&&(k.current=f.isPropagationStopped(),k.current||f.stopPropagation())})}),w&&r.jsx(D,{control:u,bubbles:!k.current,name:a,value:d,checked:h,required:i,disabled:c,form:m,style:{transform:"translateX(-100%)"}})]})});x.displayName=v;var C="SwitchThumb",y=s.forwardRef((e,o)=>{const{__scopeSwitch:t,...a}=e,n=O(C,t);return r.jsx(g.span,{"data-state":P(n.checked),"data-disabled":n.disabled?"":void 0,...a,ref:o})});y.displayName=C;var D=e=>{const{control:o,checked:t,bubbles:a=!0,...n}=e,l=s.useRef(null),i=B(t),c=q(o);return s.useEffect(()=>{const d=l.current,b=window.HTMLInputElement.prototype,p=Object.getOwnPropertyDescriptor(b,"checked").set;if(i!==t&&p){const u=new Event("click",{bubbles:a});p.call(d,t),d.dispatchEvent(u)}},[i,t,a]),r.jsx("input",{type:"checkbox","aria-hidden":!0,defaultChecked:t,...n,tabIndex:-1,ref:l,style:{...e.style,...c,position:"absolute",pointerEvents:"none",opacity:0,margin:0}})};function P(e){return e?"checked":"unchecked"}var j=x,F=y;const L=s.forwardRef(({className:e,...o},t)=>r.jsx(j,{className:S("peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",e),...o,ref:t,children:r.jsx(F,{className:S("pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0")})}));L.displayName=j.displayName;export{L as S};
|
@ -1 +0,0 @@
|
||||
import{r as s,j as o,a as t}from"./index-ra1jmRmU.js";const i=s.forwardRef(({className:e,...r},a)=>o.jsx("textarea",{className:t("flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",e),ref:a,...r}));i.displayName="Textarea";export{i as T};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,6 +0,0 @@
|
||||
import{c as e}from"./user-nav-Ch7kI57y.js";/**
|
||||
* @license lucide-react v0.399.0 - ISC
|
||||
*
|
||||
* This source code is licensed under the ISC license.
|
||||
* See the LICENSE file in the root directory of this source tree.
|
||||
*/const c=e("Trash2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);export{c as T};
|
@ -1 +0,0 @@
|
||||
import{S as l,m as p,n as h,o as d,p as a,q as b,r as o}from"./index-ra1jmRmU.js";import{n as m,s as f}from"./useQuery-BPONQpNy.js";var v=class extends l{#e;#i=void 0;#t;#s;constructor(t,s){super(),this.#e=t,this.setOptions(s),this.bindMethods(),this.#r()}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(t){const s=this.options;this.options=this.#e.defaultMutationOptions(t),p(this.options,s)||this.#e.getMutationCache().notify({type:"observerOptionsUpdated",mutation:this.#t,observer:this}),s?.mutationKey&&this.options.mutationKey&&h(s.mutationKey)!==h(this.options.mutationKey)?this.reset():this.#t?.state.status==="pending"&&this.#t.setOptions(this.options)}onUnsubscribe(){this.hasListeners()||this.#t?.removeObserver(this)}onMutationUpdate(t){this.#r(),this.#o(t)}getCurrentResult(){return this.#i}reset(){this.#t?.removeObserver(this),this.#t=void 0,this.#r(),this.#o()}mutate(t,s){return this.#s=s,this.#t?.removeObserver(this),this.#t=this.#e.getMutationCache().build(this.#e,this.options),this.#t.addObserver(this),this.#t.execute(t)}#r(){const t=this.#t?.state??d();this.#i={...t,isPending:t.status==="pending",isSuccess:t.status==="success",isError:t.status==="error",isIdle:t.status==="idle",mutate:this.mutate,reset:this.reset}}#o(t){a.batch(()=>{if(this.#s&&this.hasListeners()){const s=this.#i.variables,i=this.#i.context;t?.type==="success"?(this.#s.onSuccess?.(t.data,s,i),this.#s.onSettled?.(t.data,null,s,i)):t?.type==="error"&&(this.#s.onError?.(t.error,s,i),this.#s.onSettled?.(void 0,t.error,s,i))}this.listeners.forEach(s=>{s(this.#i)})})}};function g(t,s){const i=b(),[e]=o.useState(()=>new v(i,t));o.useEffect(()=>{e.setOptions(t)},[e,t]);const r=o.useSyncExternalStore(o.useCallback(n=>e.subscribe(a.batchCalls(n)),[e]),()=>e.getCurrentResult(),()=>e.getCurrentResult()),u=o.useCallback((n,c)=>{e.mutate(n,c).catch(m)},[e]);if(r.error&&f(e.options.throwOnError,[r.error]))throw r.error;return{...r,mutate:u,mutateAsync:r.mutate}}export{g as u};
|
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/user-D0H1hp3K.js
vendored
1
public/assets/admin/assets/user-D0H1hp3K.js
vendored
@ -1 +0,0 @@
|
||||
import{j as a}from"./index-ra1jmRmU.js";const i=e=>a.jsx("svg",{className:"inline-block",viewBox:"0 0 24 24",width:"1.2em",height:"1.2em",...e,children:a.jsx("path",{fill:"currentColor",d:"M15.71 12.71a6 6 0 1 0-7.42 0a10 10 0 0 0-6.22 8.18a1 1 0 0 0 2 .22a8 8 0 0 1 15.9 0a1 1 0 0 0 1 .89h.11a1 1 0 0 0 .88-1.1a10 10 0 0 0-6.25-8.19M12 12a4 4 0 1 1 4-4a4 4 0 0 1-4 4"})});export{i as u};
|
66
public/assets/admin/assets/user-nav-Ch7kI57y.js
vendored
66
public/assets/admin/assets/user-nav-Ch7kI57y.js
vendored
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/vendor.css
vendored
Normal file
1
public/assets/admin/assets/vendor.css
vendored
Normal file
File diff suppressed because one or more lines are too long
498
public/assets/admin/assets/vendor.js
vendored
Normal file
498
public/assets/admin/assets/vendor.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/assets/admin/assets/zod-DftZp2aV.js
vendored
1
public/assets/admin/assets/zod-DftZp2aV.js
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 494 B |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user