1
8
public/icon/add-file.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- 添加文件图标:文档+加号 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||||
<polyline points="14 2 14 8 20 8"/>
|
||||
<!-- 加号(青绿色) -->
|
||||
<line x1="12" y1="13" x2="12" y2="19" stroke="#2dd4bf" stroke-width="2"/>
|
||||
<line x1="9" y1="16" x2="15" y2="16" stroke="#2dd4bf" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 525 B |
7
public/icon/add-folder.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 添加文件夹图标:文件夹+加号 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
|
||||
<!-- 加号(青绿色) -->
|
||||
<line x1="12" y1="11" x2="12" y2="17" stroke="#2dd4bf" stroke-width="2"/>
|
||||
<line x1="9" y1="14" x2="15" y2="14" stroke="#2dd4bf" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 510 B |
10
public/icon/batch-delete.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<!-- 批量删除图标:垃圾桶+列表 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 6h18"/>
|
||||
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
|
||||
<path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
||||
<!-- 列表线(青绿色) -->
|
||||
<line x1="10" y1="11" x2="10" y2="17" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
<line x1="14" y1="11" x2="14" y2="17" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
<line x1="9" y1="9" x2="15" y2="9" stroke="#2dd4bf" stroke-width="1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 628 B |
13
public/icon/batch-scrape.svg
Normal file
@ -0,0 +1,13 @@
|
||||
<!-- 批量刮削图标:电影+列表 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="6" width="18" height="14" rx="1"/>
|
||||
<path d="M3 10h18"/>
|
||||
<path d="M7 6V3"/>
|
||||
<path d="M12 6V3"/>
|
||||
<path d="M17 6V3"/>
|
||||
<!-- 场记板条纹(青绿色) -->
|
||||
<line x1="5" y1="8" x2="7" y2="8" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
<line x1="9" y1="8" x2="11" y2="8" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
<line x1="13" y1="8" x2="15" y2="8" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
<line x1="17" y1="8" x2="19" y2="8" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 713 B |
8
public/icon/cast.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- 主演图标:面具/戏剧 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M2 12c0-5 4-9 10-9s10 4 10 9"/>
|
||||
<path d="M2 12c0 3 2 5 4 5s3-2 4-5"/>
|
||||
<path d="M14 12c1 3 2 5 4 5s4-2 4-5"/>
|
||||
<!-- 面具高亮(青绿色) -->
|
||||
<path d="M2 12c0 3 2 5 4 5s3-2 4-5" fill="#2dd4bf" stroke="#2dd4bf" stroke-width="0.3" opacity="0.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 492 B |
5
public/icon/checkbox.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<!-- 多选图标:复选框+对勾 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="3" width="18" height="18" rx="3"/>
|
||||
<path d="M7 12l3.5 3.5L17 9" stroke="#2dd4bf" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 346 B |
7
public/icon/close.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 关闭图标:X -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/>
|
||||
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||
<!-- 关闭线高亮(青绿色) -->
|
||||
<line x1="18" y1="6" x2="6" y2="18" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 410 B |
10
public/icon/delete.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<!-- 删除图标:垃圾桶 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 6h18"/>
|
||||
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
|
||||
<path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
||||
<line x1="10" y1="11" x2="10" y2="17"/>
|
||||
<line x1="14" y1="11" x2="14" y2="17"/>
|
||||
<!-- 桶身高亮(青绿色) -->
|
||||
<path d="M9 6v12a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V6" stroke="#2dd4bf" stroke-width="0.8" opacity="0.3"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 577 B |
7
public/icon/description.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 简介图标:打开的书 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
|
||||
<path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
|
||||
<!-- 书页高亮(青绿色) -->
|
||||
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" fill="#2dd4bf" stroke="#2dd4bf" stroke-width="0.3" opacity="0.15"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 495 B |
10
public/icon/detail.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<!-- 详情图标:文档+放大镜 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||||
<polyline points="14 2 14 8 20 8"/>
|
||||
<line x1="8" y1="13" x2="16" y2="13"/>
|
||||
<line x1="8" y1="17" x2="12" y2="17"/>
|
||||
<!-- 放大镜(青绿色) -->
|
||||
<circle cx="17" cy="17" r="3" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
<line x1="19.5" y1="19.5" x2="22" y2="22" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 608 B |
7
public/icon/edit.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 编辑图标:铅笔 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
<!-- 铅笔尖高亮(青绿色) -->
|
||||
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4z" fill="#2dd4bf" stroke="#2dd4bf" stroke-width="0.3" opacity="0.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 529 B |
8
public/icon/export.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- 导出图标:上传箭头 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
||||
<polyline points="17 8 12 3 7 8"/>
|
||||
<line x1="12" y1="3" x2="12" y2="15"/>
|
||||
<!-- 箭头高亮(青绿色) -->
|
||||
<polyline points="17 8 12 3 7 8" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 469 B |
7
public/icon/eye-off.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 隐藏图标:眼睛+斜线 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/>
|
||||
<line x1="1" y1="1" x2="23" y2="23"/>
|
||||
<!-- 斜线高亮(青绿色) -->
|
||||
<line x1="1" y1="1" x2="23" y2="23" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 574 B |
7
public/icon/eye.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 显示图标:眼睛 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<!-- 眼睛高亮(青绿色) -->
|
||||
<circle cx="12" cy="12" r="1.5" fill="#2dd4bf" stroke="#2dd4bf" stroke-width="0.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 436 B |
9
public/icon/fail.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<!-- 失败图标:叉号圆圈 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="9"/>
|
||||
<line x1="9" y1="9" x2="15" y2="15"/>
|
||||
<line x1="15" y1="9" x2="9" y2="15"/>
|
||||
<!-- 叉号高亮(青绿色) -->
|
||||
<line x1="9" y1="9" x2="15" y2="15" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
<line x1="15" y1="9" x2="9" y2="15" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 528 B |
9
public/icon/file.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<!-- 文件图标:文档 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||||
<polyline points="14 2 14 8 20 8"/>
|
||||
<line x1="8" y1="13" x2="16" y2="13"/>
|
||||
<line x1="8" y1="17" x2="13" y2="17"/>
|
||||
<!-- 文件折角高亮(青绿色) -->
|
||||
<polyline points="14 2 14 8 20 8" stroke="#2dd4bf" stroke-width="1" opacity="0.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 541 B |
7
public/icon/folder-open.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 打开的文件夹图标 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
|
||||
<path d="M2 10h20"/>
|
||||
<!-- 文件夹内部高亮(青绿色) -->
|
||||
<path d="M4 10h16v7a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-7z" fill="#2dd4bf" stroke="#2dd4bf" stroke-width="0.3" opacity="0.15"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 506 B |
7
public/icon/folder-refresh.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 刷新文件夹图标:文件夹+刷新箭头 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
|
||||
<!-- 刷新箭头(青绿色) -->
|
||||
<path d="M14 13a3 3 0 1 1-1-2.2L14 12" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
<polyline points="12 10 14 12 16 10" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 527 B |
6
public/icon/folder.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<!-- 文件夹图标:关闭状态 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
|
||||
<!-- 文件夹标签高亮(青绿色) -->
|
||||
<path d="M4 5h5l2 3h9" stroke="#2dd4bf" stroke-width="1" opacity="0.4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 439 B |
8
public/icon/globe.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- 网络图标:地球 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<line x1="2" y1="12" x2="22" y2="12"/>
|
||||
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>
|
||||
<!-- 地球高亮(青绿色) -->
|
||||
<path d="M12 2a15.3 15.3 0 0 1 4 10" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 514 B |
8
public/icon/info.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- 信息图标:圆圈i -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<line x1="12" y1="16" x2="12" y2="12"/>
|
||||
<line x1="12" y1="8" x2="12.01" y2="8"/>
|
||||
<!-- 信息符号高亮(青绿色) -->
|
||||
<line x1="12" y1="16" x2="12" y2="12" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 461 B |
7
public/icon/link.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 链接图标:链条 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
|
||||
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
|
||||
<!-- 链条连接处高亮(青绿色) -->
|
||||
<path d="M10 13a5 5 0 0 0 2 1.5" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 487 B |
10
public/icon/log.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<!-- 日志图标:剪贴板 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>
|
||||
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"/>
|
||||
<line x1="8" y1="10" x2="16" y2="10"/>
|
||||
<line x1="8" y1="14" x2="16" y2="14"/>
|
||||
<line x1="8" y1="18" x2="12" y2="18"/>
|
||||
<!-- 日志条目高亮(青绿色) -->
|
||||
<line x1="8" y1="10" x2="11" y2="10" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 609 B |
8
public/icon/logout.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- 退出图标:门+箭头 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/>
|
||||
<polyline points="16 17 21 12 16 7"/>
|
||||
<line x1="21" y1="12" x2="9" y2="12"/>
|
||||
<!-- 箭头高亮(青绿色) -->
|
||||
<polyline points="16 17 21 12 16 7" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 471 B |
11
public/icon/movie.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<!-- 电影图标:场记板 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="6" width="18" height="14" rx="1"/>
|
||||
<path d="M3 10h18"/>
|
||||
<path d="M7 6V3"/>
|
||||
<path d="M12 6V3"/>
|
||||
<path d="M17 6V3"/>
|
||||
<!-- 场记板条纹高亮(青绿色) -->
|
||||
<line x1="5" y1="8" x2="7" y2="8" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
<line x1="9" y1="8" x2="11" y2="8" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 557 B |
10
public/icon/network.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<!-- 内外网切换图标:双向箭头 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="4" y1="8" x2="20" y2="8"/>
|
||||
<polyline points="16 4 20 8 16 12"/>
|
||||
<line x1="20" y1="16" x2="4" y2="16"/>
|
||||
<polyline points="8 12 4 16 8 20"/>
|
||||
<!-- 箭头高亮(青绿色) -->
|
||||
<polyline points="16 4 20 8 16 12" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
<polyline points="8 12 4 16 8 20" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 577 B |
154
public/icon/preview.html
Normal file
@ -0,0 +1,154 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>图标预览 - 网盘管理系统</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||
background: #f5f7fa;
|
||||
padding: 32px;
|
||||
color: #374151;
|
||||
}
|
||||
h1 { text-align: center; font-size: 22px; font-weight: 700; margin-bottom: 8px; }
|
||||
.subtitle { text-align: center; font-size: 13px; color: #94a3b8; margin-bottom: 32px; }
|
||||
.section-title {
|
||||
font-size: 15px; font-weight: 600; color: #64748b; margin: 28px 0 12px;
|
||||
padding-bottom: 8px; border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
.icon-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
|
||||
gap: 14px;
|
||||
max-width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.icon-card {
|
||||
display: flex; flex-direction: column; align-items: center; gap: 8px;
|
||||
padding: 16px 8px 12px; background: #fff; border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.06); transition: all 0.2s;
|
||||
}
|
||||
.icon-card:hover { box-shadow: 0 4px 16px rgba(45,212,191,0.15); transform: translateY(-2px); }
|
||||
.icon-card img { width: 40px; height: 40px; object-fit: contain; }
|
||||
.icon-card span { font-size: 11px; color: #64748b; text-align: center; white-space: nowrap; }
|
||||
.style-info {
|
||||
max-width: 960px; margin: 32px auto 0; padding: 20px 24px;
|
||||
background: #fff; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.06);
|
||||
font-size: 13px; line-height: 1.8; color: #64748b;
|
||||
}
|
||||
.style-info strong { color: #374151; }
|
||||
.color-dot { display: inline-block; width: 12px; height: 12px; border-radius: 3px; vertical-align: middle; margin-right: 4px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>网盘管理系统 - 统一风格图标集</h1>
|
||||
<p class="subtitle">深色描边 + 青绿色点缀 · 简约立体风格 · 根据代码实际使用场景生成</p>
|
||||
|
||||
<div class="section-title">顶部导航栏</div>
|
||||
<div class="icon-grid" id="grid-topbar"></div>
|
||||
|
||||
<div class="section-title">用户菜单</div>
|
||||
<div class="icon-grid" id="grid-user"></div>
|
||||
|
||||
<div class="section-title">网盘与文件管理</div>
|
||||
<div class="icon-grid" id="grid-drive"></div>
|
||||
|
||||
<div class="section-title">刮削与日志</div>
|
||||
<div class="icon-grid" id="grid-scrape"></div>
|
||||
|
||||
<div class="section-title">海报详情</div>
|
||||
<div class="icon-grid" id="grid-poster"></div>
|
||||
|
||||
<div class="section-title">设置与绑定</div>
|
||||
<div class="icon-grid" id="grid-settings"></div>
|
||||
|
||||
<div class="section-title">状态与提示</div>
|
||||
<div class="icon-grid" id="grid-status"></div>
|
||||
|
||||
<div class="style-info">
|
||||
<strong>设计规范:</strong><br/>
|
||||
• 主色(描边):<span class="color-dot" style="background:#374151"></span>#374151 深灰色<br/>
|
||||
• 点缀色(高亮):<span class="color-dot" style="background:#2dd4bf"></span>#2dd4bf 青绿色<br/>
|
||||
• 尺寸:viewBox 24×24,显示 48×48px<br/>
|
||||
• 风格:线条描边 + 局部色块填充,简约立体感<br/>
|
||||
• 格式:SVG 矢量图,可无损缩放<br/>
|
||||
• 用途:替换代码中现有的 emoji 图标,实现视觉统一
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const iconGroups = {
|
||||
'grid-topbar': [
|
||||
{ file: 'search.svg', name: '搜索' },
|
||||
{ file: 'settings.svg', name: '设置' },
|
||||
{ file: 'globe.svg', name: '外网' },
|
||||
{ file: 'network.svg', name: '内外网切换' },
|
||||
{ file: 'user.svg', name: '用户' },
|
||||
{ file: 'switch-view.svg', name: '切换视图' },
|
||||
],
|
||||
'grid-user': [
|
||||
{ file: 'movie.svg', name: '海报展示' },
|
||||
{ file: 'log.svg', name: '控制台' },
|
||||
{ file: 'settings.svg', name: 'TMDB配置' },
|
||||
{ file: 'tools.svg', name: '设置' },
|
||||
{ file: 'export.svg', name: '导出数据' },
|
||||
{ file: 'refresh.svg', name: '恢复数据' },
|
||||
{ file: 'logout.svg', name: '退出登录' },
|
||||
],
|
||||
'grid-drive': [
|
||||
{ file: 'folder.svg', name: '文件夹' },
|
||||
{ file: 'folder-open.svg', name: '打开文件夹' },
|
||||
{ file: 'file.svg', name: '文件' },
|
||||
{ file: 'add-folder.svg', name: '添加文件夹' },
|
||||
{ file: 'add-file.svg', name: '添加文件' },
|
||||
{ file: 'folder-refresh.svg', name: '刷新文件夹' },
|
||||
{ file: 'checkbox.svg', name: '多选' },
|
||||
{ file: 'batch-delete.svg', name: '批量删除' },
|
||||
{ file: 'delete.svg', name: '删除' },
|
||||
{ file: 'edit.svg', name: '编辑' },
|
||||
],
|
||||
'grid-scrape': [
|
||||
{ file: 'scrape.svg', name: '刮削' },
|
||||
{ file: 'batch-scrape.svg', name: '批量刮削' },
|
||||
{ file: 'sync.svg', name: '同步' },
|
||||
{ file: 'log.svg', name: '刮削日志' },
|
||||
],
|
||||
'grid-poster': [
|
||||
{ file: 'movie.svg', name: '电影' },
|
||||
{ file: 'cast.svg', name: '主演' },
|
||||
{ file: 'tag.svg', name: '标签' },
|
||||
{ file: 'detail.svg', name: '查看详情' },
|
||||
{ file: 'description.svg', name: '简介' },
|
||||
],
|
||||
'grid-settings': [
|
||||
{ file: 'link.svg', name: '绑定链接' },
|
||||
{ file: 'globe.svg', name: 'OpenList地址' },
|
||||
{ file: 'user.svg', name: '账号' },
|
||||
{ file: 'eye.svg', name: '显示密码' },
|
||||
{ file: 'eye-off.svg', name: '隐藏密码' },
|
||||
],
|
||||
'grid-status': [
|
||||
{ file: 'success.svg', name: '成功' },
|
||||
{ file: 'fail.svg', name: '失败' },
|
||||
{ file: 'warning.svg', name: '警告' },
|
||||
{ file: 'info.svg', name: '信息' },
|
||||
{ file: 'sparkle.svg', name: '提示' },
|
||||
{ file: 'save.svg', name: '保存' },
|
||||
{ file: 'close.svg', name: '关闭' },
|
||||
],
|
||||
};
|
||||
|
||||
Object.entries(iconGroups).forEach(([gridId, icons]) => {
|
||||
const grid = document.getElementById(gridId);
|
||||
if (!grid) return;
|
||||
icons.forEach(icon => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'icon-card';
|
||||
card.innerHTML = `<img src="${icon.file}" alt="${icon.name}" /><span>${icon.name}</span>`;
|
||||
grid.appendChild(card);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
9
public/icon/refresh.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<!-- 刷新图标:循环箭头 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 2v6h-6"/>
|
||||
<path d="M3 12a9 9 0 0 1 15-6.7L21 8"/>
|
||||
<path d="M3 22v-6h6"/>
|
||||
<path d="M21 12a9 9 0 0 1-15 6.7L3 16"/>
|
||||
<!-- 箭头高亮(青绿色) -->
|
||||
<path d="M21 2v6h-6" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 458 B |
8
public/icon/save.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- 保存图标:软盘 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
|
||||
<polyline points="17 21 17 13 7 13 7 21"/>
|
||||
<polyline points="7 3 7 8 15 8"/>
|
||||
<!-- 软盘标签高亮(青绿色) -->
|
||||
<rect x="9" y="15" width="6" height="4" rx="0.5" fill="#2dd4bf" stroke="#2dd4bf" stroke-width="0.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 525 B |
11
public/icon/scrape.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<!-- 刮削图标:电影+刷新 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="6" width="18" height="14" rx="1"/>
|
||||
<path d="M3 10h18"/>
|
||||
<path d="M7 6V3"/>
|
||||
<path d="M12 6V3"/>
|
||||
<path d="M17 6V3"/>
|
||||
<!-- 刷新箭头(青绿色) -->
|
||||
<path d="M14 13a3 3 0 1 1-1-2.2L14 12" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
<polyline points="12 10 14 12 16 10" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 559 B |
7
public/icon/search.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 搜索图标:放大镜 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="10.5" cy="10.5" r="6.5"/>
|
||||
<line x1="15.5" y1="15.5" x2="21" y2="21"/>
|
||||
<!-- 镜片反光(青绿色) -->
|
||||
<path d="M7 7.5a5 5 0 0 1 3-1" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 416 B |
7
public/icon/settings.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 设置图标:齿轮 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
||||
<!-- 齿轮中心高亮(青绿色) -->
|
||||
<circle cx="12" cy="12" r="1.5" fill="#2dd4bf" stroke="#2dd4bf" stroke-width="0.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1012 B |
6
public/icon/sparkle.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<!-- 提示图标:星星/闪光 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 2l2.4 7.2L22 12l-7.6 2.8L12 22l-2.4-7.2L2 12l7.6-2.8z"/>
|
||||
<!-- 星星高亮(青绿色) -->
|
||||
<path d="M12 2l2.4 7.2L22 12l-7.6 2.8L12 22z" fill="#2dd4bf" stroke="#2dd4bf" stroke-width="0.3" opacity="0.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 450 B |
5
public/icon/success.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<!-- 成功图标:对勾圆圈 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="9"/>
|
||||
<path d="M8 12l3 3 5-6" stroke="#2dd4bf" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 319 B |
10
public/icon/switch-view.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<!-- 切换视图图标:⇄ 双向切换 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="17 1 21 5 17 9"/>
|
||||
<path d="M3 11V9a4 4 0 0 1 4-4h14"/>
|
||||
<polyline points="7 23 3 19 7 15"/>
|
||||
<path d="M21 13v2a4 4 0 0 1-4 4H3"/>
|
||||
<!-- 箭头高亮(青绿色) -->
|
||||
<polyline points="17 1 21 5 17 9" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
<polyline points="7 23 3 19 7 15" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 574 B |
7
public/icon/sync.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 同步图标:云端同步 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 12a9 9 0 1 1-6.219-8.56"/>
|
||||
<polyline points="21 3 21 9 15 9"/>
|
||||
<!-- 同步箭头高亮(青绿色) -->
|
||||
<polyline points="21 3 21 9 15 9" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 422 B |
7
public/icon/tag.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 标签图标 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/>
|
||||
<line x1="7" y1="7" x2="7.01" y2="7"/>
|
||||
<!-- 标签孔高亮(青绿色) -->
|
||||
<circle cx="7" cy="7" r="1" fill="#2dd4bf" stroke="#2dd4bf" stroke-width="0.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 467 B |
6
public/icon/tools.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<!-- 工具图标:扳手 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
|
||||
<!-- 扳手头部高亮(青绿色) -->
|
||||
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 513 B |
7
public/icon/user.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- 用户图标:人物轮廓 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
|
||||
<circle cx="12" cy="7" r="4"/>
|
||||
<!-- 头像高亮(青绿色) -->
|
||||
<path d="M10 5.5a3 3 0 0 1 2-1" stroke="#2dd4bf" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 423 B |
8
public/icon/warning.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- 警告图标:三角感叹号 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#374151" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
|
||||
<line x1="12" y1="9" x2="12" y2="13"/>
|
||||
<line x1="12" y1="17" x2="12.01" y2="17"/>
|
||||
<!-- 感叹号高亮(青绿色) -->
|
||||
<line x1="12" y1="9" x2="12" y2="13" stroke="#2dd4bf" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 534 B |
122
src/App.vue
@ -41,10 +41,11 @@
|
||||
</Transition>
|
||||
<section class="search-topbar">
|
||||
<div class="search-topbar__input">
|
||||
<span class="search-input-icon"><AppIcon name="search" :size="18" /></span>
|
||||
<input
|
||||
v-model="searchKeyword"
|
||||
type="search"
|
||||
placeholder="🔍 输入关键词搜索..."
|
||||
placeholder="输入关键词搜索..."
|
||||
@focus="isSearchFocused = true"
|
||||
@blur="isSearchFocused = false"
|
||||
@keydown.enter="handleHeroSearch"
|
||||
@ -59,22 +60,7 @@
|
||||
@click="toggleDarkMode"
|
||||
:title="isDarkMode ? '切换到白天模式' : '切换到黑夜模式'"
|
||||
>
|
||||
<svg class="theme-toggle-btn__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<g v-if="!isDarkMode" class="theme-icon--sun">
|
||||
<circle cx="12" cy="12" r="5"></circle>
|
||||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||||
</g>
|
||||
<g v-if="isDarkMode" class="theme-icon--moon">
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
<AppIcon :name="isDarkMode ? 'moon' : 'sun'" :size="20" />
|
||||
</button>
|
||||
|
||||
<!-- 快捷入口按钮和悬浮面板 -->
|
||||
@ -113,7 +99,7 @@
|
||||
@click="networkMode = 'internal'"
|
||||
>内网</button>
|
||||
</div>
|
||||
<button v-if="!hasSearched" type="button" class="quick-icons__manage" @click="showIconManageDialog = true" title="管理图标">⚙️</button>
|
||||
<button v-if="!hasSearched" type="button" class="quick-icons__manage" @click="showIconManageDialog = true" title="管理图标"><AppIcon name="settings" :size="18" /></button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="iconList.length" class="quick-icons__grid">
|
||||
@ -138,7 +124,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<div v-else class="quick-icons__empty">
|
||||
<span>暂无快捷图标,点击 ⚙️ 添加</span>
|
||||
<span>暂无快捷图标,点击 <AppIcon name="settings" :size="14" /> 添加</span>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
@ -180,29 +166,29 @@
|
||||
</div>
|
||||
<div class="user-menu__divider"></div>
|
||||
<button type="button" class="user-menu__item user-menu__item--toggle" @click="toggleView" :title="currentView === 'manage' ? '切换到海报展示' : '切换到控制台'">
|
||||
<span class="user-menu__icon">{{ currentView === 'manage' ? '🎬' : '📋' }}</span>
|
||||
<span class="user-menu__icon"><AppIcon :name="currentView === 'manage' ? 'movie' : 'log'" :size="18" /></span>
|
||||
<span>{{ currentView === 'manage' ? '海报展示' : '控制台' }}</span>
|
||||
<span class="user-menu__toggle-icon">⇄</span>
|
||||
</button>
|
||||
<button type="button" class="user-menu__item" @click="handleTmdbConfig">
|
||||
<span class="user-menu__icon">⚙️</span>
|
||||
<span class="user-menu__icon"><AppIcon name="settings" :size="18" /></span>
|
||||
<span>TMDB 配置</span>
|
||||
</button>
|
||||
<button type="button" class="user-menu__item" @click="handleSettings">
|
||||
<span class="user-menu__icon">🛠️</span>
|
||||
<span class="user-menu__icon"><AppIcon name="tools" :size="18" /></span>
|
||||
<span>设置</span>
|
||||
</button>
|
||||
<button type="button" class="user-menu__item" @click="handleExport">
|
||||
<span class="user-menu__icon">📤</span>
|
||||
<span class="user-menu__icon"><AppIcon name="export" :size="18" /></span>
|
||||
<span>导出数据</span>
|
||||
</button>
|
||||
<button type="button" class="user-menu__item" @click="handleReset">
|
||||
<span class="user-menu__icon">🔄</span>
|
||||
<span class="user-menu__icon"><AppIcon name="refresh" :size="18" /></span>
|
||||
<span>恢复初始数据</span>
|
||||
</button>
|
||||
<div class="user-menu__divider"></div>
|
||||
<button type="button" class="user-menu__item user-menu__item--danger" @click="handleLogout">
|
||||
<span class="user-menu__icon">🚪</span>
|
||||
<span class="user-menu__icon"><AppIcon name="logout" :size="18" /></span>
|
||||
<span>退出登录</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -222,13 +208,12 @@
|
||||
<!-- 主海报横幅 -->
|
||||
<Transition name="hero-fade" mode="out-in">
|
||||
<article
|
||||
v-if="featuredPosters.length"
|
||||
:key="activeFeaturedPoster.id"
|
||||
class="hero-main"
|
||||
:class="{
|
||||
'hero-loading': !heroImageLoaded,
|
||||
'hero-loaded': heroImageLoaded,
|
||||
'hero-wide': isWidePoster(activeFeaturedPoster.posterUrl)
|
||||
'hero-wide': isWidePoster(activeFeaturedPoster.posterUrl) || isHeroWideDynamic
|
||||
}"
|
||||
:style="buildHeroStyle(activeFeaturedPoster)"
|
||||
tabindex="0"
|
||||
@ -241,8 +226,7 @@
|
||||
>
|
||||
<!-- 海报图片层 -->
|
||||
<img
|
||||
v-if="activeFeaturedPoster.posterUrl"
|
||||
:src="activeFeaturedPoster.posterUrl"
|
||||
:src="activeFeaturedPoster.posterUrl || '/暂无新片上映海报生成.png'"
|
||||
:alt="activeFeaturedPoster.title"
|
||||
class="hero-bg-image"
|
||||
:class="{ 'hero-bg-image--wide': isHeroWideDynamic }"
|
||||
@ -255,9 +239,12 @@
|
||||
<h2 class="hero-main__title">{{ activeFeaturedPoster.title }}</h2>
|
||||
<p class="hero-main__desc">{{ activeFeaturedPoster.subtitle || activeFeaturedPoster.description || '根据网盘资源内容自动匹配海报展示。' }}</p>
|
||||
<div class="hero-main__meta">
|
||||
<span v-if="activeFeaturedPoster.accountName" class="hero-main__meta-item">📁 {{ activeFeaturedPoster.accountName }}</span>
|
||||
<span v-if="activeFeaturedPoster.owner" class="hero-main__meta-item">👤 {{ activeFeaturedPoster.owner }}</span>
|
||||
<span v-if="activeFeaturedPoster.status" class="hero-main__meta-item">{{ activeFeaturedPoster.status === '已删除' ? '🗑️' : '✅' }} {{ activeFeaturedPoster.status }}</span>
|
||||
<span v-if="activeFeaturedPoster.rating" class="hero-main__meta-item"><AppIcon name="sparkle" :size="14" /> {{ activeFeaturedPoster.rating }}</span>
|
||||
<template v-if="activeFeaturedPoster.tags && activeFeaturedPoster.tags.length">
|
||||
<span v-for="tag in activeFeaturedPoster.tags" :key="tag" class="hero-main__meta-item hero-main__tag"><AppIcon name="tag" :size="14" /> {{ tag }}</span>
|
||||
</template>
|
||||
<span v-if="activeFeaturedPoster.casts" class="hero-main__meta-item"><AppIcon name="cast" :size="14" /> {{ activeFeaturedPoster.casts }}</span>
|
||||
<span v-if="activeFeaturedPoster.directors" class="hero-main__meta-item"><AppIcon name="movie" :size="14" /> {{ activeFeaturedPoster.directors }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -291,7 +278,7 @@
|
||||
<Transition name="fade" mode="out-in">
|
||||
<section v-if="isSearchFocused && !hasSearched" class="search-focus-hint" key="search-hint">
|
||||
<div class="search-focus-content">
|
||||
<div class="search-focus-icon">✨</div>
|
||||
<div class="search-focus-icon"><AppIcon name="sparkle" :size="32" /></div>
|
||||
<h3>输入搜索关键词</h3>
|
||||
<p>搜索标题、标签、资源库或维护人</p>
|
||||
</div>
|
||||
@ -320,7 +307,7 @@
|
||||
@click="networkMode = 'internal'"
|
||||
>内网</button>
|
||||
</div>
|
||||
<button v-if="!hasSearched" type="button" class="quick-icons__manage" @click="showIconManageDialog = true" title="管理图标">⚙️ 管理</button>
|
||||
<button v-if="!hasSearched" type="button" class="quick-icons__manage" @click="showIconManageDialog = true" title="管理图标"><AppIcon name="settings" :size="16" /> 管理</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="iconList.length" class="quick-icons__grid">
|
||||
@ -345,7 +332,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<div v-else-if="!hasSearched" class="quick-icons__empty">
|
||||
<span>暂无快捷图标,点击 ⚙️ 添加</span>
|
||||
<span>暂无快捷图标,点击 <AppIcon name="settings" :size="14" /> 添加</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -387,7 +374,7 @@
|
||||
:alt="sheet.name"
|
||||
class="drive-tab__logo"
|
||||
/>
|
||||
<div v-else class="drive-tab__logo drive-tab__logo--fallback">📁</div>
|
||||
<div v-else class="drive-tab__logo drive-tab__logo--fallback"><AppIcon name="folder" :size="20" /></div>
|
||||
<span class="drive-tab__name">{{ sheet.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -405,10 +392,10 @@
|
||||
:class="{ active: multiSelectMode }"
|
||||
@click="toggleMultiSelectMode"
|
||||
>
|
||||
☑️ 多选删除
|
||||
<AppIcon name="checkbox" :size="16" /> 多选删除
|
||||
</button>
|
||||
<button type="button" class="folder-tree-actions__btn" @click="handleOpenScraperLogDialog">
|
||||
📋 刮削日志
|
||||
<AppIcon name="log" :size="16" /> 刮削日志
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@ -416,7 +403,7 @@
|
||||
@click="handleRefreshFolders"
|
||||
title="刷新当前网盘文件夹列表"
|
||||
>
|
||||
🗂️ 刷新文件夹
|
||||
<AppIcon name="folder-refresh" :size="16" /> 刷新文件夹
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@ -424,7 +411,7 @@
|
||||
@click="handleRescrapeAll"
|
||||
title="重新刮削所有电影文件"
|
||||
>
|
||||
🔄 重新刮削
|
||||
<AppIcon name="refresh" :size="16" /> 重新刮削
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@ -444,14 +431,14 @@
|
||||
@click="handleBatchScrape"
|
||||
title="批量刮削选中的电影文件"
|
||||
>
|
||||
🎬 批量刮削
|
||||
<AppIcon name="batch-scrape" :size="16" /> 批量刮削
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 搜索结果为空时的提示 -->
|
||||
<div v-if="hasSearched && filteredRows.length === 0" class="empty-search-result">
|
||||
<div class="empty-search-content">
|
||||
<div class="empty-search-icon">🔍</div>
|
||||
<div class="empty-search-icon"><AppIcon name="search" :size="32" /></div>
|
||||
<h3>空空如也</h3>
|
||||
<p>没有找到匹配“{{ searchKeyword }}”的内容</p>
|
||||
<button type="button" class="secondary" @click="hasSearched = false; searchKeyword = ''">
|
||||
@ -602,7 +589,7 @@
|
||||
</div>
|
||||
<div v-else class="empty-search-result">
|
||||
<div class="empty-search-content">
|
||||
<div class="empty-search-icon">🔍</div>
|
||||
<div class="empty-search-icon"><AppIcon name="search" :size="32" /></div>
|
||||
<h3>空空如也</h3>
|
||||
<p>没有找到匹配“{{ searchKeyword }}”的内容</p>
|
||||
<button type="button" class="secondary" @click="hasSearched = false; searchKeyword = ''">
|
||||
@ -662,7 +649,7 @@
|
||||
<div v-if="log.showDetail && log.detailList && log.detailList.length > 0" class="log-entry__detail">
|
||||
<template v-for="(item, idx) in log.detailList" :key="idx">
|
||||
<div class="detail-item detail-item--user">
|
||||
<span class="detail-item__name">👤 {{ item.username || '用户 ' + (item.userId || idx) }}</span>
|
||||
<span class="detail-item__name"><AppIcon name="user" :size="14" /> {{ item.username || '用户 ' + (item.userId || idx) }}</span>
|
||||
<span class="detail-item__status detail-item__status--info">
|
||||
处理: {{ item.processed || 0 }} | 成功: {{ item.success || 0 }} | 失败: {{ item.failed || 0 }} | 跳过: {{ item.skipped || 0 }}
|
||||
</span>
|
||||
@ -888,15 +875,10 @@
|
||||
@cancel="showConfirmDialog = false"
|
||||
/>
|
||||
|
||||
<!-- 设置页面 -->
|
||||
<Transition name="fade">
|
||||
<div v-if="showSettingsView" class="settings-overlay" @click.self="showSettingsView = false">
|
||||
<div class="settings-container">
|
||||
<button type="button" class="settings-close" @click="showSettingsView = false" title="关闭设置">✕</button>
|
||||
<SettingsView />
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
<!-- 设置页面(使用 SimpleDialog 统一弹窗方式) -->
|
||||
<SimpleDialog :open="showSettingsView" title="设置" @close="showSettingsView = false">
|
||||
<SettingsView :key="settingsKey" class="settings-in-dialog" />
|
||||
</SimpleDialog>
|
||||
|
||||
<!-- 网盘标签页悬浮描述提示框(Teleport到body,避免被父容器overflow裁剪) -->
|
||||
<Teleport to="body">
|
||||
@ -920,6 +902,7 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch, onUnmounted } from 'vue'
|
||||
import AppIcon from './components/AppIcon.vue'
|
||||
import LoginView from './components/LoginView.vue'
|
||||
import PosterCard from './components/PosterCard.vue'
|
||||
import RecordDialog from './components/RecordDialog.vue'
|
||||
@ -1009,7 +992,7 @@ const confirmConfig = reactive({
|
||||
title: '确认操作',
|
||||
message: '',
|
||||
hint: '',
|
||||
icon: '⚠️',
|
||||
icon: 'warning',
|
||||
confirmText: '确认',
|
||||
cancelText: '取消',
|
||||
danger: false,
|
||||
@ -1263,17 +1246,12 @@ function buildHeroStyle(poster) {
|
||||
|
||||
function buildSubThumbStyle(poster) {
|
||||
// 当没有有效海报数据时,使用默认海报
|
||||
if (!poster || poster.trim() === '') {
|
||||
const imgUrl = poster && poster.trim() !== '' ? poster : '/暂无新片上映海报生成.png'
|
||||
return {
|
||||
backgroundImage: `linear-gradient(180deg, rgba(8, 15, 29, 0.3), rgba(8, 15, 29, 0.7)), url('/暂无新片上映海报生成.png')`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
}
|
||||
}
|
||||
return {
|
||||
backgroundImage: `linear-gradient(180deg, rgba(8, 15, 29, 0.3), rgba(8, 15, 29, 0.7)), url(${poster})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundImage: `linear-gradient(180deg, rgba(8, 15, 29, 0.3), rgba(8, 15, 29, 0.7)), url(${imgUrl})`,
|
||||
backgroundSize: 'contain',
|
||||
backgroundPosition: 'center',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
}
|
||||
}
|
||||
|
||||
@ -2078,9 +2056,11 @@ function handleTmdbConfig() {
|
||||
|
||||
// 设置页面
|
||||
const showSettingsView = ref(false)
|
||||
const settingsKey = ref(0)
|
||||
|
||||
function handleSettings() {
|
||||
showUserMenu.value = false
|
||||
settingsKey.value++
|
||||
showSettingsView.value = true
|
||||
}
|
||||
|
||||
@ -2309,7 +2289,7 @@ function handleDeleteNode(node) {
|
||||
title: '确认删除',
|
||||
message: `确定要删除 <strong>“${node.title}”</strong> 吗?`,
|
||||
hint: isFolder ? '注意:该文件夹下的所有子文件夹和文件都将被永久删除!此操作不可恢复。' : '',
|
||||
icon: '⚠️',
|
||||
icon: 'warning',
|
||||
confirmText: '确认删除',
|
||||
cancelText: '取消',
|
||||
danger: true,
|
||||
@ -2503,7 +2483,7 @@ function handleDeleteSheet(sheet) {
|
||||
title: '确认删除',
|
||||
message: `确定要删除网盘 <strong>“${sheet.name}”</strong> 吗?`,
|
||||
hint: '注意:该网盘下的所有文件和文件夹都将被永久删除!此操作不可恢复。',
|
||||
icon: '⚠️',
|
||||
icon: 'warning',
|
||||
confirmText: '确认删除',
|
||||
cancelText: '取消',
|
||||
danger: true,
|
||||
@ -2774,10 +2754,12 @@ async function loadRecommendMovies() {
|
||||
id: movie.id,
|
||||
title: movie.title || '未知标题',
|
||||
description: movie.description || '',
|
||||
posterUrl: movie.posterUrl || '',
|
||||
posterUrl: movie.backdropUrl || '',
|
||||
rating: movie.rating || 0,
|
||||
category: movie.category || '',
|
||||
tags: typeof movie.tags === 'string' ? movie.tags.split(',') : movie.tags || [],
|
||||
casts: movie.casts || '',
|
||||
directors: movie.directors || '',
|
||||
createTime: movie.createTime || '',
|
||||
}))
|
||||
console.log(`成功加载 ${recommendMovies.value.length} 条每日推荐`)
|
||||
@ -2821,9 +2803,9 @@ watch(
|
||||
// 重置加载状态
|
||||
heroImageLoaded.value = false
|
||||
|
||||
// 如果没有海报URL,立即显示默认图片
|
||||
// 如果没有海报URL,用默认图片判断宽高比
|
||||
if (!newPosterUrl || newPosterUrl.trim() === '') {
|
||||
heroImageLoaded.value = true
|
||||
preloadImage('/暂无新片上映海报生成.png')
|
||||
return
|
||||
}
|
||||
|
||||
@ -2998,7 +2980,7 @@ function handleRescrapeAll() {
|
||||
title: '确认重新刮削',
|
||||
message: '确定要重新刮削当前网盘下的所有电影文件吗?',
|
||||
hint: '注意:这将重新发起对所有电影文件的 TMDB 海报刮削请求,可能需要较长时间。',
|
||||
icon: '🔄',
|
||||
icon: 'refresh',
|
||||
confirmText: '确认刮削',
|
||||
cancelText: '取消',
|
||||
danger: false,
|
||||
@ -3160,7 +3142,7 @@ async function handleBatchDelete(selectedIdSet) {
|
||||
title: '确认批量删除',
|
||||
message: `确定要删除选中的 <strong>${count}</strong> 个项目吗?`,
|
||||
hint: '注意:选中的所有文件夹和文件都将被永久删除!此操作不可恢复。',
|
||||
icon: '⚠️',
|
||||
icon: 'warning',
|
||||
confirmText: '确认删除',
|
||||
cancelText: '取消',
|
||||
danger: true,
|
||||
|
||||
363
src/components/AppIcon.vue
Normal file
@ -0,0 +1,363 @@
|
||||
<!--
|
||||
统一图标组件 - 支持白天/黑夜两种主题
|
||||
用法: <AppIcon name="search" size="20" />
|
||||
|
||||
主题颜色通过 CSS 变量自动适配:
|
||||
- 白天模式: 描边 #374151, 点缀 #0f766e (品牌青)
|
||||
- 黑夜模式: 描边 #94a3b8, 点缀 #38bdf8 (品牌蓝)
|
||||
-->
|
||||
<template>
|
||||
<span class="app-icon" :style="{ width: size + 'px', height: size + 'px' }">
|
||||
<!-- 搜索 -->
|
||||
<svg v-if="name === 'search'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="10.5" cy="10.5" r="6.5"/>
|
||||
<line x1="15.5" y1="15.5" x2="21" y2="21"/>
|
||||
<path d="M7 7.5a5 5 0 0 1 3-1" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 设置/齿轮 -->
|
||||
<svg v-else-if="name === 'settings'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
||||
<circle cx="12" cy="12" r="1.5" fill="var(--icon-accent)" stroke="var(--icon-accent)" stroke-width="0.5"/>
|
||||
</svg>
|
||||
|
||||
<!-- 文件夹(关闭) -->
|
||||
<svg v-else-if="name === 'folder'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
|
||||
<path d="M4 5h5l2 3h9" stroke="var(--icon-accent)" stroke-width="1" opacity="0.4"/>
|
||||
</svg>
|
||||
|
||||
<!-- 文件夹(打开) -->
|
||||
<svg v-else-if="name === 'folder-open'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
|
||||
<path d="M2 10h20"/>
|
||||
<path d="M4 10h16v7a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-7z" fill="var(--icon-accent)" stroke="var(--icon-accent)" stroke-width="0.3" opacity="0.15"/>
|
||||
</svg>
|
||||
|
||||
<!-- 用户 -->
|
||||
<svg v-else-if="name === 'user'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
|
||||
<circle cx="12" cy="7" r="4"/>
|
||||
<path d="M10 5.5a3 3 0 0 1 2-1" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 成功/对勾 -->
|
||||
<svg v-else-if="name === 'success'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="9"/>
|
||||
<path d="M8 12l3 3 5-6" stroke="var(--icon-accent)" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 删除/垃圾桶 -->
|
||||
<svg v-else-if="name === 'delete'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 6h18"/>
|
||||
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
|
||||
<path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
||||
<line x1="10" y1="11" x2="10" y2="17"/>
|
||||
<line x1="14" y1="11" x2="14" y2="17"/>
|
||||
<path d="M9 6v12a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V6" stroke="var(--icon-accent)" stroke-width="0.8" opacity="0.3"/>
|
||||
</svg>
|
||||
|
||||
<!-- 刷新 -->
|
||||
<svg v-else-if="name === 'refresh'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 2v6h-6"/>
|
||||
<path d="M3 12a9 9 0 0 1 15-6.7L21 8"/>
|
||||
<path d="M3 22v-6h6"/>
|
||||
<path d="M21 12a9 9 0 0 1-15 6.7L3 16"/>
|
||||
<path d="M21 2v6h-6" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 电影/场记板 -->
|
||||
<svg v-else-if="name === 'movie'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="6" width="18" height="14" rx="1"/>
|
||||
<path d="M3 10h18"/>
|
||||
<path d="M7 6V3"/>
|
||||
<path d="M12 6V3"/>
|
||||
<path d="M17 6V3"/>
|
||||
<line x1="5" y1="8" x2="7" y2="8" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
<line x1="9" y1="8" x2="11" y2="8" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
||||
<!-- 日志/剪贴板 -->
|
||||
<svg v-else-if="name === 'log'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>
|
||||
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"/>
|
||||
<line x1="8" y1="10" x2="16" y2="10"/>
|
||||
<line x1="8" y1="14" x2="16" y2="14"/>
|
||||
<line x1="8" y1="18" x2="12" y2="18"/>
|
||||
<line x1="8" y1="10" x2="11" y2="10" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
||||
<!-- 工具/扳手 -->
|
||||
<svg v-else-if="name === 'tools'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
|
||||
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 导出/上传 -->
|
||||
<svg v-else-if="name === 'export'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
||||
<polyline points="17 8 12 3 7 8"/>
|
||||
<line x1="12" y1="3" x2="12" y2="15"/>
|
||||
<polyline points="17 8 12 3 7 8" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 退出登录 -->
|
||||
<svg v-else-if="name === 'logout'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/>
|
||||
<polyline points="16 17 21 12 16 7"/>
|
||||
<line x1="21" y1="12" x2="9" y2="12"/>
|
||||
<polyline points="16 17 21 12 16 7" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 提示/闪光 -->
|
||||
<svg v-else-if="name === 'sparkle'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 2l2.4 7.2L22 12l-7.6 2.8L12 22l-2.4-7.2L2 12l7.6-2.8z"/>
|
||||
<path d="M12 2l2.4 7.2L22 12l-7.6 2.8L12 22z" fill="var(--icon-accent)" stroke="var(--icon-accent)" stroke-width="0.3" opacity="0.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 保存/软盘 -->
|
||||
<svg v-else-if="name === 'save'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
|
||||
<polyline points="17 21 17 13 7 13 7 21"/>
|
||||
<polyline points="7 3 7 8 15 8"/>
|
||||
<rect x="9" y="15" width="6" height="4" rx="0.5" fill="var(--icon-accent)" stroke="var(--icon-accent)" stroke-width="0.5"/>
|
||||
</svg>
|
||||
|
||||
<!-- 链接 -->
|
||||
<svg v-else-if="name === 'link'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
|
||||
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
|
||||
<path d="M10 13a5 5 0 0 0 2 1.5" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 地球/网络 -->
|
||||
<svg v-else-if="name === 'globe'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<line x1="2" y1="12" x2="22" y2="12"/>
|
||||
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>
|
||||
<path d="M12 2a15.3 15.3 0 0 1 4 10" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 眼睛(显示) -->
|
||||
<svg v-else-if="name === 'eye'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<circle cx="12" cy="12" r="1.5" fill="var(--icon-accent)" stroke="var(--icon-accent)" stroke-width="0.5"/>
|
||||
</svg>
|
||||
|
||||
<!-- 眼睛关闭(隐藏) -->
|
||||
<svg v-else-if="name === 'eye-off'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/>
|
||||
<line x1="1" y1="1" x2="23" y2="23" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 多选/复选框 -->
|
||||
<svg v-else-if="name === 'checkbox'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="3" width="18" height="18" rx="3"/>
|
||||
<path d="M7 12l3.5 3.5L17 9" stroke="var(--icon-accent)" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 警告 -->
|
||||
<svg v-else-if="name === 'warning'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
|
||||
<line x1="12" y1="9" x2="12" y2="13" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
<line x1="12" y1="17" x2="12.01" y2="17"/>
|
||||
</svg>
|
||||
|
||||
<!-- 文件/文档 -->
|
||||
<svg v-else-if="name === 'file'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||||
<polyline points="14 2 14 8 20 8"/>
|
||||
<line x1="8" y1="13" x2="16" y2="13"/>
|
||||
<line x1="8" y1="17" x2="13" y2="17"/>
|
||||
<polyline points="14 2 14 8 20 8" stroke="var(--icon-accent)" stroke-width="1" opacity="0.5"/>
|
||||
</svg>
|
||||
|
||||
<!-- 信息 -->
|
||||
<svg v-else-if="name === 'info'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
<line x1="12" y1="16" x2="12" y2="12" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
<line x1="12" y1="8" x2="12.01" y2="8"/>
|
||||
</svg>
|
||||
|
||||
<!-- 内外网切换 -->
|
||||
<svg v-else-if="name === 'network'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="4" y1="8" x2="20" y2="8"/>
|
||||
<polyline points="16 4 20 8 16 12" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
<line x1="20" y1="16" x2="4" y2="16"/>
|
||||
<polyline points="8 12 4 16 8 20" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 标签 -->
|
||||
<svg v-else-if="name === 'tag'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/>
|
||||
<circle cx="7" cy="7" r="1" fill="var(--icon-accent)" stroke="var(--icon-accent)" stroke-width="0.5"/>
|
||||
</svg>
|
||||
|
||||
<!-- 主演/面具 -->
|
||||
<svg v-else-if="name === 'cast'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M2 12c0-5 4-9 10-9s10 4 10 9"/>
|
||||
<path d="M2 12c0 3 2 5 4 5s3-2 4-5"/>
|
||||
<path d="M14 12c1 3 2 5 4 5s4-2 4-5"/>
|
||||
<path d="M2 12c0 3 2 5 4 5s3-2 4-5" fill="var(--icon-accent)" stroke="var(--icon-accent)" stroke-width="0.3" opacity="0.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 详情 -->
|
||||
<svg v-else-if="name === 'detail'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||||
<polyline points="14 2 14 8 20 8"/>
|
||||
<line x1="8" y1="13" x2="16" y2="13"/>
|
||||
<line x1="8" y1="17" x2="12" y2="17"/>
|
||||
<circle cx="17" cy="17" r="3" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
<line x1="19.5" y1="19.5" x2="22" y2="22" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
||||
<!-- 简介/书本 -->
|
||||
<svg v-else-if="name === 'description'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/>
|
||||
<path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>
|
||||
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" fill="var(--icon-accent)" stroke="var(--icon-accent)" stroke-width="0.3" opacity="0.15"/>
|
||||
</svg>
|
||||
|
||||
<!-- 编辑/铅笔 -->
|
||||
<svg v-else-if="name === 'edit'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
||||
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4z" fill="var(--icon-accent)" stroke="var(--icon-accent)" stroke-width="0.3" opacity="0.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 同步 -->
|
||||
<svg v-else-if="name === 'sync'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 12a9 9 0 1 1-6.219-8.56"/>
|
||||
<polyline points="21 3 21 9 15 9" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
||||
<!-- 失败/叉号 -->
|
||||
<svg v-else-if="name === 'fail'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="9"/>
|
||||
<line x1="9" y1="9" x2="15" y2="15" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
<line x1="15" y1="9" x2="9" y2="15" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
||||
<!-- 关闭/X -->
|
||||
<svg v-else-if="name === 'close'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
<line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
|
||||
<!-- 太阳(白天模式) -->
|
||||
<svg v-else-if="name === 'sun'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="5"/>
|
||||
<line x1="12" y1="1" x2="12" y2="3"/>
|
||||
<line x1="12" y1="21" x2="12" y2="23"/>
|
||||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
|
||||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
|
||||
<line x1="1" y1="12" x2="3" y2="12"/>
|
||||
<line x1="21" y1="12" x2="23" y2="12"/>
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
|
||||
<circle cx="12" cy="12" r="2.5" fill="var(--icon-accent)" stroke="var(--icon-accent)" stroke-width="0.5" opacity="0.3"/>
|
||||
</svg>
|
||||
|
||||
<!-- 月亮(黑夜模式) -->
|
||||
<svg v-else-if="name === 'moon'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
||||
<path d="M21 12.79A9 9 0 0 1 12 21" fill="var(--icon-accent)" stroke="var(--icon-accent)" stroke-width="0.3" opacity="0.2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 添加文件夹 -->
|
||||
<svg v-else-if="name === 'add-folder'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
|
||||
<line x1="12" y1="11" x2="12" y2="17" stroke="var(--icon-accent)" stroke-width="2"/>
|
||||
<line x1="9" y1="14" x2="15" y2="14" stroke="var(--icon-accent)" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 添加文件 -->
|
||||
<svg v-else-if="name === 'add-file'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||||
<polyline points="14 2 14 8 20 8"/>
|
||||
<line x1="12" y1="13" x2="12" y2="19" stroke="var(--icon-accent)" stroke-width="2"/>
|
||||
<line x1="9" y1="16" x2="15" y2="16" stroke="var(--icon-accent)" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
<!-- 批量删除 -->
|
||||
<svg v-else-if="name === 'batch-delete'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M3 6h18"/>
|
||||
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
|
||||
<path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
||||
<line x1="10" y1="11" x2="10" y2="17" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
<line x1="14" y1="11" x2="14" y2="17" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
<line x1="9" y1="9" x2="15" y2="9" stroke="var(--icon-accent)" stroke-width="1"/>
|
||||
</svg>
|
||||
|
||||
<!-- 批量刮削 -->
|
||||
<svg v-else-if="name === 'batch-scrape'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="6" width="18" height="14" rx="1"/>
|
||||
<path d="M3 10h18"/>
|
||||
<path d="M7 6V3"/><path d="M12 6V3"/><path d="M17 6V3"/>
|
||||
<line x1="5" y1="8" x2="7" y2="8" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
<line x1="9" y1="8" x2="11" y2="8" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
<line x1="13" y1="8" x2="15" y2="8" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
<line x1="17" y1="8" x2="19" y2="8" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
||||
<!-- 刮削 -->
|
||||
<svg v-else-if="name === 'scrape'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="3" y="6" width="18" height="14" rx="1"/>
|
||||
<path d="M3 10h18"/>
|
||||
<path d="M7 6V3"/><path d="M12 6V3"/><path d="M17 6V3"/>
|
||||
<path d="M14 13a3 3 0 1 1-1-2.2L14 12" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
<polyline points="12 10 14 12 16 10" stroke="var(--icon-accent)" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
||||
<!-- 切换视图 -->
|
||||
<svg v-else-if="name === 'switch-view'" viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="17 1 21 5 17 9" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
<path d="M3 11V9a4 4 0 0 1 4-4h14"/>
|
||||
<polyline points="7 23 3 19 7 15" stroke="var(--icon-accent)" stroke-width="1.2"/>
|
||||
<path d="M21 13v2a4 4 0 0 1-4 4H3"/>
|
||||
</svg>
|
||||
|
||||
<!-- 默认占位 -->
|
||||
<svg v-else viewBox="0 0 24 24" fill="none" stroke="var(--icon-stroke)" stroke-width="1.5">
|
||||
<circle cx="12" cy="12" r="10"/>
|
||||
</svg>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* AppIcon 组件属性
|
||||
* @prop {string} name - 图标名称
|
||||
* @prop {number|string} size - 图标尺寸,默认 20
|
||||
*/
|
||||
defineProps({
|
||||
name: { type: String, default: '' },
|
||||
size: { type: [Number, String], default: 20 },
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/*
|
||||
* 图标容器 - 使用 CSS 变量实现主题自适应
|
||||
* 白天模式: --ink=#172033, --brand=#0f766e
|
||||
* 黑夜模式: --ink=#e2e8f0, --brand=#38bdf8
|
||||
*/
|
||||
.app-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
/* 主色(描边): 继承当前文本颜色 */
|
||||
--icon-stroke: var(--ink);
|
||||
/* 点缀色(高亮): 继承品牌色 */
|
||||
--icon-accent: var(--brand);
|
||||
vertical-align: middle;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.app-icon svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -4,7 +4,7 @@
|
||||
<Transition name="confirm-scale-in">
|
||||
<div v-if="showContent" class="confirm-dialog">
|
||||
<header>
|
||||
<span class="confirm-icon">{{ icon }}</span>
|
||||
<span class="confirm-icon"><AppIcon v-if="icon" :name="icon" :size="22" /></span>
|
||||
{{ title }}
|
||||
</header>
|
||||
<div class="confirm-body">
|
||||
@ -28,13 +28,14 @@
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { lockScroll, unlockScroll } from '../utils/scrollLock'
|
||||
import AppIcon from './AppIcon.vue'
|
||||
|
||||
const props = defineProps({
|
||||
open: Boolean,
|
||||
title: { type: String, default: '确认操作' },
|
||||
message: { type: String, default: '' },
|
||||
hint: { type: String, default: '' },
|
||||
icon: { type: String, default: '⚠️' },
|
||||
icon: { type: String, default: 'warning' },
|
||||
confirmText: { type: String, default: '确认' },
|
||||
cancelText: { type: String, default: '取消' },
|
||||
danger: { type: Boolean, default: false },
|
||||
|
||||
@ -40,14 +40,14 @@
|
||||
:alt="drive.name"
|
||||
class="drive-logo-img"
|
||||
/>
|
||||
<div v-else class="drive-icon-small">📁</div>
|
||||
<div v-else class="drive-icon-small"><AppIcon name="folder" :size="18" /></div>
|
||||
</div>
|
||||
|
||||
<!-- 网盘名称 + 悬浮描述 -->
|
||||
<div class="drive-name-wrapper" @mouseenter="showTooltip(drive.id)" @mouseleave="hideTooltip">
|
||||
<h4 class="drive-name">{{ drive.name }}</h4>
|
||||
<!-- 悬浮提示图标 -->
|
||||
<span v-if="drive.description" class="tooltip-trigger" title="">ℹ️</span>
|
||||
<span v-if="drive.description" class="tooltip-trigger" title=""><AppIcon name="info" :size="16" /></span>
|
||||
|
||||
<!-- 悬浮描述提示框 -->
|
||||
<Transition name="tooltip-fade">
|
||||
@ -186,7 +186,7 @@
|
||||
<dialog ref="confirmRef" class="confirm-overlay" @click.self="closeConfirmDialog" @close="closeConfirmDialog">
|
||||
<Transition name="confirm-scale-in">
|
||||
<div v-if="showConfirm" class="confirm-dialog">
|
||||
<header>⚠️ 确认删除</header>
|
||||
<header><AppIcon name="warning" :size="20" /> 确认删除</header>
|
||||
<div class="confirm-body">
|
||||
<p>确定要删除网盘 <strong>"{{ confirmTarget?.name }}"</strong> 吗?</p>
|
||||
<p class="confirm-hint">注意:该网盘下的所有文件和文件夹都将被永久删除!此操作不可恢复。</p>
|
||||
@ -206,6 +206,7 @@
|
||||
import { ref, computed, watch, nextTick } from 'vue'
|
||||
import { fetchDriveList, createDrive, updateDrive, deleteDrive } from '../api'
|
||||
import { lockScroll, unlockScroll } from '../utils/scrollLock'
|
||||
import AppIcon from './AppIcon.vue'
|
||||
|
||||
// ==================== Props & Emits ====================
|
||||
const props = defineProps({
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
<div v-if="multiSelectMode" class="multi-select-toolbar">
|
||||
<span class="multi-select-toolbar__count">已选择 {{ selectedIds.size }} 项</span>
|
||||
<button type="button" class="multi-select-toolbar__btn multi-select-toolbar__btn--danger" @click="handleBatchDelete">
|
||||
🗑️ 批量删除
|
||||
<AppIcon name="batch-delete" :size="16" /> 批量删除
|
||||
</button>
|
||||
<button type="button" class="multi-select-toolbar__btn" @click="exitMultiSelect">
|
||||
✕ 退出多选
|
||||
<AppIcon name="close" :size="16" /> 退出多选
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
@ -34,8 +34,8 @@
|
||||
</span>
|
||||
<span class="icon-grid-url" :title="icon.url || icon.internalUrl">{{ icon.url || icon.internalUrl }}</span>
|
||||
<div class="icon-grid-actions">
|
||||
<button type="button" class="action-btn" title="编辑" @click="startEdit(icon)">✏️</button>
|
||||
<button type="button" class="action-btn action-btn--danger" title="删除" @click="confirmDeleteIcon(icon)">🗑️</button>
|
||||
<button type="button" class="action-btn" title="编辑" @click="startEdit(icon)"><AppIcon name="edit" :size="16" /></button>
|
||||
<button type="button" class="action-btn action-btn--danger" title="删除" @click="confirmDeleteIcon(icon)"><AppIcon name="delete" :size="16" /></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -54,13 +54,13 @@
|
||||
<span class="field-label">链接类型</span>
|
||||
<div class="link-type-group">
|
||||
<label class="link-type-option" :class="{ 'link-type-option--active': form.linkType === 'external' }">
|
||||
<input type="radio" v-model="form.linkType" value="external" />🌐 外网
|
||||
<input type="radio" v-model="form.linkType" value="external" /><AppIcon name="globe" :size="16" /> 外网
|
||||
</label>
|
||||
<label class="link-type-option" :class="{ 'link-type-option--active': form.linkType === 'internal' }">
|
||||
<input type="radio" v-model="form.linkType" value="internal" />🔒 内网
|
||||
<input type="radio" v-model="form.linkType" value="internal" /><AppIcon name="save" :size="16" /> 内网
|
||||
</label>
|
||||
<label class="link-type-option" :class="{ 'link-type-option--active': form.linkType === 'both' }">
|
||||
<input type="radio" v-model="form.linkType" value="both" />↔️ 内外网
|
||||
<input type="radio" v-model="form.linkType" value="both" /><AppIcon name="network" :size="16" /> 内外网
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -135,7 +135,7 @@
|
||||
<dialog ref="confirmRef" class="confirm-overlay" @click.self="closeConfirm" @close="closeConfirm">
|
||||
<Transition name="confirm-scale-in">
|
||||
<div v-if="showConfirm" class="confirm-dialog">
|
||||
<header><span class="confirm-icon">⚠️</span> 确认删除</header>
|
||||
<header><span class="confirm-icon"><AppIcon name="warning" :size="20" /></span> 确认删除</header>
|
||||
<div class="confirm-body">
|
||||
<p>确定要删除图标 <strong>"{{ deleteTarget?.name }}"</strong> 吗?</p>
|
||||
</div>
|
||||
@ -154,6 +154,7 @@
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { fetchIconList, createIcon, updateIcon, deleteIcon, uploadIconLogo } from '../api'
|
||||
import { lockScroll, unlockScroll } from '../utils/scrollLock'
|
||||
import AppIcon from './AppIcon.vue'
|
||||
|
||||
const props = defineProps({ open: Boolean })
|
||||
const emit = defineEmits(['close', 'success', 'error', 'refresh'])
|
||||
|
||||
@ -14,10 +14,10 @@
|
||||
|
||||
<!-- 导演和主演 -->
|
||||
<div v-if="item.directors" class="poster-director">
|
||||
🎬 {{ item.directors }}
|
||||
<AppIcon name="movie" :size="14" /> {{ item.directors }}
|
||||
</div>
|
||||
<div v-if="item.casts" class="poster-casts">
|
||||
🎭 {{ item.casts }}
|
||||
<AppIcon name="cast" :size="14" /> {{ item.casts }}
|
||||
</div>
|
||||
|
||||
<!-- 简介按钮(点击打开弹窗) -->
|
||||
@ -27,7 +27,7 @@
|
||||
class="description-toggle"
|
||||
@click.stop="showDescriptionDialog = true"
|
||||
>
|
||||
📝 查看详情
|
||||
<AppIcon name="detail" :size="14" /> 查看详情
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -48,33 +48,33 @@
|
||||
<div class="description-dialog__body">
|
||||
<!-- 基本信息 -->
|
||||
<div v-if="item.description" class="detail-section">
|
||||
<h4>📖 简介</h4>
|
||||
<h4><AppIcon name="description" :size="16" /> 简介</h4>
|
||||
<p class="detail-text">{{ item.description }}</p>
|
||||
</div>
|
||||
<div v-if="item.directors" class="detail-section">
|
||||
<h4>🎬 导演</h4>
|
||||
<h4><AppIcon name="movie" :size="16" /> 导演</h4>
|
||||
<p class="detail-text">{{ item.directors }}</p>
|
||||
</div>
|
||||
<div v-if="item.casts" class="detail-section">
|
||||
<h4>🎭 主演</h4>
|
||||
<h4><AppIcon name="cast" :size="16" /> 主演</h4>
|
||||
<p class="detail-text">{{ item.casts }}</p>
|
||||
</div>
|
||||
<div v-if="item.tags" class="detail-section">
|
||||
<h4>🏷️ 标签</h4>
|
||||
<h4><AppIcon name="tag" :size="16" /> 标签</h4>
|
||||
<div class="detail-tags">
|
||||
<span v-for="tag in displayTags" :key="tag" class="detail-tag">{{ tag }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="item.score || item.rating" class="detail-section">
|
||||
<h4>⭐ 评分</h4>
|
||||
<h4><AppIcon name="sparkle" :size="16" /> 评分</h4>
|
||||
<p class="detail-text">{{ displayScore }}</p>
|
||||
</div>
|
||||
<div v-if="item.category" class="detail-section">
|
||||
<h4>📂 分类</h4>
|
||||
<h4><AppIcon name="folder-open" :size="16" /> 分类</h4>
|
||||
<p class="detail-text">{{ item.category }}</p>
|
||||
</div>
|
||||
<div v-if="item.status" class="detail-section">
|
||||
<h4>📌 状态</h4>
|
||||
<h4><AppIcon name="info" :size="16" /> 状态</h4>
|
||||
<p class="detail-text">{{ displayStatus }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -87,6 +87,7 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import AppIcon from './AppIcon.vue'
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
@ -113,7 +114,7 @@ const posterImageUrl = computed(() => {
|
||||
// 显示评分
|
||||
const displayScore = computed(() => {
|
||||
const score = props.item.score ?? props.item.rating ?? 0
|
||||
return score ? `⭐ ${score}` : '暂无评分'
|
||||
return score ? `${score}` : '暂无评分'
|
||||
})
|
||||
|
||||
// 格式化日期时间,将 ISO 8601 格式转换为友好格式
|
||||
|
||||
@ -1,114 +1,22 @@
|
||||
<template>
|
||||
<div class="settings-view">
|
||||
<div class="settings-header">
|
||||
<h2>设置</h2>
|
||||
<p>配置 OpenList 后端接口,绑定您的云盘账户</p>
|
||||
</div>
|
||||
|
||||
<div class="settings-card">
|
||||
<h3 class="settings-card__title">
|
||||
<span class="settings-card__icon">🔗</span>
|
||||
OpenList 绑定
|
||||
</h3>
|
||||
|
||||
<form class="settings-form" @submit.prevent="handleBind">
|
||||
<!-- OpenList 地址 -->
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="openlist-url">
|
||||
<span class="form-label__icon">🌐</span>
|
||||
<span class="form-label__text">OpenList 地址</span>
|
||||
</label>
|
||||
<input
|
||||
id="openlist-url"
|
||||
v-model="formData.url"
|
||||
type="url"
|
||||
class="form-input"
|
||||
placeholder="例如:https://olist.example.com 或 http://localhost:5575"
|
||||
required
|
||||
autocomplete="off"
|
||||
/>
|
||||
<span class="form-help">请填写 OpenList 服务的完整访问地址,包含协议头</span>
|
||||
<!-- 加载状态:等待后端返回数据 -->
|
||||
<div v-if="loading" class="loading-container">
|
||||
<div class="loading-spinner-icon"></div>
|
||||
<p class="loading-text">正在加载绑定信息...</p>
|
||||
</div>
|
||||
|
||||
<!-- 账号 -->
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="openlist-username">
|
||||
<span class="form-label__icon">👤</span>
|
||||
<span class="form-label__text">账号</span>
|
||||
</label>
|
||||
<input
|
||||
id="openlist-username"
|
||||
v-model="formData.username"
|
||||
type="text"
|
||||
class="form-input"
|
||||
placeholder="请输入 OpenList 用户名"
|
||||
required
|
||||
autocomplete="username"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 密码 -->
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="openlist-password">
|
||||
<span class="form-label__icon">🔒</span>
|
||||
<span class="form-label__text">密码</span>
|
||||
</label>
|
||||
<div class="password-input-wrapper">
|
||||
<input
|
||||
id="openlist-password"
|
||||
v-model="formData.password"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
class="form-input"
|
||||
placeholder="请输入 OpenList 密码"
|
||||
required
|
||||
autocomplete="current-password"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="password-toggle"
|
||||
@click="showPassword = !showPassword"
|
||||
:title="showPassword ? '隐藏密码' : '显示密码'"
|
||||
>
|
||||
{{ showPassword ? '🙈' : '👁️' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 绑定按钮 -->
|
||||
<div class="form-actions">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn-bind"
|
||||
:disabled="binding"
|
||||
:class="{ 'btn-bind--loading': binding }"
|
||||
>
|
||||
<span v-if="!binding">🔗 绑定 OpenList</span>
|
||||
<span v-else class="loading-spinner">⏳ 绑定中...</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-reset"
|
||||
@click="resetForm"
|
||||
:disabled="binding"
|
||||
>
|
||||
重置
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 绑定状态提示 -->
|
||||
<Transition name="fade">
|
||||
<div v-if="bindStatus" class="bind-status" :class="`bind-status--${bindStatus.type}`">
|
||||
<span class="bind-status__icon">{{ bindStatus.icon }}</span>
|
||||
<span class="bind-status__text">{{ bindStatus.message }}</span>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<!-- 已绑定信息 -->
|
||||
<!-- 数据加载完成后显示内容 -->
|
||||
<div v-else class="settings-card">
|
||||
<!-- 已绑定信息(顶部展示) -->
|
||||
<Transition name="fade">
|
||||
<div v-if="boundInfo" class="bound-info">
|
||||
<div class="bound-info__header">
|
||||
<span class="bound-info__icon">✅</span>
|
||||
<span class="bound-info__icon"><AppIcon name="success" :size="18" /></span>
|
||||
<span class="bound-info__text">已绑定 OpenList</span>
|
||||
</div>
|
||||
<div class="bound-info__details">
|
||||
@ -134,12 +42,15 @@
|
||||
</div>
|
||||
<div class="bound-info__item">
|
||||
<span class="bound-info__label">Token有效:</span>
|
||||
<span class="bound-info__value">{{ boundInfo.tokenValid ? '✅ 是' : '❌ 否' }}</span>
|
||||
<span class="bound-info__value">
|
||||
<AppIcon :name="boundInfo.tokenValid ? 'success' : 'fail'" :size="14" />
|
||||
{{ boundInfo.tokenValid ? '是' : '否' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="bound-info__item" v-if="boundInfo.connectMessage">
|
||||
<span class="bound-info__label">连接状态:</span>
|
||||
<span class="bound-info__value connect-message" :class="{ 'connect-ok': boundInfo.connected === true, 'connect-error': boundInfo.connected === false }">
|
||||
{{ boundInfo.connected ? '✅' : '❌' }} {{ boundInfo.connectMessage }}
|
||||
<AppIcon :name="boundInfo.connected ? 'success' : 'fail'" :size="14" /> {{ boundInfo.connectMessage }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="bound-info__item">
|
||||
@ -156,10 +67,110 @@
|
||||
class="btn-unbind"
|
||||
@click="handleUnbind"
|
||||
>
|
||||
🗑️ 解除绑定
|
||||
<AppIcon name="delete" :size="16" /> 解除绑定
|
||||
</button>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<h3 class="settings-card__title">
|
||||
<span class="settings-card__icon"><AppIcon name="link" :size="20" /></span>
|
||||
OpenList 绑定
|
||||
</h3>
|
||||
|
||||
<form class="settings-form" @submit.prevent="handleBind">
|
||||
<!-- OpenList 地址 -->
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="openlist-url">
|
||||
<span class="form-label__icon"><AppIcon name="globe" :size="16" /></span>
|
||||
<span class="form-label__text">OpenList 地址</span>
|
||||
</label>
|
||||
<input
|
||||
id="openlist-url"
|
||||
v-model="formData.url"
|
||||
type="url"
|
||||
class="form-input"
|
||||
placeholder="例如:https://olist.example.com 或 http://localhost:5575"
|
||||
required
|
||||
autocomplete="off"
|
||||
readonly
|
||||
onfocus="this.removeAttribute('readonly')"
|
||||
/>
|
||||
<span class="form-help">请填写 OpenList 服务的完整访问地址,包含协议头</span>
|
||||
</div>
|
||||
|
||||
<!-- 账号 -->
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="openlist-username">
|
||||
<span class="form-label__icon"><AppIcon name="user" :size="16" /></span>
|
||||
<span class="form-label__text">账号</span>
|
||||
</label>
|
||||
<input
|
||||
id="openlist-username"
|
||||
v-model="formData.username"
|
||||
type="text"
|
||||
class="form-input"
|
||||
placeholder="请输入 OpenList 用户名"
|
||||
required
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 密码 -->
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="openlist-password">
|
||||
<span class="form-label__icon"><AppIcon name="save" :size="16" /></span>
|
||||
<span class="form-label__text">密码</span>
|
||||
</label>
|
||||
<div class="password-input-wrapper">
|
||||
<input
|
||||
id="openlist-password"
|
||||
v-model="formData.password"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
class="form-input"
|
||||
placeholder="请输入 OpenList 密码"
|
||||
required
|
||||
autocomplete="off"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="password-toggle"
|
||||
@click="showPassword = !showPassword"
|
||||
:title="showPassword ? '隐藏密码' : '显示密码'"
|
||||
>
|
||||
<AppIcon :name="showPassword ? 'eye-off' : 'eye'" :size="18" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 绑定按钮 -->
|
||||
<div class="form-actions">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn-bind"
|
||||
:disabled="binding"
|
||||
:class="{ 'btn-bind--loading': binding }"
|
||||
>
|
||||
<span v-if="!binding"><AppIcon name="link" :size="16" /> 绑定 OpenList</span>
|
||||
<span v-else class="loading-spinner"><AppIcon name="sync" :size="16" /> 绑定中...</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-reset"
|
||||
@click="resetForm"
|
||||
:disabled="binding"
|
||||
>
|
||||
重置
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 绑定状态提示 -->
|
||||
<Transition name="fade">
|
||||
<div v-if="bindStatus" class="bind-status" :class="`bind-status--${bindStatus.type}`">
|
||||
<span class="bind-status__icon"><AppIcon v-if="bindStatus.iconName" :name="bindStatus.iconName" :size="18" /></span>
|
||||
<span class="bind-status__text">{{ bindStatus.message }}</span>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -167,6 +178,7 @@
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { bindOpenList, unbindOpenList, getOpenListInfo } from '../api'
|
||||
import AppIcon from './AppIcon.vue'
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
@ -176,6 +188,7 @@ const formData = reactive({
|
||||
})
|
||||
|
||||
// 状态控制
|
||||
const loading = ref(true)
|
||||
const binding = ref(false)
|
||||
const showPassword = ref(false)
|
||||
const bindStatus = ref(null)
|
||||
@ -188,6 +201,7 @@ const boundInfo = ref(null)
|
||||
* - 已绑定:返回 { code: 200, data: { id, openlistUrl, openlistUsername, storageId, mountPath, status, tokenValid, connected, connectMessage, createTime, updateTime } }
|
||||
*/
|
||||
async function loadBoundInfo() {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await getOpenListInfo()
|
||||
// result 可能为 null(未绑定)或 { code: 200, data: {...} }
|
||||
@ -217,6 +231,8 @@ async function loadBoundInfo() {
|
||||
// 显示后端返回的错误信息
|
||||
const errorMsg = err?.payload?.message || err?.message || '加载绑定信息失败'
|
||||
setBindStatus('error', errorMsg)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,17 +351,17 @@ function setBindStatus(type, message, autoClear = true) {
|
||||
return
|
||||
}
|
||||
|
||||
const icons = {
|
||||
success: '✅',
|
||||
error: '❌',
|
||||
warning: '⚠️',
|
||||
info: 'ℹ️',
|
||||
const iconNames = {
|
||||
success: 'success',
|
||||
error: 'fail',
|
||||
warning: 'warning',
|
||||
info: 'info',
|
||||
}
|
||||
|
||||
bindStatus.value = {
|
||||
type,
|
||||
message,
|
||||
icon: icons[type] || '',
|
||||
iconName: iconNames[type] || '',
|
||||
}
|
||||
|
||||
// 3秒后自动清除(仅用于非错误类型的临时提示)
|
||||
@ -364,9 +380,7 @@ onMounted(() => {
|
||||
|
||||
<style scoped>
|
||||
.settings-view {
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
padding: 24px 16px;
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.settings-header {
|
||||
@ -666,6 +680,37 @@ onMounted(() => {
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* 加载容器 */
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 60px 24px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.loading-spinner-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 3px solid #e5e7eb;
|
||||
border-top-color: #3b82f6;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 过渡动画 */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
@ -759,6 +804,15 @@ onMounted(() => {
|
||||
background: #3a1a1a;
|
||||
border-color: #f56c6c;
|
||||
}
|
||||
|
||||
.loading-spinner-icon {
|
||||
border-color: #374151;
|
||||
border-top-color: #60a5fa;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
color: #9ca3af;
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式 */
|
||||
|
||||
@ -19,9 +19,9 @@
|
||||
<!-- 文件夹/文件图标 -->
|
||||
<span v-if="multiSelectMode" class="tree-icon tree-icon--checkbox"></span>
|
||||
<span v-else-if="node.type === 'folder'" class="tree-icon">
|
||||
{{ isExpanded ? '📂' : '📁' }}
|
||||
<AppIcon :name="isExpanded ? 'folder-open' : 'folder'" :size="18" />
|
||||
</span>
|
||||
<span v-else class="tree-icon">📄</span>
|
||||
<span v-else class="tree-icon"><AppIcon name="file" :size="18" /></span>
|
||||
<span v-if="node.type === 'folder' && node.isLoading" class="tree-loading">加载中...</span>
|
||||
|
||||
<!-- 刮削状态徽章(仅文件类型) -->
|
||||
@ -46,7 +46,7 @@
|
||||
v-if="node.type === 'folder' && node.description"
|
||||
class="tree-info-badge"
|
||||
title="有描述"
|
||||
>ℹ️</span>
|
||||
><AppIcon name="info" :size="16" /></span>
|
||||
|
||||
<div class="tree-actions" @click.stop>
|
||||
<!-- 刮削进度条(刮削中时显示) -->
|
||||
@ -63,7 +63,7 @@
|
||||
title="添加子文件夹"
|
||||
@click="handleAddFolder"
|
||||
>
|
||||
+📁
|
||||
<AppIcon name="add-folder" :size="16" />
|
||||
</button>
|
||||
<button
|
||||
v-if="node.type === 'folder'"
|
||||
@ -72,7 +72,7 @@
|
||||
title="添加文件"
|
||||
@click="handleAddFile"
|
||||
>
|
||||
+📄
|
||||
<AppIcon name="add-file" :size="16" />
|
||||
</button>
|
||||
<button
|
||||
v-if="node.type === 'file'"
|
||||
@ -81,7 +81,7 @@
|
||||
title="重新刮削"
|
||||
@click="handleRescrape"
|
||||
>
|
||||
🔄
|
||||
<AppIcon name="refresh" :size="16" />
|
||||
</button>
|
||||
<button
|
||||
v-if="node.type === 'file'"
|
||||
@ -90,7 +90,7 @@
|
||||
title="查询刮削状态"
|
||||
@click="handleScrapeStatus"
|
||||
>
|
||||
🔍
|
||||
<AppIcon name="search" :size="16" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@ -98,7 +98,7 @@
|
||||
title="编辑"
|
||||
@click="handleEdit"
|
||||
>
|
||||
✏️
|
||||
<AppIcon name="edit" :size="16" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@ -106,7 +106,7 @@
|
||||
title="删除"
|
||||
@click="handleDelete"
|
||||
>
|
||||
🗑️
|
||||
<AppIcon name="delete" :size="16" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -120,7 +120,7 @@
|
||||
:style="tooltipStyle"
|
||||
>
|
||||
<div class="app-tooltip__header">
|
||||
<span class="app-tooltip__icon">📁</span>
|
||||
<span class="app-tooltip__icon"><AppIcon name="folder" :size="16" /></span>
|
||||
<span class="app-tooltip__title">{{ node.title }}</span>
|
||||
</div>
|
||||
<div class="app-tooltip__body">
|
||||
@ -162,6 +162,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import AppIcon from './AppIcon.vue'
|
||||
|
||||
const props = defineProps({
|
||||
node: {
|
||||
|
||||
@ -244,7 +244,7 @@
|
||||
>
|
||||
<div class="confirm-box">
|
||||
<header class="confirm-header">
|
||||
<h3>⚠️ 确认删除</h3>
|
||||
<h3><AppIcon name="warning" :size="20" /> 确认删除</h3>
|
||||
<button type="button" class="confirm-close" @click="closeConfirmDialog">×</button>
|
||||
</header>
|
||||
|
||||
@ -269,12 +269,13 @@
|
||||
<script setup>
|
||||
import { reactive, ref, computed, watch } from 'vue'
|
||||
import {
|
||||
fetchUserList,
|
||||
fetchUsers,
|
||||
createUser,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
} from '../api'
|
||||
import { lockScroll, unlockScroll } from '../utils/scrollLock'
|
||||
import AppIcon from './AppIcon.vue'
|
||||
|
||||
// ==================== 组件属性和事件 ====================
|
||||
const props = defineProps({
|
||||
@ -1197,6 +1198,19 @@ watch(
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
transition: border-color 0.2s;
|
||||
/* 重置 select 元素的默认样式 */
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 为 select 添加自定义下拉箭头 */
|
||||
.form-group select {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23606266' d='M2 4l4 4 4-4'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 12px center;
|
||||
padding-right: 32px;
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
|
||||
523
src/style.css
@ -508,12 +508,26 @@ body.dark-mode .network-toggle__btn--active:hover {
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-input-icon {
|
||||
position: absolute;
|
||||
left: 18px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.search-topbar__input input {
|
||||
min-height: 52px;
|
||||
border-radius: 999px;
|
||||
padding: 0 20px;
|
||||
padding: 0 20px 0 48px;
|
||||
transition: all 0.3s ease;
|
||||
outline: none;
|
||||
}
|
||||
@ -960,7 +974,7 @@ body.dark-mode .quick-access-btn__icon {
|
||||
.hero-main {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 520px;
|
||||
height: 700px;
|
||||
border-radius: 24px;
|
||||
overflow: hidden;
|
||||
outline: none;
|
||||
@ -970,7 +984,7 @@ body.dark-mode .quick-access-btn__icon {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 海报图片层 */
|
||||
/* 海报图片层 - cover 填充,顶部对齐 */
|
||||
.hero-bg-image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@ -978,27 +992,15 @@ body.dark-mode .quick-access-btn__icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
object-position: top center;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
/* 横向海报适配 - 使用独立容器确保图片完整显示 */
|
||||
.hero-main.hero-wide {
|
||||
overflow: visible;
|
||||
min-height: 200px;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
/* 横版海报 - 宽度撑满,高度按比例自适应,顶部对齐,底部由容器裁剪 */
|
||||
.hero-main.hero-wide .hero-bg-image {
|
||||
position: relative;
|
||||
object-fit: contain;
|
||||
object-position: center;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: 500px;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
background-color: #0f172a;
|
||||
position: relative !important;
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
/* 海报加载状态 - 渐变动画模拟视频加载 */
|
||||
@ -1050,7 +1052,7 @@ body.dark-mode .quick-access-btn__icon {
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
padding: 48px;
|
||||
background: linear-gradient(180deg, rgba(8, 15, 29, 0.05) 0%, rgba(8, 15, 29, 0.75) 100%);
|
||||
background: linear-gradient(180deg, rgba(8, 15, 29, 0) 50%, rgba(8, 15, 29, 0.55) 100%);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@ -1223,6 +1225,12 @@ body.dark-mode .quick-access-btn__icon {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hero-main__tag {
|
||||
background: rgba(99, 102, 241, 0.25);
|
||||
font-size: 12px;
|
||||
padding: 4px 10px;
|
||||
}
|
||||
|
||||
/* ==================== 上方小海报卡片(悬浮于大海报之上,与每日推荐同级) ==================== */
|
||||
.hero-sub {
|
||||
display: flex;
|
||||
@ -4034,19 +4042,18 @@ body.dark-mode .quick-access-btn__icon {
|
||||
background: linear-gradient(135deg, #34495e 0%, #5cb8c9 100%);
|
||||
}
|
||||
|
||||
.theme-toggle-btn__icon {
|
||||
.theme-toggle-btn .app-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
color: #555;
|
||||
transition: color 0.3s ease;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.theme-toggle-btn--dark .theme-toggle-btn__icon {
|
||||
color: #f0f0f0;
|
||||
.theme-toggle-btn:hover .app-icon {
|
||||
transform: rotate(30deg);
|
||||
}
|
||||
|
||||
/* 太阳和月亮图标的动画 */
|
||||
.theme-icon--sun {
|
||||
/* 太阳图标旋转动画 */
|
||||
.theme-toggle-btn:not(.theme-toggle-btn--dark) .app-icon svg {
|
||||
animation: sun-rotate 20s linear infinite;
|
||||
}
|
||||
|
||||
@ -5055,7 +5062,8 @@ body.dark-mode .dialog-form header {
|
||||
border-bottom-color: rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
body.dark-mode .simple-dialog__header h2 {
|
||||
body.dark-mode .simple-dialog__header h2,
|
||||
body.dark-mode .dialog-form header h2 {
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
@ -5118,6 +5126,13 @@ body.dark-mode select {
|
||||
border-color: rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
/* 覆盖 scoped 组件中硬编码的浅色边框 */
|
||||
body.dark-mode .form-group input,
|
||||
body.dark-mode .form-group select,
|
||||
body.dark-mode .form-group textarea {
|
||||
border-color: rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
body.dark-mode input::placeholder,
|
||||
body.dark-mode textarea::placeholder {
|
||||
color: #64748b;
|
||||
@ -6331,3 +6346,453 @@ body.dark-mode .dialog-form header button[type="button"]:hover {
|
||||
background: rgba(71, 85, 105, 0.8);
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
/* ===== 黑夜模式:用户管理弹窗搜索和重置按钮 ===== */
|
||||
body.dark-mode .btn-search {
|
||||
background: rgba(56, 189, 248, 0.1);
|
||||
border-color: #38bdf8;
|
||||
color: #38bdf8;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-search:hover {
|
||||
background: #38bdf8;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-reset {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
border-color: #f87171;
|
||||
color: #f87171;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-reset:hover {
|
||||
background: #f87171;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
/* 用户管理弹窗表格样式 */
|
||||
body.dark-mode .user-table th {
|
||||
background: rgba(15, 23, 42, 0.6);
|
||||
color: #94a3b8;
|
||||
border-bottom-color: rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
body.dark-mode .user-table td {
|
||||
border-bottom-color: rgba(51, 65, 85, 0.3);
|
||||
}
|
||||
|
||||
body.dark-mode .user-table tbody tr:hover {
|
||||
background: rgba(56, 189, 248, 0.08);
|
||||
}
|
||||
|
||||
/* 用户管理弹窗分页样式 */
|
||||
body.dark-mode .pagination-bar {
|
||||
border-top-color: rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
body.dark-mode .pagination-controls button {
|
||||
background: rgba(15, 23, 42, 0.5);
|
||||
border-color: rgba(51, 65, 85, 0.5);
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
body.dark-mode .pagination-controls button:hover:not(:disabled) {
|
||||
background: rgba(56, 189, 248, 0.1);
|
||||
border-color: #38bdf8;
|
||||
color: #38bdf8;
|
||||
}
|
||||
|
||||
/* 用户管理弹窗编辑/删除按钮 */
|
||||
body.dark-mode .btn-edit {
|
||||
background: rgba(56, 189, 248, 0.1);
|
||||
border-color: rgba(56, 189, 248, 0.3);
|
||||
color: #38bdf8;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-edit:hover {
|
||||
background: #38bdf8;
|
||||
color: #0f172a;
|
||||
border-color: #38bdf8;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-delete {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
border-color: rgba(239, 68, 68, 0.3);
|
||||
color: #f87171;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-delete:hover {
|
||||
background: #f87171;
|
||||
color: #0f172a;
|
||||
border-color: #f87171;
|
||||
}
|
||||
|
||||
/* 用户管理弹窗角色和状态徽章 */
|
||||
body.dark-mode .role-0 {
|
||||
background: rgba(56, 189, 248, 0.15);
|
||||
color: #38bdf8;
|
||||
}
|
||||
|
||||
body.dark-mode .role-1 {
|
||||
background: rgba(251, 191, 36, 0.15);
|
||||
color: #fbbf24;
|
||||
}
|
||||
|
||||
body.dark-mode .role-2 {
|
||||
background: rgba(148, 163, 184, 0.15);
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
body.dark-mode .status-0 {
|
||||
background: rgba(239, 68, 68, 0.15);
|
||||
color: #f87171;
|
||||
}
|
||||
|
||||
body.dark-mode .status-1 {
|
||||
background: rgba(34, 197, 94, 0.15);
|
||||
color: #4ade80;
|
||||
}
|
||||
|
||||
body.dark-mode .status-2 {
|
||||
background: rgba(148, 163, 184, 0.15);
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
/* 用户管理弹窗加载遮罩 */
|
||||
body.dark-mode .global-loading-overlay {
|
||||
background: rgba(15, 23, 42, 0.85);
|
||||
}
|
||||
|
||||
body.dark-mode .spinner {
|
||||
border-color: rgba(51, 65, 85, 0.5);
|
||||
border-top-color: #38bdf8;
|
||||
}
|
||||
|
||||
body.dark-mode .loading-text {
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
/* ===== 黑夜模式:网盘管理弹窗完整兼容 ===== */
|
||||
/* 网盘管理工具栏 */
|
||||
body.dark-mode .drive-toolbar {
|
||||
border-bottom-color: rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
body.dark-mode .drive-toolbar h3 {
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
/* 网盘卡片 */
|
||||
body.dark-mode .drive-card {
|
||||
background: rgba(15, 23, 42, 0.5);
|
||||
border-color: rgba(51, 65, 85, 0.4);
|
||||
}
|
||||
|
||||
body.dark-mode .drive-card:hover {
|
||||
background: rgba(30, 41, 59, 0.6);
|
||||
border-color: rgba(56, 189, 248, 0.3);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* 网盘Logo */
|
||||
body.dark-mode .drive-logo-small {
|
||||
background: linear-gradient(135deg, #1e293b 0%, #334155 100%);
|
||||
border-color: rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
/* 网盘名称 */
|
||||
body.dark-mode .drive-name {
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
/* 网盘元数据 */
|
||||
body.dark-mode .drive-meta {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
/* 网盘悬浮提示 */
|
||||
body.dark-mode .drive-tooltip {
|
||||
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
|
||||
border-color: rgba(51, 65, 85, 0.5);
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
body.dark-mode .tooltip-header {
|
||||
color: #e2e8f0;
|
||||
border-bottom-color: rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
body.dark-mode .tooltip-content {
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
body.dark-mode .tooltip-arrow {
|
||||
background: #1e293b;
|
||||
border-color: rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
/* 网盘表单视图 */
|
||||
body.dark-mode .form-header {
|
||||
border-bottom-color: rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
body.dark-mode .form-header h3 {
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-back {
|
||||
background: rgba(51, 65, 85, 0.3);
|
||||
border-color: rgba(51, 65, 85, 0.5);
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-back:hover {
|
||||
background: rgba(51, 65, 85, 0.5);
|
||||
border-color: rgba(71, 85, 105, 0.7);
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
/* 网盘表单输入框 */
|
||||
body.dark-mode .form-input,
|
||||
body.dark-mode .form-textarea {
|
||||
background: rgba(15, 23, 42, 0.6);
|
||||
border-color: rgba(51, 65, 85, 0.5);
|
||||
color: #e2e8f0;
|
||||
}
|
||||
|
||||
body.dark-mode .form-input:focus,
|
||||
body.dark-mode .form-textarea:focus {
|
||||
background: rgba(15, 23, 42, 0.8);
|
||||
border-color: #38bdf8;
|
||||
box-shadow: 0 0 0 2px rgba(56, 189, 248, 0.15);
|
||||
}
|
||||
|
||||
body.dark-mode .form-input:disabled,
|
||||
body.dark-mode .form-textarea:disabled {
|
||||
background: rgba(15, 23, 42, 0.4);
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
body.dark-mode .form-group label {
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
body.dark-mode .char-count {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
/* Logo上传区域 */
|
||||
body.dark-mode .logo-upload-area {
|
||||
background: rgba(15, 23, 42, 0.4);
|
||||
border-color: rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
body.dark-mode .logo-upload-area:hover {
|
||||
border-color: #38bdf8;
|
||||
background: rgba(56, 189, 248, 0.05);
|
||||
}
|
||||
|
||||
body.dark-mode .upload-placeholder {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
body.dark-mode .logo-upload-tips {
|
||||
background: rgba(56, 189, 248, 0.1);
|
||||
border-color: rgba(56, 189, 248, 0.3);
|
||||
color: #7dd3fc;
|
||||
}
|
||||
|
||||
body.dark-mode .logo-upload-tips strong {
|
||||
color: #bae6fd;
|
||||
}
|
||||
|
||||
/* 表单底部 */
|
||||
body.dark-mode .form-footer {
|
||||
border-top-color: rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
body.dark-mode .btn-cancel {
|
||||
background: rgba(15, 23, 42, 0.5);
|
||||
border-color: rgba(51, 65, 85, 0.5);
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-cancel:hover:not(:disabled) {
|
||||
background: rgba(56, 189, 248, 0.1);
|
||||
border-color: rgba(56, 189, 248, 0.5);
|
||||
color: #38bdf8;
|
||||
}
|
||||
|
||||
/* 网盘编辑/删除按钮 */
|
||||
body.dark-mode .drive-actions .btn-edit {
|
||||
background: rgba(56, 189, 248, 0.1);
|
||||
border-color: rgba(56, 189, 248, 0.3);
|
||||
color: #38bdf8;
|
||||
}
|
||||
|
||||
body.dark-mode .drive-actions .btn-edit:hover {
|
||||
background: #38bdf8;
|
||||
color: #0f172a;
|
||||
border-color: #38bdf8;
|
||||
}
|
||||
|
||||
body.dark-mode .drive-actions .btn-delete {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
border-color: rgba(239, 68, 68, 0.3);
|
||||
color: #f87171;
|
||||
}
|
||||
|
||||
body.dark-mode .drive-actions .btn-delete:hover {
|
||||
background: #f87171;
|
||||
color: #0f172a;
|
||||
border-color: #f87171;
|
||||
}
|
||||
|
||||
/* 网盘加载状态 */
|
||||
body.dark-mode .spinner-small {
|
||||
border-color: rgba(51, 65, 85, 0.5);
|
||||
border-top-color: #38bdf8;
|
||||
}
|
||||
|
||||
/* ===== 黑夜模式:设置弹窗内部内容兼容 ===== */
|
||||
/* 设置弹窗在 SimpleDialog 中,需要覆盖 SettingsView 组件的 scoped 样式(加 !important 提升优先级) */
|
||||
body.dark-mode .settings-in-dialog .settings-header p {
|
||||
color: #94a3b8 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .settings-card {
|
||||
background: rgba(15, 23, 42, 0.5) !important;
|
||||
border-color: rgba(51, 65, 85, 0.4) !important;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3) !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .settings-card__title {
|
||||
color: #e2e8f0 !important;
|
||||
border-bottom-color: rgba(51, 65, 85, 0.5) !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .form-label {
|
||||
color: #cbd5e1 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .form-input {
|
||||
background: rgba(15, 23, 42, 0.6) !important;
|
||||
border-color: rgba(51, 65, 85, 0.5) !important;
|
||||
color: #e2e8f0 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .form-input:hover {
|
||||
border-color: #38bdf8 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .form-input:focus {
|
||||
background: rgba(15, 23, 42, 0.8) !important;
|
||||
border-color: #38bdf8 !important;
|
||||
box-shadow: 0 0 0 2px rgba(56, 189, 248, 0.15) !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .form-input::placeholder {
|
||||
color: #64748b !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .form-help {
|
||||
color: #64748b !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .password-toggle:hover {
|
||||
background-color: rgba(51, 65, 85, 0.5) !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .form-actions {
|
||||
border-top-color: rgba(51, 65, 85, 0.5) !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .btn-bind {
|
||||
background: linear-gradient(135deg, #38bdf8, #0ea5e9) !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .btn-bind:hover:not(:disabled) {
|
||||
background: linear-gradient(135deg, #7dd3fc, #38bdf8) !important;
|
||||
box-shadow: 0 4px 12px rgba(56, 189, 248, 0.4) !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .btn-bind--loading {
|
||||
background: linear-gradient(135deg, #475569, #334155) !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .btn-reset {
|
||||
color: #94a3b8 !important;
|
||||
background: rgba(51, 65, 85, 0.3) !important;
|
||||
border-color: rgba(51, 65, 85, 0.5) !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .btn-reset:hover:not(:disabled) {
|
||||
color: #38bdf8 !important;
|
||||
border-color: #38bdf8 !important;
|
||||
background: rgba(56, 189, 248, 0.1) !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .bind-status--success {
|
||||
background: rgba(34, 197, 94, 0.1) !important;
|
||||
border-color: rgba(34, 197, 94, 0.3) !important;
|
||||
color: #4ade80 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .bind-status--error {
|
||||
background: rgba(239, 68, 68, 0.1) !important;
|
||||
border-color: rgba(239, 68, 68, 0.3) !important;
|
||||
color: #f87171 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .bound-info {
|
||||
background: rgba(56, 189, 248, 0.05) !important;
|
||||
border-color: rgba(56, 189, 248, 0.2) !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .bound-info__header {
|
||||
color: #4ade80 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .bound-info__item {
|
||||
color: #94a3b8 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .bound-info__label {
|
||||
color: #64748b !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .bound-info__value {
|
||||
color: #e2e8f0 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .connect-ok {
|
||||
color: #4ade80 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .connect-error {
|
||||
color: #f87171 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .status-active {
|
||||
color: #4ade80 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .btn-unbind {
|
||||
color: #f87171 !important;
|
||||
background: rgba(239, 68, 68, 0.05) !important;
|
||||
border-color: rgba(239, 68, 68, 0.2) !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .btn-unbind:hover {
|
||||
background: rgba(239, 68, 68, 0.1) !important;
|
||||
border-color: #f87171 !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .loading-spinner-icon {
|
||||
border-color: #374151 !important;
|
||||
border-top-color: #60a5fa !important;
|
||||
}
|
||||
|
||||
body.dark-mode .settings-in-dialog .loading-text {
|
||||
color: #94a3b8 !important;
|
||||
}
|
||||
|
||||