feat(home): 新增创建问卷功能并优化首页样式

- 新增 CreateQuestion 组件,用于创建新问卷
- 在首页添加创建问卷入口
- 优化首页样式,调整背景图显示方式
- 在 QuestionAction 组件中添加题目移动逻辑
This commit is contained in:
陈昱达
2025-03-19 11:19:34 +08:00
parent 3cc345c21f
commit b6cb171e26
5 changed files with 269 additions and 33 deletions

3
components.d.ts vendored
View File

@@ -11,7 +11,6 @@ declare module 'vue' {
ElInput: typeof import('element-plus/es')['ElInput']
ElOption: typeof import('element-plus/es')['ElOption']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElText: typeof import('element-plus/es')['ElText']
RichText: typeof import('./src/components/RichText.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
@@ -35,6 +34,8 @@ declare module 'vue' {
VanRow: typeof import('vant/es')['Row']
VanStepper: typeof import('vant/es')['Stepper']
VanSwitch: typeof import('vant/es')['Switch']
VanTab: typeof import('vant/es')['Tab']
VanTabs: typeof import('vant/es')['Tabs']
YLCascader: typeof import('./src/components/YLCascader.vue')['default']
YLInput: typeof import('./src/components/YLInput.vue')['default']
YLPicker: typeof import('./src/components/YLPicker.vue')['default']

View File

@@ -144,7 +144,7 @@
<script setup>
import checkboxQuestionAction from './components/QuestionItemAction/CheckboxQuestionAction.vue';
import { showConfirmDialog } from 'vant';
import { toRefs, ref } from 'vue';
import { toRefs, ref, watch } from 'vue';
import QuestionBefore from '@/views/Design/components/ActionCompoents/components/QuestionItemAction/QuestionBefore.vue';
import RateQuestionAction from './components/QuestionItemAction/RateQuestionAction.vue';
import CompletionQuestionAction from '@/views/Design/components/ActionCompoents/components/QuestionItemAction/CompletionQuestionAction.vue';
@@ -171,15 +171,15 @@ const props = defineProps({
questions: {
type: Array,
default: () => []
},
questionIndex: {
type: Number,
default: 0
}
});
const { questionsInfo } = toRefs(props);
const logics = questionsInfo.value.logics;
const questions = ref(props.questions);
const questionIndex = defineModel('questionIndex', {
type: Number,
default: 0
});
// emit
const emit = defineEmits(['move', 'copy', 'delete', 'setting', 'logics']);
@@ -197,11 +197,11 @@ const activeQuestion = ref(props.data);
const show = ref(false);
const questionShow = ref(false);
const questionBeforeShow = ref(false);
const actions = [
const actions = ref([
{ name: '上移题目', action: 'up' },
{ name: '下移题目', action: 'down' },
{ name: '复制题目', action: 'copy' }
];
]);
const deleteQuestion = () => {
showConfirmDialog({
title: '提示',
@@ -209,14 +209,48 @@ const deleteQuestion = () => {
})
.then(() => {
// on confirm
const index = props.questionIndex;
questions.value.splice(props.questionIndex, 1);
const index = questionIndex.value;
questions.value.splice(questionIndex.value, 1);
emit('delete', index);
})
.catch(() => {
// on cancel
});
};
/**
* @name 监听当前题目是否可以移动
* @created_date 2025/3/19
* @description
**/
watch(
() => questionIndex.value,
(newVal) => {
if (newVal === questions.value.length - 1) {
actions.value = [
{ name: '上移题目', action: 'up' },
{ name: '下移题目', action: 'down', disabled: true },
{ name: '复制题目', action: 'copy' }
];
}
if (newVal === 0) {
actions.value = [
{ name: '上移题目', action: 'up', disabled: true },
{ name: '下移题目', action: 'down' },
{ name: '复制题目', action: 'copy' }
];
}
if (newVal > 0 && newVal < questions.value.length - 1) {
actions.value = [
{ name: '上移题目', action: 'up' },
{ name: '下移题目', action: 'down' },
{ name: '复制题目', action: 'copy' }
];
}
},
{
immediate: true
}
);
// 打开题目弹窗
const openQuestionActionModel = () => {
@@ -229,30 +263,38 @@ const openQuestionSettingModel = () => {
// 题目上下移动
const questionMove = (action) => {
if (action.action === 'down') {
if (props.questionIndex === questions.value.length - 1) {
if (questionIndex.value === questions.value.length - 1) {
return;
}
const temp = questions.value[props.questionIndex];
questions.value.splice(props.questionIndex, 1);
questions.value.splice(props.questionIndex + 1, 0, temp);
const temp = questions.value[questionIndex.value];
questions.value.splice(questionIndex.value, 1);
questions.value.splice(questionIndex.value + 1, 0, temp);
emit('move', 'down');
questionIndex.value += 1;
} else if (action.action === 'up') {
if (props.questionIndex === 0) {
if (questionIndex.value === 0) {
actions.value = [
{ name: '上移题目', action: 'up', disabled: true },
{ name: '下移题目', action: 'down' },
{ name: '复制题目', action: 'copy' }
];
questionShow.value = false;
return;
}
const temp = questions.value[props.questionIndex];
questions.value.splice(props.questionIndex, 1);
questions.value.splice(props.questionIndex - 1, 0, temp);
const temp = questions.value[questionIndex.value];
questions.value.splice(questionIndex.value, 1);
questions.value.splice(questionIndex.value - 1, 0, temp);
emit('move', 'up');
} else {
// 复制 题目 生成新的id 更新最新的 last index
const temp = JSON.parse(JSON.stringify(questions.value[props.questionIndex]));
const temp = JSON.parse(JSON.stringify(questions.value[questionIndex.value]));
const newQuestion = {
...temp,
id: uuidv4(),
question_index: questionsInfo.value.survey.last_question_index + 1
};
questions.value.splice(props.questionIndex + 1, 0, newQuestion);
questions.value.splice(questionIndex.value + 1, 0, newQuestion);
questionsInfo.value.survey.last_question_index += 1;
emit('copy', newQuestion);
questionShow.value = false;
@@ -265,8 +307,8 @@ const getSkipTypeText = (skipType) => {
const ls = [];
logics.map((item) => {
if (
item.skip_type === skipType
&& item.question_index === activeQuestion.value.question_index
item.skip_type === skipType &&
item.question_index === activeQuestion.value.question_index
) {
ls.push(item);
}

View File

@@ -2,6 +2,7 @@
import LastSurvey from './components/LastSurvey/Index.vue';
import Market from './components/Market/Index.vue';
import CreateSurvey from './components/CreateSurvey/Index.vue';
import CreateQuestion from './components/CreateSurvey/CreateQuestion.vue';
import { onMounted, ref } from 'vue';
import utils from '@/assets/js/common';
import { getUserInfo } from '@/api/common/index.js';
@@ -10,7 +11,7 @@ import appBridge from '@/assets/js/appBridge';
const contentShow = ref(false);
const show = ref(false);
onMounted(async() => {
onMounted(async () => {
if (appBridge.isInReactNative()) {
const appToken = utils.getSessionStorage('xToken');
getUserInfo(appToken)
@@ -60,7 +61,8 @@ function create() {
</div>
</div>
<van-popup v-model:show="show" round closeable position="bottom">
<CreateSurvey :createdNewPage="true"></CreateSurvey>
<!-- <CreateSurvey :createdNewPage="true"></CreateSurvey>-->
<create-question :createdNewPage="true"></create-question>
</van-popup>
</template>
@@ -96,7 +98,7 @@ function create() {
//background: linear-gradient(0deg, #f5f5f5 0%, #f5f5f5 84%, #a5d380 100%);
&> :first-child {
& > :first-child {
position: relative;
z-index: 10;
@@ -107,7 +109,7 @@ function create() {
//justify-content: space-around;
border-radius: 16px;
&>div {
& > div {
display: flex;
flex-direction: column;
width: 50px;

View File

@@ -0,0 +1,191 @@
<script setup>
import { ref, onMounted } from 'vue';
import { consoleSurveys, getQuestionList, useTemplate } from '@/api/home/index.js';
import { snQuestions, saveQuestions } from '@/api/design/index.js';
import { useRouter } from 'vue-router';
import { useCounterStore } from '@/stores/counter';
import { storeToRefs } from 'pinia';
// 获取 Store 实例
const counterStore = useCounterStore();
const store = storeToRefs(counterStore);
const router = useRouter();
const surveys = ref([]);
const createdNewPage = defineModel('createdNewPage', {
type: Boolean,
default: false
});
const createdQuestion = (item) => {
const query = {
group_id: 0,
source: 1,
project_name: `${item.title}问卷 `,
remarks: '为优化活动服务品质,烦请完成问卷,感谢配合',
scene_code: item.parentCode,
scene_code_info: item.code,
// 很迷茫 模板新增 tag 空数组 非模板 就是k
tags: ''
};
if (createdNewPage.value) {
query.scene_code = item.parentCode;
query.tags = '';
} else {
if (item.sn) {
query.scene_code = null;
query.tags = [];
}
}
// 如果放在了底部 当作新增组件
if (createdNewPage.value) {
consoleSurveys(query).then((res) => {
if (res.data) {
createdApx(res);
}
});
} else {
if (item.sn) {
useTemplate(item.sn, query).then((temp) => {
if (temp.data) {
createdApx(temp);
}
});
} else {
consoleSurveys(query).then((res) => {
if (res.data) {
createdApx(res);
}
});
}
}
};
const createdApx = (res) => {
snQuestions({ sn: res.data.data.sn }).then((ques) => {
if (ques.data) {
ques.data.data.survey.introduction = `<p>为优化活动服务品质,烦请完成问卷,感谢配合!您的反馈至关重要!(此提示语为默认提示语,您可选择自行输入本问卷的提示语)</p>`;
store.questionsInfo.value = ques.data.data;
saveQuestions({
sn: res.data.data.sn,
introduction: ques.data.data.survey.introduction,
title: ques.data.data.survey.title
}).then(() => {
router.push({
path: '/create',
query: {
sn: res.data.data.sn
}
});
});
}
});
};
// 添加获取问卷列表的方法
const getList = () => {
getQuestionList().then((res) => {
if (res.data.code === 0) {
if (res.data.data) {
res.data.data.forEach((item) => {
// if (item.parentCode && item.parentCode === 1) {
surveys.value.push(item);
// }
});
// surveys.value.push({});
}
}
});
};
// 在组件挂载时调用
onMounted(() => {
getList();
});
</script>
<template>
<!-- <div class="home-pen">-->
<!-- <img :src="homePen" alt="" />-->
<!-- </div>-->
<div class="create_survey">
<div class="create_survey_title" style="color: #000; text-align: left">新建问卷</div>
<div class="flex align-center space-between warp">
<div
v-for="survey in surveys"
:key="survey.title"
span="6"
class="survey"
@click="createdQuestion(survey)"
>
<img :src="survey.h5Image" alt="" width="40" />
<span>{{ survey.h5Title }}</span>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.home-pen {
//height: 200px;
position: absolute;
top: -10px;
left: 0;
z-index: 8;
//width: 100%;
background: #fff;
img {
width: 100%;
//height: 200px;
}
}
.create_survey {
overflow: hidden;
//border-radius: 16px;
background: #fff;
//padding: 15px;
color: #000;
.create_survey_title {
margin: 16px;
color: #000;
font-weight: bold;
font-size: 15px;
font-family: PingFangSC, 'PingFang SC';
}
& .warp {
flex-wrap: wrap;
}
}
.survey {
display: flex;
//margin-right: 30px;
flex-direction: column;
align-items: center;
//flex: 1;
width: 25%;
//margin: 0 16px;
text-align: center;
//justify-content: space-around;
span {
margin-top: 8px;
margin-bottom: 18px;
color: #000;
font-weight: 400;
font-size: 0.34rem;
}
}
</style>

View File

@@ -148,7 +148,7 @@ onMounted(() => {
border-radius: 16px;
background-image: url('@/assets/img/home/home-back.png');
background-position: center; /* 确保图片居中显示 */
background-size: contain; /* 或者使用具体的尺寸,如 100% 100% */
background-size: cover; /* 或者使用具体的尺寸,如 100% 100% */
background-repeat: no-repeat;
//padding: 15px;