用户系统与订阅管理前端实现

好的,我理解您需要我继续完成注册功能的模拟逻辑以及后续的UI更新部分。让我们从指定位置继续。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
            // 模拟注册过程
currentUser = {
username: username,
email: email,
role: 'user',
token: 'user-token-' + Date.now(), // 使用时间戳确保唯一性
registerDate: new Date().toLocaleDateString('zh-CN'),
dataLimit: 100, // GB
dataUsed: 0,
expiryDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toLocaleDateString('zh-CN'), // 30天后
status: 'active'
};

// 保存到本地存储
localStorage.setItem('v2rayUser', JSON.stringify(currentUser));
localStorage.setItem('v2rayUsers', JSON.stringify([currentUser])); // 简单模拟用户数据库

// 更新UI
updateUIAfterLogin();

// 关闭模态框
registerModal.style.display = 'none';

// 显示成功消息
showToast('注册成功!已自动登录。');
}

// 更新登录后的UI
function updateUIAfterLogin() {
// 更新用户信息显示
userName.textContent = currentUser.username;
userRole.textContent = currentUser.role === 'admin' ? '管理员' : '普通用户';

// 更新按钮状态
loginBtn.style.display = 'none';
registerBtn.style.display = 'none';
logoutBtn.style.display = 'block';

// 如果是管理员,显示管理按钮和标签
if (currentUser.role === 'admin') {
adminBtn.style.display = 'block';
adminTab.style.display = 'block';
isAdmin = true;
} else {
adminBtn.style.display = 'none';
adminTab.style.display = 'none';
isAdmin = false;
}

// 更新仪表盘数据
updateDashboardData();

// 更新订阅链接
updateSubscribeLink();
}

// 更新仪表盘数据
function updateDashboardData() {
if (!currentUser) return;

document.getElementById('account-status').textContent = currentUser.status === 'active' ? '活跃' : '离线';
document.getElementById('account-level').textContent = currentUser.role === 'admin' ? '管理员' : '普通用户';
document.getElementById('register-date').textContent = currentUser.registerDate;
document.getElementById('data-usage').textContent = `${currentUser.dataUsed.toFixed(1)}/${currentUser.dataLimit} GB`;
document.getElementById('upload-usage').textContent = (currentUser.dataUsed * 0.4).toFixed(1) + ' GB';
document.getElementById('download-usage').textContent = (currentUser.dataUsed * 0.6).toFixed(1) + ' GB';
document.getElementById('expiry-date').textContent = currentUser.expiryDate;

// 更新进度条
const progressBar = document.querySelector('.progress');
const usagePercent = (currentUser.dataUsed / currentUser.dataLimit) * 100;
progressBar.style.width = `${Math.min(usagePercent, 100)}%`;

// 根据使用量改变颜色
if (usagePercent > 90) {
progressBar.style.backgroundColor = 'var(--danger-color)';
} else if (usagePercent > 70) {
progressBar.style.backgroundColor = 'var(--warning-color)';
} else {
progressBar.style.backgroundColor = 'var(--primary-color)';
}
}

// 更新订阅链接
function updateSubscribeLink() {
if (!currentUser) return;

// 生成订阅链接 (这里使用模拟数据)
const domain = window.location.hostname || 'your-domain.com';
subscribeLink.textContent = `https://${domain}/subscribe?token=${currentUser.token}`;

// 重新生成QR码
generateQRCode();
}

// 生成QR码
function generateQRCode() {
// 清空现有QR码
qrcodeDiv.innerHTML = '';

if (!currentUser) return;

// 创建新的QR码
new QRCode(qrcodeDiv, {
text: subscribeLink.textContent,
width: 200,
height: 200,
colorDark: "#000000",
colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.H
});
}

// 复制订阅链接
function copySubscribeLink() {
if (!currentUser) {
showToast('请先登录', true);
return;
}

navigator.clipboard.writeText(subscribeLink.textContent)
.then(() => {
showToast('订阅链接已复制到剪贴板');
})
.catch(err => {
console.error('无法复制文本: ', err);
showToast('复制失败', true);
});
}

