|
|
@@ -1,7 +1,6 @@
|
|
|
<!-- アンケート照会 -->
|
|
|
<template>
|
|
|
<div class="app-container">
|
|
|
- <p>アンケートフォーム作成</p>
|
|
|
<div class="form-container">
|
|
|
<el-form ref="queryRef"
|
|
|
:model="queryParams"
|
|
|
@@ -10,7 +9,7 @@
|
|
|
<el-form-item label="タイトル" style="margin-left: 30px;margin-top: -35px;">
|
|
|
<el-input v-model="queryParams.title" class="table-input" :maxlength="100" disabled></el-input>
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="説明文" style="margin-left: 30px;margin-top: -15px;" >
|
|
|
+ <el-form-item label="説明文" style="margin-left: 30px;margin-top: -15px;">
|
|
|
<el-input
|
|
|
v-model="queryParams.description"
|
|
|
class="table-input"
|
|
|
@@ -148,7 +147,7 @@
|
|
|
|
|
|
<div v-for="(question, index) in questions" :key="question.sortOrder" class="question-block">
|
|
|
<el-form-item style="margin-left: 50px; margin-top: 3px;">
|
|
|
- <el-button disabled class="append-button" @click="addQuestionAbove(index)">この上に設問を追加</el-button>
|
|
|
+ <el-button disabled class="append-button">この上に設問を追加</el-button>
|
|
|
</el-form-item>
|
|
|
<el-form-item style="margin-left: 55px;">
|
|
|
<template #label>
|
|
|
@@ -160,7 +159,7 @@
|
|
|
<el-input disabled v-model="question.questionText" class="small-input" type="textarea" :rows="2" :maxlength="255"></el-input>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="回答型" style="margin-left: 55px;margin-top: -15px">
|
|
|
- <el-radio-group disabled v-model="question.questionTypeStr" class="custom-radio-group" @change="handleQuestionTypeChange(question, $event)">
|
|
|
+ <el-radio-group disabled v-model="question.questionTypeStr" class="custom-radio-group">
|
|
|
<el-radio label="INPUT_BOX_50">入力ボックス(50文字)</el-radio>
|
|
|
<el-radio label="INPUT_BOX_100">入力ボックス(100文字)</el-radio>
|
|
|
<el-radio label="CHECK_BOX">チェックボックス</el-radio>
|
|
|
@@ -212,14 +211,12 @@
|
|
|
<el-button
|
|
|
type="text"
|
|
|
class="delete-btn"
|
|
|
- @click="deleteCheckboxItem(index, itemIndex)"
|
|
|
disabled
|
|
|
>削除</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
<el-button
|
|
|
class="append-btn"
|
|
|
- @click="addCheckboxItem(index)"
|
|
|
disabled
|
|
|
>追加</el-button>
|
|
|
</el-form-item>
|
|
|
@@ -246,14 +243,12 @@
|
|
|
<el-button
|
|
|
type="text"
|
|
|
class="radio-btn"
|
|
|
- @click="deleteRadioItem(index, itemIndex)"
|
|
|
disabled
|
|
|
>削除</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
<el-button
|
|
|
class="append-btn"
|
|
|
- @click="addRadioItem(index)"
|
|
|
disabled
|
|
|
>追加</el-button>
|
|
|
</el-form-item>
|
|
|
@@ -279,13 +274,13 @@
|
|
|
v-model="question.questionUnit"
|
|
|
:maxlength="20"
|
|
|
style="width: 85px; margin-left: 10px;"
|
|
|
- :disabled="!question.unitHas"
|
|
|
+ disabled
|
|
|
></el-input>
|
|
|
</div>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
<el-form-item style="margin-left: 50px; margin-top: -10px;">
|
|
|
- <el-button class="append-button" disabled @click="addQuestionBelow(index)">この下に設問を追加</el-button>
|
|
|
+ <el-button class="append-button" disabled>この下に設問を追加</el-button>
|
|
|
</el-form-item>
|
|
|
</div>
|
|
|
</el-form>
|
|
|
@@ -299,22 +294,17 @@
|
|
|
import { getRegionTree,listSurveyDetail} from "@/api/fcbi/survey.js"
|
|
|
import { reactive, toRefs, ref, watch, onMounted } from 'vue';
|
|
|
import RegionTree from '../../../components/RegionTree.vue';
|
|
|
-import { ElMessage } from "element-plus";
|
|
|
-import {useRoute, useRouter} from 'vue-router';
|
|
|
+import {useRoute} from 'vue-router';
|
|
|
import useSurveyStore from '@/store/modules/survey';
|
|
|
|
|
|
const { proxy } = getCurrentInstance();
|
|
|
const surveyStore = useSurveyStore()
|
|
|
// アップロード対象を取得
|
|
|
const { yamada_fc_brand } = proxy.useDict('yamada_fc_brand');
|
|
|
-surveyStore.setBrandCode(yamada_fc_brand)
|
|
|
const { yamada_business_type } = proxy.useDict('yamada_business_type');
|
|
|
-surveyStore.setBusinessTypeCode(yamada_business_type)
|
|
|
-const error = ref('');
|
|
|
|
|
|
const regionTree = ref([]);
|
|
|
const selectedRegions = ref([]);
|
|
|
-const router = useRouter();
|
|
|
const route= useRoute()
|
|
|
const surveyId = route.params.surveyId
|
|
|
|
|
|
@@ -369,167 +359,6 @@ const data = reactive({
|
|
|
]
|
|
|
});
|
|
|
|
|
|
-// 問題を動的に追加する方法
|
|
|
-const addQuestionAbove = (index) => {
|
|
|
- const newSortOrder = data.questions[index].sortOrder;
|
|
|
- // 指定した場所に新しい問題を追加する
|
|
|
- data.questions.splice(index, 0, {
|
|
|
- questionText: '',
|
|
|
- questionType: 'INPUT_BOX_50',
|
|
|
- oldQuestionType: 'INPUT_BOX_50',
|
|
|
- input50: '',
|
|
|
- input100: '',
|
|
|
- checkboxItems: [
|
|
|
- { checked: false, optionText: '', sortOrder: 1 },
|
|
|
- { checked: false, optionText: '', sortOrder: 2 },
|
|
|
- { checked: false, optionText: '', sortOrder: 3 },
|
|
|
- ],
|
|
|
- radioItems: [
|
|
|
- { value: 'option1', optionText: '', sortOrder: 1 },
|
|
|
- { value: 'option2', optionText: '', sortOrder: 2 },
|
|
|
- { value: 'option3', optionText: '', sortOrder: 3 },
|
|
|
- ],
|
|
|
- radioGroupValue: null,
|
|
|
- numberSelectStart: '',
|
|
|
- numberSelectEnd: '',
|
|
|
- unitHas: false,
|
|
|
- sortOrder: newSortOrder,
|
|
|
- questionUnit: ''
|
|
|
- });
|
|
|
- adjustSortOrders(index);
|
|
|
-};
|
|
|
-
|
|
|
-const addQuestionBelow = (index) => {
|
|
|
- const newSortOrder = data.questions[index].sortOrder + 1;
|
|
|
- // 指定した場所の下に新しい問題を追加する
|
|
|
- data.questions.splice(index + 1, 0, {
|
|
|
- questionText: '',
|
|
|
- questionType: 'INPUT_BOX_50',
|
|
|
- oldQuestionType: 'INPUT_BOX_50',
|
|
|
- input50: '',
|
|
|
- input100: '',
|
|
|
- checkboxItems: [
|
|
|
- { checked: false, optionText: '', sortOrder: 1 },
|
|
|
- { checked: false, optionText: '', sortOrder: 2 },
|
|
|
- { checked: false, optionText: '', sortOrder: 3 },
|
|
|
- ],
|
|
|
- radioItems: [
|
|
|
- { value: 'option1', optionText: '', sortOrder: 1 },
|
|
|
- { value: 'option2', optionText: '', sortOrder: 2 },
|
|
|
- { value: 'option3', optionText: '', sortOrder: 3 },
|
|
|
- ],
|
|
|
- radioGroupValue: null,
|
|
|
- numberSelectStart: '',
|
|
|
- numberSelectEnd: '',
|
|
|
- unitHas: false,
|
|
|
- sortOrder: newSortOrder,
|
|
|
- questionUnit: ''
|
|
|
- });
|
|
|
- adjustSortOrders(index + 1);
|
|
|
-};
|
|
|
-
|
|
|
-// 問題のソートの調整
|
|
|
-const adjustSortOrders = (startIndex) => {
|
|
|
- for (let i = startIndex; i < data.questions.length; i++) {
|
|
|
- data.questions[i].sortOrder = i + 1;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 回答类型切换时重置前一类型的状态
|
|
|
-const handleQuestionTypeChange = (question, newType) => {
|
|
|
- // 保存旧类型用于判断需要重置哪些数据
|
|
|
- const oldType = question.questionTypeStr;
|
|
|
-
|
|
|
- // 如果类型未变化,不执行重置
|
|
|
- if (oldType === newType) return;
|
|
|
-
|
|
|
- // 根据旧类型重置对应的数据(回到初始状态)
|
|
|
- switch (oldType) {
|
|
|
- case 'INPUT_BOX_50':
|
|
|
- question.input50 = ''; // 重置50文字输入框
|
|
|
- break;
|
|
|
- case 'INPUT_BOX_100':
|
|
|
- question.input100 = ''; // 重置100文字输入框
|
|
|
- break;
|
|
|
- case 'CHECK_BOX':
|
|
|
- // 重置复选框选项(保留3个空选项)
|
|
|
- question.checkboxItems = [
|
|
|
- { checked: false, optionText: '', sortOrder: 1 },
|
|
|
- { checked: false, optionText: '', sortOrder: 2 },
|
|
|
- { checked: false, optionText: '', sortOrder: 3 },
|
|
|
- ];
|
|
|
- break;
|
|
|
- case 'RADIO_BUTTON':
|
|
|
- // 重置单选按钮选项(保留3个空选项)
|
|
|
- question.radioItems = [
|
|
|
- { value: 'option1', optionText: '', sortOrder: 1 },
|
|
|
- { value: 'option2', optionText: '', sortOrder: 2 },
|
|
|
- { value: 'option3', optionText: '', sortOrder: 3 },
|
|
|
- ];
|
|
|
- question.radioGroupValue = null; // 重置选中状态
|
|
|
- break;
|
|
|
- case 'NUMBER_SELECT':
|
|
|
- // 重置数字选择器相关数据
|
|
|
- question.numberSelectStart = '';
|
|
|
- question.numberSelectEnd = '';
|
|
|
- question.unitHas = false; // 重置单位选择
|
|
|
- question.questionUnit = ''; // 重置单位输入框
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- // 更新为新类型(确保数据同步)
|
|
|
- question.questionTypeStr = newType;
|
|
|
-};
|
|
|
-
|
|
|
-//ボタンの追加方法
|
|
|
-const addCheckboxItem = (questionIndex) => {
|
|
|
- const question = data.questions[questionIndex];
|
|
|
- const newSortOrder = question.checkboxItems.length + 1;
|
|
|
- question.checkboxItems.push({
|
|
|
- checked: false,
|
|
|
- optionText: '',
|
|
|
- sortOrder: newSortOrder
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-const addRadioItem = (questionIndex) => {
|
|
|
- const question = data.questions[questionIndex];
|
|
|
- const newId = question.radioItems.length + 1;
|
|
|
- const newSortOrder = question.radioItems.length + 1;
|
|
|
- question.radioItems.push({
|
|
|
- value: `option${newId}`,
|
|
|
- optionText: '',
|
|
|
- sortOrder: newSortOrder
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-//消去ボタンの方法
|
|
|
-const deleteRadioItem = (questionIndex, itemIndex) => {
|
|
|
- const question = data.questions[questionIndex];
|
|
|
- if (question.radioItems.length <= 3) {
|
|
|
- ElMessage.warning('少なくとも3つの選択肢を残してください');
|
|
|
- return;
|
|
|
- }
|
|
|
- question.radioItems.splice(itemIndex, 1);
|
|
|
- question.radioItems.forEach((item, index) => {
|
|
|
- item.sortOrder = index + 1;
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-const deleteCheckboxItem = (questionIndex, itemIndex) => {
|
|
|
- const question = data.questions[questionIndex];
|
|
|
- if (question.checkboxItems.length <= 3) {
|
|
|
- ElMessage.warning('少なくとも3つの選択肢を残してください');
|
|
|
- return;
|
|
|
- }
|
|
|
- question.checkboxItems.splice(itemIndex, 1);
|
|
|
- question.checkboxItems.forEach((item, index) => {
|
|
|
- item.sortOrder = index + 1;
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
// リアクティブオブジェクトからプロパティを参照可能なオブジェクトに変換
|
|
|
const { queryParams, questions } = toRefs(data);
|
|
|
const currentYear = new Date().getFullYear();
|
|
|
@@ -635,63 +464,38 @@ onMounted(async () => {
|
|
|
if (regionTree.value.length > 0) {
|
|
|
updateSelectedRegions(regionTree.value);
|
|
|
}
|
|
|
- } else {
|
|
|
- error.value = regionResponse?.message || '地域データの取得に失敗しました';
|
|
|
- console.error('地域データの取得に失敗しました:', regionResponse);
|
|
|
}
|
|
|
|
|
|
// 加载问卷详情数据
|
|
|
if (surveyId) {
|
|
|
- try {
|
|
|
- const requestData = { surveyId };
|
|
|
- const surveyResponse = await listSurveyDetail(requestData);
|
|
|
+ const requestData = { surveyId };
|
|
|
+ const surveyResponse = await listSurveyDetail(requestData);
|
|
|
|
|
|
- if (surveyResponse.code === 200) {
|
|
|
- // 从返回结果中获取问卷数据(假设rows是数组,取第一个元素)
|
|
|
- const surveyData = surveyResponse.rows?.[0] || {};
|
|
|
+ if (surveyResponse.code === 200) {
|
|
|
+ const surveyData = surveyResponse.rows?.[0] || {};
|
|
|
|
|
|
- // 绑定基本信息(标题、描述、公开范围等)
|
|
|
- bindSurveyBasicInfo(surveyData);
|
|
|
+ // 绑定基本信息(标题、描述、公开范围等)
|
|
|
+ bindSurveyBasicInfo(surveyData);
|
|
|
|
|
|
- // 处理问题数据(后端返回的是JSON字符串)
|
|
|
- let questionArray = [];
|
|
|
- if (surveyData.question) {
|
|
|
- try {
|
|
|
- // 解析JSON字符串为数组
|
|
|
- questionArray = JSON.parse(surveyData.question);
|
|
|
+ let questionArray = [];
|
|
|
+ if (surveyData.question) {
|
|
|
+ // 解析JSON字符串为数组
|
|
|
+ questionArray = JSON.parse(surveyData.question);
|
|
|
|
|
|
- // 验证解析结果是否为数组
|
|
|
- if (!Array.isArray(questionArray)) {
|
|
|
- console.warn('question字段解析后不是数组,已初始化为空数组');
|
|
|
- questionArray = [];
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
- // 处理JSON解析错误
|
|
|
- console.error('question字段JSON解析失败:', e);
|
|
|
- console.error('原始字符串内容:', surveyData.question);
|
|
|
- ElMessage.error('アンケートの問題データ形式が無効です');
|
|
|
- questionArray = [];
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 处理question字段为空的情况
|
|
|
- console.log('question字段为空,初始化为空数组');
|
|
|
+ // 验证解析结果是否为数组
|
|
|
+ if (!Array.isArray(questionArray)) {
|
|
|
questionArray = [];
|
|
|
}
|
|
|
+ } else {
|
|
|
+ questionArray = [];
|
|
|
+ }
|
|
|
|
|
|
- // 绑定问题列表
|
|
|
- bindSurveyQuestions(questionArray);
|
|
|
+ // 绑定问题列表
|
|
|
+ bindSurveyQuestions(questionArray);
|
|
|
|
|
|
- // 绑定地区选择
|
|
|
- bindSelectedRegions(surveyData.region || []);
|
|
|
+ // 绑定地区选择
|
|
|
+ bindSelectedRegions(surveyData.region || []);
|
|
|
|
|
|
- } else {
|
|
|
- // 处理接口返回错误状态
|
|
|
- ElMessage.error(surveyResponse?.message || 'アンケートデータの取得に失敗しました');
|
|
|
- }
|
|
|
- } catch (err) {
|
|
|
- // 处理接口调用异常
|
|
|
- console.error('アンケートデータの取得中にエラーが発生しました:', err);
|
|
|
- ElMessage.error('アンケートデータの取得中にエラーが発生しました');
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
@@ -743,12 +547,8 @@ const bindSurveyBasicInfo = (surveyData) => {
|
|
|
};
|
|
|
|
|
|
const bindSurveyQuestions = (questionsData) => {
|
|
|
- if (!questionsData.length) return;
|
|
|
-
|
|
|
- // 清空现有问题
|
|
|
data.questions = [];
|
|
|
|
|
|
- // 绑定每个问题
|
|
|
questionsData.forEach((q, index) => {
|
|
|
const question = {
|
|
|
questionText: q.questionText || '',
|
|
|
@@ -766,34 +566,49 @@ const bindSurveyQuestions = (questionsData) => {
|
|
|
questionUnit: ''
|
|
|
};
|
|
|
|
|
|
- // 根据问题类型绑定不同的内容
|
|
|
switch (question.questionTypeStr) {
|
|
|
case 'INPUT_BOX_50':
|
|
|
question.input50 = q.input50 || '';
|
|
|
break;
|
|
|
+
|
|
|
case 'INPUT_BOX_100':
|
|
|
question.input100 = q.input100 || '';
|
|
|
break;
|
|
|
+
|
|
|
case 'CHECK_BOX':
|
|
|
- question.checkboxItems = q.checkboxItems || [
|
|
|
- { checked: false, optionText: '', sortOrder: 1 },
|
|
|
- { checked: false, optionText: '', sortOrder: 2 },
|
|
|
- { checked: false, optionText: '', sortOrder: 3 },
|
|
|
- ];
|
|
|
+ // 解析复选框选项(字符串转对象/直接使用数组)
|
|
|
+ question.checkboxItems = typeof q.checkboxItems === 'string'
|
|
|
+ ? JSON.parse(q.checkboxItems)
|
|
|
+ : (Array.isArray(q.checkboxItems) ? q.checkboxItems : []);
|
|
|
+
|
|
|
+ // 格式化选项字段
|
|
|
+ question.checkboxItems = question.checkboxItems.map((item, idx) => ({
|
|
|
+ checked: Boolean(item.checked),
|
|
|
+ optionText: item.optionText || '',
|
|
|
+ sortOrder: item.sortOrder || idx + 1
|
|
|
+ }));
|
|
|
break;
|
|
|
+
|
|
|
case 'RADIO_BUTTON':
|
|
|
- question.radioItems = q.radioItems || [
|
|
|
- { value: 'option1', optionText: '', sortOrder: 1 },
|
|
|
- { value: 'option2', optionText: '', sortOrder: 2 },
|
|
|
- { value: 'option3', optionText: '', sortOrder: 3 },
|
|
|
- ];
|
|
|
+ // 解析单选按钮选项
|
|
|
+ question.radioItems = typeof q.radioItems === 'string'
|
|
|
+ ? JSON.parse(q.radioItems)
|
|
|
+ : (Array.isArray(q.radioItems) ? q.radioItems : []);
|
|
|
+
|
|
|
+ // 格式化选项字段
|
|
|
+ question.radioItems = question.radioItems.map((item, idx) => ({
|
|
|
+ value: item.value || `option${idx + 1}`,
|
|
|
+ optionText: item.optionText || '',
|
|
|
+ sortOrder: item.sortOrder || idx + 1
|
|
|
+ }));
|
|
|
question.radioGroupValue = q.radioGroupValue || null;
|
|
|
break;
|
|
|
+
|
|
|
case 'NUMBER_SELECT':
|
|
|
- question.numberSelectStart = q.numberSelectStart || '';
|
|
|
- question.numberSelectEnd = q.numberSelectEnd || '';
|
|
|
- question.unitHas = q.unitHas || false;
|
|
|
+ question.numberSelectStart = q.numberSelectStart ?? '';
|
|
|
+ question.numberSelectEnd = q.numberSelectEnd ?? '';
|
|
|
question.questionUnit = q.questionUnit || '';
|
|
|
+ question.unitHas = question.questionUnit.trim() !== '';
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
@@ -801,6 +616,8 @@ const bindSurveyQuestions = (questionsData) => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
+
|
|
|
+
|
|
|
const bindSelectedRegions = (region) => {
|
|
|
|
|
|
const regionData = typeof region === 'string' ? JSON.parse(region) : region;
|
|
|
@@ -831,27 +648,22 @@ const checkRegionNode = (nodes, regionCode, parentNode = null) => {
|
|
|
};
|
|
|
|
|
|
const updateParentNodeStatus = (parentNode) => {
|
|
|
- if (!parentNode) return; // 没有父节点则终止
|
|
|
+ if (!parentNode) return;
|
|
|
|
|
|
const children = parentNode.children || [];
|
|
|
- // 统计子节点中选中的数量
|
|
|
const checkedCount = children.filter(child => child.checked).length;
|
|
|
|
|
|
if (checkedCount === 0) {
|
|
|
- // 没有子节点选中:父节点不选中,也不是半选
|
|
|
parentNode.checked = false;
|
|
|
parentNode.indeterminate = false;
|
|
|
} else if (checkedCount === children.length) {
|
|
|
- // 所有子节点都选中:父节点选中,不是半选
|
|
|
parentNode.checked = true;
|
|
|
parentNode.indeterminate = false;
|
|
|
} else {
|
|
|
- // 部分子节点选中:父节点不选中,但为半选
|
|
|
parentNode.checked = false;
|
|
|
parentNode.indeterminate = true;
|
|
|
}
|
|
|
|
|
|
- // 继续向上更新父节点的父节点(递归)
|
|
|
updateParentNodeStatus(parentNode.parent);
|
|
|
};
|
|
|
|
|
|
@@ -865,7 +677,7 @@ const handleCheckChange = (regionId, isChecked) => {
|
|
|
if (isChecked) {
|
|
|
if (!selectedRegions.value.some(r => r.regionCode === region.regionCode)) {
|
|
|
selectedRegions.value.push({
|
|
|
- regionCode: region.regionCode // 字段名修改
|
|
|
+ regionCode: region.regionCode
|
|
|
});
|
|
|
}
|
|
|
} else {
|