Data_Analysis/analytics-demo-web/src/views/QaView.vue

218 lines
5.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { ChatDotRound } from '@element-plus/icons-vue'
import { ref } from 'vue'
import PageContainer from '@/components/PageContainer.vue'
import { useAnalysisContext } from '@/composables/useAnalysisContext'
import { resolveQaAnswer, QA_SAMPLE_QUESTIONS } from '@/lib/qa-resolve'
const { context, loading, reload } = useAnalysisContext()
const question = ref('')
const answer = ref('')
const answered = ref(false)
const lastSource = ref('')
const samplePicker = ref('')
let applyingSample = false
function submitAnswer() {
if (!context.value) return
const r = resolveQaAnswer(question.value, context.value)
answer.value = r.answer
lastSource.value = r.source
answered.value = true
}
function onSampleChange(val: string) {
if (!val) {
answer.value = ''
lastSource.value = ''
answered.value = false
return
}
applyingSample = true
question.value = val
applyingSample = false
submitAnswer()
}
function onQuestionManualInput() {
if (applyingSample) return
samplePicker.value = ''
}
function clearAll() {
question.value = ''
answer.value = ''
answered.value = false
lastSource.value = ''
samplePicker.value = ''
}
</script>
<template>
<PageContainer @refresh="reload">
<div v-loading="loading" class="qa-inner">
<div class="page-header">
<div class="header-content">
<div class="header-left">
<h2 class="page-title">
<el-icon><ChatDotRound /></el-icon>
智能问答
</h2>
<p class="page-description">
左侧可<strong>输入问题</strong>并点击「获取答案」,或通过<strong>示例问题</strong>下拉框选择后,右侧即时展示回答。本页为
<strong>Demo</strong>:答案由内置规则根据当前加载的 mock 数据即时计算;正式上线将改为调用 AI并结合数仓与项目内指标口径文档作答。
</p>
</div>
</div>
</div>
<div class="qa-split">
<el-card class="main-card qa-card qa-left" shadow="never">
<div class="qa-field">
<div class="qa-label">示例问题</div>
<el-select
v-model="samplePicker"
class="qa-sample-select"
placeholder="请选择示例问题…"
filterable
clearable
:disabled="loading"
@change="onSampleChange"
>
<el-option v-for="(s, i) in QA_SAMPLE_QUESTIONS" :key="i" :label="s" :value="s" />
</el-select>
<p class="qa-hint">选择后右侧立即显示答案;可清空后换一题。</p>
</div>
<div class="qa-field qa-field-divider">
<div class="qa-label">自定义提问</div>
<el-input
v-model="question"
type="textarea"
:rows="5"
placeholder="例如为什么11月的AE数量是10月的2倍还多"
maxlength="500"
show-word-limit
@input="onQuestionManualInput"
/>
</div>
<div class="qa-actions">
<el-button type="primary" :disabled="!question.trim() || loading" @click="submitAnswer">获取答案</el-button>
<el-button text :disabled="loading" @click="clearAll">清空</el-button>
</div>
</el-card>
<el-card class="main-card qa-card qa-answer-card qa-right" shadow="never">
<template #header>
<div class="qa-answer-head">
<span>回答</span>
<el-tag v-if="answered && lastSource" size="small" type="info" effect="plain">来源:{{ lastSource }}</el-tag>
</div>
</template>
<pre v-if="answered" class="qa-answer-body">{{ answer }}</pre>
<p v-else class="qa-answer-empty">请从左侧选择示例问题或输入问题后点击获取答案</p>
</el-card>
</div>
</div>
</PageContainer>
</template>
<style scoped>
.qa-inner {
max-width: 1120px;
display: flex;
flex-direction: column;
gap: 16px;
min-height: 120px;
}
.qa-split {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: 16px;
align-items: stretch;
}
@media (max-width: 880px) {
.qa-split {
grid-template-columns: 1fr;
}
}
.qa-sample-select {
width: 100%;
}
.qa-field-divider {
margin-top: 20px;
padding-top: 16px;
border-top: 1px solid var(--el-border-color-lighter);
}
.qa-card {
border-radius: var(--border-radius-md, 12px);
}
.qa-field {
margin-bottom: 12px;
}
.qa-label {
font-weight: 600;
margin-bottom: 8px;
font-size: 14px;
}
.qa-actions {
display: flex;
align-items: center;
gap: 12px;
}
.qa-hint {
margin: 10px 0 0;
font-size: 12px;
color: var(--el-text-color-placeholder);
}
.qa-answer-card {
border-left: 4px solid var(--customer-board-color, var(--el-color-primary));
}
.qa-answer-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.qa-answer-body {
margin: 0;
white-space: pre-wrap;
word-break: break-word;
font-family: inherit;
font-size: 14px;
line-height: 1.65;
color: var(--el-text-color-regular);
}
.qa-answer-empty {
margin: 0;
font-size: 14px;
line-height: 1.65;
color: var(--el-text-color-placeholder);
}
.qa-left,
.qa-right {
min-height: 280px;
}
.qa-right :deep(.el-card__body) {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
</style>