feat(评论): 新增功能开关管理及评论点赞功能优化

- 在管理后台添加功能开关页面,支持控制评论点赞和文章点赞功能的开启/关闭
- 优化评论点赞功能,支持取消点赞和本地存储点赞状态
- 更新点赞UI样式,提升用户体验
- 添加相关API接口和文档说明
This commit is contained in:
anghunk
2026-01-22 22:26:43 +08:00
parent 74c7fa9e1c
commit e0be92b1fe
15 changed files with 806 additions and 120 deletions

View File

@@ -0,0 +1,38 @@
import { Context } from 'hono';
import { Bindings } from '../../bindings';
import {
loadFeatureSettings,
saveFeatureSettings
} from '../../utils/featureSettings';
export const getFeatureSettings = async (c: Context<{ Bindings: Bindings }>) => {
try {
const settings = await loadFeatureSettings(c.env);
return c.json(settings);
} catch (e: any) {
return c.json({ message: e.message || 'Failed to load feature settings' }, 500);
}
};
export const updateFeatureSettings = async (c: Context<{ Bindings: Bindings }>) => {
try {
const body = await c.req.json();
const enableCommentLike =
typeof body.enableCommentLike === 'boolean'
? body.enableCommentLike
: undefined;
const enableArticleLike =
typeof body.enableArticleLike === 'boolean'
? body.enableArticleLike
: undefined;
await saveFeatureSettings(c.env, {
enableCommentLike,
enableArticleLike
});
return c.json({ message: 'Saved successfully' });
} catch (e: any) {
return c.json({ message: e.message || 'Failed to save feature settings' }, 500);
}
};

View File

@@ -7,6 +7,7 @@ import {
loadEmailNotificationSettings,
saveEmailNotificationSettings
} from './utils/email';
import { loadFeatureSettings } from './utils/featureSettings';
import packageJson from '../package.json';
import { getComments } from './api/public/getComments';
@@ -30,6 +31,10 @@ import { getLikeStatus, likePage } from './api/public/like';
import { likeComment } from './api/public/likeComment';
import { listLikes } from './api/admin/listLikes';
import { getLikeStats } from './api/admin/likeStats';
import {
getFeatureSettings,
updateFeatureSettings
} from './api/admin/featureSettings';
const app = new Hono<{ Bindings: Bindings }>();
const VERSION = `v${packageJson.version}`;
@@ -228,6 +233,7 @@ app.post('/api/comments/like', likeComment);
app.get('/api/config/comments', async (c) => {
try {
const settings = await loadCommentSettings(c.env);
const featureSettings = await loadFeatureSettings(c.env);
const {
adminKey,
adminKeySet,
@@ -236,7 +242,7 @@ app.get('/api/config/comments', async (c) => {
...publicSettings
} = settings as any;
return c.json(publicSettings);
return c.json({ ...publicSettings, ...featureSettings });
} catch (e: any) {
return c.json({ message: e.message || '加载评论配置失败' }, 500);
}
@@ -256,6 +262,8 @@ app.get('/admin/analytics/overview', getVisitOverview);
app.get('/admin/analytics/pages', getVisitPages);
app.get('/admin/likes/list', listLikes);
app.get('/admin/likes/stats', getLikeStats);
app.get('/admin/settings/features', getFeatureSettings);
app.put('/admin/settings/features', updateFeatureSettings);
app.get('/admin/settings/email', getAdminEmail);
app.put('/admin/settings/email', setAdminEmail);
app.get('/admin/settings/email-notify', async (c) => {

View File

@@ -0,0 +1,92 @@
import { Bindings } from '../bindings';
export const FEATURE_COMMENT_LIKE_KEY = 'comment_feature_comment_like';
export const FEATURE_ARTICLE_LIKE_KEY = 'comment_feature_article_like';
export type FeatureSettings = {
enableCommentLike: boolean;
enableArticleLike: boolean;
};
export async function loadFeatureSettings(env: Bindings): Promise<FeatureSettings> {
await env.CWD_DB.prepare(
'CREATE TABLE IF NOT EXISTS Settings (key TEXT PRIMARY KEY, value TEXT NOT NULL)'
).run();
const keys = [FEATURE_COMMENT_LIKE_KEY, FEATURE_ARTICLE_LIKE_KEY];
const { results } = await env.CWD_DB.prepare(
'SELECT key, value FROM Settings WHERE key IN (?, ?)'
)
.bind(...keys)
.all<{ key: string; value: string }>();
const map = new Map<string, string>();
for (const row of results) {
if (row && row.key) {
map.set(row.key, row.value);
}
}
// Default to true if not set, or false?
// Usually features might be enabled by default.
// But let's check the user requirement. "New settings... whether to enable..."
// If I default to false, existing users might lose features if they were implicit.
// But these are "new" settings.
// "comment likes" and "article likes" existed before?
// The code shows `like.ts` and `likeComment.ts`.
// `likePage` handler in `index.ts`.
// So the features exist. To avoid breaking changes, I should probably default to TRUE.
// But wait, if I default to true, then the user has to manually turn them off.
// If I default to false, they disappear.
// Given "whether to enable" implies they might be optional now.
// I'll default to TRUE to maintain backward compatibility (features visible by default).
const enableCommentLikeRaw = map.get(FEATURE_COMMENT_LIKE_KEY);
const enableCommentLike = enableCommentLikeRaw !== '0'; // Default to true if missing or '1'
const enableArticleLikeRaw = map.get(FEATURE_ARTICLE_LIKE_KEY);
const enableArticleLike = enableArticleLikeRaw !== '0'; // Default to true if missing or '1'
return {
enableCommentLike,
enableArticleLike
};
}
export async function saveFeatureSettings(
env: Bindings,
settings: Partial<FeatureSettings>
) {
await env.CWD_DB.prepare(
'CREATE TABLE IF NOT EXISTS Settings (key TEXT PRIMARY KEY, value TEXT NOT NULL)'
).run();
const entries: { key: string; value: string | undefined }[] = [
{
key: FEATURE_COMMENT_LIKE_KEY,
value:
typeof settings.enableCommentLike === 'boolean'
? settings.enableCommentLike
? '1'
: '0'
: undefined
},
{
key: FEATURE_ARTICLE_LIKE_KEY,
value:
typeof settings.enableArticleLike === 'boolean'
? settings.enableArticleLike
? '1'
: '0'
: undefined
}
];
for (const entry of entries) {
if (entry.value !== undefined) {
await env.CWD_DB.prepare('REPLACE INTO Settings (key, value) VALUES (?, ?)')
.bind(entry.key, entry.value)
.run();
}
}
}