mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-09-29 16:06:36 +08:00
添加subStore接口
This commit is contained in:
@@ -132,7 +132,7 @@ CREATE TABLE `user` (
|
||||
--
|
||||
|
||||
INSERT INTO `user` (`id`, `user`, `pwd`, `role_id`, `exp_time`, `flow`, `in_flow`, `out_flow`, `flow_reset_time`, `num`, `created_time`, `updated_time`, `status`) VALUES
|
||||
(1, 'admin_user', '3c85cdebade1c51cf64ca9f3c09d182d', 0, 1780480500000, 99999, 0, 0, 1, 99999, 1748914865000, 1751434735216, 1);
|
||||
(1, 'admin_user', '3c85cdebade1c51cf64ca9f3c09d182d', 0, 2727251700000, 99999, 0, 0, 1, 99999, 1748914865000, 1751434735216, 1);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
||||
registry.addInterceptor(jwtInterceptor())
|
||||
.addPathPatterns("/api/**")
|
||||
.excludePathPatterns("/flow/**")
|
||||
.excludePathPatterns("/api/v1/open_api/**")
|
||||
.excludePathPatterns("/api/v1/config/get")
|
||||
.excludePathPatterns("/api/v1/user/login");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.admin.controller;
|
||||
|
||||
|
||||
import com.admin.common.aop.LogAnnotation;
|
||||
import com.admin.common.lang.R;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.admin.common.utils.Md5Util;
|
||||
import com.admin.entity.User;
|
||||
import com.admin.entity.UserTunnel;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin
|
||||
@RequestMapping("/api/v1/open_api")
|
||||
public class OpenApiController extends BaseController {
|
||||
|
||||
@LogAnnotation
|
||||
@GetMapping("/sub_store")
|
||||
public R create(
|
||||
@RequestParam("user") String user,
|
||||
@RequestParam("pwd") String pwd,
|
||||
@RequestParam(value = "tunnel", required = false, defaultValue = "-1") String tunnel,
|
||||
HttpServletResponse response) {
|
||||
|
||||
// 校验 user 是否为空
|
||||
if (user == null || user.isEmpty()) {
|
||||
return R.err("用户不能为空");
|
||||
}
|
||||
if (pwd == null || pwd.isEmpty()) {
|
||||
return R.err("密码不能为空");
|
||||
}
|
||||
|
||||
User userInfo = userService.getOne(new QueryWrapper<User>().eq("user", user));
|
||||
if (userInfo == null) {
|
||||
return R.err("鉴权失败");
|
||||
}
|
||||
|
||||
String pwdMd5 = Md5Util.md5(pwd);
|
||||
if (!Objects.equals(pwdMd5, userInfo.getPwd())) {
|
||||
return R.err("鉴权失败");
|
||||
}
|
||||
|
||||
final long GIGA = 1024L * 1024L * 1024L;
|
||||
String headerValue;
|
||||
|
||||
if ("-1".equals(tunnel)) {
|
||||
headerValue = buildSubscriptionHeader(
|
||||
userInfo.getOutFlow(),
|
||||
userInfo.getInFlow(),
|
||||
userInfo.getFlow() * GIGA,
|
||||
userInfo.getExpTime() / 1000
|
||||
);
|
||||
} else {
|
||||
UserTunnel tunnelInfo = userTunnelService.getById(tunnel);
|
||||
if (tunnelInfo == null) return R.err("隧道不存在");
|
||||
if (!tunnelInfo.getUserId().toString().equals(userInfo.getId().toString())) return R.err("隧道不存在");
|
||||
headerValue = buildSubscriptionHeader(
|
||||
tunnelInfo.getOutFlow(),
|
||||
tunnelInfo.getInFlow(),
|
||||
tunnelInfo.getFlow() * GIGA,
|
||||
tunnelInfo.getExpTime() / 1000
|
||||
);
|
||||
}
|
||||
|
||||
response.setHeader("ubscription-userinfo", headerValue);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private String buildSubscriptionHeader(long upload, long download, long total, long expire) {
|
||||
return String.format("upload=%d;download=%d;total=%d;expire=%d", upload, download, total, expire);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.admin.entity;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@@ -18,6 +20,27 @@ public class User extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 创建时间(时间戳)
|
||||
*/
|
||||
private Long createdTime;
|
||||
|
||||
/**
|
||||
* 更新时间(时间戳)
|
||||
*/
|
||||
private Long updatedTime;
|
||||
|
||||
/**
|
||||
* 状态(0:正常,1:删除)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
private String user;
|
||||
|
||||
private String pwd;
|
||||
|
||||
@@ -4,7 +4,7 @@ export type SiteConfig = typeof siteConfig;
|
||||
|
||||
// 缓存相关常量
|
||||
const CACHE_PREFIX = 'vite_config_';
|
||||
const VERSION = "1.1.0";
|
||||
const VERSION = "1.1.1";
|
||||
|
||||
// 缓存策略:
|
||||
// - 长期有效,不设置过期时间
|
||||
|
||||
@@ -675,7 +675,7 @@ export default function DashboardPage() {
|
||||
<div key={tunnel.id} className="border border-gray-200 dark:border-default-100 rounded-lg p-3 lg:p-4 hover:shadow-md transition-shadow">
|
||||
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-3 mb-3">
|
||||
<div>
|
||||
<h3 className="font-semibold text-foreground">{tunnel.tunnelName}</h3>
|
||||
<h3 className="font-semibold text-foreground">{tunnel.tunnelName} ID: {tunnel.id}</h3>
|
||||
<div className="flex flex-wrap items-center gap-2 mt-1">
|
||||
<span className={`px-2 py-1 rounded-md text-xs font-medium ${tunnel.tunnelFlow === 1 ? 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-300' : 'bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-300'}`}>
|
||||
{tunnel.tunnelFlow === 1 ? '单向计费' : '双向计费'}
|
||||
|
||||
@@ -537,6 +537,25 @@ export default function NodePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* WebSocket支持说明 */}
|
||||
<div className="mb-6 p-4 bg-warning-50 dark:bg-warning-100/10 border border-warning-200 dark:border-warning-300/20 rounded-lg">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="flex-shrink-0 mt-0.5">
|
||||
<svg className="w-5 h-5 text-warning-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
|
||||
<p className="text-sm text-warning-700 dark:text-warning-300">
|
||||
节点实时监控依赖WebSocket连接。如果面板开启了<strong>反向代理</strong>或使用了<strong>CDN</strong>,
|
||||
请确保已开启WebSocket支持,否则节点状态可能不显示节点信息。
|
||||
具体配置方法请自行搜索相关教程或询问AI助手。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 节点列表 */}
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center h-64">
|
||||
@@ -694,7 +713,7 @@ export default function NodePage() {
|
||||
isLoading={node.copyLoading}
|
||||
className="flex-1 min-h-8"
|
||||
>
|
||||
复制
|
||||
安装
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
|
||||
Reference in New Issue
Block a user