feat(survey): 优化创建问卷页面功能和样式

- 添加题目按钮移至 Design 组件内部- 实现保存、投放和预览功能
- 优化问卷标题和投放设置样式
- 添加每页一题设置保存功能
- 调整问卷列表样式
This commit is contained in:
陈昱达
2025-03-12 10:18:37 +08:00
parent 4d34c293b8
commit 03698d975a
9 changed files with 113 additions and 91 deletions

View File

@@ -3,6 +3,16 @@
@import 'vant'; @import 'vant';
@import '../../fonts/moblie/iconfont.css'; @import '../../fonts/moblie/iconfont.css';
$theme-color: #70b936;
::v-deep .theme-color {
color: $theme-color;
}
::v-deep .theme-back-color {
background-color: $theme-color;
}
a, a,
.green { .green {
padding: 3px; padding: 3px;

View File

@@ -167,8 +167,8 @@ const getMaxDateLimit = computed(() => {
props.format props.format
); );
const tempStr = '0000-12-31 23:59:59'; const tempStr = '0000-12-31 23:59:59';
const result = const result
props.maxDate.length !== 0 && thisMax.length > props.maxDate.length = props.maxDate.length !== 0 && thisMax.length > props.maxDate.length
? thisMax.slice(0, props.maxDate.length) + tempStr.slice(props.maxDate.length) ? thisMax.slice(0, props.maxDate.length) + tempStr.slice(props.maxDate.length)
: thisMax; : thisMax;
return result.slice(0, props.format.length); return result.slice(0, props.format.length);
@@ -191,8 +191,8 @@ function onChange({ selectedValues, columnIndex }) {
renderMinuteColumns, renderMinuteColumns,
renderSecondColumns renderSecondColumns
]; ];
updateColumns[columnIndex] && updateColumns[columnIndex]
updateColumns[columnIndex](changeValue, getMinDateLimit.value, getMaxDateLimit.value, false); && updateColumns[columnIndex](changeValue, getMinDateLimit.value, getMaxDateLimit.value, false);
} }
// 渲染全部列 // 渲染全部列

View File

@@ -134,6 +134,7 @@ onMounted(() => {
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: 2008; z-index: 2008;
display: flex;
width: 100%; width: 100%;
height: 40px; height: 40px;
padding: 0 10px; padding: 0 10px;

View File

@@ -1,4 +1,4 @@
import './assets/css/main.scss'; import '@/assets/css/main.scss';
import 'amfe-flexible'; import 'amfe-flexible';
import { createApp } from 'vue'; import { createApp } from 'vue';
import { createPinia } from 'pinia'; import { createPinia } from 'pinia';

12
src/utils/public.js Normal file
View File

@@ -0,0 +1,12 @@
// 根据是否是每页一体 处理成不同的结构类型
export function getPages(questions, isOnePageOneQuestion) {
const pages = [];
questions.map((item) => {
if (isOnePageOneQuestion === 1) {
pages.push([item.question_index]);
} else {
pages.push(item.question_index);
}
});
return isOnePageOneQuestion === 1 ? pages : [pages];
}

View File

@@ -15,6 +15,7 @@
:index="index" :index="index"
:chooseQuestionId="chooseQuestionId" :chooseQuestionId="chooseQuestionId"
@get-choose-question-id="getChooseQuestionId" @get-choose-question-id="getChooseQuestionId"
@move="emitFun.move"
> >
<!-- 选择题 --> <!-- 选择题 -->
<Choice <Choice
@@ -103,6 +104,8 @@
</div> </div>
</template> </template>
</choose-question> </choose-question>
<!-- 增加控制按钮-->
<slot name="button" :item="element"></slot>
<!-- {{ element.question_type }}--> <!-- {{ element.question_type }}-->
<!-- {{questionInfo.survey.pages.length}}--> <!-- {{questionInfo.survey.pages.length}}-->
@@ -295,6 +298,14 @@ const actionFun = {
} }
}; };
// emit 事件
const emitFun = {
move: (ev) => {
console.log(ev);
}
};
onMounted(() => { onMounted(() => {
questionInfo.value = store.questionsInfo.value; questionInfo.value = store.questionsInfo.value;
}); });

View File