// 重置订阅链接
function resetSubscribeLink() {
if (!currentUser) {
showToast('请先登录', true);
return;
}

// 确认操作
if (!confirm('确定要重置订阅链接吗?旧链接将立即失效。')) {
return;
}

// 生成新token
currentUser.token = 'user-token-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);

// 更新本地存储
localStorage.setItem('v2rayUser', JSON.stringify(currentUser));

// 更新UI
updateSubscribeLink();

showToast('订阅链接已重置');
}

// 切换视图
function switchView(viewName) {
// 隐藏所有视图
viewSections.forEach(section => {
section.classList.remove('active');
});

// 取消所有标签的激活状态
navTabs.forEach(tab => {
tab.classList.remove('active');
});

// 显示选中的视图
document.getElementById(`${viewName}-view`).classList.add('active');

// 激活选中的标签
document.querySelector(`.nav-tab[data-view="${viewName}"]`).classList.add('active');

// 如果是订阅页面,更新QR码
if (viewName === 'subscription') {
generateQRCode();
}
}

// 退出登录
function logout() {
currentUser = null;
isAdmin = false;

// 清除本地存储
localStorage.removeItem('v2rayUser');

// 重置UI
userName.textContent = '未登录';
userRole.textContent = '请登录或注册';
loginBtn.style.display = 'block';
registerBtn.style.display = 'block';
logoutBtn.style.display = 'none';
adminBtn.style.display = 'none';
adminTab.style.display = 'none';

// 切换到仪表盘视图
switchView('dashboard');

showToast('已退出登录');
}

// 显示提示消息
function showToast(message, isError = false) {
toast.textContent = message;
toast.className = 'toast' + (isError ? ' error' : '');
toast.classList.add('show');

setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}

// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', initPage);
</script>
</body>
</html>

这个完整的实现包含了以下功能:

  1. 用户系统

    • 用户注册和登录(模拟)
    • 用户信息管理
    • 退出登录功能
  2. 订阅管理

    • 生成唯一的订阅链接
    • 复制订阅链接功能
    • 重置订阅链接功能
    • 二维码生成
  3. 数据展示

    • 流量使用情况和统计
    • 账户状态信息
    • 连接日志(模拟数据)
  4. 管理员功能

    • 用户管理界面
    • 系统状态监控
  5. 其他功能

    • 明暗主题切换
    • 响应式设计
    • 提示消息系统

要将其与您的 sing-box 脚本集成,您需要:

  1. 将此 HTML 文件部署到您的服务器
  2. 实现真实的后端 API 来处理用户注册、登录和数据存储
  3. 修改订阅链接生成逻辑,使其与您的 sing-box 配置相匹配
  4. 添加用户验证和 token 验证机制

这个前端界面已经为您提供了完整的用户交互体验,您只需要将其与后端服务连接即可。

时间: 2025-09-16T20:12:34


👤 用户

实在不知道怎么链接到真实的后端,我是通过下面这个脚本实现代理的。我的想法其实很简单,就是为每一个用户生成一个代理订阅地址,给用户一个后台系统,可以自己注册,登录,可以查看自己的信息,订阅地址等等。当然作为管理员,我可以对用户管理。

脚本说明:https://233boy.com/sing-box/sing-box-script/

之前生成过程中中断了,可能是长度超出了限制,生成的部分数据如下,请跳过已经生成部分从“// 模拟注册过程”继续生成:

V2Ray代理用户管理系统 - 完整实现
我理解您的需求了。您想要一个用户自助系统,让用户可以注册、登录、查看订阅信息,同时您作为管理员可以管理用户。我将为您设计一个完整的解决方案。

下面是完整的HTML代码,包含了用户前端和管理员后台,以及如何与您的sing-box脚本集成的说明:

V2Ray代理用户管理系统