feat(admin): 添加域名白名单功能并支持Artalk导入

- 在评论设置中添加域名白名单配置,限制组件调用
- 支持从Artalk系统导入评论数据
- 完善Twikoo和Artalk数据结构的映射处理
- 在组件端实现域名白名单检查逻辑
This commit is contained in:
anghunk
2026-01-20 14:58:27 +08:00
parent 976a38c5f3
commit 05b9425245
6 changed files with 119 additions and 15 deletions

View File

@@ -39,6 +39,7 @@ export type CommentSettingsResponse = {
adminBadge: string | null;
avatarPrefix: string | null;
adminEnabled: boolean;
allowedDomains?: string[];
};
export type EmailNotifySettingsResponse = {
@@ -122,6 +123,7 @@ export function saveCommentSettings(data: {
adminBadge?: string;
avatarPrefix?: string;
adminEnabled?: boolean;
allowedDomains?: string[];
}): Promise<{ message: string }> {
return put<{ message: string }>('/admin/settings/comments', data);
}

View File

@@ -27,7 +27,8 @@
<div class="form-group">
<label class="form-label">来源系统</label>
<select v-model="importSource" class="form-select">
<option value="twikoo">Twikoo</option>
<option value="twikoo">Twikoo (.json)</option>
<option value="artalk">Artalk (.json)</option>
</select>
</div>
@@ -188,8 +189,8 @@ async function handleFileChange(event: Event) {
// 检测前缀逻辑
let missingCount = 0;
for (const item of comments) {
// 优先检查 Twikoo 字段 href其次检查 CWD 字段 post_slug
const url = item.href || item.post_slug;
// 优先检查 Twikoo 字段 href其次 Artalk 字段 page_key最后 CWD 字段 post_slug
const url = item.href || item.page_key || item.post_slug;
if (url && typeof url === "string") {
if (!url.startsWith("http://") && !url.startsWith("https://")) {
missingCount++;
@@ -250,6 +251,16 @@ async function confirmPrefix() {
}
}
// Artalk
if (newItem.page_key && typeof newItem.page_key === "string") {
if (
!newItem.page_key.startsWith("http://") &&
!newItem.page_key.startsWith("https://")
) {
newItem.page_key = joinUrl(prefix, newItem.page_key);
}
}
// CWD
if (newItem.post_slug && typeof newItem.post_slug === "string") {
if (

View File

@@ -31,6 +31,15 @@
<label class="form-label">头像前缀默认https://gravatar.com/avatar</label>
<input v-model="avatarPrefix" class="form-input" type="text" />
</div>
<div class="form-item">
<label class="form-label">允许调用的域名多个域名用逗号分隔留空则不限制</label>
<textarea
v-model="allowedDomains"
class="form-input"
rows="3"
placeholder="例如: example.com, test.com"
></textarea>
</div>
<div class="card-actions">
<button class="card-button" :disabled="savingComment" @click="saveComment">
<span v-if="savingComment">保存中...</span>
@@ -134,6 +143,7 @@ const commentAdminEmail = ref("");
const commentAdminBadge = ref("");
const avatarPrefix = ref("");
const commentAdminEnabled = ref(false);
const allowedDomains = ref("");
const savingEmail = ref(false);
const testingEmail = ref(false);
const savingComment = ref(false);
@@ -181,6 +191,7 @@ async function load() {
commentAdminBadge.value = commentRes.adminBadge || "博主";
avatarPrefix.value = commentRes.avatarPrefix || "";
commentAdminEnabled.value = !!commentRes.adminEnabled;
allowedDomains.value = commentRes.allowedDomains ? commentRes.allowedDomains.join(", ") : "";
emailGlobalEnabled.value = !!emailNotifyRes.globalEnabled;
if (emailNotifyRes.smtp) {
@@ -287,6 +298,7 @@ async function saveComment() {
adminBadge: commentAdminBadge.value,
avatarPrefix: avatarPrefix.value,
adminEnabled: commentAdminEnabled.value,
allowedDomains: allowedDomains.value.split(/[,\n]/).map(d => d.trim()).filter(Boolean)
});
showToast(res.message || "保存成功", "success");
} catch (e: any) {