feat: add admin permissions voice input analytics and feedback
This commit is contained in:
@@ -44,6 +44,10 @@ const statusText = ref("连接后端中");
|
||||
const toastText = ref("");
|
||||
const followingOutput = ref(true);
|
||||
const messageList = ref<InstanceType<typeof MessageList> | null>(null);
|
||||
const feedbackDialogOpen = ref(false);
|
||||
const feedbackMessageId = ref<number | null>(null);
|
||||
const feedbackContent = ref("");
|
||||
const feedbackSubmitting = ref(false);
|
||||
const activeAbortController = ref<AbortController | null>(null);
|
||||
let toastTimer: number | null = null;
|
||||
let settlementPollVersion = 0;
|
||||
@@ -234,6 +238,13 @@ async function runGeneration(sessionId: number, message: string, assistantIndex:
|
||||
currentAssistant().streaming = false;
|
||||
currentAssistant().retryQuestion = undefined;
|
||||
currentAssistant().createdAt = new Date().toISOString();
|
||||
try {
|
||||
const latestHistory = await api.history(sessionId);
|
||||
const latestAssistant = [...latestHistory].reverse().find((item) => item.role === "assistant");
|
||||
if (latestAssistant) currentAssistant().id = String(latestAssistant.id);
|
||||
} catch {
|
||||
// 回答已经成功,历史记录偶发刷新失败不应将本次回答标记为失败。
|
||||
}
|
||||
await refreshSessionList();
|
||||
await refreshProfile();
|
||||
} catch (error) {
|
||||
@@ -252,6 +263,29 @@ async function runGeneration(sessionId: number, message: string, assistantIndex:
|
||||
}
|
||||
}
|
||||
|
||||
function openFeedback(messageId: string) {
|
||||
const parsed = Number(messageId);
|
||||
if (!Number.isInteger(parsed)) return;
|
||||
feedbackMessageId.value = parsed;
|
||||
feedbackContent.value = "";
|
||||
feedbackDialogOpen.value = true;
|
||||
}
|
||||
|
||||
async function submitFeedback() {
|
||||
const content = feedbackContent.value.trim();
|
||||
if (!feedbackMessageId.value || !content || feedbackSubmitting.value) return;
|
||||
feedbackSubmitting.value = true;
|
||||
try {
|
||||
await api.submitFeedback(feedbackMessageId.value, content);
|
||||
feedbackDialogOpen.value = false;
|
||||
showToast("感谢反馈,管理员会查看你提交的问题");
|
||||
} catch (error) {
|
||||
showToast(error instanceof Error ? error.message : "反馈提交失败");
|
||||
} finally {
|
||||
feedbackSubmitting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function chatErrorMessage(error: unknown) {
|
||||
const message = error instanceof Error ? error.message : "";
|
||||
if (/429|too many|请求过多|排队/i.test(message)) return "当前请求较多,AI 服务暂时繁忙。";
|
||||
@@ -607,6 +641,7 @@ async function copyText(text: string) {
|
||||
:loading-session="loadingSession"
|
||||
@follow-change="followingOutput = $event"
|
||||
@retry="retryMessage"
|
||||
@feedback="openFeedback"
|
||||
/>
|
||||
<ChatComposer :loading="sending" :disabled="!activeSessionId || loadingSession" @send="send" @stop="stop" />
|
||||
<SessionDrawer
|
||||
@@ -626,6 +661,14 @@ async function copyText(text: string) {
|
||||
|
||||
<div v-if="toastText" class="chat-toast" role="status">{{ toastText }}</div>
|
||||
|
||||
<AppDialog v-if="feedbackDialogOpen" title="反馈这次回答" labelled-by="feedback-dialog-title" @close="feedbackDialogOpen = false">
|
||||
<section class="feedback-dialog">
|
||||
<p>请简单描述这次回答存在的问题,管理员可以结合当时的对话记录查看。</p>
|
||||
<textarea v-model="feedbackContent" maxlength="200" rows="5" aria-label="反馈内容" placeholder="例如:回答没有解决我的问题、内容不准确……" />
|
||||
<div class="feedback-dialog-footer"><span>{{ feedbackContent.length }}/200</span><button type="button" :disabled="!feedbackContent.trim() || feedbackSubmitting" @click="submitFeedback">{{ feedbackSubmitting ? "提交中" : "提交反馈" }}</button></div>
|
||||
</section>
|
||||
</AppDialog>
|
||||
|
||||
<PersonalCenterDialog
|
||||
v-if="personalCenterOpen && user"
|
||||
:user="user"
|
||||
|
||||
Reference in New Issue
Block a user