feat(survey): 优化问卷创建功能
- 新增保存设置功能 - 优化题目列表渲染逻辑 - 添加断点续答、IP限制等设置项 -修复部分组件样式问题
This commit is contained in:
6
package-lock.json
generated
6
package-lock.json
generated
@@ -12,6 +12,7 @@
|
||||
"axios": "^1.8.2",
|
||||
"dotenv": "^16.4.7",
|
||||
"element-plus": "^2.7.8",
|
||||
"js-base64": "^3.7.7",
|
||||
"lodash": "^4.17.21",
|
||||
"pinia": "^2.1.7",
|
||||
"sortablejs": "^1.15.6",
|
||||
@@ -7676,6 +7677,11 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/js-base64": {
|
||||
"version": "3.7.7",
|
||||
"resolved": "https://registry.npmmirror.com/js-base64/-/js-base64-3.7.7.tgz",
|
||||
"integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"dev": true,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"axios": "^1.8.2",
|
||||
"dotenv": "^16.4.7",
|
||||
"element-plus": "^2.7.8",
|
||||
"js-base64": "^3.7.7",
|
||||
"lodash": "^4.17.21",
|
||||
"pinia": "^2.1.7",
|
||||
"sortablejs": "^1.15.6",
|
||||
|
||||
@@ -16,8 +16,7 @@ export function saveQuestion(params) {
|
||||
export function sync(params) {
|
||||
return request({
|
||||
url: `console/surveys/${params.sn}/sync`,
|
||||
method: 'post',
|
||||
data: params
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
export function questionDetails(params) {
|
||||
@@ -29,3 +28,18 @@ export function questionDetails(params) {
|
||||
data: params
|
||||
});
|
||||
}
|
||||
|
||||
// 获取setting
|
||||
export function getSetting(params) {
|
||||
return request({
|
||||
url: `/console/surveys/${params.sn}/answer_setting`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
export function saveSettings(params) {
|
||||
return request({
|
||||
url: `/console/surveys/${params.sn}/answer_setting`,
|
||||
method: 'put',
|
||||
data: params
|
||||
});
|
||||
}
|
||||
|
||||
@@ -167,8 +167,8 @@ const getMaxDateLimit = computed(() => {
|
||||
props.format
|
||||
);
|
||||
const tempStr = '0000-12-31 23:59:59';
|
||||
const result
|
||||
= props.maxDate.length !== 0 && thisMax.length > props.maxDate.length
|
||||
const result =
|
||||
props.maxDate.length !== 0 && thisMax.length > props.maxDate.length
|
||||
? thisMax.slice(0, props.maxDate.length) + tempStr.slice(props.maxDate.length)
|
||||
: thisMax;
|
||||
return result.slice(0, props.format.length);
|
||||
@@ -191,8 +191,8 @@ function onChange({ selectedValues, columnIndex }) {
|
||||
renderMinuteColumns,
|
||||
renderSecondColumns
|
||||
];
|
||||
updateColumns[columnIndex]
|
||||
&& updateColumns[columnIndex](changeValue, getMinDateLimit.value, getMaxDateLimit.value, false);
|
||||
updateColumns[columnIndex] &&
|
||||
updateColumns[columnIndex](changeValue, getMinDateLimit.value, getMaxDateLimit.value, false);
|
||||
}
|
||||
|
||||
// 渲染全部列
|
||||
|
||||
@@ -70,9 +70,13 @@ export const useCommonStore = defineStore('common', {
|
||||
}
|
||||
},
|
||||
setQuestionInfo(questionInfo) {
|
||||
console.log(questionInfo, 9998);
|
||||
console.log(this);
|
||||
this.questionsInfo = questionInfo;
|
||||
// 保持原有响应式引用,仅更新变化的部分
|
||||
this.questionsInfo = Object.assign({}, this.questionsInfo, questionInfo);
|
||||
|
||||
// 对嵌套结构特殊处理(如数组需要保持引用)
|
||||
if (questionInfo.questions) {
|
||||
this.questionsInfo.questions = [...questionInfo.questions];
|
||||
}
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import { ref, onMounted, watch, computed } from 'vue';
|
||||
import { useCounterStore } from '@/stores/counter';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import Draggable from './components/Draggable.vue';
|
||||
@@ -210,7 +210,7 @@ const counterStore = useCounterStore();
|
||||
const store = storeToRefs(counterStore);
|
||||
|
||||
const chooseQuestionId = ref('');
|
||||
const questionInfo = ref(store.questionsInfo.value);
|
||||
const questionInfo = computed(() => store.questionsInfo.value);
|
||||
|
||||
const emit = defineEmits(['getActiveQuestion']);
|
||||
// 获取选中的题目的ID
|
||||
|
||||
@@ -46,7 +46,11 @@
|
||||
</option-action>
|
||||
</van-radio-group>
|
||||
<van-checkbox-group v-if="element.question_type === 2" shape="square">
|
||||
<option-action v-model:data="element.options[index]" :active="active" :question="element">
|
||||
<option-action
|
||||
v-model:data="element.options[optionIndex]"
|
||||
:active="active"
|
||||
:question="element"
|
||||
>
|
||||
<template #item="{ element: it, index: itIndex }">
|
||||
<van-checkbox
|
||||
:key="itIndex"
|
||||
|
||||
@@ -25,13 +25,17 @@
|
||||
></contenteditable>
|
||||
</div>
|
||||
|
||||
<button @click="show = true">添加题目</button>
|
||||
<button v-if="questionInfo.questions.length === 0" @click="show = true">添加题目</button>
|
||||
</div>
|
||||
</van-cell-group>
|
||||
|
||||
<div class="ques">
|
||||
<!-- 题目-->
|
||||
<Design :active-id="activeId" @get-active-question="getActiveQuestion"></Design>
|
||||
<Design
|
||||
:active-id="activeId"
|
||||
class="desgin"
|
||||
@get-active-question="getActiveQuestion"
|
||||
></Design>
|
||||
<!-- <van-button @click="show = true">添加题目</van-button>-->
|
||||
<!-- 弹出的新增题目弹窗-->
|
||||
<van-popup
|
||||
@@ -87,7 +91,7 @@
|
||||
<van-cell title="每页一题" :border="false" label-align="left">
|
||||
<template #right-icon>
|
||||
<van-switch
|
||||
v-model="questionInfo.survey.is_page_one_question"
|
||||
v-model="questionInfo.survey.is_one_page_one_question"
|
||||
class="option-action-sheet-switch"
|
||||
size="0.5rem"
|
||||
:active-value="1"
|
||||
@@ -104,6 +108,7 @@
|
||||
size="0.5rem"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="saveSetting('is_publish_number', ['publish_number'])"
|
||||
></van-switch>
|
||||
</template>
|
||||
</van-cell>
|
||||
@@ -112,7 +117,13 @@
|
||||
class="child-group"
|
||||
:border="false"
|
||||
>
|
||||
<van-field label="投放数量最大为" input-align="right">
|
||||
<van-field
|
||||
v-model="questionInfo.survey.publish_number"
|
||||
label="投放数量最大为"
|
||||
input-align="right"
|
||||
type="number"
|
||||
@blur="saveSetting($event, 'publish_number')"
|
||||
>
|
||||
<template #right-icon> 份 </template>
|
||||
</van-field>
|
||||
</van-cell-group>
|
||||
@@ -125,13 +136,14 @@
|
||||
size="0.5rem"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="saveSetting('is_time', ['start_time', 'end_time'])"
|
||||
></van-switch>
|
||||
</template>
|
||||
</van-cell>
|
||||
<!--有效期-->
|
||||
<van-cell-group v-if="questionInfo.survey.is_time === 1" class="child-group" :border="false">
|
||||
<van-field
|
||||
v-model="questionInfo.survey.startTime"
|
||||
v-model="questionInfo.survey.start_time"
|
||||
is-link
|
||||
label="起始时间"
|
||||
input-align="right"
|
||||
@@ -140,7 +152,7 @@
|
||||
>
|
||||
</van-field>
|
||||
<van-field
|
||||
v-model="questionInfo.survey.endTime"
|
||||
v-model="questionInfo.survey.end_time"
|
||||
is-link
|
||||
label="截至时间"
|
||||
input-align="right"
|
||||
@@ -158,6 +170,7 @@
|
||||
size="0.5rem"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="saveSetting"
|
||||
></van-switch>
|
||||
</template>
|
||||
</van-cell>
|
||||
@@ -174,6 +187,7 @@
|
||||
size="0.5rem"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="saveSetting"
|
||||
></van-switch>
|
||||
</template>
|
||||
</van-cell>
|
||||
@@ -186,6 +200,7 @@
|
||||
size="0.5rem"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="saveSetting('is_ip_number', ['is_number'])"
|
||||
></van-switch>
|
||||
</template>
|
||||
</van-cell>
|
||||
@@ -195,6 +210,7 @@
|
||||
label="同一个IP地址只能作答"
|
||||
:border="false"
|
||||
input-align="right"
|
||||
@blur="saveSetting($event, 'is_number')"
|
||||
>
|
||||
<template #right-icon> 次 </template>
|
||||
</van-field>
|
||||
@@ -207,6 +223,7 @@
|
||||
size="0.5rem"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
@change="saveSetting('is_browser_number', 'browser_number')"
|
||||
></van-switch>
|
||||
</template>
|
||||
</van-cell>
|
||||
@@ -220,22 +237,23 @@
|
||||
label="同一个浏览器只能作答"
|
||||
:border="false"
|
||||
input-align="right"
|
||||
@blur="saveSetting($event, 'browser_number')"
|
||||
>
|
||||
<template #right-icon> 次 </template>
|
||||
</van-field>
|
||||
</van-cell-group>
|
||||
<van-divider></van-divider>
|
||||
<van-field
|
||||
v-model="endText"
|
||||
label="结束语"
|
||||
:border="false"
|
||||
readonly
|
||||
label-align="left"
|
||||
input-align="right"
|
||||
is-link
|
||||
@click="openEndTextModel"
|
||||
>
|
||||
</van-field>
|
||||
<!-- <van-field-->
|
||||
<!-- v-model="endText"-->
|
||||
<!-- label="结束语"-->
|
||||
<!-- :border="false"-->
|
||||
<!-- readonly-->
|
||||
<!-- label-align="left"-->
|
||||
<!-- input-align="right"-->
|
||||
<!-- is-link-->
|
||||
<!-- @click="openEndTextModel"-->
|
||||
<!-- >-->
|
||||
<!-- </van-field>-->
|
||||
</van-cell-group>
|
||||
</van-action-sheet>
|
||||
|
||||
@@ -253,15 +271,22 @@
|
||||
</van-popup>
|
||||
|
||||
<!-- 结束语选择-->
|
||||
<van-popup v-model:show="textModel" position="bottom" round>
|
||||
<van-picker :columns="columns" @confirm="onConfirm"></van-picker>
|
||||
</van-popup>
|
||||
<!-- <van-popup v-model:show="textModel" position="bottom" round>-->
|
||||
<!-- <van-picker :columns="columns" @confirm="onConfirm"></van-picker>-->
|
||||
<!-- </van-popup>-->
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
|
||||
import { questionDetails, snQuestions } from '@/api/design/index';
|
||||
import { ref, computed, onMounted, watch } from 'vue';
|
||||
import * as Base64 from 'js-base64';
|
||||
import {
|
||||
getSetting,
|
||||
questionDetails,
|
||||
saveQuestion,
|
||||
snQuestions,
|
||||
sync,
|
||||
saveSettings
|
||||
} from '@/api/design/index';
|
||||
import Design from '@/views/Design/Index.vue';
|
||||
import { useCounterStore } from '@/stores/counter';
|
||||
import { storeToRefs } from 'pinia';
|
||||
@@ -291,35 +316,12 @@ const currentType = ref();
|
||||
const route = useRoute();
|
||||
const surveyTitle = route.meta.title as string;
|
||||
const show = ref(false);
|
||||
const textModel = ref(false);
|
||||
// const textModel = ref(false);
|
||||
const activeId = ref(0);
|
||||
|
||||
const showSetting = ref(false);
|
||||
const timePickerModel = ref(false);
|
||||
|
||||
// picker 结束语选择器
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
text: '成功完成',
|
||||
value: '1'
|
||||
},
|
||||
{
|
||||
text: '题前终止',
|
||||
value: '2'
|
||||
},
|
||||
{
|
||||
text: '配额超限',
|
||||
value: '3'
|
||||
}
|
||||
]);
|
||||
|
||||
const endText = ref('');
|
||||
const onConfirm = (ev) => {
|
||||
endText.value = columns.value[ev.selectedValues[0] - 1].text;
|
||||
textModel.value = false;
|
||||
};
|
||||
|
||||
const openSettingAction = () => {
|
||||
showSetting.value = true;
|
||||
};
|
||||
@@ -330,15 +332,11 @@ const showTimePicker = (type, value) => {
|
||||
currentDate.value = value;
|
||||
};
|
||||
|
||||
const openEndTextModel = () => {
|
||||
textModel.value = true;
|
||||
};
|
||||
|
||||
const onConfirmDate = (e) => {
|
||||
if (currentType.value === 'start') {
|
||||
questionInfo.value.survey.startTime = e;
|
||||
questionInfo.value.survey.start_time = e;
|
||||
} else {
|
||||
questionInfo.value.survey.endTime = e;
|
||||
questionInfo.value.survey.end_time = e;
|
||||
}
|
||||
timePickerModel.value = false;
|
||||
};
|
||||
@@ -460,9 +458,10 @@ const questionEvent = (item) => {
|
||||
: []
|
||||
})
|
||||
);
|
||||
|
||||
// 给store 装数据 判断是 push 还是 splice
|
||||
if (activeQuestionIndex.value === -1) {
|
||||
questionInfo.value.questions.push(questionJson);
|
||||
questionInfo.value.questions.splice(questionInfo.value.questions.length + 1, 0, questionJson);
|
||||
} else {
|
||||
questionInfo.value.questions.splice(activeQuestionIndex.value + 1, 0, questionJson);
|
||||
}
|
||||
@@ -470,6 +469,55 @@ const questionEvent = (item) => {
|
||||
questionInfo.value.survey.last_question_index += 1;
|
||||
activeId.value = id;
|
||||
show.value = false;
|
||||
saveQuestionItem(questionJson);
|
||||
};
|
||||
|
||||
// 新增保存增加的一个
|
||||
const saveQuestionItem = (questionJson) => {
|
||||
const query = {
|
||||
sn: route.query.sn,
|
||||
|
||||
data: {
|
||||
logics: questionInfo.value.logics,
|
||||
questions: [questionJson],
|
||||
survey: {
|
||||
local_pages: [],
|
||||
pages: questionInfo.value.questions.map((item) => {
|
||||
return [item.question_index];
|
||||
}),
|
||||
version: Base64.encode(`${new Date().getTime()}`)
|
||||
}
|
||||
}
|
||||
};
|
||||
saveQuestion(query).then(() => {
|
||||
sync({ sn: query.sn });
|
||||
});
|
||||
};
|
||||
|
||||
// 保存设置
|
||||
const saveSetting = (parentKey, childKeys) => {
|
||||
const query = {};
|
||||
settingList.map((item) => {
|
||||
if (item === 'access_password') {
|
||||
query[item] = JSON.stringify(questionInfo.value.survey[item]);
|
||||
} else {
|
||||
query[item] = questionInfo.value.survey[item];
|
||||
}
|
||||
});
|
||||
// 增删 修改 数据结构
|
||||
if (parentKey) {
|
||||
childKeys.map((key) => {
|
||||
query[key] = query[parentKey] === 1 ? query[key] : 0;
|
||||
if (parentKey === 'is_time' && query[parentKey] === 0) {
|
||||
delete query[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
saveSettings({
|
||||
sn: route.query.sn,
|
||||
...query
|
||||
});
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
@@ -478,17 +526,45 @@ const init = () => {
|
||||
};
|
||||
defineExpose({ init });
|
||||
|
||||
// 获取题目象棋
|
||||
// 定义setting 接口返回的数据集和 调用put接口时对比以下
|
||||
|
||||
let settingList = [];
|
||||
// 获取题目相亲
|
||||
|
||||
const getQuestionDetail = () => {
|
||||
return snQuestions({ sn: route.query.sn }).then((res) => {
|
||||
if (res.data) {
|
||||
counterStore.setQuestionInfo(res.data.data);
|
||||
return res.data.data; // 返回数据以便在onMounted中使用
|
||||
questionInfo.value.survey = Object.assign({}, res.data.data.survey);
|
||||
questionInfo.value.questions = res.data.data.questions.map((item) => {
|
||||
return {
|
||||
...item
|
||||
};
|
||||
});
|
||||
questionInfo.value.logics = res.data.data.logics.map((item) => {
|
||||
return {
|
||||
...item
|
||||
};
|
||||
});
|
||||
|
||||
getSetting({ sn: route.query.sn }).then((setting) => {
|
||||
if (setting.data) {
|
||||
// 获取所有的key
|
||||
settingList = Object.keys(setting.data.data);
|
||||
questionInfo.value.survey = Object.assign(questionInfo.value.survey, setting.data.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
const questionInfo = computed(() => store.questionsInfo.value);
|
||||
|
||||
watch(
|
||||
() => questionInfo.value.questions,
|
||||
() => {
|
||||
// questionInfo.value.questions = newVal;
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
onMounted(async () => {
|
||||
await getQuestionDetail(); // 等待接口返回数据
|
||||
});
|
||||
@@ -548,6 +624,10 @@ onMounted(async () => {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
& .desgin {
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
.ques_list {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user