|
|
|
|
@ -58,32 +58,35 @@
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<section v-if="form.activeStep === 0" class="step-panel">
|
|
|
|
|
<div class="questionnaire-head">
|
|
|
|
|
<p class="task-desc questionnaire-desc">
|
|
|
|
|
借助AI,生成智能产品购买决策因素调研问卷,提示词参考:设计问卷,用于分析用户购买智能产品的决策因素。问卷完成后复制到下述编辑框,并上传问卷pdf文档。
|
|
|
|
|
<div class="hypothesis-head">
|
|
|
|
|
<p class="task-desc hypothesis-desc">
|
|
|
|
|
基于实训 8 的用户画像结论,明确本次问卷调查的目标人群与核心假设,填写下表。
|
|
|
|
|
</p>
|
|
|
|
|
<el-button class="upload-action questionnaire-upload" :loading="uploading" @click="triggerFileSelect('questionnaire')">
|
|
|
|
|
<el-icon><Upload /></el-icon>
|
|
|
|
|
上传问卷
|
|
|
|
|
</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="form.questionnaireFileName" class="file-chip questionnaire-file">
|
|
|
|
|
<el-icon><Document /></el-icon>
|
|
|
|
|
<span>{{ form.questionnaireFileName }}</span>
|
|
|
|
|
<div class="hypothesis-actions">
|
|
|
|
|
<el-button class="hypothesis-action" @click="addTargetHypothesis">增加一行</el-button>
|
|
|
|
|
<el-button class="hypothesis-action hypothesis-action--quiet" :disabled="form.targetHypotheses.length <= 1" @click="removeTargetHypothesis">删除一行</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
<el-button class="training-eight-action" @click="viewTargetUserProfile">查看实训8</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="field-block questionnaire-field">
|
|
|
|
|
<span>示例:</span>
|
|
|
|
|
<div
|
|
|
|
|
ref="questionnaireEditorRef"
|
|
|
|
|
class="large-textarea questionnaire-textarea"
|
|
|
|
|
contenteditable="true"
|
|
|
|
|
role="textbox"
|
|
|
|
|
aria-multiline="true"
|
|
|
|
|
data-placeholder="请将借助AI设计完成的问卷内容复制到这里"
|
|
|
|
|
@input="syncQuestionnaireText"
|
|
|
|
|
@blur="syncQuestionnaireText"
|
|
|
|
|
></div>
|
|
|
|
|
<div class="target-hypothesis-table-wrap">
|
|
|
|
|
<table class="target-hypothesis-table">
|
|
|
|
|
<thead>
|
|
|
|
|
<tr>
|
|
|
|
|
<th>目标人群</th>
|
|
|
|
|
<th>实训8关键发现</th>
|
|
|
|
|
<th>本次问卷需验证的核心假设</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<tr v-for="(hypothesis, index) in form.targetHypotheses" :key="index">
|
|
|
|
|
<td><input v-model="hypothesis.targetGroup" class="hypothesis-input" placeholder="例如:职场白领(25-35岁)" /></td>
|
|
|
|
|
<td><textarea v-model="hypothesis.keyFinding" class="hypothesis-textarea" placeholder="例如:高压工作、入睡困难、看重效率" /></td>
|
|
|
|
|
<td><textarea v-model="hypothesis.coreHypothesis" class="hypothesis-textarea" placeholder="例如:是否更关注白噪声质量与智能场景联动?对价格的敏感度如何?" /></td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
<p class="hypothesis-tip">可编辑表格内容;请基于实训 8 的结论明确每类目标人群的问卷验证方向。</p>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section v-else-if="form.activeStep === 1" class="step-panel">
|
|
|
|
|
@ -179,7 +182,7 @@ import TrainingAiSidebar from "@/views/components/TrainingAiSidebar.vue";
|
|
|
|
|
import TrainingMaterialButton from "@/views/components/TrainingMaterialButton.vue";
|
|
|
|
|
import TrainingTaskBrief from "@/views/components/TrainingTaskBrief.vue";
|
|
|
|
|
import { getTrainingTaskByKey } from "@/api/trainingTask";
|
|
|
|
|
import { getStudentTrainingAnswer, saveStudentTrainingAnswer, uploadStudentTrainingFile } from "@/api/studentTrainingAnswer";
|
|
|
|
|
import { checkConsumerBehaviorStepOne, getStudentTrainingAnswer, saveStudentTrainingAnswer, uploadStudentTrainingFile } from "@/api/studentTrainingAnswer";
|
|
|
|
|
|
|
|
|
|
const TASK_KEY = "consumer-behavior";
|
|
|
|
|
const { proxy } = getCurrentInstance();
|
|
|
|
|
@ -380,6 +383,7 @@ const uploadAccept = computed(() => {
|
|
|
|
|
function createForm() {
|
|
|
|
|
return {
|
|
|
|
|
activeStep: 0,
|
|
|
|
|
targetHypotheses: createTargetHypotheses(),
|
|
|
|
|
questionnaireText: questionnaireTemplate,
|
|
|
|
|
questionnaireFileName: "",
|
|
|
|
|
questionnaireFileUrl: "",
|
|
|
|
|
@ -390,6 +394,18 @@ function createForm() {
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createTargetHypotheses() {
|
|
|
|
|
return [
|
|
|
|
|
{ targetGroup: "职场白领(25-35岁)", keyFinding: "", coreHypothesis: "" },
|
|
|
|
|
{ targetGroup: "精致妈妈(28-38岁)", keyFinding: "", coreHypothesis: "" },
|
|
|
|
|
{ targetGroup: "银发人群(50-65岁)", keyFinding: "", coreHypothesis: "" },
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createEmptyTargetHypothesis() {
|
|
|
|
|
return { targetGroup: "", keyFinding: "", coreHypothesis: "" };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const form = ref(createForm());
|
|
|
|
|
|
|
|
|
|
const taskTitle = computed(() => taskConfig.value?.taskName || "消费者需求与行为");
|
|
|
|
|
@ -458,6 +474,7 @@ function applySavedAnswer(value) {
|
|
|
|
|
...parsed,
|
|
|
|
|
activeStep: Number.isInteger(parsed.activeStep) ? parsed.activeStep : 0,
|
|
|
|
|
questionnaireText: normalizeQuestionnaireContent(parsed.questionnaireText || questionnaireTemplate),
|
|
|
|
|
targetHypotheses: normalizeTargetHypotheses(parsed.targetHypotheses),
|
|
|
|
|
chartFiles: parsed.chartFiles || {},
|
|
|
|
|
report: normalizeReport(parsed.report),
|
|
|
|
|
};
|
|
|
|
|
@ -467,6 +484,15 @@ function applySavedAnswer(value) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function normalizeTargetHypotheses(rows) {
|
|
|
|
|
if (!Array.isArray(rows) || !rows.length) return createTargetHypotheses();
|
|
|
|
|
return rows.map((row) => ({
|
|
|
|
|
targetGroup: String(row?.targetGroup || ""),
|
|
|
|
|
keyFinding: String(row?.keyFinding || ""),
|
|
|
|
|
coreHypothesis: String(row?.coreHypothesis || ""),
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function normalizeReport(value = {}) {
|
|
|
|
|
return Object.keys(emptyReport).reduce((report, key) => {
|
|
|
|
|
const currentValue = value?.[key] || "";
|
|
|
|
|
@ -528,6 +554,19 @@ function setActiveStep(index) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function addTargetHypothesis() {
|
|
|
|
|
form.value.targetHypotheses.push(createEmptyTargetHypothesis());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function removeTargetHypothesis() {
|
|
|
|
|
if (form.value.targetHypotheses.length <= 1) return;
|
|
|
|
|
form.value.targetHypotheses.pop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function viewTargetUserProfile() {
|
|
|
|
|
window.open("/demand/people", "_blank", "noopener");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleFileChange(event) {
|
|
|
|
|
const file = event.target.files?.[0];
|
|
|
|
|
if (!file) return;
|
|
|
|
|
@ -561,7 +600,8 @@ function goPrev() {
|
|
|
|
|
if (form.value.activeStep > 0) setActiveStep(form.value.activeStep - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function goNext() {
|
|
|
|
|
async function goNext() {
|
|
|
|
|
if (form.value.activeStep === 0) await persist("IN_PROGRESS");
|
|
|
|
|
if (form.value.activeStep < flowSteps.value.length - 1) setActiveStep(form.value.activeStep + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -589,6 +629,9 @@ function buildAnswerPayload(status) {
|
|
|
|
|
async function persist(status = "IN_PROGRESS") {
|
|
|
|
|
saving.value = true;
|
|
|
|
|
try {
|
|
|
|
|
if (status !== "RESET" && (form.value.activeStep === 0 || status === "SUBMITTED")) {
|
|
|
|
|
await checkConsumerBehaviorStepOne({ hypotheses: form.value.targetHypotheses });
|
|
|
|
|
}
|
|
|
|
|
await saveStudentTrainingAnswer(TASK_KEY, buildAnswerPayload(status));
|
|
|
|
|
proxy?.$modal?.msgSuccess(status === "SUBMITTED" ? "提交成功" : "保存成功");
|
|
|
|
|
} finally {
|
|
|
|
|
@ -618,6 +661,9 @@ function exportOutcome() {
|
|
|
|
|
"",
|
|
|
|
|
`当前步骤:${flowSteps.value[form.value.activeStep] || ""}`,
|
|
|
|
|
"",
|
|
|
|
|
"问卷调查目标人群与核心假设:",
|
|
|
|
|
...form.value.targetHypotheses.map((item, index) => `${index + 1}. 目标人群:${item.targetGroup || ""}\n实训8关键发现:${item.keyFinding || ""}\n核心假设:${item.coreHypothesis || ""}`),
|
|
|
|
|
"",
|
|
|
|
|
"问卷设计:",
|
|
|
|
|
questionnaireTextForExport(),
|
|
|
|
|
"",
|
|
|
|
|
@ -1009,6 +1055,127 @@ function exportOutcome() {
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hypothesis-head {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 18px 28px;
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hypothesis-desc {
|
|
|
|
|
margin: 0;
|
|
|
|
|
color: #d9eaf4;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hypothesis-actions {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
gap: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hypothesis-actions :deep(.hypothesis-action),
|
|
|
|
|
.training-eight-action {
|
|
|
|
|
min-width: 146px;
|
|
|
|
|
height: 42px;
|
|
|
|
|
border: 1px solid rgba(92, 224, 255, 0.7);
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
background: linear-gradient(95deg, #0b84bd, #096491);
|
|
|
|
|
font-size: 15px;
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hypothesis-actions :deep(.hypothesis-action--quiet) {
|
|
|
|
|
border-color: rgba(115, 191, 220, 0.58);
|
|
|
|
|
color: #d9f4ff;
|
|
|
|
|
background: rgba(13, 85, 117, 0.72);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.training-eight-action {
|
|
|
|
|
grid-column: 2;
|
|
|
|
|
grid-row: 1;
|
|
|
|
|
min-width: 136px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.target-hypothesis-table-wrap {
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
border: 1px solid rgba(0, 180, 255, 0.24);
|
|
|
|
|
border-radius: 18px;
|
|
|
|
|
background: rgba(1, 14, 26, 0.72);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.target-hypothesis-table {
|
|
|
|
|
width: 100%;
|
|
|
|
|
min-width: 920px;
|
|
|
|
|
border-collapse: collapse;
|
|
|
|
|
table-layout: fixed;
|
|
|
|
|
|
|
|
|
|
th,
|
|
|
|
|
td {
|
|
|
|
|
padding: 12px;
|
|
|
|
|
border-right: 1px solid rgba(77, 167, 220, 0.26);
|
|
|
|
|
border-bottom: 1px solid rgba(77, 167, 220, 0.26);
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
th {
|
|
|
|
|
color: #ecfbff;
|
|
|
|
|
background: linear-gradient(100deg, #158fc4, #08739f);
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
th:nth-child(1) { width: 28%; }
|
|
|
|
|
th:nth-child(2) { width: 28%; }
|
|
|
|
|
th:nth-child(3) { width: 44%; }
|
|
|
|
|
|
|
|
|
|
tr:last-child td { border-bottom: 0; }
|
|
|
|
|
th:last-child,
|
|
|
|
|
td:last-child { border-right: 0; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hypothesis-input,
|
|
|
|
|
.hypothesis-textarea {
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
width: 100%;
|
|
|
|
|
border: 1px solid rgba(67, 134, 166, 0.8);
|
|
|
|
|
outline: none;
|
|
|
|
|
color: #eaf7ff;
|
|
|
|
|
background: rgba(7, 29, 43, 0.92);
|
|
|
|
|
font-family: inherit;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
line-height: 1.65;
|
|
|
|
|
|
|
|
|
|
&::placeholder { color: #8da5b2; opacity: 1; }
|
|
|
|
|
&:focus {
|
|
|
|
|
border-color: #5fe7ff;
|
|
|
|
|
box-shadow: 0 0 0 3px rgba(34, 207, 255, 0.14);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hypothesis-input {
|
|
|
|
|
height: 42px;
|
|
|
|
|
padding: 0 12px;
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hypothesis-textarea {
|
|
|
|
|
min-height: 86px;
|
|
|
|
|
padding: 10px 12px;
|
|
|
|
|
border-radius: 10px;
|
|
|
|
|
resize: vertical;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hypothesis-tip {
|
|
|
|
|
margin: 12px 0 0;
|
|
|
|
|
color: #75dff7;
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.questionnaire-desc {
|
|
|
|
|
flex: 1;
|
|
|
|
|
margin: 0;
|
|
|
|
|
@ -1399,6 +1566,24 @@ function exportOutcome() {
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hypothesis-head {
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.training-eight-action {
|
|
|
|
|
grid-column: auto;
|
|
|
|
|
grid-row: auto;
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hypothesis-actions {
|
|
|
|
|
justify-content: stretch;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.hypothesis-actions :deep(.hypothesis-action) {
|
|
|
|
|
flex: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.step-indicator {
|
|
|
|
|
align-items: stretch;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|