@@ -158,6 +158,8 @@ const deleteQuestion = () => {
}); });
}; };
// emit
const emit = defineEmits(['move', 'copy']);
// 打开题目弹窗 // 打开题目弹窗
const openQuestionActionModel = () => { const openQuestionActionModel = () => {
show.value = true; show.value = true;
@@ -166,6 +168,7 @@ const openQuestionActionModel = () => {
const openQuestionSettingModel = () => { const openQuestionSettingModel = () => {
questionShow.value = true; questionShow.value = true;
}; };
// 题目上下移动 // 题目上下移动
const questionMove = (action) => { const questionMove = (action) => {
if (action.action === 'down') { if (action.action === 'down') {
@@ -175,6 +178,8 @@ const questionMove = (action) => {
const temp = questions.value[props.questionIndex]; const temp = questions.value[props.questionIndex];
questions.value.splice(props.questionIndex, 1); questions.value.splice(props.questionIndex, 1);
questions.value.splice(props.questionIndex + 1, 0, temp); questions.value.splice(props.questionIndex + 1, 0, temp);
emit('move', 'down');
} else if (action.action === 'up') { } else if (action.action === 'up') {
if (props.questionIndex === 0) { if (props.questionIndex === 0) {
return; return;
@@ -182,6 +187,7 @@ const questionMove = (action) => {
const temp = questions.value[props.questionIndex]; const temp = questions.value[props.questionIndex];
questions.value.splice(props.questionIndex, 1); questions.value.splice(props.questionIndex, 1);
questions.value.splice(props.questionIndex - 1, 0, temp); questions.value.splice(props.questionIndex - 1, 0, temp);
emit('move', 'up');
} else { } else {
// 复制 题目 生成新的id 更新最新的 last index // 复制 题目 生成新的id 更新最新的 last index
const temp = questions.value[props.questionIndex]; const temp = questions.value[props.questionIndex];
@@ -191,6 +197,7 @@ const questionMove = (action) => {
question_index: questionsInfo.value.survey.last_question_index + 1 question_index: questionsInfo.value.survey.last_question_index + 1
}); });
questionsInfo.value.survey.last_question_index += 1; questionsInfo.value.survey.last_question_index += 1;
emit('copy', 'down');
} }
}; };

View File

@@ -17,20 +17,10 @@
v-model:data="element" v-model:data="element"
:questions="questions" :questions="questions"
:questionIndex="index" :questionIndex="index"
@move="emit('move', $event)"
@copy="emit('copy', $event)"
></question-action> ></question-action>
</template> </template>
<!-- <div-->
<!-- v-for="item in questionAction"-->
<!-- :key="item.key"-->
<!-- class=""-->
<!-- :class="item.class ? item.class : ''"-->
<!-- @click="itemAction(item)"-->
<!-- >-->
<!-- <i class="icon iconfont choose-question-active-container-icon" v-html="item.icon"></i>-->
<!-- <div class="choose-question-active-container-name">-->
<!-- {{ item.name }}-->
<!-- </div>-->
<!-- </div>-->
</van-cell> </van-cell>
</div> </div>
</div> </div>
@@ -59,70 +49,14 @@ const props = defineProps({
} }
}); });
const element = ref(props.element); const element = ref(props.element);
// 选中题目后出现的操作 // 选中题目后出现的操作
// const questionAction = ref([ const emit = defineEmits(['getChooseQuestionId', 'move', 'copy']);
// {
// icon: '&#xe630;',
// name: '编辑',
// key: 'edit',
// class: ''
// },
// {
// icon: '&#xe632;',
// name: '复制',
// key: 'copy',
// class: ''
// },
// {
// icon: '&#xe6a0;',
// name: '移动',
// key: 'moveUp',
// class: 'moverQues'
// },
// // {
// // icon:'',
// // name:'下移',
// // key:'moveDown',
// // class:''
// // },
// {
// icon: '&#xe63f;',
// name: '删除',
// key: 'delete',
// class: ''
// }
// ]);
const emit = defineEmits(['getChooseQuestionId']);
// 选中题目 // 选中题目
const chooseItem = () => { const chooseItem = () => {
// 使用从 defineProps 接收的 element 对象 // 使用从 defineProps 接收的 element 对象
emit('getChooseQuestionId', props.element); emit('getChooseQuestionId', props.element);
}; };
// const itemAction = (item) => {
// switch (item.key) {
// case 'edit':
// // vue router跳转到/edit
//
// router.push({
// path: '/design/edit',
// query: {
// id: props.element.id
// }
// });
// break;
// case 'copy':
// break;
// case 'moveUp':
// break;
// case 'moveDown':
// break;
// case 'delete':
// break;
// }
// };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.choose-question-container { .choose-question-container {

View File

