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:
xboard 2025-01-07 12:41:52 +08:00
parent 07eaddcb83
commit 4728784d1f
105 changed files with 1088 additions and 3245 deletions

View File

@ -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"]

View File

@ -1,7 +0,0 @@
unixsocket /run/redis-socket/redis.sock
unixsocketperm 777
port 0
save 900 1
save 300 10
save 60 10000

View File

@ -7,9 +7,8 @@ name: Docker
on: on:
push: push:
branches: [ "dev" ] branches: [ "new" ]
# Publish semver tags as releases. # Publish semver tags as releases.
tags: [ 'v*.*.*' ]
workflow_dispatch: # Enable manual trigger workflow_dispatch: # Enable manual trigger
env: env:
@ -73,7 +72,7 @@ jobs:
context: . context: .
push: true push: true
platforms: linux/amd64,linux/arm64 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. # Sign the resulting Docker image digest except on PRs.
# This will only write to the public Rekor transparency log when the Docker # 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 # repository is public to avoid leaking data. If you would like to publish

View File

@ -14,4 +14,10 @@ RUN composer install --optimize-autoloader --no-cache --no-dev \
&& chown -R www:www /www \ && chown -R www:www /www \
&& chmod -R 775 /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}

View File

@ -1,26 +1,19 @@
# 关于Xboard # 关于Xboard
Xboard是基于V2board二次开发在性能上和功能上都有大部分增强的**面板 Xboard New是基于Xboard二次开发重写后台管理并优化系统架构的**面板,提升可维护性
# 免责声明 # 免责声明
本项目只是本人个人学习开发并维护,本人不保证任何可用性,也不对使用本软件造成的任何后果负责。 本项目只是本人个人学习开发并维护,本人不保证任何可用性,也不对使用本软件造成的任何后果负责。
# Xboard 特点 # Xboard New 特点
基于V2board 二次开发,增加了以下特性 基于Xboard 二次开发,增加了以下特性
- 升级Laravel10 - 增加Octane支持
- 适配Laravels 提升至10+倍并发) - 使用React + Shadcn UI + TailwindCSS重构后台管理
- 适配Webman 比laravels快50%左右)
- 修改配置从数据库中获取
- 支持Docker部署、分布式部署
- 支持根据用户IP归属地来下发订阅
- 增加Hy2支持
- 增加sing-box下发
- 支持直接从cloudflare获取访问者真实IP
- 支持根据客户端版本自动下发新协议
- 支持线路筛选(订阅地址后面增加 &filter=香港|美国)
- 支持Sqlite安装代替Mysql自用用户福音
- 使用Vue3 + TypeScript + NaiveUI + Unocss + Pinia重构用户前端 - 使用Vue3 + TypeScript + NaiveUI + Unocss + Pinia重构用户前端
- 修复大量BUG - 使用Docker Compose作为容器化部署工具
- 使用Docker作为容器化部署工具
- 重构主题管理,增加主题上传,并且只暴露激活主题
- 使用Octane Cache作为设置的缓存
- 优化系统架构,提升可维护性
# **系统架构** # **系统架构**
- PHP8.1+ - PHP8.1+
@ -28,15 +21,26 @@ Xboard是基于V2board二次开发在性能上和功能上都有大部分增
- MySQL5.7+ - MySQL5.7+
- Redis - Redis
- Laravel - Laravel
- Octane
## 性能对比 [查看详情](./docs/性能对比.md) ## 快速体验
> xboard 无论前端还是后端性能都有巨大的提升
|场景 | php-fpm(传统) | php-fpm(传统开启opcache) | laravels | webman(docker)| 使用以下命令快速部署并体验 Xboard基于 Docker + SQLite
|---- | ---- |---- |----| ---|
|首页 | 6请求/秒 | 157请求/秒 | 477请求/秒 | 803请求/秒 | ```bash
|用户订阅 | 6请求/秒 | 196请求/秒 | 586请求/秒 | 1064请求/秒 | git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard && \
|用户首页延迟| 308ms | 110ms | 101ms | 98ms | 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) ![示例图片](./docs/images/dashboard.png)

View File

@ -3,12 +3,9 @@
namespace App\Http\Controllers\V2\Admin; namespace App\Http\Controllers\V2\Admin;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\PlanSort;
use App\Models\Order; use App\Models\Order;
use App\Models\Plan; use App\Models\Plan;
use App\Models\ServerGroup;
use App\Models\User; use App\Models\User;
use App\Services\PlanService;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;

View File

@ -17,6 +17,7 @@ class ServerSave extends FormRequest
$protocolRules = [ $protocolRules = [
'type' => 'required|in:shadowsocks,vmess,trojan,hysteria,vless', 'type' => 'required|in:shadowsocks,vmess,trojan,hysteria,vless',
'spectific_key' => 'nullable|string', 'spectific_key' => 'nullable|string',
'code' => 'nullable|string',
'show' => '', 'show' => '',
'name' => 'required|string', 'name' => 'required|string',
'group_ids' => 'nullable|array', 'group_ids' => 'nullable|array',

View File

@ -66,7 +66,7 @@ class BTCPay implements PaymentInterface
]; ];
} }
public function notify(): array|bool public function notify($params): array|bool
{ {
$payload = trim(get_request_content()); $payload = trim(get_request_content());

View File

@ -1,125 +1,88 @@
当然可以。以下是增强了步骤性的部署教程: ## 1Panel 快速部署指南
# 1panel 部署教程 本指南介绍如何使用 1Panel 部署 Xboard。
本文将介绍如何使用 1panel 快速部署 Xboard。 ### 1. 环境准备
## 安装部署
### 步骤 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
在站点目录中执行以下命令:
安装 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.7ARM 架构可使用 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 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`,然后在站点目录中执行以下命令: - ⚠️ 请确保防火墙已开启,避免 7001 端口暴露到公网
- 代码修改后需要重启服务才能生效
``` - 建议配置 SSL 证书以确保安全访问
docker compose down xboard
docker compose pull
docker compose up -d
```
🎉: 在此,你已完成 Xboard 的更新。
## 注意
- 启用 webman 后做的任何代码修改都需要重启生效。

