主要变更: 1. 移除摇一摇相关功能代码与依赖 2. 新增自定义频道导入与管理功能 3. 优化iOS/macOS平台配置与适配 4. 重构路由转场逻辑为原生Cupertino风格 5. 修复设备发现与文件传输相关bug 6. 调整深色模式默认值为纯黑AMOLED 7. 新增运行模式标签与Spotlight搜索优化 8. 清理废弃的本地化字符串与设置项
916 lines
58 KiB
HTML
916 lines
58 KiB
HTML
<!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>
|