mirror of
https://github.com/lkddi/Xboard.git
synced 2026-04-03 10:30:51 +08:00
feat: new xboard
This commit is contained in:
@@ -95,5 +95,23 @@
|
||||
"Sending frequently, please try again later": "Sending frequently, please try again later",
|
||||
"Current product is sold out": "Current product is sold out",
|
||||
"There are too many password errors, please try again after :minute minutes.": "There are too many password errors, please try again after :minute minutes.",
|
||||
"Reset failed, Please try again later": "Reset failed, Please try again later"
|
||||
"Reset failed, Please try again later": "Reset failed, Please try again later",
|
||||
"Subscribe": "Subscribe",
|
||||
"User Information": "User Information",
|
||||
"Username": "Username",
|
||||
"Status": "Status",
|
||||
"Active": "Active",
|
||||
"Inactive": "Inactive",
|
||||
"Data Used": "Data Used",
|
||||
"Data Limit": "Data Limit",
|
||||
"Expiration Date": "Expiration Date",
|
||||
"Reset In": "Reset In",
|
||||
"Days": "Days",
|
||||
"Subscription Link": "Subscription Link",
|
||||
"Copy": "Copy",
|
||||
"Copied": "Copied",
|
||||
"QR Code": "QR Code",
|
||||
"Unlimited": "Unlimited",
|
||||
"Device Limit": "Device Limit",
|
||||
"Devices": "Devices"
|
||||
}
|
||||
|
||||
@@ -95,5 +95,23 @@
|
||||
"Sending frequently, please try again later": "发送频繁,请稍后再试",
|
||||
"Current product is sold out": "当前商品已售罄",
|
||||
"There are too many password errors, please try again after :minute minutes.": "密码错误次数过多,请 :minute 分钟后再试",
|
||||
"Reset failed, Please try again later": "重置失败,请稍后再试"
|
||||
"Reset failed, Please try again later": "重置失败,请稍后再试",
|
||||
"Subscribe": "订阅信息",
|
||||
"User Information": "用户信息",
|
||||
"Username": "用户名",
|
||||
"Status": "状态",
|
||||
"Active": "正常",
|
||||
"Inactive": "未激活",
|
||||
"Data Used": "已用流量",
|
||||
"Data Limit": "流量限制",
|
||||
"Expiration Date": "到期时间",
|
||||
"Reset In": "距离重置",
|
||||
"Days": "天",
|
||||
"Subscription Link": "订阅链接",
|
||||
"Copy": "复制",
|
||||
"Copied": "已复制",
|
||||
"QR Code": "二维码",
|
||||
"Unlimited": "长期有效",
|
||||
"Device Limit": "设备限制",
|
||||
"Devices": "台设备"
|
||||
}
|
||||
|
||||
117
resources/lang/zh-TW.json
Normal file
117
resources/lang/zh-TW.json
Normal file
@@ -0,0 +1,117 @@
|
||||
{
|
||||
"The user does not exist": "該用戶不存在",
|
||||
"The old password is wrong": "舊密碼有誤",
|
||||
"Save failed": "保存失敗",
|
||||
"Subscription plan does not exist": "訂閱計劃不存在",
|
||||
"Reset failed": "重置失敗",
|
||||
"Invalid parameter": "參數錯誤",
|
||||
"Insufficient commission balance": "推廣佣金餘額不足",
|
||||
"Transfer failed": "劃轉失敗",
|
||||
"Ticket does not exist": "工單不存在",
|
||||
"There are other unresolved tickets": "存在其他工單尚未處理",
|
||||
"Failed to open ticket": "工單創建失敗",
|
||||
"Message cannot be empty": "消息不能為空",
|
||||
"The ticket is closed and cannot be replied": "工單已關閉,無法回復",
|
||||
"Please wait for the technical enginneer to reply": "請等待技術支持回復",
|
||||
"Ticket reply failed": "工單回復失敗",
|
||||
"Close failed": "關閉失敗",
|
||||
"Unsupported withdrawal method": "不支持的提現方式",
|
||||
"The current required minimum withdrawal commission is :limit": "當前系統要求的最少提現佣金為:¥:limitCNY",
|
||||
"[Commission Withdrawal Request] This ticket is opened by the system": "[提現申請] 本工單由系統發出",
|
||||
"Withdrawal method": "提現方式",
|
||||
"Withdrawal account": "提現賬號",
|
||||
"Unsupported withdrawal": "不支持提現",
|
||||
"Order does not exist": "訂單不存在",
|
||||
"You have an unpaid or pending order, please try again later or cancel it": "您有未付款或開通中的訂單,請稍後再試或將其取消",
|
||||
"This subscription has been sold out, please choose another subscription": "該訂閱已售罄,請更換其它訂閱",
|
||||
"This subscription cannot be renewed, please change to another subscription": "該訂閱無法續費,請更換其它訂閱",
|
||||
"This payment period cannot be purchased, please choose another period": "該訂閱週期無法進行購買,請選擇其它週期",
|
||||
"Subscription has expired or no active subscription, unable to purchase Data Reset Package": "訂閱已過期或無有效訂閱,無法購買重置包",
|
||||
"This subscription has expired, please change to another subscription": "訂閱已過期,請更換其它訂閱",
|
||||
"Coupon failed": "優惠券使用失敗",
|
||||
"Insufficient balance": "餘額不足",
|
||||
"Failed to create order": "訂單創建失敗",
|
||||
"Order does not exist or has been paid": "訂單不存在或已支付",
|
||||
"Payment method is not available": "支付方式不可用",
|
||||
"You can only cancel pending orders": "只可以取消待支付訂單",
|
||||
"Cancel failed": "取消失敗",
|
||||
"Currency conversion has timed out, please try again later": "貨幣轉換超時,請稍後再試",
|
||||
"Payment gateway request failed": "支付網關請求失敗",
|
||||
"Oops, there's a problem... Please refresh the page and try again later": "出現了點問題,請刷新頁面稍後再試",
|
||||
"Payment failed. Please check your credit card information": "扣款失敗,請檢查信用卡信息",
|
||||
"Article does not exist": "文章不存在",
|
||||
"No active subscription. Unable to use our provided Apple ID": "無有效訂閱,無法使用本站提供的 Apple ID",
|
||||
"You must have a valid subscription to view content in this area": "您必須擁有有效的訂閱才可以查看該區域的內容",
|
||||
"The maximum number of creations has been reached": "已達到創建數量上限",
|
||||
"Coupon cannot be empty": "優惠券不能為空",
|
||||
"This coupon is no longer available": "優惠券已無可用次數",
|
||||
"This coupon has not yet started": "優惠券還未到可用時間",
|
||||
"This coupon has expired": "優惠券已過期",
|
||||
"The coupon code cannot be used for this subscription": "該訂閱無法使用此優惠碼",
|
||||
"Invalid coupon": "優惠券無效",
|
||||
"Invalid code is incorrect": "驗證碼有誤",
|
||||
"Email suffix is not in the Whitelist": "郵箱後綴不處於白名單中",
|
||||
"Gmail alias is not supported": "不支持 Gmail 別名郵箱",
|
||||
"Registration has closed": "本站已關閉註冊",
|
||||
"You must use the invitation code to register": "必須使用邀請碼才可以註冊",
|
||||
"Email verification code cannot be empty": "郵箱驗證碼不能為空",
|
||||
"Incorrect email verification code": "郵箱驗證碼有誤",
|
||||
"Email already exists": "郵箱已在系統中存在",
|
||||
"Invalid invitation code": "邀請碼無效",
|
||||
"Register failed": "註冊失敗",
|
||||
"Incorrect email or password": "郵箱或密碼錯誤",
|
||||
"Your account has been suspended": "該賬戶已被停止使用",
|
||||
"Token error": "令牌有誤",
|
||||
"This email is not registered in the system": "該郵箱不存在系統中",
|
||||
"Email verification code has been sent, please request again later": "驗證碼已發送,請過一會兒再請求",
|
||||
"Email verification code": "郵箱驗證碼",
|
||||
"Plan ID cannot be empty": "套餐 ID 不能為空",
|
||||
"Plan period cannot be empty": "套餐週期不能為空",
|
||||
"Wrong plan period": "套餐週期參數有誤",
|
||||
"Ticket subject cannot be empty": "工單主題不能為空",
|
||||
"Ticket level cannot be empty": "工單等級不能為空",
|
||||
"Incorrect ticket level format": "工單等級參數有誤",
|
||||
"The withdrawal method cannot be empty": "提現方式不能為空",
|
||||
"The withdrawal account cannot be empty": "提現賬號不能為空",
|
||||
"Old password cannot be empty": "舊密碼不能為空",
|
||||
"New password cannot be empty": "新密碼不能為空",
|
||||
"Password must be greater than 8 digits": "密碼必須大於 8 個字符",
|
||||
"The transfer amount cannot be empty": "劃轉金額不能為空",
|
||||
"The transfer amount parameter is wrong": "劃轉金額參數有誤",
|
||||
"Incorrect format of expiration reminder": "過期提醒參數有誤",
|
||||
"Incorrect traffic alert format": "流量提醒參數有誤",
|
||||
"Email can not be empty": "郵箱不能為空",
|
||||
"Email format is incorrect": "郵箱格式不正確",
|
||||
"Password can not be empty": "密碼不能為空",
|
||||
"The traffic usage in :app_name has reached 80%": "在 :app_name 的已用流量已達到 80%",
|
||||
"The service in :app_name is about to expire": "在 :app_name 的服務即將到期",
|
||||
"The coupon can only be used :limit_use_with_user per person": "該優惠券每人只能用 :limit_use_with_user 次",
|
||||
"The coupon code cannot be used for this period": "此優惠券無法用於該付款週期",
|
||||
"Request failed, please try again later": "請求失敗,請稍後再試",
|
||||
"Register frequently, please try again after :minute minute": "註冊頻繁,請等待 :minute 分鐘後再次嘗試",
|
||||
"Uh-oh, we've had some problems, we're working on it.": "遇到了些問題,我們正在進行處理",
|
||||
"This subscription reset package does not apply to your subscription": "該訂閱重置包不適用於你的訂閱",
|
||||
"Login to :name": "登入到 :name",
|
||||
"Sending frequently, please try again later": "發送頻繁,請稍後再試",
|
||||
"Current product is sold out": "當前商品已售罄",
|
||||
"There are too many password errors, please try again after :minute minutes.": "密碼錯誤次數過多,請 :minute 分鐘後再試",
|
||||
"Reset failed, Please try again later": "重置失敗,請稍後再試",
|
||||
"Subscribe": "訂閱資訊",
|
||||
"User Information": "用戶資訊",
|
||||
"Username": "用戶名",
|
||||
"Status": "狀態",
|
||||
"Active": "正常",
|
||||
"Inactive": "未啟用",
|
||||
"Data Used": "已用流量",
|
||||
"Data Limit": "流量限制",
|
||||
"Expiration Date": "到期時間",
|
||||
"Reset In": "距離重置",
|
||||
"Days": "天",
|
||||
"Subscription Link": "訂閱連結",
|
||||
"Copy": "複製",
|
||||
"Copied": "已複製",
|
||||
"QR Code": "二維碼",
|
||||
"Unlimited": "長期有效",
|
||||
"Device Limit": "設備限制",
|
||||
"Devices": "台設備"
|
||||
}
|
||||
@@ -49,8 +49,7 @@
|
||||
"auto_route": true,
|
||||
"domain_strategy": "prefer_ipv4",
|
||||
"endpoint_independent_nat": true,
|
||||
"inet4_address": "172.19.0.1/30",
|
||||
"inet6_address": "2001:0470:f9da:fdfa::1/64",
|
||||
"address": ["172.19.0.1/30", "2001:0470:f9da:fdfa::1/64"],
|
||||
"mtu": 9000,
|
||||
"sniff": true,
|
||||
"sniff_override_destination": true,
|
||||
|
||||
@@ -1,36 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<link rel="stylesheet" href="/assets/admin/components.chunk.css?v={{$version}}">
|
||||
<link rel="stylesheet" href="/assets/admin/umi.css?v={{$version}}">
|
||||
<link rel="stylesheet" href="/assets/admin/custom.css?v={{$version}}">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no">
|
||||
<title>{{$title}}</title>
|
||||
<!-- <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,400i,600,700"> -->
|
||||
<script>window.routerBase = "/";</script>
|
||||
<script>
|
||||
window.settings = {
|
||||
title: '{{$title}}',
|
||||
theme: {
|
||||
sidebar: '{{$theme_sidebar}}',
|
||||
header: '{{$theme_header}}',
|
||||
color: '{{$theme_color}}',
|
||||
},
|
||||
version: '{{$version}}',
|
||||
background_url: '{{$background_url}}',
|
||||
logo: '{{$logo}}',
|
||||
secure_path: '{{$secure_path}}'
|
||||
}
|
||||
</script>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{{ $title }}</title>
|
||||
<script>
|
||||
window.settings = {
|
||||
base_url: "/",
|
||||
title: "{{ $title }}",
|
||||
version: "{{ $version }}",
|
||||
logo: "{{ $logo }}",
|
||||
secure_path: "{{ $secure_path }}",
|
||||
};
|
||||
</script>
|
||||
<script type="module" crossorigin src="/assets/admin/assets/index.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/admin/assets/index.css" />
|
||||
<link rel="stylesheet" crossorigin href="/assets/admin/assets/vendor.css">
|
||||
<script src="/assets/admin/locales/en-US.js"></script>
|
||||
<script src="/assets/admin/locales/zh-CN.js"></script>
|
||||
<script src="/assets/admin/locales/ko-KR.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="/assets/admin/vendors.async.js?v={{$version}}"></script>
|
||||
<script src="/assets/admin/components.async.js?v={{$version}}"></script>
|
||||
<script src="/assets/admin/umi.js?v={{$version}}"></script>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
296
resources/views/client/subscribe.blade.php
Normal file
296
resources/views/client/subscribe.blade.php
Normal file
@@ -0,0 +1,296 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ __('Subscribe') }}</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--text: #000000;
|
||||
--text-secondary: #666666;
|
||||
--primary: #2196f3;
|
||||
--success: #4caf50;
|
||||
--danger: #f44336;
|
||||
--border: #eee;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
line-height: 1.6;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
padding: 2rem 1rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.75rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.info-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.25rem;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
min-width: 100px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.info-value {
|
||||
color: var(--text);
|
||||
flex: 1;
|
||||
font-weight: 500;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.status {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status.active {
|
||||
background: var(--success);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.status.inactive {
|
||||
background: var(--danger);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.links-section {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.links-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.link-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.link-input {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
padding-right: 4rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
font-size: 0.875rem;
|
||||
color: var(--text);
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.link-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
position: absolute;
|
||||
right: 0.5rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
padding: 0.5rem;
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
font-size: 0.875rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.copy-btn:hover {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.copy-btn svg {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.copy-btn.copied {
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.qr-section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.qr-section img {
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
padding: 0.75rem;
|
||||
background: white;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
body {
|
||||
padding: 1.5rem 1rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.qr-section img {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bg: #000000;
|
||||
--text: #ffffff;
|
||||
--text-secondary: #999999;
|
||||
--border: #222;
|
||||
}
|
||||
|
||||
.link-input {
|
||||
background: #111;
|
||||
border-color: var(--border);
|
||||
color: var(--text);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1 class="title">{{ __('User Information') }}</h1>
|
||||
|
||||
<div class="info-list">
|
||||
<div class="info-item">
|
||||
<div class="info-label">{{ __('Username') }}</div>
|
||||
<div class="info-value">{{ $username }}</div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">{{ __('Status') }}</div>
|
||||
<div class="info-value">
|
||||
<span class="status {{ $status }}">
|
||||
{{ $status === 'active' ? __('Active') : __('Inactive') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">{{ __('Data Used') }}</div>
|
||||
<div class="info-value">{{ $data_used }}</div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">{{ __('Data Limit') }}</div>
|
||||
<div class="info-value">{{ $data_limit }}</div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">{{ __('Expiration Date') }}</div>
|
||||
<div class="info-value">{{ $expired_date }}</div>
|
||||
</div>
|
||||
|
||||
@if (isset($device_limit))
|
||||
<div class="info-item">
|
||||
<div class="info-label">{{ __('Device Limit') }}</div>
|
||||
<div class="info-value">{{ $device_limit }} {{ __('Devices') }}</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($reset_day)
|
||||
<div class="info-item">
|
||||
<div class="info-label">{{ __('Reset In') }}</div>
|
||||
<div class="info-value">{{ $reset_day }} {{ __('Days') }}</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="links-section">
|
||||
<h2 class="links-title">{{ __('Subscription Link') }}</h2>
|
||||
<div class="link-item">
|
||||
<input type="text" value="{{ $subscription_url }}" readonly id="sub_url" class="link-input" onclick="this.select()">
|
||||
<button class="copy-btn" onclick="copyToClipboard('sub_url')" title="{{ __('Copy') }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
|
||||
</svg>
|
||||
<span>{{ __('Copy') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="qr-section">
|
||||
<img src="data:image/svg+xml;base64,{{ $qr_code }}" alt="{{ __('QR Code') }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function copyToClipboard(elementId) {
|
||||
const element = document.getElementById(elementId);
|
||||
element.select();
|
||||
document.execCommand('copy');
|
||||
element.blur();
|
||||
|
||||
const btn = element.nextElementSibling;
|
||||
const span = btn.querySelector('span');
|
||||
const originalText = span.textContent;
|
||||
|
||||
btn.classList.add('copied');
|
||||
span.textContent = '{{ __('Copied') }}';
|
||||
|
||||
setTimeout(() => {
|
||||
btn.classList.remove('copied');
|
||||
span.textContent = originalText;
|
||||
}, 1000);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -184,4 +184,4 @@
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
Reference in New Issue
Block a user