feat: 问卷功能开发

This commit is contained in:
duanshuwen
2026-01-30 22:38:24 +08:00
parent 5c3bcc4fef
commit c19f129a9c
10 changed files with 223 additions and 109 deletions

View File

@@ -2,7 +2,7 @@
VITE_ENV = development VITE_ENV = development
# vconsole开关控制器 # vconsole开关控制器
VITE_CONSOLE = 1 VITE_CONSOLE = 0
# 接口地址 # 接口地址
VITE_BASE_API = http://8.138.234.141/ingress/hotelBiz VITE_BASE_API = http://8.138.234.141/ingress/hotelBiz

View File

@@ -1,7 +1,7 @@
// .preitterrc.js // .preitterrc.js
module.exports = { module.exports = {
// 一行的字符数如果超过会进行换行默认为80 // 一行的字符数如果超过会进行换行默认为80
printWidth: 80, printWidth: 200,
// 一个tab代表几个空格数默认为80 // 一个tab代表几个空格数默认为80
tabWidth: 2, tabWidth: 2,
// 是否使用tab进行缩进默认为false表示用空格进行缩减 // 是否使用tab进行缩进默认为false表示用空格进行缩减
@@ -11,7 +11,7 @@ module.exports = {
// 行位是否使用分号默认为true // 行位是否使用分号默认为true
semi: false, semi: false,
// 是否使用尾逗号,有三个可选值"<none|es5|all>" // 是否使用尾逗号,有三个可选值"<none|es5|all>"
trailingComma: "none", trailingComma: 'none',
// 对象大括号直接是否有空格默认为true效果{ foo: bar } // 对象大括号直接是否有空格默认为true效果{ foo: bar }
bracketSpacing: true, bracketSpacing: true,
// 代码的解析引擎默认为babylon与babel相同 // 代码的解析引擎默认为babylon与babel相同

View File

@@ -1,20 +1,18 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, viewport-fit=cover, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
<meta name="format-detection" content="telephone=no" />
<meta name="applicable-device" content="mobile" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<title>&lrm;</title>
</head>
<head> <body>
<meta charset="UTF-8" /> <div id="app"></div>
<meta name="viewport" <script type="module" src="/src/main.js"></script>
content="width=device-width, viewport-fit=cover, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" /> <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<meta name="format-detection" content="telephone=no" /> </body>
<meta name="applicable-device" content="mobile" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<title>&lrm;</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html> </html>

View File

@@ -11,7 +11,6 @@
} }
[data-theme='dark'] { [data-theme='dark'] {
&, &,
* { * {
color-scheme: dark !important; color-scheme: dark !important;
@@ -20,7 +19,6 @@
} }
[data-theme='light'] { [data-theme='light'] {
&, &,
* { * {
color-scheme: light !important; color-scheme: light !important;
@@ -54,43 +52,67 @@
} }
} }
.van-safe-area-top { .flex {
padding-top: var(--safe-area-inset-top) !important; display: flex;
} }
.van-image-preview__index, .item-center {
.van-image-preview__close-icon--top-right { align-items: center;
top: 46px !important;
} }
// 表单样式 .justify-center {
.van-field__error-message { justify-content: center;
text-align: right !important;
} }
.van-hairline--top-bottom:after, .mb-12 {
.van-hairline-unset--top-bottom:after { margin-bottom: 12px;
border-width: 0 !important;
} }
// 弹窗样式 .m-16 {
.van-dialog { margin: 16px;
width: 270px !important;
} }
.van-dialog__confirm, .mb-30 {
.van-dialog__confirm:active { margin-bottom: 30px;
color: #14b498 !important;
} }
.van-dialog__content--isolated { .van-cell-group__title {
min-height: 72px !important; color: #333 !important;
} }
.van-dialog__message { .fz-14 {
color: #333333; font-size: 14px;
font-size: 17px !important; }
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600; .fz-26 {
line-height: 24px !important; font-size: 26px;
}
.color-66 {
color: #666;
}
.line-height-21 {
line-height: 21px;
}
.text-center {
text-align: center;
}
.round-100 {
background-color: #1989fa;
border-radius: 100%;
}
.w-100 {
width: 100px;
}
.w-200 {
width: 200px;
}
.h-100 {
height: 100px;
} }

View File

@@ -1,7 +1,6 @@
<template> <template>
<div class="page-container" :style="{ backgroundColor: bgColor }"> <div class="page-container" :style="{ backgroundColor: bgColor }">
<van-nav-bar :class="['nav-bar', navBgColor, isCustom ? 'custom-style' : '']" safe-area-inset-top left-arrow fixed <van-nav-bar class="nav-bar" safe-area-inset-top left-arrow :border="false" @click-left="handleBack">
v-if="showNavigator" :border="false" :left-text="navBarLeftText" @click-left="handleBack">
<template #title> <template #title>
<slot name="title">{{ title === '首页' ? '' : metaTitle }}</slot> <slot name="title">{{ title === '首页' ? '' : metaTitle }}</slot>
</template> </template>
@@ -87,45 +86,34 @@ const handleBack = () => {
<style scoped lang="scss"> <style scoped lang="scss">
.page-container { .page-container {
height: 100vh; height: 100vh;
overflow-y: auto;
background-color: white; background-color: white;
padding-bottom: var(--safe-area-inset-bottom); padding-bottom: var(--safe-area-inset-bottom);
display: flex;
flex-direction: column;
}
.body { .nav-bar {
min-height: calc(100vh - 46px + var(--safe-area-inset-top)); :deep(.van-icon-arrow-left) {
padding-top: calc(46px + var(--safe-area-inset-top)); color: #333;
overflow-y: auto; font-size: 20px;
&::-webkit-scrollbar {
display: none;
}
} }
.nav-bar { :deep(.van-nav-bar__title) {
background-color: transparent; color: #333;
z-index: 2000; font-size: 18px;
position: fixed; font-weight: bold;
line-height: 22px;
opacity: 1;
}
}
:deep(.van-icon-arrow-left) { .body {
color: #333; flex: 1;
font-size: 20px; overflow-y: auto;
} padding: 0 12px;
:deep(.van-nav-bar__title) { &::-webkit-scrollbar {
color: #333; display: none;
font-size: 18px;
font-weight: bold;
line-height: 22px;
opacity: 1;
}
&.custom-style {
background-color: rgba(22, 187, 191, 1);
:deep(.van-icon-arrow-left) {
color: #fff;
}
}
} }
} }
</style> </style>

View File

@@ -7,6 +7,8 @@ import store from '@/store'
import Layout from '@/components/Layout.vue' import Layout from '@/components/Layout.vue'
import 'vant/lib/index.css'
const app = createApp(App) const app = createApp(App)
app.config.globalProperties.$store = store app.config.globalProperties.$store = store

View File

@@ -10,6 +10,15 @@ const routes = [
title: '问卷调查', // 自动设置当前页面的标题 title: '问卷调查', // 自动设置当前页面的标题
keepAlive: true keepAlive: true
} }
},
{
path: '/result',
name: 'result', // 请和文件名一样
component: () => import('@/views/result/index.vue'),
meta: {
title: '问卷调查结果', // 自动设置当前页面的标题
keepAlive: true
}
} }
] ]

