feat: 增强插件可靠性与可用性
- 修复 PromptBuilder ClassLoader 冲突,改为 ConfigMap 直读 - 实现失败重试机制,指数退避策略 - 评论者黑名单支持邮箱匹配,可从评论列表选择 - 日志页面支持按状态/情感筛选和关键词搜索 - AI角色邮箱配置增加 Gravatar 头像实时预览 - 插件依赖声明修正:ai-foundation 改为必须依赖 - 新增定时清理旧记录功能,可配置保留天数 - 更新 README 和 VitePress 文档
This commit is contained in:
@@ -38,6 +38,41 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Filter Bar -->
|
||||
<div class="mx-4 mt-2 flex items-center gap-3">
|
||||
<select
|
||||
v-model="filterStatus"
|
||||
class="rounded-md border border-gray-300 px-3 py-1.5 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
|
||||
>
|
||||
<option value="">全部状态</option>
|
||||
<option value="PASS">通过</option>
|
||||
<option value="FAIL">失败</option>
|
||||
<option value="PENDING">待审核</option>
|
||||
<option value="REJECTED">已拒绝</option>
|
||||
</select>
|
||||
<select
|
||||
v-model="filterSentiment"
|
||||
class="rounded-md border border-gray-300 px-3 py-1.5 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
|
||||
>
|
||||
<option value="">全部情感</option>
|
||||
<option value="POSITIVE">正面</option>
|
||||
<option value="NEUTRAL">中性</option>
|
||||
<option value="NEGATIVE">负面</option>
|
||||
</select>
|
||||
<input
|
||||
v-model="filterKeyword"
|
||||
type="text"
|
||||
placeholder="搜索回复内容..."
|
||||
class="rounded-md border border-gray-300 px-3 py-1.5 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
|
||||
/>
|
||||
<button
|
||||
class="text-xs text-gray-500 hover:text-gray-700"
|
||||
@click="resetFilters"
|
||||
>
|
||||
重置
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="m-4">
|
||||
<VLoading v-if="loading" />
|
||||
|
||||
@@ -312,6 +347,11 @@ const totalPages = ref(0)
|
||||
const selectedNames = ref<Set<string>>(new Set())
|
||||
const selectAll = ref(false)
|
||||
|
||||
// Filter state
|
||||
const filterStatus = ref("")
|
||||
const filterSentiment = ref("")
|
||||
const filterKeyword = ref("")
|
||||
|
||||
const toggleSelect = (name: string) => {
|
||||
if (selectedNames.value.has(name)) {
|
||||
selectedNames.value.delete(name)
|
||||
@@ -340,9 +380,13 @@ const conversationMessages = ref<ConversationMessage[]>([])
|
||||
const fetchReplies = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params: Record<string, string | number> = { page: page.value, size: size.value }
|
||||
if (filterStatus.value) params.status = filterStatus.value
|
||||
if (filterSentiment.value) params.sentiment = filterSentiment.value
|
||||
if (filterKeyword.value) params.keyword = filterKeyword.value
|
||||
const { data } = await axiosInstance.get(
|
||||
"/apis/console.api.comment-ai-autopilot.nxxy335.top/v1alpha1/replies",
|
||||
{ params: { page: page.value, size: size.value } },
|
||||
{ params },
|
||||
)
|
||||
replies.value = data.items || []
|
||||
total.value = data.total || 0
|
||||
@@ -561,6 +605,19 @@ const renderContent = (content: string) => {
|
||||
.replace(/<a /gi, "<a target='_blank' rel='noopener noreferrer' ")
|
||||
}
|
||||
|
||||
const resetFilters = () => {
|
||||
filterStatus.value = ""
|
||||
filterSentiment.value = ""
|
||||
filterKeyword.value = ""
|
||||
page.value = 1
|
||||
fetchReplies()
|
||||
}
|
||||
|
||||
watch([filterStatus, filterSentiment, filterKeyword], () => {
|
||||
page.value = 1
|
||||
fetchReplies()
|
||||
})
|
||||
|
||||
watch(page, () => {
|
||||
selectedNames.value.clear()
|
||||
selectAll.value = false
|
||||
|
||||
Reference in New Issue
Block a user