refactor(layout): 优化页面布局和滚动体验

- 在 index.vue 和 redirect.vue 中添加 layout-body 类,用于控制内容区域高度和滚动
- 调整 Publish 和 Survey 组件中的样式,以适应新的布局结构
- 优化部分组件的代码格式和逻辑
This commit is contained in:
陈昱达
2025-03-19 14:45:43 +08:00
parent ae5b36d82e
commit 5387155e06
12 changed files with 187 additions and 172 deletions

View File

@@ -16,8 +16,10 @@
</van-nav-bar> </van-nav-bar>
</header> </header>
<!-- content --> <!-- content -->
<div class="layout-body">
<RouterView /> <RouterView />
</div> </div>
</div>
</template> </template>
<script setup> <script setup>
@@ -35,7 +37,12 @@ function goBack() {
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import '@/assets/css/main';
.common-layout { .common-layout {
overflow: hidden;
height: 100vh;
//background-size: contain; /* 或者使用具体的尺寸,如 100% 100% */ //background-size: contain; /* 或者使用具体的尺寸,如 100% 100% */
//background-position: center; /* 确保图片居中显示 */ //background-position: center; /* 确保图片居中显示 */
//background-repeat: no-repeat; //background-repeat: no-repeat;
@@ -50,6 +57,11 @@ function goBack() {
background-image: url('@/assets/img/home/home-pen.png'); background-image: url('@/assets/img/home/home-pen.png');
} }
.layout-body {
overflow: scroll;
height: calc(100vh - var(--sticky-top-height) - 5px);
}
.header { .header {
position: sticky; position: sticky;
top: 0; top: 0;

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="common-layout"> <div class="common-layout container">
<!-- title 标题和搜索栏 --> <!-- title 标题和搜索栏 -->
<header class="header"> <header class="header">
<van-nav-bar <van-nav-bar
@@ -16,8 +16,10 @@
</van-nav-bar> </van-nav-bar>
</header> </header>
<!-- content --> <!-- content -->
<div class="redirect-body">
<RouterView /> <RouterView />
</div> </div>
</div>
</template> </template>
<script setup> <script setup>
@@ -35,16 +37,28 @@ function goBack() {
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import '@/assets/css/main';
.common-layout { .common-layout {
overflow: hidden;
height: 100vh;
background-color: white; background-color: white;
color: #333; color: #333;
} }
.redirect-body {
overflow: scroll;
height: calc(100vh - var(--sticky-top-height) - 1px);
//padding: 10px 0 0 0;
background: transparent;
}
.header { .header {
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 1000; z-index: 1000;
background-color: #a5d380; background-color: transparent;
.title { .title {
display: flex; display: flex;

View File

@@ -48,14 +48,12 @@ const router = createRouter({
title: '模板' title: '模板'
}, },
component: () => import('../views/Market/Index.vue') component: () => import('../views/Market/Index.vue')
}
]
}, },
{ {
path: '/design', path: '/create',
name: 'design', name: 'create',
meta: {}, meta: { title: '问卷编辑' },
component: Design component: () => import('../views/Survey/views/Create/Index.vue')
}, },
{ {
path: '/preview', path: '/preview',
@@ -65,12 +63,7 @@ const router = createRouter({
}, },
component: () => import('@/views/Survey/views/Preview/Index.vue') component: () => import('@/views/Survey/views/Preview/Index.vue')
}, },
{
path: '/create',
name: 'create',
meta: { title: '问卷编辑' },
component: () => import('../views/Survey/views/Create/Index.vue')
},
{ {
path: '/publish', path: '/publish',
name: 'publish', name: 'publish',
@@ -78,6 +71,14 @@ const router = createRouter({
component: () => import('../views/Survey/views/Publish/Index.vue') component: () => import('../views/Survey/views/Publish/Index.vue')
} }
] ]
},
{
path: '/design',
name: 'design',
meta: {},
component: Design
}
]
}); });
export default router; export default router;

View File