View File

@ -1,68 +1,67 @@
## Docker-Compose 部署教程 ## aaPanel + Docker 快速部署指南
本文教你如何在命令行使用aapanel + docker-compose来快速Xboard
### 部署 本指南介绍如何使用 aaPanel + Docker Compose 部署 Xboard。
1. 安装aaPanel + 和docker
``` ### 1. 环境准备
# 安装Docker
1. 安装 Docker
```bash
# 安装 Docker
curl -sSL https://get.docker.com | bash curl -sSL https://get.docker.com | bash
# Centos系统可能还需要执行下面命令来启动Docker
# CentOS 系统需要执行:
systemctl enable docker systemctl enable docker
systemctl start docker systemctl start docker
``` ```
```
# 安装宝塔 2. 安装 aaPanel
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 ```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. 环境配置
2. 选择使用LNMP的环境安装方式勾选如下信息
☑️ Nginx 任意版本
☑️ MySQL 5.7
选择 Fast 快速编译后进行安装。
<span style="color:yellow">⚠️ 无需安装php 与 redis</span> 在 aaPanel 中安装 LNMP
- Nginx任意版本
- MySQL 5.7
- ⚠️ 无需安装 PHP 和 Redis
3. 添加站点 ### 3. 部署步骤
>aaPanel 面板 > Website > Add site。
>>在 Domain 填入你指向服务器的域名
>>在 Database 选择MySQL
>>在 PHP Verison 选择纯静态
4. 安装 Xborad 1. 添加站点:
>通过SSH登录到服务器后访问站点路径如/www/wwwroot/你的站点域名。 - 进入 aaPanel > Website > Add site
>以下命令都需要在站点目录进行执行。 - 域名:填写你的域名
``` - 数据库:选择 MySQL
# 删除目录下文件 - PHP 版本:选择纯静态
2. 安装 Xboard
```bash
# 进入站点目录
cd /www/wwwroot/你的域名
# 清理目录
chattr -i .user.ini chattr -i .user.ini
rm -rf .htaccess 404.html 502.html index.html .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 docker compose up -d
``` ```
6. 设置反向代理
> 站点设置 > 反向代理 > 添加反向代理 4. 配置反向代理:
>> 在 **代理名称** 填入 Xboard ```nginx
>> 在 **目标URL** 填入 ```http://127.0.0.1:7001```
>> 修改反向代理规则为:
```
location ^~ / { location ^~ / {
proxy_pass http://127.0.0.1:7001; proxy_pass http://127.0.0.1:7001;
proxy_http_version 1.1; 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的更新
### 注意 - ⚠️ 请确保防火墙已开启,避免 7001 端口暴露到公网
启用webman后做的任何代码修改都需要重启生效 - 代码修改后需要重启服务才能生效
- 建议配置 SSL 证书以确保安全访问

View File

@ -1,64 +1,66 @@
## aapanel部署指南 ## aaPanel 快速部署指南
> 本文将教你如何使用aapanel进行部署
<span style="color:red">Centos7有部分反馈部署失败请尽量避免使用Centos7进行部署</span> 本指南介绍如何使用 aaPanel 部署 Xboard。
### 安装
1. 安装aaPanel
``` ⚠️ 不建议在 CentOS 7 上部署,可能会遇到兼容性问题。
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
### 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. 环境配置
2. 选择使用LNMP的环境安装方式勾选如下信息
☑️ Nginx 任意版本
☑️ MySQL 5.7
☑️ PHP 8.1 如果没看到8.1先不选去App Store安装
选择 Fast 快速编译后进行安装。
3. 安装扩展 1. 在 aaPanel 中安装 LNMP
> aaPanel 面板 > App Store > 找到PHP 8.1点击Setting > Install extentions选择以下扩展进行安装 - Nginx任意版本
- redis - MySQL 5.7
- fileinfo - PHP 8.1
- swoole4
- readline
- event
- inotify (可选,热重载依赖)
4. 解除被禁止函数 2. 安装 PHP 扩展:
> aaPanel 面板 > App Store > 找到PHP 8.1点击Setting > Disabled functions 将以下函数从列表中删除 - redis
- putenv - fileinfo
- proc_open - swoole4
- pcntl_alarm - readline
- pcntl_signal - event
5. 添加站点 3. 解除 PHP 禁用函数:
>aaPanel 面板 > Website > Add site。 - putenv
>>在 Domain 填入你指向服务器的域名 - proc_open
>>在 Database 选择MySQL - pcntl_alarm
>>在 PHP Verison 选择PHP-81 - pcntl_signal
6. 安装 Xborad ### 3. 部署步骤
>通过SSH登录到服务器后访问站点路径如/www/wwwroot/你的站点域名。
>以下命令都需要在站点目录进行执行。 1. 添加站点:
``` - 进入 aaPanel > Website > Add site
# 删除目录下文件 - 填写域名
- 数据库选择 MySQL
- PHP 版本选择 8.1
2. 安装 Xboard
```bash
# 进入站点目录
cd /www/wwwroot/你的域名
# 清理目录
chattr -i .user.ini chattr -i .user.ini
rm -rf .htaccess 404.html 502.html index.html .user.ini rm -rf .htaccess 404.html 502.html index.html .user.ini
```
> 执行命令从 Github 克隆到当前目录。 # 克隆代码
``` git clone -b new https://github.com/cedar2025/Xboard.git ./
git clone https://github.com/cedar2025/Xboard.git ./
``` # 安装依赖
> 执行命令安装依赖包以及V2board
```
sh init.sh sh init.sh
``` ```
> 根据提示完成安装
7. 配置站点目录及伪静态 3. 配置站点:
> 添加完成后编辑添加的站点 > Site directory > Running directory 选择 /public 保存。 - 设置运行目录为 `/public`
> 添加完成后编辑添加的站点 > URL rewrite 填入伪静态信息。 - 配置伪静态规则:
``` ```nginx
location /downloads { location /downloads {
} }
@ -73,82 +75,70 @@ location ~ .*\.(js|css)?$
access_log /dev/null; 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. 配置定时任务# 5. 添加计划任务:
aaPanel 面板 > Cron。 - 类型Shell Script
- 在 Type of Task 选择 Shell Script - 任务名v2board
- 在 Name of Task 填写 v2board - 周期1分钟
- 在 Period 选择 N Minutes 1 Minute - 脚本内容:`php /www/wwwroot/站点目录/artisan schedule:run`
- 在 Script content 填写 `php /www/wwwroot/路径/artisan schedule:run`
根据上述信息添加每1分钟执行一次的定时任务。 ### 4. 开启 Octane可选
1. 配置 PHP
### 开启webman ```bash
> 在上述安装的基础上开启webman提高性能
1. 配置php.ini
> 通过SSH登录到服务器后访问站点路径如/www/wwwroot/你的站点域名。
```
cp /www/server/php/81/etc/php.ini cli-php.ini 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 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. 修改伪静态 2. 添加 Octane 守护进程:
> 站点设置 > URL Rewrite(伪静态) 填入一下内容<span style="color:red">(覆盖前伪静态配置)</span> - 名称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 ~* \.(jpg|jpeg|png|gif|js|css|svg|woff2|woff|ttf|eot|wasm|json|ico)$ {
} }
location ~ .* { location ~ .* {
proxy_pass http://127.0.0.1:7010; proxy_pass http://127.0.0.1:7010;
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Connection ""; proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port; proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme; proxy_set_header Scheme $scheme;
proxy_set_header Server-Protocol $server_protocol; proxy_set_header Server-Protocol $server_protocol;
proxy_set_header Server-Name $server_name; proxy_set_header Server-Name $server_name;
proxy_set_header Server-Addr $server_addr; proxy_set_header Server-Addr $server_addr;
proxy_set_header Server-Port $server_port; proxy_set_header Server-Port $server_port;
} }
``` ```
> 在此你的webman已经成功部署了 ### 5. 版本更新
### 更新 ```bash
# 更新代码
1. 更新代码 cd /www/wwwroot/你的域名
> 通过SSH登录到服务器后访问站点路径如/www/wwwroot/你的站点域名。
```
sh update.sh sh update.sh
# 如果启用了 Octane需要重启守护进程
# aaPanel > App Store > Tools > Supervisor > 重启 Octane
``` ```
2. 重启webman 守护进程(如果启用了webman)
- 1⃣. aaPanel 面板 > App Store > Tools
- 2⃣. 找到Supervisor点击设置找到名为webman的守护进程点击重启即可
### 注意事项
### 注意 - 修改后台路径需要重启服务才能生效
启用webman后做的任何代码修改都需要重启生效 - 启用 octane 后的任何代码修改都需要重启才能生效

View File

@ -1,36 +1,54 @@
#### config/v2board.php 迁移 ## 配置迁移指南
> xboard将配置储存到数据库了 不再使用file进行储存你需要对配置文件进行迁移。
#### docker-compose 环境 本指南介绍如何将 v2board 的配置文件迁移到 Xboard。Xboard 使用数据库存储配置,不再使用文件存储。
1. 在xboard 目录下创建 config文件夹
2. 复制旧项目的 v2board.php 到config目录 ### 1. Docker Compose 环境
3. 修改docker-compose.yaml 取消下面代码的注释(删除 "#"
``` 1. 准备配置文件:
# - ./config/v2board.php:/www/config/v2board.php ```bash
``` # 创建配置目录
4. 执行下面的命令即可完成迁移 mkdir config
```
docker compose down # 复制旧配置文件
docker compose run -it --rm xboard php artisan migrateFromV2b config cp 旧项目路径/config/v2board.php 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
``` ```
## 注意 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 守护进程

