From fede66cac366f85970beef55a26be3b9bf7242dc Mon Sep 17 00:00:00 2001 From: Christian Moellmann Date: Sat, 23 May 2026 12:44:37 +0200 Subject: [PATCH] feat(interviews): Step4b Vue scaffold with five-tab navigation, API client, i18n keys Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/src/api/interview.js | 29 +++ frontend/src/components/Step4bInterviews.vue | 79 +++++++ .../src/components/interviews/DelphiPanel.vue | 4 + .../components/interviews/DiversityPanel.vue | 4 + .../interviews/LongitudinalPanel.vue | 4 + .../components/interviews/ScenarioPanel.vue | 4 + .../components/interviews/SynthesisPanel.vue | 4 + frontend/src/router/index.js | 7 + frontend/src/views/InterviewView.vue | 192 ++++++++++++++++++ locales/de.json | 15 ++ locales/en.json | 13 ++ locales/zh.json | 13 ++ 12 files changed, 368 insertions(+) create mode 100644 frontend/src/api/interview.js create mode 100644 frontend/src/components/Step4bInterviews.vue create mode 100644 frontend/src/components/interviews/DelphiPanel.vue create mode 100644 frontend/src/components/interviews/DiversityPanel.vue create mode 100644 frontend/src/components/interviews/LongitudinalPanel.vue create mode 100644 frontend/src/components/interviews/ScenarioPanel.vue create mode 100644 frontend/src/components/interviews/SynthesisPanel.vue create mode 100644 frontend/src/views/InterviewView.vue create mode 100644 locales/de.json diff --git a/frontend/src/api/interview.js b/frontend/src/api/interview.js new file mode 100644 index 00000000..0f5cdbf5 --- /dev/null +++ b/frontend/src/api/interview.js @@ -0,0 +1,29 @@ +import service from './index' + +export async function startPre(simId) { + const r = await service.post(`/api/interview/${simId}/pre`) + return r +} +export async function startPost(simId) { + const r = await service.post(`/api/interview/${simId}/post`) + return r +} +export async function rerun(simId, subagent) { + const r = await service.post(`/api/interview/${simId}/rerun`, { subagent }) + return r +} +export async function getStatus(simId, taskId) { + const r = await service.get(`/api/interview/${simId}/status`, { params: { task_id: taskId } }) + return r +} +export async function getResults(simId, subagent) { + const r = await service.get(`/api/interview/${simId}/results/${subagent}`) + return r +} +export async function getSynthesis(simId) { + const r = await service.get(`/api/interview/${simId}/results/synthesis`) + return r +} +export function exportCsvUrl(simId) { + return `/api/interview/${simId}/export.csv` +} diff --git a/frontend/src/components/Step4bInterviews.vue b/frontend/src/components/Step4bInterviews.vue new file mode 100644 index 00000000..d2aed844 --- /dev/null +++ b/frontend/src/components/Step4bInterviews.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/frontend/src/components/interviews/DelphiPanel.vue b/frontend/src/components/interviews/DelphiPanel.vue new file mode 100644 index 00000000..f8b27647 --- /dev/null +++ b/frontend/src/components/interviews/DelphiPanel.vue @@ -0,0 +1,4 @@ + + diff --git a/frontend/src/components/interviews/DiversityPanel.vue b/frontend/src/components/interviews/DiversityPanel.vue new file mode 100644 index 00000000..759114b3 --- /dev/null +++ b/frontend/src/components/interviews/DiversityPanel.vue @@ -0,0 +1,4 @@ + + diff --git a/frontend/src/components/interviews/LongitudinalPanel.vue b/frontend/src/components/interviews/LongitudinalPanel.vue new file mode 100644 index 00000000..189c2488 --- /dev/null +++ b/frontend/src/components/interviews/LongitudinalPanel.vue @@ -0,0 +1,4 @@ + + diff --git a/frontend/src/components/interviews/ScenarioPanel.vue b/frontend/src/components/interviews/ScenarioPanel.vue new file mode 100644 index 00000000..ea2686e3 --- /dev/null +++ b/frontend/src/components/interviews/ScenarioPanel.vue @@ -0,0 +1,4 @@ + + diff --git a/frontend/src/components/interviews/SynthesisPanel.vue b/frontend/src/components/interviews/SynthesisPanel.vue new file mode 100644 index 00000000..7f3f7966 --- /dev/null +++ b/frontend/src/components/interviews/SynthesisPanel.vue @@ -0,0 +1,4 @@ + + diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index 62d23201..30b072b8 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -4,6 +4,7 @@ import Process from '../views/MainView.vue' import SimulationView from '../views/SimulationView.vue' import SimulationRunView from '../views/SimulationRunView.vue' import ReportView from '../views/ReportView.vue' +import InterviewView from '../views/InterviewView.vue' import InteractionView from '../views/InteractionView.vue' const routes = [ @@ -36,6 +37,12 @@ const routes = [ component: ReportView, props: true }, + { + path: '/interview/:simulationId', + name: 'Interview', + component: InterviewView, + props: true + }, { path: '/interaction/:reportId', name: 'Interaction', diff --git a/frontend/src/views/InterviewView.vue b/frontend/src/views/InterviewView.vue new file mode 100644 index 00000000..767ac9b7 --- /dev/null +++ b/frontend/src/views/InterviewView.vue @@ -0,0 +1,192 @@ + + + + + diff --git a/locales/de.json b/locales/de.json new file mode 100644 index 00000000..4032d4db --- /dev/null +++ b/locales/de.json @@ -0,0 +1,15 @@ +{ + "interview": { + "title": "Stakeholder-Interviews", + "subtitle": "Vier unabhängige Befragungen der simulierten Stakeholder-Population.", + "runAll": "Alle Post-Simulations-Interviews starten", + "downloadCsv": "CSV herunterladen", + "tab": { + "longitudinal": "Längsschnitt (Δ)", + "diversity": "Diversität", + "delphi": "Delphi", + "scenario": "Szenarien", + "synthesis": "Synthese" + } + } +} diff --git a/locales/en.json b/locales/en.json index 544c68b1..d22cf64f 100644 --- a/locales/en.json +++ b/locales/en.json @@ -661,5 +661,18 @@ "llmSelectAgentFailed": "LLM agent selection failed, using default selection: {error}", "generateInterviewQuestionsFailed": "Failed to generate interview questions: {error}", "generateInterviewSummaryFailed": "Failed to generate interview summary: {error}" + }, + "interview": { + "title": "Stakeholder interviews", + "subtitle": "Four independent surveys of the simulated stakeholder population.", + "runAll": "Run all post-simulation interviews", + "downloadCsv": "Download CSV", + "tab": { + "longitudinal": "Longitudinal (Δ)", + "diversity": "Diversity", + "delphi": "Delphi", + "scenario": "Scenarios", + "synthesis": "Synthesis" + } } } diff --git a/locales/zh.json b/locales/zh.json index cd747e2f..71ed6c4b 100644 --- a/locales/zh.json +++ b/locales/zh.json @@ -661,5 +661,18 @@ "llmSelectAgentFailed": "LLM选择Agent失败,使用默认选择: {error}", "generateInterviewQuestionsFailed": "生成采访问题失败: {error}", "generateInterviewSummaryFailed": "生成采访摘要失败: {error}" + }, + "interview": { + "title": "利益相关者访谈", + "subtitle": "对模拟利益相关者群体进行的四项独立调查。", + "runAll": "运行所有模拟后访谈", + "downloadCsv": "下载 CSV", + "tab": { + "longitudinal": "纵向分析 (Δ)", + "diversity": "多样性", + "delphi": "德尔菲法", + "scenario": "情景分析", + "synthesis": "综合分析" + } } }