View File

@@ -2,15 +2,59 @@
<Layout> <Layout>
<template #title>{{ questionnaire.title }}</template> <template #title>{{ questionnaire.title }}</template>
<div class="list"> <van-form @submit="onSubmit">
{{ questionnaire.questions }} <van-cell-group :title="`${index + 1}. ${item.question}`" v-for="(item, index) in questionnaire.questions"
</div> :key="item.id">
<!-- 单选框 -->
<van-field v-if="item.type === 'radio'" name="radio">
<template #input>
<van-radio-group v-model="item.answer">
<van-radio v-for="(option, index) in item.options" :key="item.id + index" :name="option.id" class="mb-12">
{{ option.text }}
</van-radio>
</van-radio-group>
</template>
</van-field>
<!-- 复选框 -->
<van-field v-if="item.type === 'checkbox'" name="checkboxGroup">
<template #input>
<van-checkbox-group v-model="item.answer" shape="square">
<van-checkbox v-for="(option, index) in item.options" :key="item.id + index" :name="option.id"
class="mb-12">
{{ option.text }}
</van-checkbox>
</van-checkbox-group>
</template>
</van-field>
<!-- 输入框 -->
<van-field v-if="item.type === 'text'" v-model="item.answer" placeholder="请填写内容" />
<!-- 文本域 -->
<van-field v-if="item.type === 'textarea'" type="textarea" v-model="item.answer" placeholder="请填写内容"
maxlength="100" show-word-limit />
</van-cell-group>
<div class="m-16">
<van-button round block type="primary" native-type="submit">
提交
</van-button>
</div>
</van-form>
</Layout> </Layout>
</template> </template>
<script setup name="home"> <script setup name="home">
import { getSurveyQuestionnaireUsingGet } from '@api' import { getSurveyQuestionnaireUsingGet, submitSurveyQuestionnaireAnswerUsingPost } from '@api'
const router = useRouter() import { showToast } from 'vant';
const form = ref({
surveyId: '',
answers: []
})
// 跳转按钮操作 // 跳转按钮操作
const handleClick = () => { const handleClick = () => {
@@ -19,17 +63,45 @@ const handleClick = () => {
const questionnaire = ref({}) const questionnaire = ref({})
const getQuestionnaire = async () => { const getQuestionnaire = async () => {
questionnaire.value = await getSurveyQuestionnaireUsingGet({}) const res = await getSurveyQuestionnaireUsingGet({})
questionnaire.value = {
surveyId: res.id,
title: res.title,
questions: res.questions.map((item) => ({
...item,
answer: item.type === 'checkbox' ? [] : ''
}))
}
} }
onMounted(() => { onMounted(() => getQuestionnaire())
console.log('onMounted')
getQuestionnaire() const router = useRouter()
}) const onSubmit = async () => {
// 验证表单
if (questionnaire.value.questions.some((item) => !item.answer)) {
showToast('请填写完整')
return
}
form.value.surveyId = questionnaire.value.surveyId
form.value.answers = questionnaire.value.questions.map((item) => ({
questionId: item.id,
answer: item.type === 'checkbox' ? item.answer.join(',') : item.answer
}))
console.log('onSubmit', form.value)
const res = await submitSurveyQuestionnaireAnswerUsingPost({ body: form.value })
if (res) {
getQuestionnaire()
form.value.surveyId = ''
form.value.answers = []
router.push({ name: 'result' })
}
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped></style>
section {
padding: 20px;
}
</style>

View File

@@ -0,0 +1,35 @@
<template>
<section>
<div class="round-100 h-100 w-100 flex item-center justify-center mb-30">
<van-icon name="success" color="#fff" size="70" />
</div>
<div class="fz-26 mb-12">提交成功</div>
<div class="color-66 fz-14 line-height-21 mb-12 text-center mb-30">感谢您参与息烽南山天沐温泉的客户调研问卷, 您的宝贵意见将帮助我们不断提升服务质量,
请凭此截图于前台兑换精美礼品一份!
</div>
<van-button class="fz-14 w-200" round block type="primary" @click="handleClick">
完成
</van-button>
</section>
</template>
<script setup>
const handleClick = () => {
// 确保在wx.ready中调用
wx.ready(() => {
// 关闭当前H5页面
wx.miniProgram.navigateBack({});
});
}
</script>
<style lang="scss" scoped>
section {
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 100px 30px 0;
}
</style>

View File

@@ -43,18 +43,6 @@ export default defineConfig(({ mode }) => {
// dts: 'src/auto-imports...', // 可以自定义文件生成的位置与是否生成,默认是根目录下 // dts: 'src/auto-imports...', // 可以自定义文件生成的位置与是否生成,默认是根目录下
dts: false dts: false
}), }),
createStyleImportPlugin({
resolves: [VantResolve()],
libs: [
{
libraryName: 'vant',
esModule: false,
resolveStyle: (name) => {
return `vant/es/${name}/style`
}
}
]
}),
viteVConsole({ viteVConsole({
entry: [resolve('src/main.js')], entry: [resolve('src/main.js')],
localEnabled: isVconsole, localEnabled: isVconsole,