feat(questions): make brand questions the primary monitoring & template axis
Deployment Config CI / Deployment Config (push) Successful in 29s
Frontend CI / Frontend (push) Successful in 4m4s
Backend CI / Backend (push) Failing after 7m12s

- add /questions/combination-fill endpoint with AI-driven, IP-region-aware matrix fill
- extract ip2region resolver from ops/app into shared/ipregion for cross-service use
- thread question_id filter through dashboard composite, citation summary, and collect-now
- switch template wizard from keyword inputs to brand-question selection (primary + supplemental)
- pass brand_question and supplemental_questions through assist/title/outline prompts
- add AiWaitingModal + 45s client timeout and request_timeout error mapping for long AI flows

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-13 15:59:39 +08:00
parent 37b0b32327
commit 1eae6fb6d4
36 changed files with 2119 additions and 412 deletions
@@ -0,0 +1,95 @@
<script setup lang="ts">
withDefaults(
defineProps<{
open: boolean
title: string
progress: number
stage?: string
width?: string | number
}>(),
{
stage: '',
width: '640px',
},
)
</script>
<template>
<a-modal
:open="open"
:footer="null"
:closable="false"
:mask-closable="false"
centered
:width="width"
wrap-class-name="ai-waiting-modal-wrap"
>
<div class="ai-waiting-modal">
<div class="ai-waiting-modal__orb" />
<h3>{{ title }}</h3>
<a-progress :percent="progress" status="active" :show-info="false" />
<p>{{ stage }}</p>
</div>
</a-modal>
</template>
<style scoped>
.ai-waiting-modal {
display: flex;
flex-direction: column;
align-items: center;
gap: 24px;
padding: 24px 20px 12px;
text-align: center;
}
.ai-waiting-modal__orb {
width: 76px;
height: 76px;
border-radius: 999px;
background:
radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.92), transparent 38%),
conic-gradient(from 120deg, #4f8fff, #7dd3fc, #e879f9, #4f8fff);
box-shadow:
0 18px 38px rgba(79, 143, 255, 0.2),
inset 0 0 18px rgba(255, 255, 255, 0.4);
animation: ai-orb-float 2.6s ease-in-out infinite;
}
.ai-waiting-modal h3 {
margin: 0;
color: #1b2741;
font-size: 22px;
font-weight: 700;
line-height: 1.35;
}
.ai-waiting-modal p {
min-height: 22px;
margin: 0;
color: #5f6f8a;
font-size: 15px;
line-height: 1.5;
}
@keyframes ai-orb-float {
0%,
100% {
transform: translateY(0) scale(1);
}
50% {
transform: translateY(-6px) scale(1.04);
}
}
@media (max-width: 768px) {
.ai-waiting-modal {
gap: 20px;
padding: 20px 12px 8px;
}
.ai-waiting-modal h3 {
font-size: 20px;
}
}
</style>