View File

@ -1,77 +1,66 @@
## Docker-Compose 部署教程 ## Docker Compose 快速部署指南
本文教你如何在命令行使用docker-compose + sqlite来快速部署Xboard
如果你需要使用Mysql你需要自行处理好Mysql的安装 本指南介绍如何使用 Docker Compose 快速部署 Xboard。默认使用 SQLite 数据库,无需额外安装 MySQL
### 部署 (使用docker-compose 2分钟部署)
> 在此提供Xboard安装、快速体验Xboard的步骤。 ### 1. 环境准备
使用docker compose + sqlite 快速部署站点(**无需安装Mysql以及redis**
1. 安装docker 安装 Docker:
``` ```bash
curl -sSL https://get.docker.com | bash curl -sSL https://get.docker.com | bash
```
Centos系统可能需要执行下面命令来启动Docker。 # CentOS 系统需要执行:
```
systemctl enable docker systemctl enable docker
systemctl start docker systemctl start docker
``` ```
2. 获取Docker compose 文件
``` ### 2. 部署步骤
git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard
1. 获取项目文件:
```bash
git clone -b docker-compose --depth 1 https://github.com/cedar2025/Xboard
cd 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 docker compose up -d
``` ```
> 安装完成之后即可访问你的站点
5. 访问站点
> 启动之后网站端口默认为7001, 你可以配置nginx反向代理使用80端口
网站地址: http://你的IP:7001/ 4. 访问站点:
在此你已经成功部署了, 你可以访问网址体验Xboard的完整功能 - 默认端口7001
- 网站地址http://服务器IP:7001
> 如果你需要使用mysql请自行安装Mysql后重新部署 ### 3. 版本更新
### **更新** ```bash
1. 修改版本
```
cd Xboard cd Xboard
vi docker-compose.yaml
```
> 修改docker-compose.yaml 当中image后面的版本号为你需要的版本
> 如果为版本为latest 则可以忽略这一步,直接进行第二步
2. 更新数据库(可以执行多次都是安全的)
```
docker compose pull docker compose pull
docker compose down docker compose down
docker compose run -it --rm xboard php artisan xboard:update docker compose run -it --rm web php artisan xboard:update
docker compose up -d
```
> 即可更新成功
### **回滚**
> 此回滚不回滚数据库,是否回滚数据库请查看相关文档
1. 回退版本
```
vi docker-compose.yaml
```
> 修改docker-compose.yaml 当中image后面的版本号为更新前的版本号
2. 启动
```
docker compose up -d docker compose up -d
``` ```
### 注意 ### 4. 版本回滚
启用webman后做的任何代码修改都需要重启生效
1. 修改 `docker-compose.yaml` 中的版本号为需要回滚的版本
2. 执行:`docker compose up -d`
### 注意事项
- 如需使用 MySQL请自行安装并重新部署
- 代码修改后需要重启服务才能生效
- 可以配置 Nginx 反向代理使用 80 端口

View File

@ -1,59 +1,63 @@
## V2borad 1.7.3版本迁移指南 ## V2board 1.7.3 迁移指南
### 迁移脚本会对你的数据库做以下更改 本指南介绍如何将 V2board 1.7.3 版本迁移到 Xboard。
- 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
- 添加 v2_log 数据表 ### 1. 数据库变更说明
- 添加 v2_server_hysteria 数据表
- 添加 v2_server_vless 数据表
## 迁移之前 - `v2_stat_order` 表更名为 `v2_stat`
迁移之前你需要执行正常安装步骤(记得不可选择Sqlite) - `order_amount``order_total`
> sqlite迁移请自行学习相关知识 - `commission_amount``commission_total`
- [Docker Compose 纯命令行快速部署](./docs/docker-compose安装指南.md) - 新增字段:
- [aapanel + Docker Compose](./docs/aapanel+docker安装指南.md) - `paid_count` (integer, nullable)
- [aapanel 部署](./docs/) - `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 环境 ### 2. 准备工作
> 以下命令需要你打开SSH进入到项目目录进行执行
1. 停止Xboard ⚠️ 请先完成 Xboard 基础安装(不支持 SQLite
``` - [Docker Compose 部署](./docker-compose安装指南.md)
- [aaPanel + Docker 部署](./aapanel+docker安装指南.md)
- [aaPanel 部署](./aapanel安装指南.md)
### 3. 迁移步骤
#### Docker 环境
```bash
# 1. 停止服务
docker compose down 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. 执行迁移命令 # 2. 清空数据库
``` docker compose run -it --rm web php artisan db:wipe
docker compose run -it --rm xboard php artisan migratefromv2b 1.7.3
``` # 3. 导入旧数据库(重要)
## aapanel 环境 # 请手动导入 V2board 1.7.3 的数据库
1. 清空数据库
# 4. 执行迁移
docker compose run -it --rm web php artisan migratefromv2b 1.7.3
``` ```
#### aaPanel 环境
```bash
# 1. 清空数据库
php artisan db:wipe 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 php artisan migratefromv2b 1.7.3
``` ```
> 上述迁移完成之后你需要进行 配置文件迁移 ### 4. 配置迁移
## config/v2board.php 配置文件迁移 [点击查看步骤](./config迁移指南.md)
> xboard将配置储存到数据库 不再使用file进行储存你需要对配置文件进行迁移。 完成数据迁移后,还需要迁移配置文件:
- [配置迁移指南](./config迁移指南.md)

View File

@ -1,48 +1,51 @@
## V2borad 1.7.4版本迁移指南 ## V2board 1.7.4 迁移指南
### 迁移脚本会对你的数据库做以下更改 本指南介绍如何将 V2board 1.7.4 版本迁移到 Xboard。
- 添加 v2_server_vless 数据表
## 迁移之前 ### 1. 数据库变更说明
迁移之前你需要执行正常安装步骤(记得不可选择Sqlite)
> sqlite迁移请自行学习相关知识
- [Docker Compose 纯命令行快速部署](./docs/docker-compose安装指南.md)
- [aapanel + Docker Compose](./docs/aapanel+docker安装指南.md)
- [aapanel 部署](./docs/)
## 开始迁移 - 新增数据表:
> 针对docker与非docker用户提供不同的迁移步骤你根据你的安装环境选择其一即可。 - `v2_server_vless`
### docker 环境 ### 2. 准备工作
> 以下命令需要你打开SSH进入到项目目录进行执行
1. 停止Xboard ⚠️ 请先完成 Xboard 基础安装(不支持 SQLite
``` - [Docker Compose 部署](./docker-compose安装指南.md)
- [aaPanel + Docker 部署](./aapanel+docker安装指南.md)
- [aaPanel 部署](./aapanel安装指南.md)
### 3. 迁移步骤
#### Docker 环境
```bash
# 1. 停止服务
docker compose down 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. 执行迁移命令 # 2. 清空数据库
``` docker compose run -it --rm web php artisan db:wipe
docker compose run -it --rm xboard php artisan migratefromv2b 1.7.4
``` # 3. 导入旧数据库(重要)
## aapanel 环境 # 请手动导入 V2board 1.7.4 的数据库
1. 清空数据库
# 4. 执行迁移
docker compose run -it --rm web php artisan migratefromv2b 1.7.4
``` ```
#### aaPanel 环境
```bash
# 1. 清空数据库
php artisan db:wipe 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 php artisan migratefromv2b 1.7.4
``` ```
> 上述迁移完成之后你需要进行 配置文件迁移 ### 4. 配置迁移
## config/v2board.php 配置文件迁移 [点击查看步骤](./config迁移指南.md)
> xboard将配置储存到数据库 不再使用file进行储存你需要对配置文件进行迁移。 完成数据迁移后,还需要迁移配置文件:
- [配置迁移指南](./config迁移指南.md)

View File

@ -1,56 +1,61 @@
## V2borad Dev版本迁移指南 ## V2board Dev 迁移指南
> 请先按照官方升级指导升级到 2023/10/27的版本后再执行迁移操作
### 迁移脚本会对你的数据库做以下更改 本指南介绍如何将 V2board Dev2023/10/27版本迁移到 Xboard。
- 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` 字段
## 迁移之前 ⚠️ 请先按照官方指南升级到 2023/10/27 版本后再执行迁移。
迁移之前你需要执行正常安装步骤(记得不可选择Sqlite)
> sqlite迁移请自行学习相关知识
- [Docker Compose 纯命令行快速部署](./docs/docker-compose安装指南.md)
- [aapanel + Docker Compose](./docs/aapanel+docker安装指南.md)
- [aapanel 部署](./docs/)
## 开始迁移 ### 1. 数据库变更说明
> 针对docker与非docker用户提供不同的迁移步骤你根据你的安装环境选择其一即可。
### docker 环境 - `v2_order` 表:
> 以下命令需要你打开SSH进入到项目目录进行执行 - 新增 `surplus_order_ids` (text, nullable) - 折抵订单
1. 停止Xboard
``` - `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 docker compose down
```
2. 清空数据库
```
docker compose run -it --rm xboard php artisan db:wipe
```
3. 导入旧数据库<span style="color:red">(重要)</span>数据库
>导入你dev v2board的数据库到当前数据库当中
4. 执行迁移命令 # 2. 清空数据库
``` docker compose run -it --rm web php artisan db:wipe
docker compose run -it --rm xboard php artisan migratefromv2b dev231027
``` # 3. 导入旧数据库(重要)
## aapanel 环境 # 请手动导入 V2board Dev 的数据库
1. 清空数据库
# 4. 执行迁移
docker compose run -it --rm web php artisan migratefromv2b dev231027
``` ```
#### aaPanel 环境
```bash
# 1. 清空数据库
php artisan db:wipe php artisan db:wipe
```
2. 导入旧数据库<span style="color:red">(重要)</span>数据库
>导入你dev v2board的数据库到当前数据库当中
3. 执行迁移命令 # 2. 导入旧数据库(重要)
``` # 请手动导入 V2board Dev 的数据库
# 3. 执行迁移
php artisan migratefromv2b dev231027 php artisan migratefromv2b dev231027
``` ```
> 上述迁移完成之后你需要进行 配置文件迁移 ### 4. 配置迁移
## config/v2board.php 配置文件迁移 [点击查看步骤](./config迁移指南.md)
> xboard将配置储存到数据库 不再使用file进行储存你需要对配置文件进行迁移。 完成数据迁移后,还需要迁移配置文件:
- [配置迁移指南](./config迁移指南.md)

View File

@ -1,62 +1,68 @@
## V2borad wyx2685版本迁移指南 ## V2board wyx2685 迁移指南
> 此迁移指南写于 2023/11/17 其他时间的版本可能会迁移失败
- wyx2685 添加了设备限制的功能,如果你迁移过来你会失去这个功能
- 你会失去wyx2685佬添加的 trojan的 **(我也不知道) 功能
- 你的hysteria2 线路需要重新配置
### 迁移脚本会对你的数据库做以下更改 本指南介绍如何将 V2board wyx26852023/11/17版本迁移到 Xboard。
- v2_plan
- 删除字段 `device_limit` nullable
- v2_server_hysteria
- 删除字段 `version`
- 删除字段 `obfs`
- 删除字段 `obfs_password`
- v2_server_trojan
- 删除字段 `network`
- 删除字段 `network_settings`
- v2_user
- 删除字段 `device_limit`
## 迁移之前 ⚠️ 迁移注意事项:
迁移之前你需要执行正常安装步骤(记得不可选择Sqlite) - 将失去设备限制功能
> sqlite迁移请自行学习相关知识 - 将失去 Trojan 的特殊功能
- [Docker Compose 纯命令行快速部署](./docs/docker-compose安装指南.md) - Hysteria2 线路需要重新配置
- [aapanel + Docker Compose](./docs/aapanel+docker安装指南.md)
- [aapanel 部署](./docs/)
## 开始迁移 ### 1. 数据库变更说明
> 针对docker与非docker用户提供不同的迁移步骤你根据你的安装环境选择其一即可。
### docker 环境 - `v2_plan` 表:
> 以下命令需要你打开SSH进入到项目目录进行执行 - 删除 `device_limit` (nullable)
1. 停止Xboard
``` - `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 docker compose down
```
2. 清空数据库
```
docker compose run -it --rm xboard php artisan db:wipe
```
3. 导入旧数据库<span style="color:red">(重要)</span>数据库
>导入你wyx2685 v2board的数据库到当前数据库当中
4. 执行迁移命令 # 2. 清空数据库
``` docker compose run -it --rm web php artisan db:wipe
docker compose run -it --rm xboard php artisan migratefromv2b wyx2685
``` # 3. 导入旧数据库(重要)
## aapanel 环境 # 请手动导入 V2board wyx2685 的数据库
1. 清空数据库
# 4. 执行迁移
docker compose run -it --rm web php artisan migratefromv2b wyx2685
``` ```
#### aaPanel 环境
```bash
# 1. 清空数据库
php artisan db:wipe php artisan db:wipe
```
2. 导入旧数据库<span style="color:red">(重要)</span>数据库
>导入你wyx2685 v2board的数据库到当前数据库当中
3. 执行迁移命令 # 2. 导入旧数据库(重要)
``` # 请手动导入 V2board wyx2685 的数据库
# 3. 执行迁移
php artisan migratefromv2b wyx2685 php artisan migratefromv2b wyx2685
``` ```
> 上述迁移完成之后你需要进行 配置文件迁移 ### 4. 配置迁移
## config/v2board.php 配置文件迁移 [点击查看步骤](./config迁移指南.md)
> xboard将配置储存到数据库 不再使用file进行储存你需要对配置文件进行迁移。 完成数据迁移后,还需要迁移配置文件:
- [配置迁移指南](./config迁移指南.md)

1942
php.ini

File diff suppressed because it is too large Load Diff

View File

@ -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};

View File

@ -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

View File

@ -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};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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};

View File

@ -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};

View File

@ -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};

View File

@ -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};

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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};

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

File diff suppressed because one or more lines are too long

View File

@ -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};

File diff suppressed because one or more lines are too long

View File

@ -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};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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};

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

File diff suppressed because one or more lines are too long

View File

@ -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};

File diff suppressed because one or more lines are too long

View File

@ -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};

View File

@ -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};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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};

File diff suppressed because one or more lines are too long

View File

@ -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};

View File

@ -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};

View File

@ -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};

View File

@ -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端口加密方式一般为SSL587端口加密方式一般为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};

View File

@ -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};

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

View File

@ -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};

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

View File

@ -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};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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};

View File

@ -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};

View File

@ -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

View File

@ -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};

View File

@ -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};

View File

@ -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

View File

@ -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};

View File

@ -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

View File

@ -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};

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

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