feat: 新增知资札记工具及相关功能
1. 新增知资札记完整站点:包含首页、详情页、管理后台 2. 添加站点图标、鉴权配置与后端API鉴权逻辑 3. 在市场页面新增知资札记入口跳转 4. 新增经典乡村音乐播放列表文件 5. 临时添加养生谚语批量导入脚本
This commit is contained in:
@@ -0,0 +1,594 @@
|
||||
/**
|
||||
* 知资札记 - C端前端逻辑
|
||||
* 证券投资图文存档站
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// ── 常量 ──
|
||||
const API_BASE = '/api/zhizi_notes';
|
||||
const STORAGE_KEY = 'zhizi_notes_theme';
|
||||
const STORAGE_VIEW = 'zhizi_notes_view';
|
||||
const STORAGE_FAVORITES = 'zhizi_notes_favorites';
|
||||
|
||||
// ── 状态 ──
|
||||
let state = {
|
||||
page: 1,
|
||||
pageSize: 12,
|
||||
totalPages: 0,
|
||||
loading: false,
|
||||
done: false,
|
||||
viewMode: localStorage.getItem(STORAGE_VIEW) || 'card',
|
||||
filter: { category: '', tag: '', timeRange: '', contentType: '', search: '' },
|
||||
favorites: new Set()
|
||||
};
|
||||
|
||||
// ── DOM 缓存 ──
|
||||
const $ = (sel) => document.querySelector(sel);
|
||||
const $$ = (sel) => document.querySelectorAll(sel);
|
||||
|
||||
// ── 链接清洗函数 ──
|
||||
window.clearAllLink = function (htmlStr) {
|
||||
if (!htmlStr || typeof htmlStr !== 'string') return '';
|
||||
return htmlStr.replace(/<a\b[^>]*>(.*?)<\/a>/gi, '$1');
|
||||
};
|
||||
|
||||
// ── Toast 提示 ──
|
||||
function showToast(msg, type) {
|
||||
type = type || 'info';
|
||||
const t = $('#zs-toast');
|
||||
if (!t) return;
|
||||
t.textContent = msg;
|
||||
t.className = 'zs-toast ' + type + ' show';
|
||||
const duration = type === 'error' ? 4000 : 2000;
|
||||
clearTimeout(t._timer);
|
||||
t._timer = setTimeout(function () { t.classList.remove('show'); }, duration);
|
||||
}
|
||||
|
||||
// ── 暗黑模式 ──
|
||||
function initTheme() {
|
||||
const saved = localStorage.getItem(STORAGE_KEY);
|
||||
if (saved === 'dark') {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
const btn = $('#zs-theme-btn');
|
||||
if (btn) {
|
||||
btn.textContent = saved === 'dark' ? '☀️' : '🌙';
|
||||
btn.addEventListener('click', toggleTheme);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleTheme() {
|
||||
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
||||
if (isDark) {
|
||||
document.documentElement.removeAttribute('data-theme');
|
||||
localStorage.setItem(STORAGE_KEY, 'light');
|
||||
$('#zs-theme-btn').textContent = '🌙';
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
localStorage.setItem(STORAGE_KEY, 'dark');
|
||||
$('#zs-theme-btn').textContent = '☀️';
|
||||
}
|
||||
}
|
||||
|
||||
// ── API 请求 ──
|
||||
async function apiGet(path) {
|
||||
try {
|
||||
const res = await fetch(API_BASE + path, { credentials: 'same-origin' });
|
||||
return await res.json();
|
||||
} catch (e) {
|
||||
return { ok: false, error: e.message };
|
||||
}
|
||||
}
|
||||
|
||||
async function apiPost(path, body) {
|
||||
try {
|
||||
const res = await fetch(API_BASE + path, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
return await res.json();
|
||||
} catch (e) {
|
||||
return { ok: false, error: e.message };
|
||||
}
|
||||
}
|
||||
|
||||
// ── 加载文章列表 ──
|
||||
async function loadArticles(reset) {
|
||||
if (reset) {
|
||||
state.page = 1; state.done = false;
|
||||
const grid = $('#zs-card-grid');
|
||||
if (grid) grid.innerHTML = '';
|
||||
}
|
||||
if (state.loading || state.done) return;
|
||||
state.loading = true;
|
||||
showLoading(true);
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.set('page', state.page);
|
||||
params.set('pageSize', state.pageSize);
|
||||
if (state.filter.category) params.set('category', state.filter.category);
|
||||
if (state.filter.tag) params.set('tag', state.filter.tag);
|
||||
if (state.filter.timeRange) params.set('timeRange', state.filter.timeRange);
|
||||
if (state.filter.contentType) params.set('contentType', state.filter.contentType);
|
||||
if (state.filter.search) params.set('search', state.filter.search);
|
||||
|
||||
const data = await apiGet('/articles?' + params.toString());
|
||||
showLoading(false);
|
||||
state.loading = false;
|
||||
|
||||
if (!data.ok) {
|
||||
showToast('加载失败:' + (data.error || '未知错误'), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const articles = data.data || [];
|
||||
const pag = data.pagination || {};
|
||||
state.totalPages = pag.totalPages || 0;
|
||||
if (state.page >= state.totalPages) state.done = true;
|
||||
if (articles.length === 0 && state.page === 1) {
|
||||
showEmpty(true);
|
||||
} else {
|
||||
showEmpty(false);
|
||||
renderCards(articles);
|
||||
state.page++;
|
||||
}
|
||||
}
|
||||
|
||||
function showLoading(show) {
|
||||
const el = $('#zs-loading');
|
||||
if (el) el.style.display = show ? 'block' : 'none';
|
||||
}
|
||||
|
||||
function showEmpty(show) {
|
||||
const el = $('#zs-empty');
|
||||
if (el) el.style.display = show ? 'block' : 'none';
|
||||
}
|
||||
|
||||
// ── 渲染卡片 ──
|
||||
function renderCards(articles) {
|
||||
const grid = $('#zs-card-grid');
|
||||
if (!grid) return;
|
||||
articles.forEach(function (article) {
|
||||
const card = createCard(article);
|
||||
grid.appendChild(card);
|
||||
});
|
||||
lazyLoadImages();
|
||||
}
|
||||
|
||||
function createCard(article) {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'zs-card';
|
||||
card.setAttribute('data-id', article.id);
|
||||
card.addEventListener('click', function (e) {
|
||||
if (e.target.closest('.fav-btn')) return;
|
||||
openDetail(article.id);
|
||||
});
|
||||
|
||||
// 封面区
|
||||
const cover = document.createElement('div');
|
||||
cover.className = 'card-cover';
|
||||
if (article.cover_url) {
|
||||
const img = document.createElement('img');
|
||||
img.setAttribute('data-src', article.cover_url);
|
||||
img.setAttribute('alt', article.title);
|
||||
img.className = 'lazy-img';
|
||||
cover.appendChild(img);
|
||||
} else {
|
||||
const badge = document.createElement('div');
|
||||
badge.className = 'text-badge';
|
||||
badge.textContent = '文';
|
||||
cover.appendChild(badge);
|
||||
}
|
||||
|
||||
// 角标
|
||||
const imgCount = article.image_count || 0;
|
||||
const badge = document.createElement('span');
|
||||
badge.className = 'card-badge';
|
||||
badge.textContent = article.content_type === 'image' ? '含' + imgCount + '张附图' : '纯文字';
|
||||
cover.appendChild(badge);
|
||||
|
||||
// 正文区
|
||||
const body = document.createElement('div');
|
||||
body.className = 'card-body';
|
||||
|
||||
const title = document.createElement('div');
|
||||
title.className = 'card-title';
|
||||
title.textContent = article.title;
|
||||
|
||||
const source = document.createElement('div');
|
||||
source.className = 'card-source';
|
||||
source.textContent = article.source || '';
|
||||
|
||||
// 标签
|
||||
const tagsRow = document.createElement('div');
|
||||
tagsRow.className = 'card-tags';
|
||||
try {
|
||||
const tags = JSON.parse(article.tags_json || '[]');
|
||||
tags.forEach(function (t) {
|
||||
const span = document.createElement('span');
|
||||
span.className = 'card-tag';
|
||||
span.textContent = t;
|
||||
tagsRow.appendChild(span);
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
// 底部
|
||||
const footer = document.createElement('div');
|
||||
footer.className = 'card-footer';
|
||||
|
||||
const meta = document.createElement('span');
|
||||
meta.textContent = (article.created_at || '').slice(0, 10) + ' · ' + (article.views || 0) + ' 阅读';
|
||||
|
||||
const favBtn = document.createElement('button');
|
||||
favBtn.className = 'fav-btn';
|
||||
favBtn.setAttribute('data-id', article.id);
|
||||
favBtn.title = '收藏';
|
||||
if (state.favorites.has(article.id)) {
|
||||
favBtn.classList.add('favorited');
|
||||
favBtn.textContent = '♥';
|
||||
} else {
|
||||
favBtn.textContent = '♡';
|
||||
}
|
||||
favBtn.addEventListener('click', function (e) { e.stopPropagation(); toggleFavorite(article.id, favBtn); });
|
||||
|
||||
footer.appendChild(meta);
|
||||
footer.appendChild(favBtn);
|
||||
|
||||
body.appendChild(title);
|
||||
body.appendChild(source);
|
||||
body.appendChild(tagsRow);
|
||||
body.appendChild(footer);
|
||||
|
||||
card.appendChild(cover);
|
||||
card.appendChild(body);
|
||||
return card;
|
||||
}
|
||||
|
||||
// ── 图片懒加载 ──
|
||||
function lazyLoadImages() {
|
||||
const imgs = document.querySelectorAll('img.lazy-img[data-src]');
|
||||
if (!('IntersectionObserver' in window)) {
|
||||
imgs.forEach(function (img) { img.src = img.getAttribute('data-src'); img.removeAttribute('data-src'); });
|
||||
return;
|
||||
}
|
||||
const observer = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
if (entry.isIntersecting) {
|
||||
const img = entry.target;
|
||||
img.src = img.getAttribute('data-src');
|
||||
img.removeAttribute('data-src');
|
||||
img.classList.remove('lazy-img');
|
||||
observer.unobserve(img);
|
||||
}
|
||||
});
|
||||
}, { rootMargin: '100px' });
|
||||
imgs.forEach(function (img) { observer.observe(img); });
|
||||
}
|
||||
|
||||
// ── 滚动触底加载 ──
|
||||
let scrollTimer = null;
|
||||
function onScroll() {
|
||||
if (scrollTimer) return;
|
||||
scrollTimer = setTimeout(function () {
|
||||
scrollTimer = null;
|
||||
if (state.loading || state.done) return;
|
||||
const scrollY = window.scrollY + window.innerHeight;
|
||||
const docH = document.documentElement.scrollHeight;
|
||||
if (scrollY >= docH - 300) loadArticles(false);
|
||||
}, 200);
|
||||
}
|
||||
|
||||
// ── 收藏切换 ──
|
||||
async function toggleFavorite(articleId, btn) {
|
||||
if (btn._pending) return;
|
||||
btn._pending = true;
|
||||
btn.style.opacity = '0.5';
|
||||
try {
|
||||
const data = await apiPost('/articles/' + articleId + '/toggle_favorite', {});
|
||||
if (data.ok) {
|
||||
if (data.data && data.data.favorited) {
|
||||
state.favorites.add(articleId);
|
||||
btn.classList.add('favorited');
|
||||
btn.textContent = '♥';
|
||||
showToast('已收藏', 'success');
|
||||
} else {
|
||||
state.favorites.delete(articleId);
|
||||
btn.classList.remove('favorited');
|
||||
btn.textContent = '♡';
|
||||
showToast('已取消收藏', 'info');
|
||||
}
|
||||
} else {
|
||||
showToast('操作失败:' + (data.error || '未知错误'), 'error');
|
||||
}
|
||||
} catch (e) {
|
||||
showToast('网络错误', 'error');
|
||||
}
|
||||
btn._pending = false;
|
||||
btn.style.opacity = '1';
|
||||
}
|
||||
|
||||
// ── 打开详情页 ──
|
||||
function openDetail(id) {
|
||||
window.open('/tools/zhizi_notes/detail.html?id=' + id, '_blank');
|
||||
}
|
||||
|
||||
// ── 筛选逻辑 ──
|
||||
function setFilter(key, value) {
|
||||
if (key === 'category') {
|
||||
if (state.filter.category === value) value = '';
|
||||
} else if (key === 'tag') {
|
||||
if (state.filter.tag === value) value = '';
|
||||
} else if (key === 'timeRange') {
|
||||
if (state.filter.timeRange === value) value = '';
|
||||
} else if (key === 'contentType') {
|
||||
if (state.filter.contentType === value) value = '';
|
||||
}
|
||||
state.filter[key] = value;
|
||||
updateFilterUI();
|
||||
loadArticles(true);
|
||||
}
|
||||
|
||||
function setSearch(value) {
|
||||
state.filter.search = value;
|
||||
loadArticles(true);
|
||||
}
|
||||
|
||||
function updateFilterUI() {
|
||||
// 分类
|
||||
$$('.zs-sidebar .cat-item').forEach(function (el) {
|
||||
var cat = el.getAttribute('data-cat');
|
||||
el.classList.toggle('active', cat === state.filter.category);
|
||||
});
|
||||
// 标签
|
||||
$$('.zs-sidebar .tag-item').forEach(function (el) {
|
||||
var tag = el.getAttribute('data-tag');
|
||||
el.classList.toggle('active', tag === state.filter.tag);
|
||||
});
|
||||
// 时间
|
||||
$$('.zs-sidebar .time-item').forEach(function (el) {
|
||||
var tr = el.getAttribute('data-time');
|
||||
el.classList.toggle('active', tr === state.filter.timeRange);
|
||||
});
|
||||
// 图文类型
|
||||
$$('.zs-sidebar .type-btn').forEach(function (el) {
|
||||
var ct = el.getAttribute('data-type');
|
||||
el.classList.toggle('active', ct === state.filter.contentType);
|
||||
});
|
||||
// 筛选标签显示
|
||||
renderFilterTags();
|
||||
}
|
||||
|
||||
function renderFilterTags() {
|
||||
var container = $('#zs-filter-tags');
|
||||
if (!container) return;
|
||||
container.innerHTML = '';
|
||||
var items = [];
|
||||
if (state.filter.category) items.push({ label: state.filter.category, key: 'category' });
|
||||
if (state.filter.tag) items.push({ label: state.filter.tag, key: 'tag' });
|
||||
if (state.filter.timeRange) {
|
||||
var labels = { week: '本周', month: '本月', quarter: '本季度' };
|
||||
items.push({ label: labels[state.filter.timeRange] || state.filter.timeRange, key: 'timeRange' });
|
||||
}
|
||||
if (state.filter.contentType) {
|
||||
items.push({ label: state.filter.contentType === 'text' ? '纯文字' : '图文多图', key: 'contentType' });
|
||||
}
|
||||
items.forEach(function (item) {
|
||||
var span = document.createElement('span');
|
||||
span.className = 'filter-tag';
|
||||
span.textContent = item.label;
|
||||
var rm = document.createElement('button');
|
||||
rm.className = 'remove-filter';
|
||||
rm.textContent = '×';
|
||||
rm.addEventListener('click', function () { setFilter(item.key, ''); });
|
||||
span.appendChild(rm);
|
||||
container.appendChild(span);
|
||||
});
|
||||
}
|
||||
|
||||
// ── 视图切换 ──
|
||||
function setViewMode(mode) {
|
||||
state.viewMode = mode;
|
||||
localStorage.setItem(STORAGE_VIEW, mode);
|
||||
var grid = $('#zs-card-grid');
|
||||
if (grid) grid.className = mode === 'list' ? 'card-grid list-view' : 'card-grid';
|
||||
$$('.zs-main .view-toggle button').forEach(function (btn) {
|
||||
btn.classList.toggle('active', btn.getAttribute('data-view') === mode);
|
||||
});
|
||||
}
|
||||
|
||||
// ── 加载右侧栏 ──
|
||||
async function loadRightbar() {
|
||||
// 置顶
|
||||
try {
|
||||
var pinned = await apiGet('/articles/pinned');
|
||||
var pinnedContainer = $('#zs-pinned');
|
||||
if (pinnedContainer && pinned.ok && pinned.data) {
|
||||
pinnedContainer.innerHTML = '';
|
||||
pinned.data.forEach(function (a) {
|
||||
var div = document.createElement('div');
|
||||
div.className = 'pinned-item';
|
||||
div.innerHTML = '<div class="pinned-title">' + escapeHtml(a.title) + '</div><div class="pinned-date">' + (a.created_at || '').slice(0, 10) + '</div>';
|
||||
div.addEventListener('click', function () { openDetail(a.id); });
|
||||
pinnedContainer.appendChild(div);
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
// 最新
|
||||
try {
|
||||
var latest = await apiGet('/articles/latest');
|
||||
var latestContainer = $('#zs-latest');
|
||||
if (latestContainer && latest.ok && latest.data) {
|
||||
latestContainer.innerHTML = '';
|
||||
latest.data.forEach(function (a) {
|
||||
var div = document.createElement('div');
|
||||
div.className = 'latest-item';
|
||||
div.textContent = a.title;
|
||||
div.addEventListener('click', function () { openDetail(a.id); });
|
||||
latestContainer.appendChild(div);
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
// 统计数据
|
||||
try {
|
||||
var stats = await apiGet('/stats');
|
||||
if (stats.ok && stats.data) {
|
||||
var totalArticles = $('#zs-stat-articles');
|
||||
var totalImages = $('#zs-stat-images');
|
||||
if (totalArticles) totalArticles.textContent = stats.data.totalArticles || 0;
|
||||
if (totalImages) totalImages.textContent = stats.data.totalImages || 0;
|
||||
// 分类占比
|
||||
var chartContainer = $('#zs-chart');
|
||||
if (chartContainer && stats.data.catStats) {
|
||||
var maxCount = Math.max.apply(null, stats.data.catStats.map(function (c) { return c.c; }));
|
||||
chartContainer.innerHTML = '';
|
||||
stats.data.catStats.forEach(function (c) {
|
||||
var pct = maxCount > 0 ? Math.round((c.c / maxCount) * 100) : 0;
|
||||
var row = document.createElement('div');
|
||||
row.className = 'chart-bar';
|
||||
row.innerHTML = '<span class="bar-label">' + escapeHtml(c.category) + '</span>' +
|
||||
'<span class="bar-track"><span class="bar-fill" style="width:' + pct + '%"></span></span>' +
|
||||
'<span class="bar-count">' + c.c + '</span>';
|
||||
chartContainer.appendChild(row);
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function escapeHtml(str) {
|
||||
if (!str) return '';
|
||||
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
}
|
||||
|
||||
// ── 加载分类/标签 ──
|
||||
async function loadSidebarFilters() {
|
||||
// 分类
|
||||
try {
|
||||
var cats = await apiGet('/categories');
|
||||
var catContainer = $('#zs-categories');
|
||||
if (catContainer && cats.ok && cats.data) {
|
||||
catContainer.innerHTML = '';
|
||||
cats.data.forEach(function (c) {
|
||||
var btn = document.createElement('button');
|
||||
btn.className = 'cat-item';
|
||||
btn.setAttribute('data-cat', c.name);
|
||||
btn.textContent = c.name;
|
||||
btn.addEventListener('click', function () { setFilter('category', c.name); });
|
||||
catContainer.appendChild(btn);
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
// 标签
|
||||
try {
|
||||
var tags = await apiGet('/tags');
|
||||
var tagContainer = $('#zs-tags');
|
||||
if (tagContainer && tags.ok && tags.data) {
|
||||
tagContainer.innerHTML = '';
|
||||
tags.data.forEach(function (t) {
|
||||
var btn = document.createElement('button');
|
||||
btn.className = 'tag-item';
|
||||
btn.setAttribute('data-tag', t.name);
|
||||
btn.textContent = t.name + '(' + (t.article_count || 0) + ')';
|
||||
btn.addEventListener('click', function () { setFilter('tag', t.name); });
|
||||
tagContainer.appendChild(btn);
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// ── 加载收藏状态 ──
|
||||
async function loadFavorites() {
|
||||
try {
|
||||
var data = await apiGet('/favorites');
|
||||
if (data.ok && data.data) {
|
||||
state.favorites = new Set();
|
||||
data.data.forEach(function (a) { state.favorites.add(a.id); });
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// ── 初始化 ──
|
||||
function init() {
|
||||
initTheme();
|
||||
|
||||
// 视图切换
|
||||
setViewMode(state.viewMode);
|
||||
$$('.zs-main .view-toggle button').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () { setViewMode(btn.getAttribute('data-view')); });
|
||||
});
|
||||
|
||||
// 分类筛选
|
||||
$$('.zs-sidebar .cat-item').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () { setFilter('category', btn.getAttribute('data-cat')); });
|
||||
});
|
||||
|
||||
// 标签筛选
|
||||
// (动态生成的,在 loadSidebarFilters 中绑定)
|
||||
|
||||
// 时间筛选
|
||||
$$('.zs-sidebar .time-item').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () { setFilter('timeRange', btn.getAttribute('data-time')); });
|
||||
});
|
||||
|
||||
// 图文类型筛选
|
||||
$$('.zs-sidebar .type-btn').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () { setFilter('contentType', btn.getAttribute('data-type')); });
|
||||
});
|
||||
|
||||
// 搜索
|
||||
var searchInput = $('#zs-search');
|
||||
var searchBtn = $('#zs-search-btn');
|
||||
if (searchBtn && searchInput) {
|
||||
searchBtn.addEventListener('click', function () { setSearch(searchInput.value.trim()); });
|
||||
searchInput.addEventListener('keydown', function (e) { if (e.key === 'Enter') setSearch(searchInput.value.trim()); });
|
||||
}
|
||||
|
||||
// 滚动加载
|
||||
window.addEventListener('scroll', onScroll, { passive: true });
|
||||
|
||||
// 汉堡菜单
|
||||
var hamburger = $('#zs-hamburger');
|
||||
var sidebar = $('#zs-sidebar');
|
||||
var overlay = $('#zs-sidebar-overlay');
|
||||
if (hamburger && sidebar) {
|
||||
hamburger.addEventListener('click', function () {
|
||||
var open = sidebar.classList.contains('open');
|
||||
if (open) {
|
||||
sidebar.classList.remove('open');
|
||||
if (overlay) overlay.classList.remove('show');
|
||||
} else {
|
||||
sidebar.classList.add('open');
|
||||
if (overlay) overlay.classList.add('show');
|
||||
}
|
||||
});
|
||||
if (overlay) {
|
||||
overlay.addEventListener('click', function () {
|
||||
sidebar.classList.remove('open');
|
||||
overlay.classList.remove('show');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 提交存档按钮
|
||||
var submitBtn = $('#zs-submit-btn');
|
||||
if (submitBtn) {
|
||||
submitBtn.addEventListener('click', function () {
|
||||
window.open('/tools/zhizi_notes/admin.html', '_blank');
|
||||
});
|
||||
}
|
||||
|
||||
// 初始加载
|
||||
loadSidebarFilters();
|
||||
loadFavorites().then(function () { loadArticles(true); });
|
||||
loadRightbar();
|
||||
}
|
||||
|
||||
// ── 启动 ──
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
})();
|
||||
Reference in New Issue
Block a user