Files
xianyan/docs/design-preview/sentence-source-import.html
Developer 3a38c69521 chore: 完成v1.2.3版本迭代更新
主要变更:
1. 移除摇一摇相关功能代码与依赖
2. 新增自定义频道导入与管理功能
3. 优化iOS/macOS平台配置与适配
4. 重构路由转场逻辑为原生Cupertino风格
5. 修复设备发现与文件传输相关bug
6. 调整深色模式默认值为纯黑AMOLED
7. 新增运行模式标签与Spotlight搜索优化
8. 清理废弃的本地化字符串与设置项
2026-06-10 07:57:58 +08:00

916 lines
58 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN" data-theme="dark" data-style="default">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>句子来源导入 v2 - 交互式设计预览</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap');
/* ========== 设计令牌 ========== */
:root {
--primary: #6C63FF;
--primary-light: #8B83FF;
--primary-dark: #4A42E0;
--secondary: #FF6B6B;
--accent: #4ECDC4;
--success: #10B981;
--warning: #F59E0B;
--error: #EF4444;
--info: #3B82F6;
--gold: #D4A843;
--radius-xs: 4px; --radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px; --radius-xl: 20px; --radius-full: 999px;
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 20px; --space-6: 24px; --space-8: 32px;
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
--shadow-card: 0 4px 24px rgba(0,0,0,0.4);
--font-sans: 'Inter', 'Noto Sans SC', system-ui, sans-serif;
--transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
--transition-fast: 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}
[data-theme="dark"] {
--bg: #0D0D0D; --bg-elevated: #141414; --bg-card: #1A1A1A; --bg-card-light: #252525;
--bg-input: #1E1E1E; --bg-hover: #2A2A2A; --text: #F5F5F5; --text-secondary: #AEAEB2;
--text-dim: #636366; --border: #2A2A2A; --border-light: #333;
--divider: rgba(255,255,255,0.06); --overlay: rgba(0,0,0,0.6);
--glass-bg: rgba(30,30,30,0.72); --glass-border: rgba(255,255,255,0.08);
--tag-bg: rgba(108,99,255,0.15); --tag-text: #8B83FF;
--success-bg: rgba(16,185,129,0.12); --warning-bg: rgba(245,158,11,0.12);
--error-bg: rgba(239,68,68,0.12); --info-bg: rgba(59,130,246,0.12);
--custom-badge-bg: rgba(78,205,196,0.15); --custom-badge-text: #4ECDC4;
}
[data-theme="light"] {
--bg: #F2F2F7; --bg-elevated: #FFFFFF; --bg-card: #FFFFFF; --bg-card-light: #F9F9FB;
--bg-input: #F2F2F7; --bg-hover: #E5E5EA; --text: #1C1C1E; --text-secondary: #636366;
--text-dim: #AEAEB2; --border: #E5E5EA; --border-light: #D1D1D6;
--divider: rgba(0,0,0,0.05); --overlay: rgba(0,0,0,0.3);
--glass-bg: rgba(255,255,255,0.72); --glass-border: rgba(0,0,0,0.06);
--tag-bg: rgba(108,99,255,0.1); --tag-text: #4A42E0;
--success-bg: rgba(16,185,129,0.08); --warning-bg: rgba(245,158,11,0.08);
--error-bg: rgba(239,68,68,0.08); --info-bg: rgba(59,130,246,0.08);
--custom-badge-bg: rgba(78,205,196,0.1); --custom-badge-text: #2D9F97;
--shadow-card: 0 2px 16px rgba(0,0,0,0.08);
}
[data-theme="amoled"] {
--bg: #000000; --bg-elevated: #0A0A0A; --bg-card: #111111; --bg-card-light: #1A1A1A;
--bg-input: #111111; --bg-hover: #1A1A1A; --text: #F5F5F5; --text-secondary: #AEAEB2;
--text-dim: #48484A; --border: #1C1C1E; --border-light: #2C2C2E;
--divider: rgba(255,255,255,0.04); --overlay: rgba(0,0,0,0.8);
--glass-bg: rgba(17,17,17,0.72); --glass-border: rgba(255,255,255,0.06);
--tag-bg: rgba(108,99,255,0.2); --tag-text: #8B83FF;
--success-bg: rgba(16,185,129,0.15); --warning-bg: rgba(245,158,11,0.15);
--error-bg: rgba(239,68,68,0.15); --info-bg: rgba(59,130,246,0.15);
--custom-badge-bg: rgba(78,205,196,0.2); --custom-badge-text: #4ECDC4;
--shadow-card: 0 4px 24px rgba(0,0,0,0.6);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: var(--bg); color: var(--text); font-family: var(--font-sans); min-height: 100vh; transition: background var(--transition), color var(--transition); -webkit-font-smoothing: antialiased; overflow-x: hidden; }
.app-shell { max-width: 480px; margin: 0 auto; min-height: 100vh; position: relative; background: var(--bg); }
/* 导航栏 */
.nav-bar { position: sticky; top: 0; z-index: 100; background: var(--glass-bg); backdrop-filter: blur(20px) saturate(180%); -webkit-backdrop-filter: blur(20px) saturate(180%); border-bottom: 1px solid var(--glass-border); }
.nav-bar-inner { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; }
.nav-back { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-full); background: transparent; border: none; color: var(--primary); font-size: 20px; cursor: pointer; }
.nav-title { font-size: 17px; font-weight: 600; display: flex; align-items: center; gap: 6px; }
.nav-actions { display: flex; gap: 4px; }
.nav-btn { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-full); background: transparent; border: none; color: var(--primary); font-size: 18px; cursor: pointer; }
/* 主题栏 */
.theme-bar { display: flex; gap: var(--space-2); padding: var(--space-3) var(--space-4); background: var(--bg-elevated); border-bottom: 1px solid var(--divider); overflow-x: auto; }
.theme-chip, .style-chip { padding: 6px 14px; border-radius: var(--radius-full); font-size: 13px; font-weight: 500; border: 1px solid var(--border); background: transparent; color: var(--text-secondary); cursor: pointer; white-space: nowrap; transition: all var(--transition-fast); }
.theme-chip.active { background: var(--primary); color: white; border-color: var(--primary); }
.style-chip.active { background: var(--accent); color: white; border-color: var(--accent); }
/* 本地提示 */
.local-banner { margin: var(--space-3) var(--space-4); padding: var(--space-3) var(--space-4); background: var(--success-bg); border-radius: var(--radius-md); border: 1px solid rgba(16,185,129,0.2); display: flex; align-items: center; gap: var(--space-2); font-size: 13px; color: var(--success); }
/* Tab */
.tab-bar { display: flex; background: var(--bg-elevated); border-bottom: 1px solid var(--divider); position: sticky; top: 60px; z-index: 90; }
.tab-item { flex: 1; padding: 12px 6px; text-align: center; font-size: 12px; font-weight: 500; color: var(--text-secondary); border: none; background: transparent; cursor: pointer; position: relative; transition: color var(--transition-fast); }
.tab-item.active { color: var(--primary); }
.tab-item.active::after { content: ''; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 24px; height: 3px; border-radius: 2px; background: var(--primary); }
.tab-icon { font-size: 18px; display: block; margin-bottom: 2px; }
.content { padding: var(--space-4); }
.tab-content { display: none; }
.tab-content.active { display: block; }
/* 卡片 */
.card { background: var(--bg-card); border-radius: var(--radius-lg); padding: var(--space-5); margin-bottom: var(--space-4); border: 1px solid var(--border); transition: all var(--transition); }
.card-title { font-size: 15px; font-weight: 600; margin-bottom: var(--space-3); display: flex; align-items: center; gap: var(--space-2); }
.card-title .icon { font-size: 18px; }
/* 表单 */
.form-group { margin-bottom: var(--space-4); }
.form-label { font-size: 13px; font-weight: 500; color: var(--text-secondary); margin-bottom: var(--space-2); display: flex; align-items: center; gap: var(--space-1); }
.form-input { width: 100%; padding: 12px 14px; border-radius: var(--radius-md); border: 1px solid var(--border); background: var(--bg-input); color: var(--text); font-size: 15px; font-family: var(--font-sans); transition: all var(--transition-fast); outline: none; }
.form-input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(108,99,255,0.15); }
.form-input::placeholder { color: var(--text-dim); }
.form-hint { font-size: 12px; color: var(--text-dim); margin-top: var(--space-1); }
select.form-input { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='%23636366' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; padding-right: 36px; }
/* 按钮 */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); padding: 12px 20px; border-radius: var(--radius-md); font-size: 15px; font-weight: 600; border: none; cursor: pointer; transition: all var(--transition-fast); font-family: var(--font-sans); }
.btn:active { transform: scale(0.97); }
.btn-primary { background: var(--primary); color: white; }
.btn-secondary { background: var(--bg-card-light); color: var(--text); border: 1px solid var(--border); }
.btn-accent { background: var(--accent); color: white; }
.btn-full { width: 100%; }
.btn-sm { padding: 8px 14px; font-size: 13px; border-radius: var(--radius-sm); }
/* 标签 */
.tag { display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; border-radius: var(--radius-full); font-size: 12px; font-weight: 500; }
.tag-primary { background: var(--tag-bg); color: var(--tag-text); }
.tag-success { background: var(--success-bg); color: var(--success); }
.tag-warning { background: var(--warning-bg); color: var(--warning); }
.tag-error { background: var(--error-bg); color: var(--error); }
.tag-info { background: var(--info-bg); color: var(--info); }
.tag-custom { background: var(--custom-badge-bg); color: var(--custom-badge-text); }
/* 格式选择 */
.format-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.format-card { padding: var(--space-4); border-radius: var(--radius-md); border: 2px solid var(--border); background: var(--bg-card-light); cursor: pointer; transition: all var(--transition-fast); text-align: center; }
.format-card:hover { border-color: var(--primary); }
.format-card.active { border-color: var(--primary); background: var(--tag-bg); }
.format-card .format-icon { font-size: 28px; margin-bottom: var(--space-2); }
.format-card .format-name { font-size: 14px; font-weight: 600; }
.format-card .format-desc { font-size: 11px; color: var(--text-secondary); margin-top: 2px; }
/* 上传区 */
.upload-zone { border: 2px dashed var(--border); border-radius: var(--radius-lg); padding: var(--space-8) var(--space-4); text-align: center; cursor: pointer; transition: all var(--transition-fast); background: var(--bg-card-light); }
.upload-zone:hover, .upload-zone.dragover { border-color: var(--primary); background: var(--tag-bg); }
.upload-zone .upload-icon { font-size: 40px; margin-bottom: var(--space-3); }
.upload-zone .upload-text { font-size: 15px; font-weight: 500; }
.upload-zone .upload-hint { font-size: 12px; color: var(--text-secondary); margin-top: var(--space-2); }
/* 文件格式 */
.file-format-row { display: flex; gap: var(--space-2); margin-bottom: var(--space-4); }
.file-format-btn { flex: 1; padding: 10px; border-radius: var(--radius-md); border: 1px solid var(--border); background: var(--bg-card-light); color: var(--text-secondary); font-size: 13px; font-weight: 500; cursor: pointer; text-align: center; transition: all var(--transition-fast); }
.file-format-btn.active { border-color: var(--primary); background: var(--tag-bg); color: var(--primary); }
.file-format-btn .fmt-icon { font-size: 20px; display: block; margin-bottom: 2px; }
/* 字段映射 */
.field-map { display: flex; flex-direction: column; gap: var(--space-3); }
.field-map-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3); border-radius: var(--radius-md); background: var(--bg-card-light); border: 1px solid var(--border); }
.field-map-label { font-size: 13px; font-weight: 600; color: var(--primary); min-width: 60px; white-space: nowrap; }
.field-map-arrow { color: var(--text-dim); font-size: 14px; }
.field-map-select { flex: 1; padding: 8px 10px; border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--bg-input); color: var(--text); font-size: 13px; font-family: var(--font-sans); outline: none; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' fill='%23636366' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 8px center; padding-right: 28px; }
.field-required { color: var(--secondary); }
/* 预览列表 */
.preview-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-3); }
.preview-count { font-size: 13px; color: var(--text-secondary); }
.preview-list { display: flex; flex-direction: column; gap: var(--space-3); }
.preview-item { padding: var(--space-4); border-radius: var(--radius-md); background: var(--bg-card-light); border: 1px solid var(--border); transition: all var(--transition-fast); cursor: pointer; }
.preview-item:hover { border-color: var(--primary); }
.preview-item.selected { border-color: var(--primary); background: var(--tag-bg); }
.preview-item-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-2); }
.preview-item-title { font-size: 14px; font-weight: 600; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.preview-item-content { font-size: 13px; color: var(--text-secondary); line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.preview-item-meta { display: flex; align-items: center; gap: var(--space-3); margin-top: var(--space-2); font-size: 12px; color: var(--text-dim); }
/* 来源列表 */
.source-list { display: flex; flex-direction: column; gap: var(--space-3); }
.source-item { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-4); border-radius: var(--radius-md); background: var(--bg-card); border: 1px solid var(--border); transition: all var(--transition-fast); cursor: pointer; }
.source-item:hover { border-color: var(--primary); }
.source-icon { width: 44px; height: 44px; border-radius: var(--radius-md); display: flex; align-items: center; justify-content: center; font-size: 22px; flex-shrink: 0; }
.source-icon.url { background: var(--info-bg); }
.source-icon.file { background: var(--success-bg); }
.source-icon.api { background: var(--tag-bg); }
.source-info { flex: 1; min-width: 0; }
.source-name { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.source-detail { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
.source-tags { display: flex; gap: var(--space-1); margin-top: var(--space-1); }
.source-actions { display: flex; flex-direction: column; gap: var(--space-1); align-items: flex-end; }
/* 分析面板 */
.analysis-panel { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.analysis-item { padding: var(--space-3); border-radius: var(--radius-md); background: var(--bg-card-light); border: 1px solid var(--border); }
.analysis-label { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: var(--space-1); }
.analysis-value { font-size: 14px; font-weight: 600; }
/* 开关 */
.switch-row { display: flex; align-items: center; justify-content: space-between; padding: var(--space-3) 0; }
.switch-row + .switch-row { border-top: 1px solid var(--divider); }
.switch-label { font-size: 14px; font-weight: 500; }
.switch-desc { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
.toggle { width: 51px; height: 31px; border-radius: var(--radius-full); background: var(--border-light); position: relative; cursor: pointer; transition: background var(--transition-fast); flex-shrink: 0; }
.toggle.active { background: var(--success); }
.toggle::after { content: ''; position: absolute; width: 27px; height: 27px; border-radius: 50%; background: white; top: 2px; left: 2px; transition: transform var(--transition-fast); box-shadow: 0 1px 3px rgba(0,0,0,0.2); }
.toggle.active::after { transform: translateX(20px); }
/* 校验状态 */
.validate-list { display: flex; flex-direction: column; gap: var(--space-2); }
.validate-item { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); font-size: 13px; }
.validate-item.pass { background: var(--success-bg); color: var(--success); }
.validate-item.fail { background: var(--error-bg); color: var(--error); }
.validate-item.warn { background: var(--warning-bg); color: var(--warning); }
.validate-item.pending { background: var(--bg-card-light); color: var(--text-dim); }
/* 频道预览(主页模拟) */
.channel-preview { display: flex; gap: var(--space-2); overflow-x: auto; padding: var(--space-3) 0; -webkit-overflow-scrolling: touch; }
.channel-chip { display: flex; align-items: center; gap: 4px; padding: 8px 14px; border-radius: var(--radius-full); font-size: 13px; font-weight: 500; border: 1px solid var(--border); background: var(--bg-card-light); color: var(--text-secondary); white-space: nowrap; cursor: pointer; transition: all var(--transition-fast); }
.channel-chip.active { background: var(--primary); color: white; border-color: var(--primary); }
.channel-chip .ch-icon { font-size: 14px; }
.channel-chip .custom-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); flex-shrink: 0; }
/* 分享Sheet */
.share-sheet { position: fixed; bottom: 0; left: 50%; transform: translateX(-50%); width: 100%; max-width: 480px; background: var(--bg-elevated); border-radius: var(--radius-xl) var(--radius-xl) 0 0; z-index: 200; padding: var(--space-5); transition: transform 0.35s ease; }
.share-sheet.hidden { transform: translateX(-50%) translateY(100%); }
.share-sheet-handle { width: 36px; height: 4px; border-radius: 2px; background: var(--border-light); margin: 0 auto var(--space-4); }
.share-sheet-title { font-size: 17px; font-weight: 600; text-align: center; margin-bottom: var(--space-5); }
.share-option { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-4); border-radius: var(--radius-md); border: 1px solid var(--border); margin-bottom: var(--space-3); cursor: pointer; transition: all var(--transition-fast); }
.share-option:hover { border-color: var(--primary); background: var(--tag-bg); }
.share-option .opt-icon { width: 44px; height: 44px; border-radius: var(--radius-md); display: flex; align-items: center; justify-content: center; font-size: 22px; }
.share-option .opt-info { flex: 1; }
.share-option .opt-title { font-size: 14px; font-weight: 600; }
.share-option .opt-desc { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
/* 设备性能 */
.perf-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--space-2); }
.perf-item { padding: var(--space-3); border-radius: var(--radius-md); background: var(--bg-card-light); border: 1px solid var(--border); text-align: center; }
.perf-value { font-size: 18px; font-weight: 700; }
.perf-value.good { color: var(--success); }
.perf-value.warn { color: var(--warning); }
.perf-value.bad { color: var(--error); }
.perf-label { font-size: 11px; color: var(--text-dim); margin-top: 2px; }
/* 模板下载 */
.template-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2); }
.template-btn { padding: var(--space-3); border-radius: var(--radius-md); border: 1px solid var(--border); background: var(--bg-card-light); cursor: pointer; text-align: center; transition: all var(--transition-fast); }
.template-btn:hover { border-color: var(--primary); background: var(--tag-bg); }
.template-btn .tmpl-icon { font-size: 24px; display: block; margin-bottom: 4px; }
.template-btn .tmpl-name { font-size: 11px; font-weight: 500; color: var(--text-secondary); }
/* 底部栏 */
.bottom-bar { position: sticky; bottom: 0; z-index: 100; padding: var(--space-3) var(--space-4); background: var(--glass-bg); backdrop-filter: blur(20px) saturate(180%); -webkit-backdrop-filter: blur(20px) saturate(180%); border-top: 1px solid var(--glass-border); display: flex; gap: var(--space-3); }
.bottom-bar .btn { flex: 1; }
/* 统计 */
.stats-row { display: flex; gap: var(--space-3); margin-bottom: var(--space-4); }
.stat-item { flex: 1; padding: var(--space-3); border-radius: var(--radius-md); background: var(--bg-card-light); border: 1px solid var(--border); text-align: center; }
.stat-value { font-size: 20px; font-weight: 700; color: var(--primary); }
.stat-label { font-size: 11px; color: var(--text-dim); margin-top: 2px; }
/* 搜索 */
.search-bar { display: flex; gap: var(--space-2); margin-bottom: var(--space-4); }
.search-input-wrap { flex: 1; position: relative; }
.search-input-wrap .search-icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--text-dim); font-size: 14px; }
.search-input { width: 100%; padding: 10px 12px 10px 36px; border-radius: var(--radius-md); border: 1px solid var(--border); background: var(--bg-input); color: var(--text); font-size: 14px; font-family: var(--font-sans); outline: none; }
/* 筛选 */
.filter-row { display: flex; gap: var(--space-2); margin-bottom: var(--space-4); overflow-x: auto; }
.filter-chip { padding: 6px 12px; border-radius: var(--radius-full); font-size: 12px; font-weight: 500; border: 1px solid var(--border); background: transparent; color: var(--text-secondary); cursor: pointer; white-space: nowrap; transition: all var(--transition-fast); }
.filter-chip.active { background: var(--primary); color: white; border-color: var(--primary); }
/* Toast */
.toast { position: fixed; top: 80px; left: 50%; transform: translateX(-50%) translateY(-20px); background: var(--bg-card); color: var(--text); padding: 12px 20px; border-radius: var(--radius-md); font-size: 14px; font-weight: 500; box-shadow: var(--shadow-lg); border: 1px solid var(--border); z-index: 999; opacity: 0; pointer-events: none; transition: all 0.3s ease; display: flex; align-items: center; gap: var(--space-2); }
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
/* 合并来源标签 */
.merge-sources { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }
.merge-source-tag { display: flex; align-items: center; gap: 4px; padding: 4px 8px; border-radius: var(--radius-sm); font-size: 11px; font-weight: 500; background: var(--bg-card-light); border: 1px solid var(--border); }
.merge-source-tag .remove { cursor: pointer; color: var(--text-dim); font-size: 14px; }
.merge-source-tag .remove:hover { color: var(--error); }
/* 进度条 */
.progress-bar { height: 4px; background: var(--border); border-radius: 2px; overflow: hidden; margin-top: var(--space-2); }
.progress-fill { height: 100%; border-radius: 2px; background: var(--primary); transition: width 0.5s ease; }
@keyframes fadeInUp { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }
.animate-in { animation: fadeInUp 0.4s ease forwards; }
/* 频道卡片行模拟ChannelCard */
.channel-card-row {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-3) var(--space-4);
border-radius: var(--radius-lg);
background: var(--bg-card);
border: 1px solid var(--border);
transition: all var(--transition-fast);
cursor: pointer;
}
.channel-card-row:hover { border-color: var(--primary); }
.ch-icon-box {
width: 44px; height: 44px;
border-radius: var(--radius-md);
display: flex; align-items: center; justify-content: center;
font-size: 22px;
position: relative;
flex-shrink: 0;
}
.ch-info { flex: 1; min-width: 0; }
.ch-name {
font-size: 14px;
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: flex;
align-items: center;
gap: var(--space-1);
}
.ch-count { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
/* 自定义频道徽标 */
.custom-badge {
position: absolute;
top: -4px;
right: -4px;
font-size: 10px;
line-height: 1;
background: var(--bg-card);
border-radius: var(--radius-full);
padding: 1px;
}
/* 来源类型徽标 */
.source-type-badge {
display: inline-flex;
align-items: center;
padding: 1px 6px;
border-radius: var(--radius-full);
font-size: 10px;
font-weight: 600;
letter-spacing: 0.3px;
vertical-align: middle;
}
.url-badge { background: var(--info-bg); color: var(--info); }
.file-badge { background: var(--success-bg); color: var(--success); }
.merge-badge { background: var(--custom-badge-bg); color: var(--custom-badge-text); }
/* 设置行 */
.setting-row {
display: flex;
align-items: center;
padding: var(--space-3) var(--space-4);
gap: var(--space-3);
}
.setting-icon {
width: 32px; height: 32px;
border-radius: var(--radius-sm);
display: flex; align-items: center; justify-content: center;
font-size: 16px;
flex-shrink: 0;
}
.setting-info { flex: 1; min-width: 0; }
.setting-title { font-size: 14px; font-weight: 600; }
.setting-sub { font-size: 12px; color: var(--text-secondary); margin-top: 1px; }
</style>
</head>
<body>
<div class="app-shell">
<!-- 导航栏 -->
<nav class="nav-bar">
<div class="nav-bar-inner">
<button class="nav-back" onclick="showToast('返回')"></button>
<div class="nav-title">📥 导入来源</div>
<div class="nav-actions">
<button class="nav-btn" onclick="toggleShareSheet()">📤</button>
</div>
</div>
</nav>
<!-- 主题栏 -->
<div class="theme-bar">
<button class="theme-chip active" onclick="setTheme('dark')">🌙 深色</button>
<button class="theme-chip" onclick="setTheme('light')">☀️ 浅色</button>
<button class="theme-chip" onclick="setTheme('amoled')">🖤 AMOLED</button>
<span style="width:1px;background:var(--border);margin:0 4px"></span>
<button class="style-chip active" onclick="setStyle('default')">默认</button>
<button class="style-chip" onclick="setStyle('compact')">紧凑</button>
<button class="style-chip" onclick="setStyle('rounded')">圆润</button>
</div>
<!-- 本地提示 -->
<div class="local-banner">
<span style="font-size:18px">🔒</span>
<div><strong>本地模式</strong> — 导入内容仅存储在本地不上传服务器。URL获取和文件解析均在本地完成。</div>
</div>
<!-- 主页频道栏预览 -->
<div style="padding:var(--space-2) var(--space-4);background:var(--bg-elevated);border-bottom:1px solid var(--divider)">
<div style="font-size:11px;color:var(--text-dim);margin-bottom:var(--space-1)">主页频道栏预览(自定义频道带 🫧 标识)</div>
<div class="channel-preview" id="channelPreview">
<div class="channel-chip active" onclick="selectChannel(this)"><span class="ch-icon">🔥</span>推荐</div>
<div class="channel-chip" onclick="selectChannel(this)"><span class="ch-icon">📜</span>古诗词</div>
<div class="channel-chip" onclick="selectChannel(this)"><span class="ch-icon">💡</span>名言</div>
<div class="channel-chip" onclick="selectChannel(this)"><span class="ch-icon">💬</span>一言</div>
<div class="channel-chip" onclick="selectChannel(this)"><span class="ch-icon">🎵</span>歌词</div>
<div class="channel-chip" onclick="selectChannel(this)"><span class="custom-dot"></span><span class="ch-icon">🎯</span>我的诗词集</div>
<div class="channel-chip" onclick="selectChannel(this)"><span class="custom-dot"></span><span class="ch-icon">📚</span>名言精选</div>
</div>
</div>
<!-- Tab -->
<div class="tab-bar">
<button class="tab-item active" onclick="switchTab('url')"><span class="tab-icon">🔗</span>URL</button>
<button class="tab-item" onclick="switchTab('file')"><span class="tab-icon">📁</span>文件</button>
<button class="tab-item" onclick="switchTab('channels')"><span class="tab-icon">📺</span>频道管理</button>
<button class="tab-item" onclick="switchTab('validate')"><span class="tab-icon"></span>校验</button>
</div>
<!-- ========== URL导入 ========== -->
<div class="content tab-content active" id="tab-url">
<div class="card animate-in">
<div class="card-title"><span class="icon">🔗</span>输入URL地址</div>
<div class="form-group">
<input type="url" class="form-input" placeholder="https://api.example.com/sentences" value="https://v1.hitokoto.cn/">
<div class="form-hint">支持 HTTP/HTTPS返回 JSON 数据</div>
</div>
<button class="btn btn-primary btn-full" onclick="analyzeUrl()">🔍 分析URL</button>
</div>
<div class="card animate-in">
<div class="card-title"><span class="icon">📐</span>数据格式</div>
<div class="format-grid">
<div class="format-card active" onclick="selectFormat(this,'hitokoto')">
<div class="format-icon">💬</div>
<div class="format-name">Hitokoto</div>
<div class="format-desc">一言API格式</div>
</div>
<div class="format-card" onclick="selectFormat(this,'xianyan_v1')">
<div class="format-icon">🎯</div>
<div class="format-name">闲言 v1</div>
<div class="format-desc">自研兼容格式</div>
</div>
<div class="format-card" onclick="selectFormat(this,'custom')">
<div class="format-icon">⚙️</div>
<div class="format-name">自定义</div>
<div class="format-desc">手动映射字段</div>
</div>
</div>
</div>
<!-- URL分析结果 -->
<div class="card animate-in" id="urlAnalysis" style="display:none">
<div class="card-title"><span class="icon">📊</span>URL分析</div>
<div class="analysis-panel">
<div class="analysis-item"><div class="analysis-label">请求方式</div><div class="analysis-value">GET</div></div>
<div class="analysis-item"><div class="analysis-label">响应格式</div><div class="analysis-value">JSON</div></div>
<div class="analysis-item"><div class="analysis-label">数据条数</div><div class="analysis-value">1条/次</div></div>
<div class="analysis-item"><div class="analysis-label">响应时间</div><div class="analysis-value">128ms</div></div>
</div>
</div>
<!-- 字段映射 -->
<div class="card animate-in" id="fieldMapping" style="display:none">
<div class="card-title"><span class="icon">🗺️</span>字段映射</div>
<div class="field-map">
<div class="field-map-row"><span class="field-map-label">标题 <span class="field-required">*</span></span><span class="field-map-arrow"></span><select class="field-map-select"><option>hitokoto</option><option>text</option><option>content</option></select></div>
<div class="field-map-row"><span class="field-map-label">分类</span><span class="field-map-arrow"></span><select class="field-map-select"><option>type_name</option><option>category</option><option>tag</option></select></div>
<div class="field-map-row"><span class="field-map-label">内容 <span class="field-required">*</span></span><span class="field-map-arrow"></span><select class="field-map-select"><option>hitokoto</option><option>text</option><option>content</option></select></div>
<div class="field-map-row"><span class="field-map-label">详情</span><span class="field-map-arrow"></span><select class="field-map-select"><option>from_source</option><option>source</option></select></div>
<div class="field-map-row"><span class="field-map-label">时间</span><span class="field-map-arrow"></span><select class="field-map-select"><option>created_at</option><option>time</option></select></div>
<div class="field-map-row"><span class="field-map-label">作者</span><span class="field-map-arrow"></span><select class="field-map-select"><option>from_who</option><option>author</option></select></div>
</div>
</div>
<!-- URL设置 -->
<div class="card animate-in">
<div class="card-title"><span class="icon">⚙️</span>导入设置</div>
<div class="form-group">
<label class="form-label">请求频率</label>
<select class="form-input">
<option value="realtime">实时请求</option>
<option value="5min" selected>每5分钟缓存</option>
<option value="30min">每30分钟缓存</option>
<option value="1hour">每1小时缓存</option>
<option value="1day">每天缓存</option>
</select>
</div>
<div class="switch-row"><div><div class="switch-label">启用缓存</div><div class="switch-desc">减少重复请求</div></div><div class="toggle active" onclick="toggleSwitch(this)"></div></div>
<div class="switch-row"><div><div class="switch-label">自动刷新</div><div class="switch-desc">缓存过期后自动重新请求</div></div><div class="toggle active" onclick="toggleSwitch(this)"></div></div>
<div class="switch-row"><div><div class="switch-label">去重检测</div><div class="switch-desc">自动跳过已导入的重复句子</div></div><div class="toggle active" onclick="toggleSwitch(this)"></div></div>
</div>
<!-- 频道配置 -->
<div class="card animate-in">
<div class="card-title"><span class="icon">📺</span>频道配置</div>
<div class="form-group">
<label class="form-label">频道名称</label>
<input type="text" class="form-input" placeholder="如:我的诗词集" value="Hitokoto 一言">
</div>
<div class="form-group">
<label class="form-label">频道图标</label>
<div style="display:flex;gap:var(--space-2);flex-wrap:wrap">
<button class="btn btn-sm btn-secondary" style="font-size:18px" onclick="selectIcon(this)">💬</button>
<button class="btn btn-sm btn-secondary" style="font-size:18px" onclick="selectIcon(this)">📜</button>
<button class="btn btn-sm btn-secondary" style="font-size:18px" onclick="selectIcon(this)">🎯</button>
<button class="btn btn-sm btn-secondary" style="font-size:18px" onclick="selectIcon(this)">📚</button>
<button class="btn btn-sm btn-secondary" style="font-size:18px" onclick="selectIcon(this)">🎵</button>
<button class="btn btn-sm btn-secondary" style="font-size:18px" onclick="selectIcon(this)">💡</button>
<button class="btn btn-sm btn-secondary" style="font-size:18px" onclick="selectIcon(this)">🌟</button>
<button class="btn btn-sm btn-secondary" style="font-size:18px" onclick="selectIcon(this)">🔥</button>
</div>
</div>
<div class="switch-row"><div><div class="switch-label">在主页显示</div><div class="switch-desc">开启后此频道出现在主页频道栏</div></div><div class="toggle active" onclick="toggleSwitch(this)"></div></div>
</div>
<div class="bottom-bar">
<button class="btn btn-secondary" onclick="showToast('预览数据')">👁️ 预览</button>
<button class="btn btn-primary" onclick="showToast('已创建频道并导入3条')">📺 创建频道</button>
</div>
</div>
<!-- ========== 文件导入 ========== -->
<div class="content tab-content" id="tab-file">
<div class="card animate-in">
<div class="card-title"><span class="icon">📄</span>选择文件格式</div>
<div class="file-format-row">
<div class="file-format-btn active" onclick="selectFileFormat(this,'json')"><span class="fmt-icon">📋</span>JSON</div>
<div class="file-format-btn" onclick="selectFileFormat(this,'csv')"><span class="fmt-icon">📊</span>CSV</div>
<div class="file-format-btn" onclick="selectFileFormat(this,'xml')"><span class="fmt-icon">📰</span>XML</div>
</div>
</div>
<div class="card animate-in">
<div class="card-title"><span class="icon">📤</span>上传文件</div>
<div class="upload-zone" onclick="showToast('选择文件')">
<div class="upload-icon">📁</div>
<div class="upload-text">点击或拖拽文件到此处</div>
<div class="upload-hint">支持 JSON / CSV / XML<br>单文件 ≤ 5MB≤ 1000条</div>
</div>
</div>
<div class="card animate-in">
<div class="card-title"><span class="icon">📥</span>下载模板</div>
<div class="template-grid">
<div class="template-btn" onclick="showToast('下载JSON模板')"><span class="tmpl-icon">📋</span><span class="tmpl-name">JSON</span></div>
<div class="template-btn" onclick="showToast('下载CSV模板')"><span class="tmpl-icon">📊</span><span class="tmpl-name">CSV</span></div>
<div class="template-btn" onclick="showToast('下载XML模板')"><span class="tmpl-icon">📰</span><span class="tmpl-name">XML</span></div>
</div>
</div>
<div class="card animate-in">
<div class="card-title"><span class="icon">🗺️</span>字段映射</div>
<div class="form-hint" style="margin-bottom:var(--space-3)">自动识别字段,可手动调整</div>
<div class="field-map">
<div class="field-map-row"><span class="field-map-label">标题 <span class="field-required">*</span></span><span class="field-map-arrow"></span><select class="field-map-select"><option selected>title</option><option>name</option></select></div>
<div class="field-map-row"><span class="field-map-label">分类 <span class="field-required">*</span></span><span class="field-map-arrow"></span><select class="field-map-select"><option selected>category</option><option>type</option></select></div>
<div class="field-map-row"><span class="field-map-label">内容 <span class="field-required">*</span></span><span class="field-map-arrow"></span><select class="field-map-select"><option selected>content</option><option>text</option></select></div>
<div class="field-map-row"><span class="field-map-label">详情</span><span class="field-map-arrow"></span><select class="field-map-select"><option selected>detail</option><option>source</option></select></div>
<div class="field-map-row"><span class="field-map-label">时间</span><span class="field-map-arrow"></span><select class="field-map-select"><option selected>created_at</option><option>time</option></select></div>
<div class="field-map-row"><span class="field-map-label">作者</span><span class="field-map-arrow"></span><select class="field-map-select"><option selected>author</option><option>from_who</option></select></div>
</div>
</div>
<!-- 频道配置 -->
<div class="card animate-in">
<div class="card-title"><span class="icon">📺</span>频道配置</div>
<div class="form-group">
<label class="form-label">频道名称</label>
<input type="text" class="form-input" placeholder="如:古诗词精选集" value="古诗词精选集">
</div>
<div class="form-group">
<label class="form-label">频道图标</label>
<div style="display:flex;gap:var(--space-2);flex-wrap:wrap">
<button class="btn btn-sm btn-secondary" style="font-size:18px">💬</button>
<button class="btn btn-sm btn-secondary" style="font-size:18px;background:var(--tag-bg);border-color:var(--primary)">📜</button>
<button class="btn btn-sm btn-secondary" style="font-size:18px">🎯</button>
<button class="btn btn-sm btn-secondary" style="font-size:18px">📚</button>
<button class="btn btn-sm btn-secondary" style="font-size:18px">🎵</button>
<button class="btn btn-sm btn-secondary" style="font-size:18px">💡</button>
</div>
</div>
<div class="switch-row"><div><div class="switch-label">在主页显示</div><div class="switch-desc">开启后此频道出现在主页频道栏</div></div><div class="toggle active" onclick="toggleSwitch(this)"></div></div>
</div>
<div class="bottom-bar">
<button class="btn btn-secondary" onclick="showToast('预览')">👁️ 预览</button>
<button class="btn btn-primary" onclick="showToast('已创建频道并导入156条')">📺 创建频道</button>
</div>
</div>
<!-- ========== 频道管理(模拟句子来源页面) ========== -->
<div class="content tab-content" id="tab-channels">
<!-- 数据总览 -->
<div class="card animate-in" style="padding:var(--space-4)">
<div style="display:flex;align-items:center;margin-bottom:var(--space-3)">
<span style="font-size:18px;margin-right:var(--space-2)">📊</span>
<span style="font-size:15px;font-weight:700">数据总览</span>
<span style="flex:1"></span>
<span style="font-size:12px;color:var(--text-dim);cursor:pointer">🌐 s2ss.com</span>
</div>
<div style="display:flex;text-align:center">
<div style="flex:1"><div style="font-size:22px;font-weight:800;color:var(--accent)">307.5k</div><div style="font-size:11px;color:var(--text-dim);margin-top:2px">总内容</div></div>
<div style="width:1px;background:var(--divider)"></div>
<div style="flex:1"><div style="font-size:22px;font-weight:800;color:var(--accent)">10</div><div style="font-size:11px;color:var(--text-dim);margin-top:2px">开启频道</div></div>
<div style="width:1px;background:var(--divider)"></div>
<div style="flex:1"><div style="font-size:22px;font-weight:800;color:var(--accent)">12.8k</div><div style="font-size:11px;color:var(--text-dim);margin-top:2px">总浏览</div></div>
</div>
</div>
<!-- 搜索栏 -->
<div class="search-bar animate-in">
<div class="search-input-wrap">
<span class="search-icon">🔍</span>
<input type="text" class="search-input" placeholder="搜索频道...">
</div>
</div>
<!-- 频道管理标题 -->
<div style="display:flex;align-items:center;padding:0 var(--space-4);margin-bottom:var(--space-3)">
<span style="font-size:16px;margin-right:var(--space-1)">🔲</span>
<span style="font-size:15px;font-weight:700">频道管理</span>
<span class="tag tag-primary" style="margin-left:var(--space-2)">10 已启用</span>
<span style="flex:1"></span>
<span style="font-size:14px;color:var(--primary);cursor:pointer;font-weight:600" onclick="showToast('管理操作')">管理</span>
</div>
<!-- 频道列表(系统+自定义混合) -->
<div style="padding:0 var(--space-4);display:flex;flex-direction:column;gap:var(--space-2)">
<!-- 系统频道 - 古诗词 -->
<div class="channel-card-row">
<div class="ch-icon-box" style="background:rgba(245,158,11,0.12)">📜</div>
<div class="ch-info">
<div class="ch-name">古诗词</div>
<div class="ch-count">303,640 条</div>
</div>
<div class="toggle active" onclick="toggleSwitch(this)"></div>
</div>
<!-- 自定义频道 - Hitokoto带🫧标志 -->
<div class="channel-card-row" style="border-color:var(--accent)">
<div class="ch-icon-box" style="background:var(--info-bg)">
<span>💬</span>
<span class="custom-badge">🫧</span>
</div>
<div class="ch-info">
<div class="ch-name">Hitokoto 一言 <span class="source-type-badge url-badge">URL</span></div>
<div class="ch-count">1,280 条 · v1.hitokoto.cn</div>
</div>
<div class="toggle active" onclick="toggleSwitch(this)"></div>
</div>
<!-- 系统频道 - 名言 -->
<div class="channel-card-row">
<div class="ch-icon-box" style="background:rgba(245,158,11,0.12)">💡</div>
<div class="ch-info">
<div class="ch-name">名言</div>
<div class="ch-count">89,200 条</div>
</div>
<div class="toggle active" onclick="toggleSwitch(this)"></div>
</div>
<!-- 系统频道 - 一言 -->
<div class="channel-card-row">
<div class="ch-icon-box" style="background:rgba(245,158,11,0.12)">💬</div>
<div class="ch-info">
<div class="ch-name">一言</div>
<div class="ch-count">45,800 条</div>
</div>
<div class="toggle active" onclick="toggleSwitch(this)"></div>
</div>
<!-- 自定义频道 - 古诗词精选集(文件导入,带🫧标志) -->
<div class="channel-card-row" style="border-color:var(--accent)">
<div class="ch-icon-box" style="background:var(--success-bg)">
<span>📜</span>
<span class="custom-badge">🫧</span>
</div>
<div class="ch-info">
<div class="ch-name">古诗词精选集 <span class="source-type-badge file-badge">文件</span></div>
<div class="ch-count">512 条 · poetry.json</div>
</div>
<div class="toggle active" onclick="toggleSwitch(this)"></div>
</div>
<!-- 系统频道 - 歌词 -->
<div class="channel-card-row">
<div class="ch-icon-box" style="background:rgba(245,158,11,0.12)">🎵</div>
<div class="ch-info">
<div class="ch-name">歌词</div>
<div class="ch-count">67,300 条</div>
</div>
<div class="toggle active" onclick="toggleSwitch(this)"></div>
</div>
<!-- 自定义频道 - 名言精选(合并频道,带🫧标志) -->
<div class="channel-card-row" style="border-color:var(--accent)">
<div class="ch-icon-box" style="background:var(--custom-badge-bg)">
<span>🎯</span>
<span class="custom-badge">🫧</span>
</div>
<div class="ch-info">
<div class="ch-name">名言精选 <span class="source-type-badge merge-badge">合并</span></div>
<div class="ch-count">1,055 条 · 3个来源</div>
<div class="merge-sources" style="margin-top:4px">
<span class="merge-source-tag">💡 名言API</span>
<span class="merge-source-tag">📄 wisdom.csv</span>
<span class="merge-source-tag">💬 hitokoto/哲学</span>
</div>
</div>
<div class="toggle active" onclick="toggleSwitch(this)"></div>
</div>
<!-- 系统频道 - 哲学 -->
<div class="channel-card-row">
<div class="ch-icon-box" style="background:rgba(245,158,11,0.12)">🤔</div>
<div class="ch-info">
<div class="ch-name">哲学</div>
<div class="ch-count">23,100 条</div>
</div>
<div class="toggle active" onclick="toggleSwitch(this)"></div>
</div>
<!-- 自定义频道 - 名人名言集(已暂停,带🫧标志) -->
<div class="channel-card-row" style="opacity:0.5">
<div class="ch-icon-box" style="background:var(--success-bg)">
<span>💡</span>
<span class="custom-badge">🫧</span>
</div>
<div class="ch-info">
<div class="ch-name">名人名言集 <span class="source-type-badge file-badge">文件</span></div>
<div class="ch-count">199 条 · wisdom.csv</div>
</div>
<div class="toggle" onclick="toggleSwitch(this)"></div>
</div>
<!-- 系统频道 - 故事 -->
<div class="channel-card-row">
<div class="ch-icon-box" style="background:rgba(245,158,11,0.12)">📖</div>
<div class="ch-info">
<div class="ch-name">故事</div>
<div class="ch-count">15,600 条</div>
</div>
<div class="toggle active" onclick="toggleSwitch(this)"></div>
</div>
</div>
<!-- 显示设置 -->
<div style="padding:var(--space-5) var(--space-4) 0">
<div style="display:flex;align-items:center;margin-bottom:var(--space-3)">
<span style="font-size:16px;margin-right:var(--space-1)">🎚️</span>
<span style="font-size:15px;font-weight:700">显示设置</span>
</div>
<div class="card" style="padding:0">
<div class="setting-row"><div class="setting-icon" style="background:rgba(108,99,255,0.12)">🔽</div><div class="setting-info"><div class="setting-title">排序方式</div><div class="setting-sub">最新优先</div></div><div class="segment-control" style="width:auto"><button class="segment-btn active" style="padding:6px 12px;font-size:12px">最新</button><button class="segment-btn" style="padding:6px 12px;font-size:12px">最热</button></div></div>
<div style="height:1px;background:var(--divider);margin:0 var(--space-4)"></div>
<div class="setting-row"><div class="setting-icon" style="background:rgba(108,99,255,0.12)">🚫</div><div class="setting-info"><div class="setting-title">内容去重</div><div class="setting-sub">自动跳过重复内容</div></div><div class="toggle active" onclick="toggleSwitch(this)"></div></div>
<div style="height:1px;background:var(--divider);margin:0 var(--space-4)"></div>
<div class="setting-row"><div class="setting-icon" style="background:rgba(108,99,255,0.12)">🔀</div><div class="setting-info"><div class="setting-title">混合模式</div><div class="setting-sub">随机混排</div></div><span style="color:var(--text-dim);font-size:14px"></span></div>
<div style="height:1px;background:var(--divider);margin:0 var(--space-4)"></div>
<div class="setting-row"><div class="setting-icon" style="background:rgba(108,99,255,0.12)">📄</div><div class="setting-info"><div class="setting-title">每页数量</div><div class="setting-sub">20 条</div></div><div style="display:flex;align-items:center;gap:var(--space-2)"><button class="btn btn-sm btn-secondary" style="padding:4px 8px;min-width:28px"></button><span style="font-size:14px;font-weight:700;color:var(--accent);min-width:24px;text-align:center">20</span><button class="btn btn-sm btn-secondary" style="padding:4px 8px;min-width:28px">+</button></div></div>
</div>
</div>
<!-- 高级 -->
<div style="padding:var(--space-5) var(--space-4) 0">
<div style="display:flex;align-items:center;margin-bottom:var(--space-3)">
<span style="font-size:16px;margin-right:var(--space-1);color:var(--text-dim)">⚙️</span>
<span style="font-size:15px;font-weight:700;color:var(--text-secondary)">高级</span>
</div>
<div class="card" style="padding:0">
<div class="setting-row" onclick="switchTab('url')" style="cursor:pointer">
<div class="setting-icon" style="background:rgba(108,99,255,0.08)">📥</div>
<div class="setting-info"><div class="setting-title" style="color:var(--text-secondary)">导入来源</div><div class="setting-sub">从URL或文件导入句子创建自定义频道</div></div>
<span style="color:var(--text-dim);font-size:14px"></span>
</div>
<div style="height:1px;background:var(--divider);margin:0 var(--space-4)"></div>
<div class="setting-row" style="cursor:pointer">
<div class="setting-icon" style="background:rgba(108,99,255,0.08)">🧭</div>
<div class="setting-info"><div class="setting-title" style="color:var(--text-secondary)">更多来源</div><div class="setting-sub">发现更多句子来源</div></div>
<span style="color:var(--text-dim);font-size:14px"></span>
</div>
</div>
</div>
<div style="height:120px"></div>
</div>
<!-- ========== 校验 ========== -->
<div class="content tab-content" id="tab-validate">
<!-- 设备性能 -->
<div class="card animate-in">
<div class="card-title"><span class="icon">📱</span>设备性能评估</div>
<div class="form-hint" style="margin-bottom:var(--space-3)">根据设备性能自动调整导入限制</div>
<div class="perf-grid">
<div class="perf-item">
<div class="perf-value good">5 MB</div>
<div class="perf-label">文件大小上限</div>
</div>
<div class="perf-item">
<div class="perf-value good">1000</div>
<div class="perf-label">单次条数上限</div>
</div>
<div class="perf-item">
<div class="perf-value warn">50</div>
<div class="perf-label">频道数上限</div>
</div>
</div>
<div class="form-hint" style="margin-top:var(--space-2)">💡 高端设备可提升至 10MB/2000条/100频道</div>
</div>
<!-- URL校验 -->
<div class="card animate-in">
<div class="card-title"><span class="icon">🔗</span>URL校验规则</div>
<div class="validate-list">
<div class="validate-item pass">✅ URL可达性 — 请求成功HTTP 200</div>
<div class="validate-item pass">✅ 返回JSON格式 — Content-Type: application/json</div>
<div class="validate-item pass">✅ 字段匹配 — 检测到 hitokoto/type_name 等字段</div>
<div class="validate-item pass">✅ 响应时间 — 128ms < 3000ms</div>
<div class="validate-item warn">⚠️ CORS限制 — 浏览器端可能无法直接请求,需代理</div>
<div class="validate-item pass">✅ 频率合理 — 无明显限流</div>
</div>
</div>
<!-- 文件校验 -->
<div class="card animate-in">
<div class="card-title"><span class="icon">📁</span>文件校验规则</div>
<div class="validate-list">
<div class="validate-item pass">✅ 文件大小 — 12.3KB < 5MB</div>
<div class="validate-item pass">✅ 文件格式 — JSON格式有效</div>
<div class="validate-item pass">✅ 数据条数 — 156条 < 1000条</div>
<div class="validate-item pass">✅ 必填字段 — title/content 字段完整</div>
<div class="validate-item warn">⚠️ 编码格式 — 检测到BOM头已自动处理</div>
</div>
</div>
<!-- 内容质量 -->
<div class="card animate-in">
<div class="card-title"><span class="icon">📝</span>内容质量校验</div>
<div class="validate-list">
<div class="validate-item pass">✅ 内容长度 — 2~500字符符合规范</div>
<div class="validate-item pass">✅ 重复率 — 2.3%低于10%阈值</div>
<div class="validate-item pass">✅ 敏感词 — 未检测到敏感内容</div>
<div class="validate-item warn">⚠️ 空字段 — 3条缺少作者信息已跳过</div>
<div class="validate-item pass">✅ 编码格式 — UTF-8编码正确</div>
</div>
</div>
<!-- 频率限制 -->
<div class="card animate-in">
<div class="card-title"><span class="icon">⏱️</span>频率与限制</div>
<div class="validate-list">
<div class="validate-item pass">✅ 请求频率 — 每5分钟合理范围</div>
<div class="validate-item pass">✅ 无需认证 — 公开API</div>
<div class="validate-item pass">✅ 本地缓存 — 减少实际请求次数</div>
<div class="validate-item pass">✅ 设备负载 — 当前3个活跃频道负载正常</div>
</div>
</div>
</div>
</div>
<!-- 分享Sheet -->
<div class="share-sheet hidden" id="shareSheet">
<div class="share-sheet-handle"></div>
<div class="share-sheet-title">📤 分享频道</div>
<div class="share-option" onclick="showToast('分享配置+数据');toggleShareSheet()">
<div class="opt-icon" style="background:var(--tag-bg)">📦</div>
<div class="opt-info">
<div class="opt-title">配置 + 数据</div>
<div class="opt-desc">导出频道配置和全部句子数据,对方导入后直接可用</div>
</div>
</div>
<div class="share-option" onclick="showToast('仅分享配置');toggleShareSheet()">
<div class="opt-icon" style="background:var(--info-bg)">⚙️</div>
<div class="opt-info">
<div class="opt-title">仅配置</div>
<div class="opt-desc">仅导出URL地址、字段映射、显示设置对方需自行获取数据</div>
</div>
</div>
<div class="share-option" onclick="showToast('内容分析报告');toggleShareSheet()">
<div class="opt-icon" style="background:var(--success-bg)">📊</div>
<div class="opt-info">
<div class="opt-title">内容分析报告</div>
<div class="opt-desc">导出频道统计、分类分布、质量评估等分析数据</div>
</div>
</div>
<button class="btn btn-secondary btn-full" onclick="toggleShareSheet()" style="margin-top:var(--space-3)">取消</button>
</div>
<!-- 遮罩 -->
<div id="shareOverlay" style="display:none;position:fixed;inset:0;background:var(--overlay);z-index:199" onclick="toggleShareSheet()"></div>
<!-- Toast -->
<div class="toast" id="toast"></div>
<script>
function setTheme(t){document.documentElement.setAttribute('data-theme',t);document.querySelectorAll('.theme-chip').forEach(c=>c.classList.remove('active'));event.target.classList.add('active')}
function setStyle(s){document.documentElement.setAttribute('data-style',s);document.querySelectorAll('.style-chip').forEach(c=>c.classList.remove('active'));event.target.classList.add('active');const r=document.documentElement;if(s==='compact'){r.style.setProperty('--radius-md','8px');r.style.setProperty('--radius-lg','12px')}else if(s==='rounded'){r.style.setProperty('--radius-md','16px');r.style.setProperty('--radius-lg','24px')}else{r.style.setProperty('--radius-md','12px');r.style.setProperty('--radius-lg','16px')}}
function switchTab(t){document.querySelectorAll('.tab-item').forEach(t=>t.classList.remove('active'));document.querySelectorAll('.tab-content').forEach(c=>c.classList.remove('active'));document.getElementById('tab-'+t).classList.add('active');const m={url:0,file:1,channels:2,validate:3};document.querySelectorAll('.tab-item')[m[t]].classList.add('active')}
function selectFormat(el,f){document.querySelectorAll('.format-card').forEach(c=>c.classList.remove('active'));el.classList.add('active');document.getElementById('fieldMapping').style.display=f==='custom'?'block':'none'}
function selectFileFormat(el,f){document.querySelectorAll('.file-format-btn').forEach(c=>c.classList.remove('active'));el.classList.add('active')}
function toggleSwitch(el){el.classList.toggle('active')}
function selectChannel(el){document.querySelectorAll('.channel-chip').forEach(c=>c.classList.remove('active'));el.classList.add('active')}
function selectIcon(el){el.parentElement.querySelectorAll('button').forEach(b=>{b.style.background='';b.style.borderColor=''});el.style.background='var(--tag-bg)';el.style.borderColor='var(--primary)'}
function analyzeUrl(){showToast('正在分析URL...','info');setTimeout(()=>{document.getElementById('urlAnalysis').style.display='block';showToast('分析完成!','success')},800)}
function toggleShareSheet(){const s=document.getElementById('shareSheet');const o=document.getElementById('shareOverlay');s.classList.toggle('hidden');o.style.display=s.classList.contains('hidden')?'none':'block'}
document.querySelectorAll('.filter-chip').forEach(c=>{c.addEventListener('click',function(){document.querySelectorAll('.filter-chip').forEach(x=>x.classList.remove('active'));this.classList.add('active')})});
function showToast(m,t){const e=document.getElementById('toast');const i={success:'✅',error:'❌',info:'',warning:'⚠️'};e.innerHTML=(i[t]||'📌')+' '+m;e.classList.add('show');setTimeout(()=>e.classList.remove('show'),2500)}
</script>
</body>
</html>