@@ -307,8 +307,8 @@ const getSkipTypeText = (skipType) => {
const ls = []; const ls = [];
logics.map((item) => { logics.map((item) => {
if ( if (
item.skip_type === skipType && item.skip_type === skipType
item.question_index === activeQuestion.value.question_index && item.question_index === activeQuestion.value.question_index
) { ) {
ls.push(item); ls.push(item);
} }

View File

@@ -95,6 +95,7 @@ function create() {
.container-body { .container-body {
padding: 0 10px 80px; padding: 0 10px 80px;
& > :first-child { & > :first-child {
& > div { & > div {
display: flex; display: flex;
@@ -104,6 +105,7 @@ function create() {
margin: 10px; margin: 10px;
} }
} }
.new_survey { .new_survey {
position: fixed; position: fixed;
bottom: 0; bottom: 0;

View File

@@ -5,10 +5,10 @@ import { snQuestions, saveQuestions } from '@/api/design/index.js';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useCounterStore } from '@/stores/counter'; import { useCounterStore } from '@/stores/counter';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import homePen from '@/assets/img/home/home-pen.png';
// 获取 Store 实例 // 获取 Store 实例
const counterStore = useCounterStore(); const counterStore = useCounterStore();
const store = storeToRefs(counterStore); const store = storeToRefs(counterStore);
import homePen from '@/assets/img/home/home-pen.png';
const router = useRouter(); const router = useRouter();
const surveys = ref([]); const surveys = ref([]);

View File

@@ -88,7 +88,7 @@ const deleteItem = (item) => {
}); });
}; };
const setImg = (code) => { const setImg = (code) => {
let text = 'src/assets/img/home/' + code + '.png'; const text = `src/assets/img/home/${code}.png`;
return text; return text;
}; };

View File

@@ -272,7 +272,7 @@ onMounted(() => {
.survey-search { .survey-search {
position: sticky; position: sticky;
top: var(--sticky-top-height); top: 0;
z-index: 1000; z-index: 1000;
width: 100%; width: 100%;
padding: 0; padding: 0;

View File

@@ -1,18 +1,5 @@
<template> <template>
<div class="container"> <div class="">
<van-nav-bar
:border="false"
class="navbar-header"
:title="surveyTitle"
left-text=""
left-arrow
@click-left="$router.go(-1)"
>
<template #left>
<van-icon name="left-long" class-prefix="mobilefont" size="18" style="color: #fff" />
</template>
</van-nav-bar>
<div class="question-title flex space-between"> <div class="question-title flex space-between">
<div class="title-left"> <div class="title-left">
<!--问卷标题--> <!--问卷标题-->
@@ -370,7 +357,6 @@ const currentDate = ref();
const currentType = ref(); const currentType = ref();
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const surveyTitle = route.meta.title as string;
const show = ref(false); const show = ref(false);
// const textModel = ref(false); // const textModel = ref(false);
const activeId = ref(0); const activeId = ref(0);

View File

@@ -1,5 +1,5 @@
<template> <template>
<layout /> <!-- <layout />-->
<div ref="scrollbar" class="preview-container"> <div ref="scrollbar" class="preview-container">
<!-- <van-nav-bar :title="getDomString(questionsData?.survey?.title)" left-arrow />--> <!-- <van-nav-bar :title="getDomString(questionsData?.survey?.title)" left-arrow />-->
@@ -529,7 +529,6 @@ import PreviewMatrixText from '@/views/Survey/views/Preview/components/questions
import PreviewNPS from '@/views/Survey/views/Preview/components/questions/PreviewNPS.vue'; import PreviewNPS from '@/views/Survey/views/Preview/components/questions/PreviewNPS.vue';
import msg from './js/message'; import msg from './js/message';
import answerMock from '@/views/Survey/views/Preview/js/mock.js'; import answerMock from '@/views/Survey/views/Preview/js/mock.js';
import Layout from '@/layouts/redirect.vue';
// const isPreview = ref(true); // const isPreview = ref(true);
// hooks file // hooks file
@@ -670,9 +669,9 @@ async function answer(callback, callbackBeforePage) {
question.error = translatedText.value.ThisIsARequiredQuestion; question.error = translatedText.value.ThisIsARequiredQuestion;
} }
} else if ( } else if (
answer answer &&
&& questionType === 1 questionType === 1 &&
&& Object.keys(answer).findIndex((value) => !answer[value]) !== -1 Object.keys(answer).findIndex((value) => !answer[value]) !== -1
) { ) {
// 单选题 // 单选题
isError = true; isError = true;
@@ -852,16 +851,16 @@ async function answer(callback, callbackBeforePage) {
// eslint-disable-next-line // eslint-disable-next-line
const reg = const reg =
/^[a-zA-Z·~@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]]+$/; /^[a-zA-Z·~@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]]+$/;
isError isError =
= config.include_mark === 1 config.include_mark === 1
? !reg.test(newValue) || !newValue.length ? !reg.test(newValue) || !newValue.length
: !/^[a-zA-Z]+$/.test(newValue) || !newValue.length; : !/^[a-zA-Z]+$/.test(newValue) || !newValue.length;
question.error = isError ? translatedText.value.PleaseEnterEnglishLetters : ''; question.error = isError ? translatedText.value.PleaseEnterEnglishLetters : '';
break; break;
// 中文 // 中文
case 4: case 4:
isError isError =
= config.include_mark === 1 config.include_mark === 1
? !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|[a-zA-Z·~@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]])+$/.test( ? !/^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|[a-zA-Z·~@#¥%…&*()—\-+={}|《》?:“”【】、;‘’,。`!$^()_<>?:",./;'\\[\]])+$/.test(
newValue newValue
) || !newValue.length ) || !newValue.length
@@ -872,8 +871,8 @@ async function answer(callback, callbackBeforePage) {
break; break;
// 邮箱 // 邮箱
case 5: case 5:
isError isError =
= !/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test( !/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(
value value
); );
question.error = isError ? translatedText.value.PleaseEnterACorrectEmail : ''; question.error = isError ? translatedText.value.PleaseEnterACorrectEmail : '';
@@ -885,8 +884,8 @@ async function answer(callback, callbackBeforePage) {
break; break;
// 身份证号 // 身份证号
case 7: case 7:
isError isError =
= !/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test( !/^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/.test(
value value
); );
question.error = isError ? translatedText.value.PleaseEnterACorrectID : ''; question.error = isError ? translatedText.value.PleaseEnterACorrectID : '';
@@ -1028,14 +1027,14 @@ async function answer(callback, callbackBeforePage) {
currentQuestions.forEach((question, index) => { currentQuestions.forEach((question, index) => {
if (index >= warnStart && index < warnEnd) { if (index >= warnStart && index < warnEnd) {
if (repeat.repeat_type) { if (repeat.repeat_type) {
question.warning question.warning =
= translatedText.value.TheAnswerIsRepeatedMoreThanOneTimesPleaseRevise( translatedText.value.TheAnswerIsRepeatedMoreThanOneTimesPleaseRevise(
repeat.allow_repeat_num, repeat.allow_repeat_num,
repeat.repeat_type repeat.repeat_type
); );
} else { } else {
question.error question.error =
= translatedText.value.TheAnswerIsRepeatedMoreThanOneTimesPleaseRevise( translatedText.value.TheAnswerIsRepeatedMoreThanOneTimesPleaseRevise(
repeat.allow_repeat_num, repeat.allow_repeat_num,
repeat.repeat_type repeat.repeat_type
); );
@@ -1382,8 +1381,8 @@ function updateAnswer(auto) {
const evt1 = {}; const evt1 = {};
if ([1].includes(question.question_type)) { if ([1].includes(question.question_type)) {
evt1.value evt1.value =
= Object.keys(question.answer) Object.keys(question.answer)
.map((key) => (question.answer[key] ? key : undefined)) .map((key) => (question.answer[key] ? key : undefined))
.filter((i) => !!i)?.[0] || undefined; .filter((i) => !!i)?.[0] || undefined;
evt1.options = question.list.flatMap((i) => i.options); evt1.options = question.list.flatMap((i) => i.options);

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="container"> <div class="">
<layout /> <!-- <layout />-->
<div class="content"> <div class="content">
<div v-if="status === 1" inset> <div v-if="status === 1" inset>
<div> <div>
@@ -42,7 +42,6 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import layout from '@/layouts/index.vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { onMounted, reactive, ref, watch } from 'vue'; import { onMounted, reactive, ref, watch } from 'vue';
import { showFailToast, showToast } from 'vant'; import { showFailToast, showToast } from 'vant';
@@ -121,7 +120,11 @@ function copyLink() {
function shareLink() { function shareLink() {
const params = { const params = {
type: 'shareToWx', type: 'shareToWx',
title: surveyTitle.value || (publishInfo.value.download_url.title ? publishInfo.value.download_url.title.replace(/_发布二维码\.[a-zA-Z]+$/, '') : ''), title:
surveyTitle.value ||
(publishInfo.value.download_url.title
? publishInfo.value.download_url.title.replace(/_发布二维码\.[a-zA-Z]+$/, '')
: ''),
description: publishInfo.value.desc || '填写问卷', description: publishInfo.value.desc || '填写问卷',
thumbImageUrl: publishInfo.value.img_url, thumbImageUrl: publishInfo.value.img_url,
webpageUrl: publishInfo.value.url, webpageUrl: publishInfo.value.url,
@@ -199,9 +202,6 @@ onMounted(async() => {
<style scoped lang="scss"> <style scoped lang="scss">
.container { .container {
height: 100vh;
background: linear-gradient(to bottom, #70b937 5.3rem, #f2f2f2 8rem);
button { button {
padding: 3px 20px; padding: 3px 20px;
border: none; border: none;
@@ -210,7 +210,8 @@ onMounted(async() => {
.content { .content {
margin: 10px; margin: 10px;
padding-bottom: 30px;
//padding-bottom: 30px;
border-radius: 8px; border-radius: 8px;
background: #fff; background: #fff;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.1); box-shadow: 0 0 2px rgba(0, 0, 0, 0.1);