1969 lines
100 KiB
HTML
1969 lines
100 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>网盘系统 API 接口文档</title>
|
||
<style>
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
min-height: 100vh;
|
||
padding: 20px;
|
||
}
|
||
.container {
|
||
background: white;
|
||
border-radius: 16px;
|
||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||
max-width: 1000px;
|
||
margin: 0 auto;
|
||
overflow: hidden;
|
||
}
|
||
.header {
|
||
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
||
color: white;
|
||
padding: 30px 40px;
|
||
text-align: center;
|
||
}
|
||
.header h1 { font-size: 28px; margin-bottom: 8px; }
|
||
.header p { color: #a0aec0; font-size: 14px; }
|
||
.gateway-badge {
|
||
display: inline-block;
|
||
background: #48bb78;
|
||
color: white;
|
||
padding: 6px 16px;
|
||
border-radius: 20px;
|
||
font-size: 13px;
|
||
margin-top: 12px;
|
||
font-family: monospace;
|
||
}
|
||
.nav {
|
||
display: flex;
|
||
background: #f7fafc;
|
||
border-bottom: 1px solid #e2e8f0;
|
||
overflow-x: auto;
|
||
}
|
||
.nav-item {
|
||
padding: 14px 24px;
|
||
cursor: pointer;
|
||
border-bottom: 3px solid transparent;
|
||
white-space: nowrap;
|
||
font-size: 14px;
|
||
color: #4a5568;
|
||
transition: all 0.2s;
|
||
}
|
||
.nav-item:hover { background: #edf2f7; }
|
||
.nav-item.active {
|
||
border-bottom-color: #667eea;
|
||
color: #667eea;
|
||
font-weight: 600;
|
||
}
|
||
.badge-danger { background: #e53e3e; color: white; padding: 2px 8px; border-radius: 4px; font-size: 12px; }
|
||
.content { padding: 24px 40px; }
|
||
.section { display: none; }
|
||
.section.active { display: block; }
|
||
.service-card {
|
||
background: #f7fafc;
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
border-left: 4px solid #667eea;
|
||
}
|
||
.service-card h2 {
|
||
font-size: 18px;
|
||
color: #2d3748;
|
||
margin-bottom: 4px;
|
||
}
|
||
.service-card .port {
|
||
font-size: 12px;
|
||
color: #718096;
|
||
font-family: monospace;
|
||
}
|
||
.api-item {
|
||
background: white;
|
||
border: 1px solid #e2e8f0;
|
||
border-radius: 8px;
|
||
margin: 12px 0;
|
||
overflow: hidden;
|
||
}
|
||
.api-header {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 14px 18px;
|
||
cursor: pointer;
|
||
transition: background 0.2s;
|
||
}
|
||
.api-header:hover { background: #f7fafc; }
|
||
.method {
|
||
display: inline-block;
|
||
padding: 4px 10px;
|
||
border-radius: 4px;
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
font-family: monospace;
|
||
margin-right: 12px;
|
||
min-width: 65px;
|
||
text-align: center;
|
||
}
|
||
.method.GET { background: #c6f6d5; color: #276749; }
|
||
.method.POST { background: #bee3f8; color: #2a4365; }
|
||
.method.PUT { background: #fefcbf; color: #744210; }
|
||
.method.DELETE { background: #fed7d7; color: #742a2a; }
|
||
.api-path {
|
||
font-family: monospace;
|
||
font-size: 14px;
|
||
color: #2d3748;
|
||
flex: 1;
|
||
}
|
||
.api-desc {
|
||
font-size: 13px;
|
||
color: #718096;
|
||
margin-left: 12px;
|
||
}
|
||
.api-detail {
|
||
display: none;
|
||
padding: 0 18px 18px;
|
||
border-top: 1px solid #e2e8f0;
|
||
}
|
||
.api-detail.show { display: block; }
|
||
.detail-section { margin: 12px 0; }
|
||
.detail-section h4 {
|
||
font-size: 13px;
|
||
color: #4a5568;
|
||
margin-bottom: 6px;
|
||
font-weight: 600;
|
||
}
|
||
.param-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: 13px;
|
||
}
|
||
.param-table th, .param-table td {
|
||
padding: 8px 12px;
|
||
text-align: left;
|
||
border-bottom: 1px solid #e2e8f0;
|
||
}
|
||
.param-table th {
|
||
background: #f7fafc;
|
||
color: #4a5568;
|
||
font-weight: 600;
|
||
}
|
||
.param-table td { color: #2d3748; }
|
||
.code-block {
|
||
background: #1a202c;
|
||
color: #a0aec0;
|
||
padding: 14px 18px;
|
||
border-radius: 6px;
|
||
font-family: 'Fira Code', monospace;
|
||
font-size: 12px;
|
||
overflow-x: auto;
|
||
line-height: 1.6;
|
||
}
|
||
.code-block .key { color: #63b3ed; }
|
||
.code-block .string { color: #68d391; }
|
||
.code-block .number { color: #f6ad55; }
|
||
.code-block .keyword { color: #fc8181; }
|
||
.status-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin-top: 12px;
|
||
}
|
||
.status-table th, .status-table td {
|
||
padding: 10px 14px;
|
||
text-align: left;
|
||
border-bottom: 1px solid #e2e8f0;
|
||
font-size: 13px;
|
||
}
|
||
.status-table th { background: #f7fafc; color: #4a5568; }
|
||
.arch-diagram {
|
||
background: #f7fafc;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
text-align: center;
|
||
margin: 16px 0;
|
||
}
|
||
.arch-flow {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
font-size: 13px;
|
||
}
|
||
.arch-box {
|
||
padding: 8px 16px;
|
||
border-radius: 6px;
|
||
color: white;
|
||
font-weight: 600;
|
||
}
|
||
.arch-box.gateway { background: #48bb78; }
|
||
.arch-box.user { background: #4299e1; }
|
||
.arch-box.drive { background: #ed8936; }
|
||
.arch-box.tmdb { background: #9f7aea; }
|
||
.arch-arrow { color: #a0aec0; font-size: 18px; }
|
||
|
||
/* 认证标识 */
|
||
.auth-badge {
|
||
display: inline-block;
|
||
background: #ed8936;
|
||
color: white;
|
||
padding: 2px 8px;
|
||
border-radius: 10px;
|
||
font-size: 10px;
|
||
font-weight: 600;
|
||
margin-left: 8px;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
/* 搜索框样式 */
|
||
.search-container {
|
||
padding: 16px 40px;
|
||
background: #f7fafc;
|
||
border-bottom: 1px solid #e2e8f0;
|
||
}
|
||
.search-box {
|
||
display: flex;
|
||
align-items: center;
|
||
background: white;
|
||
border: 2px solid #e2e8f0;
|
||
border-radius: 8px;
|
||
padding: 10px 16px;
|
||
transition: all 0.2s;
|
||
}
|
||
.search-box:focus-within {
|
||
border-color: #667eea;
|
||
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
||
}
|
||
.search-icon {
|
||
color: #a0aec0;
|
||
margin-right: 10px;
|
||
font-size: 16px;
|
||
}
|
||
.search-input {
|
||
flex: 1;
|
||
border: none;
|
||
outline: none;
|
||
font-size: 14px;
|
||
color: #2d3748;
|
||
}
|
||
.search-input::placeholder {
|
||
color: #a0aec0;
|
||
}
|
||
.search-clear {
|
||
cursor: pointer;
|
||
color: #a0aec0;
|
||
font-size: 18px;
|
||
padding: 0 4px;
|
||
display: none;
|
||
}
|
||
.search-clear:hover {
|
||
color: #e53e3e;
|
||
}
|
||
.search-clear.show {
|
||
display: block;
|
||
}
|
||
.search-result-count {
|
||
font-size: 12px;
|
||
color: #718096;
|
||
margin-top: 8px;
|
||
display: none;
|
||
}
|
||
.search-result-count.show {
|
||
display: block;
|
||
}
|
||
/* 搜索高亮 */
|
||
.highlight {
|
||
background: #fefcbf;
|
||
padding: 1px 2px;
|
||
border-radius: 2px;
|
||
}
|
||
/* 搜索时隐藏不匹配的项 */
|
||
.api-item.search-hidden {
|
||
display: none;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="header">
|
||
<h1>网盘系统 API 接口文档</h1>
|
||
<p>微服务架构 · 统一网关入口</p>
|
||
<div class="gateway-badge">网关地址:http://localhost:8888</div>
|
||
</div>
|
||
|
||
<div class="nav">
|
||
<div class="nav-item active" data-section="overview">架构总览</div>
|
||
<div class="nav-item" data-section="user">用户服务</div>
|
||
<div class="nav-item" data-section="users">用户管理</div>
|
||
<div class="nav-item" data-section="drive">网盘服务</div>
|
||
<div class="nav-item" data-section="icon">Icon服务</div>
|
||
<div class="nav-item" data-section="tmdb">TMDB服务</div>
|
||
<div class="nav-item" data-section="status">状态码</div>
|
||
</div>
|
||
|
||
<!-- 搜索框 -->
|
||
<div class="search-container">
|
||
<div class="search-box">
|
||
<span class="search-icon">🔍</span>
|
||
<input type="text" class="search-input" id="apiSearch" placeholder="搜索接口路径、描述或功能...">
|
||
<span class="search-clear" id="searchClear">×</span>
|
||
</div>
|
||
<div class="search-result-count" id="searchResultCount"></div>
|
||
</div>
|
||
|
||
<div class="content">
|
||
<!-- 架构总览 -->
|
||
<div class="section active" id="overview">
|
||
<div class="arch-diagram">
|
||
<h3 style="margin-bottom: 16px; color: #2d3748;">服务架构图</h3>
|
||
<div class="arch-flow">
|
||
<div class="arch-box" style="background: #4a5568;">前端</div>
|
||
<span class="arch-arrow">→</span>
|
||
<div class="arch-box gateway">Gateway:8888</div>
|
||
<span class="arch-arrow">→</span>
|
||
<div class="arch-box user">User:8081</div>
|
||
</div>
|
||
<div class="arch-flow" style="margin-top: 8px;">
|
||
<div class="arch-box" style="background: #4a5568; visibility: hidden;">前端</div>
|
||
<span class="arch-arrow" style="visibility: hidden;">→</span>
|
||
<div class="arch-box gateway" style="visibility: hidden;">Gateway</div>
|
||
<span class="arch-arrow">→</span>
|
||
<div class="arch-box drive">Drive:8082</div>
|
||
</div>
|
||
<div class="arch-flow" style="margin-top: 8px;">
|
||
<div class="arch-box" style="background: #4a5568; visibility: hidden;">前端</div>
|
||
<span class="arch-arrow" style="visibility: hidden;">→</span>
|
||
<div class="arch-box gateway" style="visibility: hidden;">Gateway</div>
|
||
<span class="arch-arrow">→</span>
|
||
<div class="arch-box tmdb">TMDB:8083</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="service-card">
|
||
<h2>路由规则</h2>
|
||
<table class="param-table">
|
||
<tr><th>请求路径</th><th>转发服务</th><th>说明</th></tr>
|
||
<tr><td>/api/login, /api/register</td><td>user-service</td><td>登录注册</td></tr>
|
||
<tr><td>/api/token/**, /api/login-logs/**</td><td>user-service</td><td>令牌/日志</td></tr>
|
||
<tr><td>/api/drive/**</td><td>drive-service</td><td>网盘管理</td></tr>
|
||
<tr><td>/api/movies/**</td><td>tmdb-service</td><td>电影管理</td></tr>
|
||
<tr><td>/api/tmdb/**, /api/tmdb-scraper/**</td><td>tmdb-service</td><td>TMDB刮削</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 用户服务 -->
|
||
<div class="section" id="user">
|
||
<div class="service-card">
|
||
<h2>用户认证服务</h2>
|
||
<span class="port">wangpan-user-service : 8081</span>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/login</span>
|
||
<span class="api-desc">用户登录</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求体</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"username"</span>: <span class="string">"用户名"</span>,
|
||
<span class="key">"password"</span>: <span class="string">"密码"</span>
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>成功响应示例</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"message"</span>: <span class="string">"登录成功"</span>,
|
||
<span class="key">"data"</span>: {
|
||
<span class="key">"id"</span>: <span class="number">7</span>,
|
||
<span class="key">"username"</span>: <span class="string">"lrq"</span>,
|
||
<span class="key">"userType"</span>: <span class="number">0</span>, <span style="color:#718096">// 0=普通用户, 1=VIP, 2=管理员</span>
|
||
<span class="key">"status"</span>: <span class="number">1</span>,
|
||
<span class="key">"email"</span>: <span class="string">"xxx@xx.com"</span>,
|
||
<span class="key">"phone"</span>: <span class="string">"138****0000"</span>,
|
||
<span class="key">"realName"</span>: <span class="string">"张三"</span>,
|
||
<span class="key">"avatarUrl"</span>: <span class="string">""</span>,
|
||
<span class="key">"lastLoginIp"</span>: <span class="string">"127.0.0.1"</span>,
|
||
<span class="key">"lastLoginTime"</span>: <span class="string">"2026-06-10T11:20:21"</span>,
|
||
<span class="key">"hasTmdbKey"</span>: <span class="keyword">false</span>,
|
||
<span class="key">"token"</span>: <span class="string">"tk_xxx..."</span>,
|
||
<span class="key">"tokenType"</span>: <span class="string">"Bearer"</span>,
|
||
<span class="key">"expireIn"</span>: <span class="number">604800</span>
|
||
}
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>userType 说明</h4>
|
||
<table class="param-table">
|
||
<tr><th>值</th><th>角色</th><th>权限说明</th></tr>
|
||
<tr><td><strong>0</strong></td><td>普通用户</td><td>仅访问自己的数据(如日志只看自己的)</td></tr>
|
||
<tr><td><strong>1</strong></td><td>VIP 用户</td><td>普通用户 + 更多存储空间</td></tr>
|
||
<tr><td><strong>2</strong></td><td>管理员</td><td>可查看所有用户数据(如全部日志)</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/register</span>
|
||
<span class="api-desc">用户注册</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求体</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"username"</span>: <span class="string">"用户名"</span>,
|
||
<span class="key">"password"</span>: <span class="string">"密码"</span>
|
||
}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/token/validate</span>
|
||
<span class="api-desc">令牌验证</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求头</h4>
|
||
<div class="code-block">Authorization: Bearer <token></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/login-logs</span>
|
||
<span class="api-desc">登录日志查询</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>权限说明</h4>
|
||
<table class="param-table">
|
||
<tr><th>用户类型</th><th>可见范围</th></tr>
|
||
<tr><td>普通用户(userType=0/1)</td><td style="color:#e53e3e">仅自己的登录记录</td></tr>
|
||
<tr><td>管理员(userType=2)</td><td style="color:#38a169">所有用户的登录记录</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>查询参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||
<tr><td>username</td><td>String</td><td>否</td><td>按用户名模糊筛选(管理员可用)</td></tr>
|
||
<tr><td>result</td><td>String</td><td>否</td><td>登录结果:success / fail</td></tr>
|
||
<tr><td>startDate</td><td>String</td><td>否</td><td>开始日期(含),格式:yyyy-MM-dd,如 2026-06-01</td></tr>
|
||
<tr><td>endDate</td><td>String</td><td>否</td><td>结束日期(含),格式:yyyy-MM-dd,如 2026-06-10</td></tr>
|
||
<tr><td>pageNo</td><td>int</td><td>否</td><td>页码,默认 1</td></tr>
|
||
<tr><td>pageSize</td><td>int</td><td>否</td><td>每页条数,默认 20</td></tr>
|
||
</table>
|
||
<p style="color:#718096; font-size:13px; margin-top:8px;">提示:可组合使用多个筛选条件,如 ?result=fail&startDate=2026-06-01&endDate=2026-06-10</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 用户管理(管理员专用) -->
|
||
<div class="section" id="users">
|
||
<div class="service-card">
|
||
<h2>用户管理</h2>
|
||
<span class="port">wangpan-user-service : 8081</span>
|
||
<span class="badge badge-danger">仅管理员 (userType=2)</span>
|
||
</div>
|
||
|
||
<!-- 查询用户列表 -->
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/users</span>
|
||
<span class="api-desc">查询用户列表</span><span class="auth-badge">需Token + 管理员</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>权限说明</h4>
|
||
<table class="param-table">
|
||
<tr><th>角色</th><th>访问权限</th></tr>
|
||
<tr><td>普通/VIP 用户</td><td style="color:#e53e3e">403 权限不足</td></tr>
|
||
<tr><td><strong>管理员</strong></td><td style="color:#38a169">可查看所有用户列表</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>查询参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||
<tr><td>username</td><td>String</td><td>否</td><td>用户名模糊搜索</td></tr>
|
||
<tr><td>status</td><td>int</td><td>否</td><td>状态:0=禁用, 1=正常, 2=锁定</td></tr>
|
||
<tr><td>userType</td><td>int</td><td>否</td><td>角色:0=普通, 1=VIP, 2=管理员</td></tr>
|
||
<tr><td>pageNo</td><td>int</td><td>否</td><td>页码,默认 1</td></tr>
|
||
<tr><td>pageSize</td><td>int</td><td>否</td><td>每页条数,默认 20</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>响应示例</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"data"</span>: {
|
||
<span class="key">"total"</span>: <span class="number">5</span>,
|
||
<span class="key">"list"</span>: [
|
||
{ <span class="key">"id"</span>: <span class="number">7</span>, <span class="key">"username"</span>: <span class="string">"lrq"</span>, <span class="key">"userType"</span>: <span class="number">0</span>, <span class="key">"status"</span>: <span class="number">1</span>, ... }
|
||
],
|
||
<span class="key">"pageNo"</span>: <span class="number">1</span>,
|
||
<span class="key">"pageSize"</span>: <span class="number">20</span>
|
||
}
|
||
}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 新增用户 -->
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/users</span>
|
||
<span class="api-desc">新增用户</span><span class="auth-badge">需Token + 管理员</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求体</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"username"</span>: <span class="string">"必填"</span>,
|
||
<span class="key">"password"</span>: <span class="string">"必填"</span>,
|
||
<span class="key">"email"</span>: <span class="string">"可选"</span>,
|
||
<span class="key">"phone"</span>: <span class="string">"可选"</span>,
|
||
<span class="key">"realName"</span>: <span class="string">"可选"</span>,
|
||
<span class="key">"status"</span>: <span class="number">1</span>, <span style="color:#718096">// 可选:0=禁用, 1=正常, 默认1</span>
|
||
<span class="key">"userType"</span>: <span class="number">0</span> <span style="color:#718096">// 可选:0=普通, 1=VIP, 2=管理员, 默认0</span>
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>成功响应</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"message"</span>: <span class="string">"用户创建成功"</span>,
|
||
<span class="key">"data"</span>: {
|
||
<span class="key">"id"</span>: <span class="number">10</span>,
|
||
<span class="key">"username"</span>: <span class="string">"newuser"</span>,
|
||
<span class="key">"email"</span>: <span class="string">"new@test.com"</span>,
|
||
<span class="key">"status"</span>: <span class="number">1</span>,
|
||
<span class="key">"userType"</span>: <span class="number">0</span>
|
||
}
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>错误码</h4>
|
||
<table class="param-table">
|
||
<tr><th>code</th><th>说明</th></tr>
|
||
<tr><td>400</td><td>用户名或密码为空</td></tr>
|
||
<tr><td>409</td><td>用户名已被占用</td></tr>
|
||
<tr><td>401</td><td>未登录或 Token 无效</td></tr>
|
||
<tr><td>403</td><td>非管理员,无权限操作</td></tr>
|
||
<tr><td>500</td><td>服务器内部错误</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 修改用户 -->
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method PUT">PUT</span>
|
||
<span class="api-path">/api/users/{userId}</span>
|
||
<span class="api-desc">修改用户信息</span><span class="auth-badge">需Token + 管理员</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>userId</td><td>Long</td><td>目标用户 ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>请求体(部分更新,只传需要修改的字段)</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"email"</span>: <span class="string">"新邮箱"</span>, <span style="color:#718096">// 可选</span>
|
||
<span class="key">"phone"</span>: <span class="string">"新手机号"</span>, <span style="color:#718096">// 可选</span>
|
||
<span class="key">"realName"</span>: <span class="string">"新姓名"</span>, <span style="color:#718096">// 可选</span>
|
||
<span class="key">"status"</span>: <span class="number">0</span>, <span style="color:#718096">// 可选:0=禁用, 1=正常, 2=锁定</span>
|
||
<span class="key">"userType"</span>: <span class="number">1</span> <span style="color:#718096">// 可选:0=普通, 1=VIP, 2=管理员</span>
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>成功响应</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"message"</span>: <span class="string">"用户信息更新成功"</span>,
|
||
<span class="key">"data"</span>: {
|
||
<span class="key">"id"</span>: <span class="number">10</span>,
|
||
<span class="key">"username"</span>: <span class="string">"newuser"</span>,
|
||
<span class="key">"email"</span>: <span class="string">"new@test.com"</span>,
|
||
<span class="key">"status"</span>: <span class="number">1</span>,
|
||
<span class="key">"userType"</span>: <span class="number">0</span>
|
||
}
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>错误码</h4>
|
||
<table class="param-table">
|
||
<tr><th>code</th><th>说明</th></tr>
|
||
<tr><td>404</td><td>目标用户不存在</td></tr>
|
||
<tr><td>400</td><td>没有需要更新的字段</td></tr>
|
||
<tr><td>403</td><td>非管理员</td></tr>
|
||
<tr><td>500</td><td>服务器内部错误</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 删除用户 -->
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method DELETE">DELETE</span>
|
||
<span class="api-path">/api/users/{userId}</span>
|
||
<span class="api-desc">删除用户(软删除)</span><span class="auth-badge">需Token + 管理员</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>userId</td><td>Long</td><td>要删除的用户 ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>说明</h4>
|
||
<p>软删除操作,将 <code>is_deleted</code> 设为 1,不物理删除数据。</p>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>成功响应</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"message"</span>: <span class="string">"用户删除成功"</span>,
|
||
<span class="key">"data"</span>: <span class="keyword">null</span>
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>错误码</h4>
|
||
<table class="param-table">
|
||
<tr><th>code</th><th>说明</th></tr>
|
||
<tr><td>404</td><td>目标用户不存在</td></tr>
|
||
<tr><td>400</td><td>删除失败(可能已被删除)</td></tr>
|
||
<tr><td>403</td><td>非管理员</td></tr>
|
||
<tr><td>500</td><td>服务器内部错误</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 网盘服务 -->
|
||
<div class="section" id="drive">
|
||
<div class="service-card">
|
||
<h2>网盘管理服务</h2>
|
||
<span class="port">wangpan-drive-service : 8082</span>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/drive</span>
|
||
<span class="api-desc">创建网盘</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求体</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"name"</span>: <span class="string">"网盘名称"</span>,
|
||
<span class="key">"description"</span>: <span class="string">"网盘描述"</span>,
|
||
<span class="key">"logoData"</span>: <span class="string">"data:image/png;base64,iVBOR..."</span>
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>参数说明</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||
<tr><td>name</td><td>String</td><td>是</td><td>网盘名称</td></tr>
|
||
<tr><td>description</td><td>String</td><td>否</td><td>网盘描述</td></tr>
|
||
<tr><td>logoData</td><td>String</td><td>否</td><td>Logo图片Base64编码,支持 data:image/xxx;base64, 前缀格式,上传后存储到MinIO,数据库仅保存URL</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/drive</span>
|
||
<span class="api-desc">查询网盘列表</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>查询参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
||
<tr><td>pageNo</td><td>1</td><td>页码</td></tr>
|
||
<tr><td>pageSize</td><td>20</td><td>每页条数</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>响应字段</h4>
|
||
<table class="param-table">
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>id</td><td>Long</td><td>网盘ID</td></tr>
|
||
<tr><td>name</td><td>String</td><td>网盘名称</td></tr>
|
||
<tr><td>description</td><td>String</td><td>网盘描述</td></tr>
|
||
<tr><td>logoUrl</td><td>String</td><td>网盘Logo图片链接(MinIO存储地址)</td></tr>
|
||
<tr><td>folderCount</td><td>Integer</td><td>文件夹数量</td></tr>
|
||
<tr><td>fileCount</td><td>Integer</td><td>文件数量</td></tr>
|
||
<tr><td>totalSize</td><td>Long</td><td>总大小(字节)</td></tr>
|
||
<tr><td>status</td><td>String</td><td>状态</td></tr>
|
||
<tr><td>createTime</td><td>String</td><td>创建时间</td></tr>
|
||
<tr><td>updateTime</td><td>String</td><td>更新时间</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/drive/{id}</span>
|
||
<span class="api-desc">查询网盘详情</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>id</td><td>Long</td><td>网盘ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>响应字段</h4>
|
||
<table class="param-table">
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>id</td><td>Long</td><td>网盘ID</td></tr>
|
||
<tr><td>name</td><td>String</td><td>网盘名称</td></tr>
|
||
<tr><td>description</td><td>String</td><td>网盘描述</td></tr>
|
||
<tr><td>logoUrl</td><td>String</td><td>网盘Logo图片链接(MinIO存储地址)</td></tr>
|
||
<tr><td>folderCount</td><td>Integer</td><td>文件夹数量</td></tr>
|
||
<tr><td>fileCount</td><td>Integer</td><td>文件数量</td></tr>
|
||
<tr><td>totalSize</td><td>Long</td><td>总大小(字节)</td></tr>
|
||
<tr><td>status</td><td>String</td><td>状态</td></tr>
|
||
<tr><td>createTime</td><td>String</td><td>创建时间</td></tr>
|
||
<tr><td>updateTime</td><td>String</td><td>更新时间</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method PUT">PUT</span>
|
||
<span class="api-path">/api/drive/{id}</span>
|
||
<span class="api-desc">更新网盘</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求体</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"name"</span>: <span class="string">"新网盘名称"</span>,
|
||
<span class="key">"description"</span>: <span class="string">"新描述"</span>,
|
||
<span class="key">"logoData"</span>: <span class="string">"data:image/png;base64,iVBOR..."</span>
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>参数说明</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||
<tr><td>name</td><td>String</td><td>否</td><td>网盘名称</td></tr>
|
||
<tr><td>description</td><td>String</td><td>否</td><td>网盘描述</td></tr>
|
||
<tr><td>logoData</td><td>String</td><td>否</td><td>新的Logo图片Base64编码,传入后覆盖旧Logo;不传则保留原Logo</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method DELETE">DELETE</span>
|
||
<span class="api-path">/api/drive/{id}</span>
|
||
<span class="api-desc">删除网盘</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail"></div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/drive/{driveId}/folders</span>
|
||
<span class="api-desc">创建文件夹</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求体</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"name"</span>: <span class="string">"文件夹名称"</span>,
|
||
<span class="key">"parentId"</span>: <span class="number">0</span>
|
||
}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/drive/{driveId}/folders</span>
|
||
<span class="api-desc">查询文件夹列表</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>查询参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
||
<tr><td>parentId</td><td>0</td><td>父文件夹 ID</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/drive/{driveId}/folders/{folderId}</span>
|
||
<span class="api-desc">查询文件夹详情</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>driveId</td><td>Long</td><td>网盘ID</td></tr>
|
||
<tr><td>folderId</td><td>Long</td><td>文件夹ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>响应字段</h4>
|
||
<table class="param-table">
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>id</td><td>Long</td><td>文件夹ID</td></tr>
|
||
<tr><td>driveId</td><td>Long</td><td>所属网盘ID</td></tr>
|
||
<tr><td>parentId</td><td>Long</td><td>父文件夹ID(0表示根目录)</td></tr>
|
||
<tr><td>name</td><td>String</td><td>文件夹名称</td></tr>
|
||
<tr><td>description</td><td>String</td><td>文件夹描述</td></tr>
|
||
<tr><td>depth</td><td>Integer</td><td>层级深度</td></tr>
|
||
<tr><td>childFolderCount</td><td>Integer</td><td>子文件夹数量</td></tr>
|
||
<tr><td>fileCount</td><td>Integer</td><td>文件数量</td></tr>
|
||
<tr><td>totalSize</td><td>Long</td><td>总大小(字节)</td></tr>
|
||
<tr><td>createTime</td><td>String</td><td>创建时间</td></tr>
|
||
<tr><td>updateTime</td><td>String</td><td>更新时间</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method PUT">PUT</span>
|
||
<span class="api-path">/api/drive/{driveId}/folders/{folderId}</span>
|
||
<span class="api-desc">更新文件夹</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>driveId</td><td>Long</td><td>网盘ID</td></tr>
|
||
<tr><td>folderId</td><td>Long</td><td>文件夹ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>请求体(部分更新)</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"name"</span>: <span class="string">"新文件夹名称"</span>,
|
||
<span class="key">"description"</span>: <span class="string">"新描述"</span>,
|
||
<span class="key">"parentId"</span>: <span class="number">0</span>
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>参数说明</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||
<tr><td>name</td><td>String</td><td>否</td><td>文件夹名称</td></tr>
|
||
<tr><td>description</td><td>String</td><td>否</td><td>文件夹描述</td></tr>
|
||
<tr><td>parentId</td><td>Long</td><td>否</td><td>父文件夹ID(可移动文件夹)</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method DELETE">DELETE</span>
|
||
<span class="api-path">/api/drive/{driveId}/folders/{folderId}</span>
|
||
<span class="api-desc">删除文件夹</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>driveId</td><td>Long</td><td>网盘ID</td></tr>
|
||
<tr><td>folderId</td><td>Long</td><td>文件夹ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>说明</h4>
|
||
<p>删除文件夹前会检查文件夹是否为空,如果包含子文件夹或电影文件则拒绝删除。</p>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>错误码</h4>
|
||
<table class="param-table">
|
||
<tr><th>code</th><th>说明</th></tr>
|
||
<tr><td>400</td><td>文件夹不为空或数据库操作失败</td></tr>
|
||
<tr><td>401</td><td>未登录或Token无效</td></tr>
|
||
<tr><td>403</td><td>无权访问该文件夹</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/drive/{driveId}/movies</span>
|
||
<span class="api-desc">上传电影文件</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>driveId</td><td>Long</td><td>网盘ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>请求体</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"title"</span>: <span class="string">"电影名称"</span>, <span style="color:#718096">// 必填</span>
|
||
<span class="key">"folderId"</span>: <span class="number">0</span>, <span style="color:#718096">// 可选,默认0(根目录)</span>
|
||
<span class="key">"subtitle"</span>: <span class="string">"副标题"</span>, <span style="color:#718096">// 可选</span>
|
||
<span class="key">"description"</span>: <span class="string">"描述"</span>, <span style="color:#718096">// 可选</span>
|
||
<span class="key">"fileData"</span>: <span class="string">"Base64编码的文件数据"</span>, <span style="color:#718096">// 必填</span>
|
||
<span class="key">"rating"</span>: <span class="number">85</span>, <span style="color:#718096">// 可选,评分0-100</span>
|
||
<span class="key">"tags"</span>: <span class="string">"标签1,标签2"</span> <span style="color:#718096">// 可选</span>
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>参数说明</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||
<tr><td>title</td><td>String</td><td>是</td><td>电影名称(同时作为文件名)</td></tr>
|
||
<tr><td>folderId</td><td>Long</td><td>否</td><td>目标文件夹ID,默认0(根目录)</td></tr>
|
||
<tr><td>subtitle</td><td>String</td><td>否</td><td>副标题</td></tr>
|
||
<tr><td>description</td><td>String</td><td>否</td><td>描述</td></tr>
|
||
<tr><td>fileData</td><td>String</td><td>是</td><td>Base64编码的视频文件数据</td></tr>
|
||
<tr><td>rating</td><td>Integer</td><td>否</td><td>评分</td></tr>
|
||
<tr><td>tags</td><td>String</td><td>否</td><td>标签</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>说明</h4>
|
||
<p>文件通过 Base64 编码上传,服务端解码后存储到 MinIO,返回文件访问 URL。自动检测 MIME 类型(mp4/mkv/avi → video/mp4)。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/drive/{driveId}/folders/{folderId}/movies</span>
|
||
<span class="api-desc">查询电影文件列表</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>driveId</td><td>Long</td><td>网盘ID</td></tr>
|
||
<tr><td>folderId</td><td>Long</td><td>文件夹ID(0表示根目录)</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>查询参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
||
<tr><td>pageNo</td><td>1</td><td>页码</td></tr>
|
||
<tr><td>pageSize</td><td>20</td><td>每页条数(最大100)</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>响应字段</h4>
|
||
<table class="param-table">
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>list[].id</td><td>Long</td><td>电影ID</td></tr>
|
||
<tr><td>list[].title</td><td>String</td><td>电影名称</td></tr>
|
||
<tr><td>list[].originalName</td><td>String</td><td>原始文件名</td></tr>
|
||
<tr><td>list[].mimeType</td><td>String</td><td>MIME类型</td></tr>
|
||
<tr><td>list[].fileSize</td><td>Long</td><td>文件大小(字节)</td></tr>
|
||
<tr><td>list[].extension</td><td>String</td><td>文件扩展名</td></tr>
|
||
<tr><td>list[].minioUrl</td><td>String</td><td>MinIO文件访问URL</td></tr>
|
||
<tr><td>list[].rating</td><td>Integer</td><td>评分</td></tr>
|
||
<tr><td>list[].tags</td><td>String</td><td>标签</td></tr>
|
||
<tr><td>total</td><td>Integer</td><td>总数</td></tr>
|
||
<tr><td>pageNo</td><td>Integer</td><td>当前页码</td></tr>
|
||
<tr><td>pageSize</td><td>Integer</td><td>每页条数</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/drive/{driveId}/movies/{movieId}</span>
|
||
<span class="api-desc">查询电影文件详情</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>driveId</td><td>Long</td><td>网盘ID</td></tr>
|
||
<tr><td>movieId</td><td>Long</td><td>电影ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>响应字段</h4>
|
||
<table class="param-table">
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>id</td><td>Long</td><td>电影ID</td></tr>
|
||
<tr><td>driveId</td><td>Long</td><td>所属网盘ID</td></tr>
|
||
<tr><td>folderId</td><td>Long</td><td>所属文件夹ID</td></tr>
|
||
<tr><td>title</td><td>String</td><td>电影名称</td></tr>
|
||
<tr><td>subtitle</td><td>String</td><td>副标题</td></tr>
|
||
<tr><td>originalName</td><td>String</td><td>原始文件名</td></tr>
|
||
<tr><td>mimeType</td><td>String</td><td>MIME类型</td></tr>
|
||
<tr><td>fileSize</td><td>Long</td><td>文件大小(字节)</td></tr>
|
||
<tr><td>extension</td><td>String</td><td>文件扩展名</td></tr>
|
||
<tr><td>description</td><td>String</td><td>描述</td></tr>
|
||
<tr><td>resourceLibrary</td><td>String</td><td>资源库</td></tr>
|
||
<tr><td>maintainer</td><td>String</td><td>维护者</td></tr>
|
||
<tr><td>status</td><td>String</td><td>状态</td></tr>
|
||
<tr><td>category</td><td>String</td><td>分类</td></tr>
|
||
<tr><td>scrapeType</td><td>String</td><td>刮削类型</td></tr>
|
||
<tr><td>rating</td><td>Integer</td><td>评分</td></tr>
|
||
<tr><td>tags</td><td>String</td><td>标签</td></tr>
|
||
<tr><td>minioUrl</td><td>String</td><td>MinIO文件访问URL</td></tr>
|
||
<tr><td>posterUrl</td><td>String</td><td>海报URL</td></tr>
|
||
<tr><td>createTime</td><td>String</td><td>创建时间</td></tr>
|
||
<tr><td>updateTime</td><td>String</td><td>更新时间</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method PUT">PUT</span>
|
||
<span class="api-path">/api/drive/{driveId}/movies/{movieId}</span>
|
||
<span class="api-desc">更新电影文件信息</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>driveId</td><td>Long</td><td>网盘ID</td></tr>
|
||
<tr><td>movieId</td><td>Long</td><td>电影ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>请求体(部分更新)</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"title"</span>: <span class="string">"新电影名称"</span>,
|
||
<span class="key">"subtitle"</span>: <span class="string">"新副标题"</span>,
|
||
<span class="key">"description"</span>: <span class="string">"新描述"</span>,
|
||
<span class="key">"rating"</span>: <span class="number">90</span>,
|
||
<span class="key">"tags"</span>: <span class="string">"新标签"</span>,
|
||
<span class="key">"category"</span>: <span class="string">"新分类"</span>
|
||
}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method DELETE">DELETE</span>
|
||
<span class="api-path">/api/drive/{driveId}/movies/{movieId}</span>
|
||
<span class="api-desc">删除电影文件</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>driveId</td><td>Long</td><td>网盘ID</td></tr>
|
||
<tr><td>movieId</td><td>Long</td><td>电影ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>说明</h4>
|
||
<p>逻辑删除(软删除),删除后自动更新网盘和文件夹的统计信息。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 重复电影检查 -->
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/drive/movies/duplicates</span>
|
||
<span class="api-desc">检查重复电影</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>功能说明</h4>
|
||
<p>查询当前用户所有网盘下所有文件夹中的电影,按标题(title)分组找出重复的电影。返回每组重复电影的详细信息,包括所在文件夹的完整路径,前端可让用户选择删除其中一个。</p>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>成功响应</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"message"</span>: <span class="string">"查询成功"</span>,
|
||
<span class="key">"data"</span>: {
|
||
<span class="key">"duplicateGroups"</span>: [
|
||
{
|
||
<span class="key">"title"</span>: <span class="string">"电影名称"</span>,
|
||
<span class="key">"count"</span>: <span class="number">2</span>,
|
||
<span class="key">"movies"</span>: [
|
||
{
|
||
<span class="key">"id"</span>: <span class="number">10</span>,
|
||
<span class="key">"driveId"</span>: <span class="number">1</span>,
|
||
<span class="key">"folderId"</span>: <span class="number">5</span>,
|
||
<span class="key">"title"</span>: <span class="string">"电影名称"</span>,
|
||
<span class="key">"originalName"</span>: <span class="string">"电影名称.mp4"</span>,
|
||
<span class="key">"fileSize"</span>: <span class="number">1073741824</span>,
|
||
<span class="key">"extension"</span>: <span class="string">"mp4"</span>,
|
||
<span class="key">"category"</span>: <span class="string">"sci-fi"</span>,
|
||
<span class="key">"rating"</span>: <span class="number">85</span>,
|
||
<span class="key">"createTime"</span>: <span class="string">"2025-01-01T10:00:00"</span>,
|
||
<span class="key">"folderPath"</span>: <span class="string">"我的电影库/科幻/2024"</span>
|
||
},
|
||
{
|
||
<span class="key">"id"</span>: <span class="number">20</span>,
|
||
<span class="key">"driveId"</span>: <span class="number">1</span>,
|
||
<span class="key">"folderId"</span>: <span class="number">8</span>,
|
||
<span class="key">"title"</span>: <span class="string">"电影名称"</span>,
|
||
<span class="key">"originalName"</span>: <span class="string">"电影名称.mkv"</span>,
|
||
<span class="key">"fileSize"</span>: <span class="number">2147483648</span>,
|
||
<span class="key">"extension"</span>: <span class="string">"mkv"</span>,
|
||
<span class="key">"category"</span>: <span class="string">"sci-fi"</span>,
|
||
<span class="key">"rating"</span>: <span class="keyword">null</span>,
|
||
<span class="key">"createTime"</span>: <span class="string">"2025-02-01T15:00:00"</span>,
|
||
<span class="key">"folderPath"</span>: <span class="string">"我的电影库/动作"</span>
|
||
}
|
||
]
|
||
}
|
||
],
|
||
<span class="key">"totalGroups"</span>: <span class="number">1</span>,
|
||
<span class="key">"totalDuplicates"</span>: <span class="number">2</span>
|
||
}
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>返回字段说明</h4>
|
||
<table class="param-table">
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>duplicateGroups</td><td>Array</td><td>重复电影分组列表</td></tr>
|
||
<tr><td>duplicateGroups[].title</td><td>String</td><td>重复的电影标题</td></tr>
|
||
<tr><td>duplicateGroups[].count</td><td>Integer</td><td>该标题下的重复数量</td></tr>
|
||
<tr><td>duplicateGroups[].movies</td><td>Array</td><td>该标题下的所有电影记录</td></tr>
|
||
<tr><td>duplicateGroups[].movies[].id</td><td>Long</td><td>电影ID(可用于删除接口)</td></tr>
|
||
<tr><td>duplicateGroups[].movies[].folderPath</td><td>String</td><td>所在文件夹完整路径,如"网盘名/文件夹1/文件夹2"</td></tr>
|
||
<tr><td>totalGroups</td><td>Integer</td><td>重复组总数</td></tr>
|
||
<tr><td>totalDuplicates</td><td>Integer</td><td>涉及重复的电影总数</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>错误码</h4>
|
||
<table class="param-table">
|
||
<tr><th>code</th><th>说明</th></tr>
|
||
<tr><td>401</td><td>未登录或 Token 无效</td></tr>
|
||
<tr><td>500</td><td>服务器内部错误</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Icon服务 -->
|
||
<div class="section" id="icon">
|
||
<div class="service-card">
|
||
<h2>Icon 管理服务</h2>
|
||
<span class="port">wangpan-drive-service : 8082</span>
|
||
</div>
|
||
|
||
<!-- 创建 Icon -->
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/icon</span>
|
||
<span class="api-desc">创建 Icon</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求体(JSON)</h4>
|
||
<table class="param-table">
|
||
<tr><th>字段</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||
<tr><td>name</td><td>String</td><td>是</td><td>Icon 名称(最大100字符)</td></tr>
|
||
<tr><td>url</td><td>String</td><td>条件必填</td><td>外网链接 URL(最大500字符,linkType为external或both时必填)</td></tr>
|
||
<tr><td>internalUrl</td><td>String</td><td>条件必填</td><td>内网链接 URL(最大500字符,linkType为internal或both时必填)</td></tr>
|
||
<tr><td>linkType</td><td>String</td><td>否</td><td>链接类型:external(仅外网,默认)/ internal(仅内网)/ both(内外网)</td></tr>
|
||
<tr><td>description</td><td>String</td><td>否</td><td>Icon 描述(最大500字符)</td></tr>
|
||
<tr><td>sortOrder</td><td>Integer</td><td>否</td><td>排序值,数字越小越靠前,默认0</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>请求示例(仅外网)</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"name"</span>: <span class="string">"百度"</span>,
|
||
<span class="key">"url"</span>: <span class="string">"https://www.baidu.com"</span>,
|
||
<span class="key">"linkType"</span>: <span class="string">"external"</span>,
|
||
<span class="key">"description"</span>: <span class="string">"搜索引擎"</span>,
|
||
<span class="key">"sortOrder"</span>: <span class="number">1</span>
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>请求示例(内外网都有)</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"name"</span>: <span class="string">"内部系统"</span>,
|
||
<span class="key">"url"</span>: <span class="string">"https://system.example.com"</span>,
|
||
<span class="key">"internalUrl"</span>: <span class="string">"http://192.168.1.100:8080"</span>,
|
||
<span class="key">"linkType"</span>: <span class="string">"both"</span>,
|
||
<span class="key">"description"</span>: <span class="string">"内部管理系统"</span>,
|
||
<span class="key">"sortOrder"</span>: <span class="number">2</span>
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>成功响应(200)</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"message"</span>: <span class="string">"创建成功"</span>,
|
||
<span class="key">"data"</span>: {
|
||
<span class="key">"id"</span>: <span class="number">1</span>,
|
||
<span class="key">"name"</span>: <span class="string">"百度"</span>,
|
||
<span class="key">"url"</span>: <span class="string">"https://www.baidu.com"</span>,
|
||
<span class="key">"internalUrl"</span>: <span class="keyword">null</span>,
|
||
<span class="key">"linkType"</span>: <span class="string">"external"</span>,
|
||
<span class="key">"description"</span>: <span class="string">"搜索引擎"</span>,
|
||
<span class="key">"sortOrder"</span>: <span class="number">1</span>,
|
||
<span class="key">"status"</span>: <span class="string">"active"</span>,
|
||
<span class="key">"logoUrl"</span>: <span class="string">"http://118.178.238.159:39000/wangpan/icons/2/1718265600000.png"</span>,
|
||
<span class="key">"createTime"</span>: <span class="string">"2026-06-13T16:00:00"</span>
|
||
}
|
||
}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 查询 Icon 列表 -->
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/icon</span>
|
||
<span class="api-desc">查询当前用户的 Icon 列表</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>功能说明</h4>
|
||
<p>查询当前登录用户的所有 Icon,按 sortOrder 升序、createTime 降序排列。每个用户只能看到自己创建的 Icon。</p>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>成功响应(200)</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"message"</span>: <span class="string">"查询成功"</span>,
|
||
<span class="key">"data"</span>: {
|
||
<span class="key">"list"</span>: [
|
||
{
|
||
<span class="key">"id"</span>: <span class="number">1</span>,
|
||
<span class="key">"name"</span>: <span class="string">"百度"</span>,
|
||
<span class="key">"url"</span>: <span class="string">"https://www.baidu.com"</span>,
|
||
<span class="key">"internalUrl"</span>: <span class="keyword">null</span>,
|
||
<span class="key">"linkType"</span>: <span class="string">"external"</span>,
|
||
<span class="key">"description"</span>: <span class="string">"搜索引擎"</span>,
|
||
<span class="key">"sortOrder"</span>: <span class="number">1</span>,
|
||
<span class="key">"status"</span>: <span class="string">"active"</span>,
|
||
<span class="key">"logoUrl"</span>: <span class="string">"http://118.178.238.159:39000/wangpan/icons/2/1718265600000.png"</span>,
|
||
<span class="key">"createTime"</span>: <span class="string">"2026-06-13T16:00:00"</span>,
|
||
<span class="key">"updateTime"</span>: <span class="string">"2026-06-13T16:00:00"</span>
|
||
}
|
||
],
|
||
<span class="key">"total"</span>: <span class="number">1</span>
|
||
}
|
||
}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 查询单个 Icon -->
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/icon/{id}</span>
|
||
<span class="api-desc">查询单个 Icon 详情</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>id</td><td>Long</td><td>Icon ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>成功响应(200)</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"message"</span>: <span class="string">"查询成功"</span>,
|
||
<span class="key">"data"</span>: {
|
||
<span class="key">"id"</span>: <span class="number">1</span>,
|
||
<span class="key">"name"</span>: <span class="string">"百度"</span>,
|
||
<span class="key">"url"</span>: <span class="string">"https://www.baidu.com"</span>,
|
||
<span class="key">"internalUrl"</span>: <span class="keyword">null</span>,
|
||
<span class="key">"linkType"</span>: <span class="string">"external"</span>,
|
||
<span class="key">"description"</span>: <span class="string">"搜索引擎"</span>,
|
||
<span class="key">"sortOrder"</span>: <span class="number">1</span>,
|
||
<span class="key">"status"</span>: <span class="string">"active"</span>,
|
||
<span class="key">"logoUrl"</span>: <span class="string">"http://118.178.238.159:39000/wangpan/icons/2/1718265600000.png"</span>,
|
||
<span class="key">"createTime"</span>: <span class="string">"2026-06-13T16:00:00"</span>,
|
||
<span class="key">"updateTime"</span>: <span class="string">"2026-06-13T16:00:00"</span>
|
||
}
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>错误码</h4>
|
||
<table class="param-table">
|
||
<tr><th>code</th><th>说明</th></tr>
|
||
<tr><td>401</td><td>未登录或 Token 无效</td></tr>
|
||
<tr><td>500</td><td>Icon 不存在或无权访问</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 更新 Icon -->
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method PUT">PUT</span>
|
||
<span class="api-path">/api/icon/{id}</span>
|
||
<span class="api-desc">更新 Icon</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>id</td><td>Long</td><td>Icon ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>请求体(JSON,所有字段可选)</h4>
|
||
<table class="param-table">
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>name</td><td>String</td><td>Icon 名称</td></tr>
|
||
<tr><td>url</td><td>String</td><td>外网链接</td></tr>
|
||
<tr><td>internalUrl</td><td>String</td><td>内网链接</td></tr>
|
||
<tr><td>linkType</td><td>String</td><td>链接类型:external / internal / both</td></tr>
|
||
<tr><td>description</td><td>String</td><td>Icon 描述</td></tr>
|
||
<tr><td>sortOrder</td><td>Integer</td><td>排序值</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>请求示例</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"name"</span>: <span class="string">"新名称"</span>,
|
||
<span class="key">"url"</span>: <span class="string">"https://new-url.com"</span>,
|
||
<span class="key">"internalUrl"</span>: <span class="string">"http://192.168.1.100:8080"</span>,
|
||
<span class="key">"linkType"</span>: <span class="string">"both"</span>,
|
||
<span class="key">"sortOrder"</span>: <span class="number">2</span>
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>成功响应(200)</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"message"</span>: <span class="string">"更新成功"</span>,
|
||
<span class="key">"data"</span>: {
|
||
<span class="key">"id"</span>: <span class="number">1</span>,
|
||
<span class="key">"name"</span>: <span class="string">"新名称"</span>,
|
||
<span class="key">"url"</span>: <span class="string">"https://new-url.com"</span>,
|
||
<span class="key">"internalUrl"</span>: <span class="string">"http://192.168.1.100:8080"</span>,
|
||
<span class="key">"linkType"</span>: <span class="string">"both"</span>,
|
||
<span class="key">"description"</span>: <span class="string">"搜索引擎"</span>,
|
||
<span class="key">"sortOrder"</span>: <span class="number">2</span>,
|
||
<span class="key">"status"</span>: <span class="string">"active"</span>,
|
||
<span class="key">"logoUrl"</span>: <span class="string">"http://118.178.238.159:39000/wangpan/icons/2/1718265600000.png"</span>,
|
||
<span class="key">"createTime"</span>: <span class="string">"2026-06-13T16:00:00"</span>,
|
||
<span class="key">"updateTime"</span>: <span class="string">"2026-06-13T17:00:00"</span>
|
||
}
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>错误码</h4>
|
||
<table class="param-table">
|
||
<tr><th>code</th><th>说明</th></tr>
|
||
<tr><td>401</td><td>未登录或 Token 无效</td></tr>
|
||
<tr><td>500</td><td>Icon 不存在或无权修改</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 删除 Icon -->
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method DELETE">DELETE</span>
|
||
<span class="api-path">/api/icon/{id}</span>
|
||
<span class="api-desc">删除 Icon</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>路径参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>id</td><td>Long</td><td>Icon ID</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>成功响应(200)</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"message"</span>: <span class="string">"删除成功"</span>,
|
||
<span class="key">"data"</span>: <span class="keyword">null</span>
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>错误码</h4>
|
||
<table class="param-table">
|
||
<tr><th>code</th><th>说明</th></tr>
|
||
<tr><td>401</td><td>未登录或 Token 无效</td></tr>
|
||
<tr><td>500</td><td>Icon 不存在或无权删除</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- TMDB服务 -->
|
||
<div class="section" id="tmdb">
|
||
<div class="service-card">
|
||
<h2>TMDB 刮削服务</h2>
|
||
<span class="port">wangpan-tmdb-service : 8083</span>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/movies/recommend</span>
|
||
<span class="api-desc">今日推荐(随机推荐3部电影)</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>功能说明</h4>
|
||
<p>从当前用户的电影库中随机抽取3部电影用于首页展示,每次请求返回不同的推荐结果。</p>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>成功响应示例</h4>
|
||
<div class="code-block">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"message"</span>: <span class="string">"查询成功"</span>,
|
||
<span class="key">"data"</span>: {
|
||
<span class="key">"list"</span>: [
|
||
{
|
||
<span class="key">"id"</span>: <span class="number">10</span>,
|
||
<span class="key">"title"</span>: <span class="string">"电影名称1"</span>,
|
||
<span class="key">"subtitle"</span>: <span class="string">"副标题"</span>,
|
||
<span class="key">"posterUrl"</span>: <span class="string">"海报URL"</span>,
|
||
<span class="key">"rating"</span>: <span class="number">85</span>,
|
||
<span class="key">"category"</span>: <span class="string">"动作"</span>,
|
||
<span class="key">"tags"</span>: <span class="string">"标签1,标签2"</span>,
|
||
<span class="key">"createTime"</span>: <span class="string">"2025-01-01T10:00:00"</span>
|
||
},
|
||
{
|
||
<span class="key">"id"</span>: <span class="number">20</span>,
|
||
<span class="key">"title"</span>: <span class="string">"电影名称2"</span>,
|
||
...
|
||
},
|
||
{
|
||
<span class="key">"id"</span>: <span class="number">30</span>,
|
||
<span class="key">"title"</span>: <span class="string">"电影名称3"</span>,
|
||
...
|
||
}
|
||
],
|
||
<span class="key">"count"</span>: <span class="number">3</span>
|
||
}
|
||
}</div>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>返回字段说明</h4>
|
||
<table class="param-table">
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td>list</td><td>Array</td><td>推荐的电影列表(最多3部)</td></tr>
|
||
<tr><td>list[].id</td><td>Long</td><td>电影ID</td></tr>
|
||
<tr><td>list[].title</td><td>String</td><td>电影标题</td></tr>
|
||
<tr><td>list[].subtitle</td><td>String</td><td>副标题</td></tr>
|
||
<tr><td>list[].posterUrl</td><td>String</td><td>海报URL</td></tr>
|
||
<tr><td>list[].rating</td><td>Integer</td><td>评分(0-100)</td></tr>
|
||
<tr><td>list[].category</td><td>String</td><td>分类</td></tr>
|
||
<tr><td>list[].tags</td><td>String</td><td>标签</td></tr>
|
||
<tr><td>list[].createTime</td><td>String</td><td>创建时间</td></tr>
|
||
<tr><td>count</td><td>Integer</td><td>实际返回的电影数量(可能小于3)</td></tr>
|
||
</table>
|
||
</div>
|
||
<div class="detail-section">
|
||
<h4>错误码</h4>
|
||
<table class="param-table">
|
||
<tr><th>code</th><th>说明</th></tr>
|
||
<tr><td>401</td><td>未登录或 Token 无效</td></tr>
|
||
<tr><td>500</td><td>服务器内部错误</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/movies</span>
|
||
<span class="api-desc">电影列表查询</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>查询参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||
<tr><td>keyword</td><td>String</td><td>否</td><td>搜索关键词</td></tr>
|
||
<tr><td>status</td><td>String</td><td>否</td><td>pending / scraped / failed</td></tr>
|
||
<tr><td>category</td><td>String</td><td>否</td><td>分类</td></tr>
|
||
<tr><td>scrapeType</td><td>String</td><td>否</td><td>刮削类型</td></tr>
|
||
<tr><td>pageNo</td><td>int</td><td>否</td><td>页码,默认 1</td></tr>
|
||
<tr><td>pageSize</td><td>int</td><td>否</td><td>每页条数,默认 20</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/movies/{id}</span>
|
||
<span class="api-desc">电影详情查询</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail"></div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/movies</span>
|
||
<span class="api-desc">创建电影</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求体</h4>
|
||
<div class="code-block">{ <span class="key">"title"</span>: <span class="string">"电影名称"</span> }</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method PUT">PUT</span>
|
||
<span class="api-path">/api/movies/{id}</span>
|
||
<span class="api-desc">更新电影</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail"></div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method DELETE">DELETE</span>
|
||
<span class="api-path">/api/movies/{id}</span>
|
||
<span class="api-desc">删除电影</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail"></div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/movies/batch-delete</span>
|
||
<span class="api-desc">批量删除电影</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求体</h4>
|
||
<div class="code-block">{ <span class="key">"ids"</span>: [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>] }</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/movies/stats</span>
|
||
<span class="api-desc">电影统计</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail"></div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/tmdb/key</span>
|
||
<span class="api-desc">获取 TMDB API Key</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail"></div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/tmdb/key</span>
|
||
<span class="api-desc">设置 TMDB API Key</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求体</h4>
|
||
<div class="code-block">{ <span class="key">"tmdbApiKey"</span>: <span class="string">"你的API Key"</span> }</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/tmdb-scraper/scrape</span>
|
||
<span class="api-desc">单部电影刮削</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求体</h4>
|
||
<div class="code-block">{ <span class="key">"movieId"</span>: <span class="number">1</span> }</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/tmdb-scraper/batch-scrape</span>
|
||
<span class="api-desc">批量刮削</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>请求体</h4>
|
||
<div class="code-block">{ <span class="key">"movieIds"</span>: [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>] }</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/tmdb-scraper/caches</span>
|
||
<span class="api-desc">查询缓存列表</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>查询参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
||
<tr><td>pageNo</td><td>1</td><td>页码</td></tr>
|
||
<tr><td>pageSize</td><td>20</td><td>每页条数</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/tmdb-scraper/stats</span>
|
||
<span class="api-desc">刮削统计</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail"></div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method POST">POST</span>
|
||
<span class="api-path">/api/tmdb-scraper/trigger</span>
|
||
<span class="api-desc">手动触发定时任务</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail"></div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method GET">GET</span>
|
||
<span class="api-path">/api/tmdb-scraper/scraper-logs</span>
|
||
<span class="api-desc">查询刮削日志</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail">
|
||
<div class="detail-section">
|
||
<h4>查询参数</h4>
|
||
<table class="param-table">
|
||
<tr><th>参数</th><th>默认值</th><th>说明</th></tr>
|
||
<tr><td>pageNo</td><td>1</td><td>页码</td></tr>
|
||
<tr><td>pageSize</td><td>20</td><td>每页条数</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="api-item">
|
||
<div class="api-header" onclick="toggleDetail(this)">
|
||
<span class="method DELETE">DELETE</span>
|
||
<span class="api-path">/api/tmdb-scraper/cache/{movieId}</span>
|
||
<span class="api-desc">删除缓存</span><span class="auth-badge">需Token</span>
|
||
</div>
|
||
<div class="api-detail"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 状态码 -->
|
||
<div class="section" id="status">
|
||
<div class="service-card">
|
||
<h2>通用响应格式</h2>
|
||
<div class="code-block" style="margin-top: 12px;">{
|
||
<span class="key">"code"</span>: <span class="number">200</span>,
|
||
<span class="key">"message"</span>: <span class="string">"操作结果描述"</span>,
|
||
<span class="key">"data"</span>: { <span class="string">...</span> }
|
||
}</div>
|
||
</div>
|
||
|
||
<div class="service-card">
|
||
<h2>状态码说明</h2>
|
||
<table class="status-table">
|
||
<tr><th>状态码</th><th>说明</th></tr>
|
||
<tr><td>200</td><td>请求成功</td></tr>
|
||
<tr><td>400</td><td>请求参数错误</td></tr>
|
||
<tr><td>401</td><td>未授权 / 令牌无效</td></tr>
|
||
<tr><td>403</td><td>权限不足</td></tr>
|
||
<tr><td>404</td><td>资源不存在</td></tr>
|
||
<tr><td>500</td><td>服务器内部错误</td></tr>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="service-card">
|
||
<h2>认证说明</h2>
|
||
<p style="font-size: 14px; color: #4a5568; line-height: 1.8;">
|
||
除以下 <strong>3 个接口</strong> 外,所有接口都需要在请求头中携带访问令牌:<br><br>
|
||
|
||
<strong>无需 Token 的接口:</strong><br>
|
||
<code style="background:#c6f6d5;padding:2px 8px;border-radius:4px;">POST /api/login</code> 用户登录<br>
|
||
<code style="background:#c6f6d5;padding:2px 8px;border-radius:4px;">POST /api/register</code> 用户注册<br>
|
||
<code style="background:#c6f6d5;padding:2px 8px;border-radius:4px;">GET /api/token/validate?token=xxx</code> 令牌验证(token 通过 URL 参数传递)<br><br>
|
||
|
||
<strong>需要 Token 的接口(带 <span style="background:#ed8936;color:white;padding:1px 6px;border-radius:10px;font-size:10px;font-weight:600;">需Token</span> 标识):</strong><br>
|
||
在请求头中添加:<code style="background: #edf2f7; padding: 2px 8px; border-radius: 4px;">Authorization: Bearer <token></code>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 导航切换
|
||
document.querySelectorAll('.nav-item').forEach(item => {
|
||
item.addEventListener('click', function() {
|
||
document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
|
||
document.querySelectorAll('.section').forEach(s => s.classList.remove('active'));
|
||
this.classList.add('active');
|
||
document.getElementById(this.dataset.section).classList.add('active');
|
||
});
|
||
});
|
||
|
||
// API 详情展开/收起
|
||
function toggleDetail(header) {
|
||
const detail = header.nextElementSibling;
|
||
detail.classList.toggle('show');
|
||
}
|
||
|
||
// 搜索功能
|
||
const searchInput = document.getElementById('apiSearch');
|
||
const searchClear = document.getElementById('searchClear');
|
||
const searchResultCount = document.getElementById('searchResultCount');
|
||
let searchTimeout;
|
||
|
||
searchInput.addEventListener('input', function() {
|
||
clearTimeout(searchTimeout);
|
||
searchTimeout = setTimeout(() => performSearch(this.value), 200);
|
||
|
||
// 显示/隐藏清除按钮
|
||
searchClear.classList.toggle('show', this.value.length > 0);
|
||
});
|
||
|
||
searchClear.addEventListener('click', function() {
|
||
searchInput.value = '';
|
||
performSearch('');
|
||
searchClear.classList.remove('show');
|
||
searchInput.focus();
|
||
});
|
||
|
||
// 支持快捷键 Ctrl/Cmd + K 聚焦搜索框
|
||
document.addEventListener('keydown', function(e) {
|
||
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
||
e.preventDefault();
|
||
searchInput.focus();
|
||
searchInput.select();
|
||
}
|
||
// ESC 键清除搜索
|
||
if (e.key === 'Escape' && document.activeElement === searchInput) {
|
||
searchInput.value = '';
|
||
performSearch('');
|
||
searchClear.classList.remove('show');
|
||
}
|
||
});
|
||
|
||
function performSearch(keyword) {
|
||
const apiItems = document.querySelectorAll('.api-item');
|
||
const sections = document.querySelectorAll('.section');
|
||
|
||
// 清除之前的高亮
|
||
document.querySelectorAll('.highlight').forEach(el => {
|
||
const parent = el.parentNode;
|
||
parent.replaceChild(document.createTextNode(el.textContent), el);
|
||
parent.normalize();
|
||
});
|
||
|
||
if (!keyword.trim()) {
|
||
// 恢复所有项目
|
||
apiItems.forEach(item => item.classList.remove('search-hidden'));
|
||
searchResultCount.classList.remove('show');
|
||
|
||
// 恢复导航栏
|
||
document.querySelectorAll('.nav-item').forEach(item => {
|
||
item.style.display = '';
|
||
});
|
||
|
||
// 恢复 section 显示状态
|
||
sections.forEach(section => {
|
||
section.style.display = '';
|
||
});
|
||
return;
|
||
}
|
||
|
||
const lowerKeyword = keyword.toLowerCase();
|
||
let matchCount = 0;
|
||
const matchedSections = new Set();
|
||
|
||
// 全局搜索:遍历所有分类中的所有接口
|
||
apiItems.forEach(item => {
|
||
const path = item.querySelector('.api-path');
|
||
const desc = item.querySelector('.api-desc');
|
||
const method = item.querySelector('.method');
|
||
|
||
if (!path || !desc) return;
|
||
|
||
const pathText = path.textContent.toLowerCase();
|
||
const descText = desc.textContent.toLowerCase();
|
||
const methodText = method ? method.textContent.toLowerCase() : '';
|
||
|
||
const isMatch = pathText.includes(lowerKeyword) ||
|
||
descText.includes(lowerKeyword) ||
|
||
methodText.includes(lowerKeyword);
|
||
|
||
if (isMatch) {
|
||
item.classList.remove('search-hidden');
|
||
matchCount++;
|
||
|
||
// 记录匹配的 section
|
||
const section = item.closest('.section');
|
||
if (section) {
|
||
matchedSections.add(section.id);
|
||
}
|
||
|
||
// 高亮匹配内容
|
||
highlightText(path, keyword);
|
||
highlightText(desc, keyword);
|
||
|
||
// 自动展开匹配的详情
|
||
const detail = item.querySelector('.api-detail');
|
||
if (detail && !detail.classList.contains('show')) {
|
||
detail.classList.add('show');
|
||
}
|
||
} else {
|
||
item.classList.add('search-hidden');
|
||
}
|
||
});
|
||
|
||
// 全局搜索模式:显示所有有匹配结果的分类
|
||
sections.forEach(section => {
|
||
if (section.id === 'overview' || section.id === 'status') {
|
||
// 架构总览和状态码始终显示
|
||
section.style.display = '';
|
||
} else if (matchedSections.has(section.id)) {
|
||
// 有匹配结果的分类强制显示
|
||
section.style.display = 'block';
|
||
} else {
|
||
// 无匹配结果的分类隐藏
|
||
section.style.display = 'none';
|
||
}
|
||
});
|
||
|
||
// 更新导航栏显示(只显示有匹配结果的分类)
|
||
document.querySelectorAll('.nav-item').forEach(item => {
|
||
const sectionId = item.dataset.section;
|
||
if (sectionId === 'overview' || sectionId === 'status') {
|
||
item.style.display = '';
|
||
} else if (matchedSections.has(sectionId)) {
|
||
item.style.display = '';
|
||
} else {
|
||
item.style.display = 'none';
|
||
}
|
||
});
|
||
|
||
// 显示搜索结果
|
||
searchResultCount.textContent = `找到 ${matchCount} 个匹配的接口(跨 ${matchedSections.size} 个分类)`;
|
||
searchResultCount.classList.add('show');
|
||
}
|
||
|
||
function highlightText(element, keyword) {
|
||
const text = element.textContent;
|
||
const lowerText = text.toLowerCase();
|
||
const lowerKeyword = keyword.toLowerCase();
|
||
const index = lowerText.indexOf(lowerKeyword);
|
||
|
||
if (index === -1) return;
|
||
|
||
const before = text.substring(0, index);
|
||
const match = text.substring(index, index + keyword.length);
|
||
const after = text.substring(index + keyword.length);
|
||
|
||
element.innerHTML = '';
|
||
if (before) element.appendChild(document.createTextNode(before));
|
||
|
||
const highlight = document.createElement('span');
|
||
highlight.className = 'highlight';
|
||
highlight.textContent = match;
|
||
element.appendChild(highlight);
|
||
|
||
if (after) element.appendChild(document.createTextNode(after));
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|