@@ -25,17 +25,23 @@
></contenteditable> ></contenteditable>
</div> </div>
<button v-if="questionInfo.questions.length === 0" @click="show = true">添加题目</button> <van-button v-if="questionInfo.questions.length === 0" size="small" @click="show = true">
添加题目
</van-button>
</div> </div>
</van-cell-group> </van-cell-group>
<div class="ques"> <div class="ques">
<!-- 题目--> <!-- 题目-->
<Design <Design :active-id="activeId" class="design" @get-active-question="getActiveQuestion">
:active-id="activeId" <template #button="{ item }">
class="desgin" <div class="design-button">
@get-active-question="getActiveQuestion" <van-button v-if="activeId === item.id" size="small" @click="show = true">
></Design> 添加题目
</van-button>
</div>
</template>
</Design>
<!-- <van-button @click="show = true">添加题目</van-button>--> <!-- <van-button @click="show = true">添加题目</van-button>-->
<!-- 弹出的新增题目弹窗--> <!-- 弹出的新增题目弹窗-->
<van-popup <van-popup
@@ -74,9 +80,9 @@
<span>投放设置</span> <span>投放设置</span>
</div> </div>
<div class="survey-action_btn"> <div class="survey-action_btn">
<van-button size="small">预览</van-button> <van-button size="small" @click="previewQuestion">预览</van-button>
<van-button size="small">保存</van-button> <van-button size="small" @click="saveAs">保存</van-button>
<van-button size="small" @click="$router.push({ name: 'publish' })">投放</van-button> <van-button size="small" @click="publishQuestion">投放</van-button>
</div> </div>
</div> </div>
</div> </div>
@@ -96,6 +102,7 @@
size="0.5rem" size="0.5rem"
:active-value="1" :active-value="1"
:inactive-value="0" :inactive-value="0"
@change="saveIsOnePage"
></van-switch> ></van-switch>
</template> </template>
</van-cell> </van-cell>
@@ -302,8 +309,9 @@ import {
signQuestion, signQuestion,
nps nps
} from '@/utils/importJsons'; } from '@/utils/importJsons';
import { useRoute } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import YLPicker from '@/components/YLPicker.vue'; import YLPicker from '@/components/YLPicker.vue';
import { getPages } from '@/utils/public';
// 获取 Store 实例 // 获取 Store 实例
const counterStore = useCounterStore(); const counterStore = useCounterStore();
@@ -314,6 +322,7 @@ const activeQuestionIndex = ref(-1);
const currentDate = ref(); const currentDate = ref();
const currentType = ref(); const currentType = ref();
const route = useRoute(); const route = useRoute();
const router = useRouter();
const surveyTitle = route.meta.title as string; const surveyTitle = route.meta.title as string;
const show = ref(false); const show = ref(false);
// const textModel = ref(false); // const textModel = ref(false);
@@ -344,6 +353,7 @@ const onConfirmDate = (e) => {
// 获取选中的题目 // 获取选中的题目
const getActiveQuestion = (activeQues) => { const getActiveQuestion = (activeQues) => {
chooseQuestionId.value = activeQues.id; chooseQuestionId.value = activeQues.id;
activeId.value = activeQues.id;
// 在questions 里 查找index 给 activeQuestionIndex // 在questions 里 查找index 给 activeQuestionIndex
questionInfo.value.questions.forEach((item, index) => { questionInfo.value.questions.forEach((item, index) => {
if (item.id === activeQues.id) { if (item.id === activeQues.id) {
@@ -482,9 +492,10 @@ const saveQuestionItem = (questionJson) => {
questions: [questionJson], questions: [questionJson],
survey: { survey: {
local_pages: [], local_pages: [],
pages: questionInfo.value.questions.map((item) => { pages: getPages(
return [item.question_index]; questionInfo.value.questions,
}), questionInfo.value.survey.is_one_page_one_question
),
version: Base64.encode(`${new Date().getTime()}`) version: Base64.encode(`${new Date().getTime()}`)
} }
} }
@@ -520,6 +531,13 @@ const saveSetting = (parentKey, childKeys) => {
}); });
}; };
// 保存是否每页一题
const saveIsOnePage = () => {
questionDetails({
sn: route.query.sn,
is_one_page_one_question: questionInfo.value.survey.is_one_page_one_question
});
};
const init = () => { const init = () => {
// event.detail 为当前输入的值 // event.detail 为当前输入的值
show.value = true; show.value = true;
@@ -565,6 +583,20 @@ watch(
}, },
{ deep: true } { deep: true }
); );
// 保存 目前没有任何逻辑可以执行所有保存
const saveAs = () => {
// 保存所有
};
// 投放
const publishQuestion = () => {
router.push({ name: 'publish', query: { ...route.query } });
};
// 预览
const previewQuestion = () => {
router.push({ name: 'preview', query: { ...route.query } });
};
onMounted(async () => { onMounted(async () => {
await getQuestionDetail(); // 等待接口返回数据 await getQuestionDetail(); // 等待接口返回数据
}); });
@@ -598,8 +630,10 @@ onMounted(async () => {
& > button { & > button {
margin: 20px; margin: 20px;
border-radius: 10px;
background-color: lightgreen; //border-radius: 10px;
background-color: #70b936;
color: #fff;
} }
} }
} }
@@ -624,8 +658,21 @@ onMounted(async () => {
font-size: 16px; font-size: 16px;
} }
& .desgin { & .design {
padding-bottom: 50px; padding-bottom: 60px;
& .design-button {
width: 100%;
text-align: center;
::v-deep .van-button {
background-color: #70b936;
//width: 140px;
color: #fff;
font-size: 12px;
}
}
} }
.ques_list { .ques_list {