You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

564 lines
14 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="survey-fill-page">
<image class="cbg" :src="base.imgHost('common_bg.png')"></image>
<!-- 进度条 -->
<view class="progress-bar-container">
<view class="progress-info">
<view class="progress-info-progress">
<u-line-progress :height="10" :percent="progressPercent" :show-percent="false"
active-color="#2018a0"></u-line-progress>
</view>
<text class="progress-text">{{ answeredCount }}/{{ questionList.length }}</text>
</view>
</view>
<view class="survey-container">
<view class="survey-header">
<h1 class="survey-title">{{survey.title||''}}
</h1>
<p class="survey-description">
{{survey.desc||''}}
</p>
</view>
<!-- 问卷头部 -->
<!-- <view class="survey-header">
<view class="survey-header-item">
<view>
<span>课程名称</span>
<span>{{survey.name || ''}}</span>
</view>
<view v-if="!course_id">
<span>课程主题</span>
<span>{{survey.theme || ''}}</span>
</view>
<view v-if="!course_id">
<span>授课老师</span>
<span>{{survey.teacher?survey.teacher.name:''}}</span>
</view>
<view>
<span>授课时间</span>
<span v-if="course_id">{{survey.start_date || ''}} 至 {{survey.end_date || ''}}</span>
<span v-else>{{survey.date}} {{survey.start_time?survey.start_time:''}}-{{survey.end_time?survey.end_time:''}}</span>
</view>
</view>
</view> -->
<!-- 问卷表单 -->
<view class="survey-form">
<view v-for="(q, index) in questionList" :key="q.id" class="question-item">
<view class="question-header">
<view class="question-number">{{ index + 1 }}</view>
<view class="question-title">
<text>{{ q.name }}</text>
<text v-if="q.rule && q.rule.includes('required')" class="required-mark">*</text>
</view>
</view>
<view class="question-content">
<!-- 单选题 -->
<view v-if="q.edit_input === 'radio'">
<u-radio-group wrap v-model="q.value" @change="onValueChange">
<u-radio active-color="#2018a0" v-for="(opt, i) in q.select_item" :key="i"
:name="opt.value">{{ opt.value }}</u-radio>
</u-radio-group>
<u-input v-if="q.allow_input" v-model="q.allow_input_text" type="text"
:placeholder="'请输入'" />
</view>
<!-- 多选题 -->
<view v-if="q.edit_input === 'checkbox'">
<!-- @change="(e)=>{onValueChange(e,q)}" -->
<!-- <u-checkbox-group >
<u-checkbox @change="(e)=>{changeCheck(e,q.select_item)}" v-model="opt.checked" v-for="(opt, i) in q.select_item" :key="i"
:name="opt.value">{{ opt.value }}</u-checkbox>
</u-checkbox-group> -->
<checkbox-group style="display: flex;flex-wrap: wrap;"
@change="(e)=>{onValueChange(e,q)}">
<label style="flex-basis: 100%;margin-bottom:10rpx" v-for="(checkboxitem, checkboxindex) in q.select_item">
<checkbox activeBackgroundColor="#2018a0" :value="checkboxitem.value" :checked="checkboxitem.checked" />
{{checkboxitem.value}}
</label>
</checkbox-group>
<u-input v-if="q.allow_input" v-model="q.allow_input_text" type="text"
:placeholder="'请输入'" />
</view>
<!-- 文本题 -->
<u-input v-if="q.edit_input === 'text'" v-model="q.value" type="text"
:placeholder="q.help||'请输入'" @input="onValueChange" />
<!-- 文本域 -->
<u-input v-if="q.edit_input === 'textarea'" v-model="q.value" type="textarea"
:placeholder="q.help||'请输入'" :maxlength="9999" @input="onValueChange" />
<!-- 评分题 -->
<!-- <u-rate v-if="q.edit_input === 'rating'" v-model="answers[index]" :count="q.select_item.maxRating"
@change="onValueChange"></u-rate> -->
<!-- 量表题 -->
<!-- <view v-if="q.edit_input === 'scale'" class="scale-container">
<text>{{ q.select_item.min }}</text>
<u-slider v-model="answers[index]" :min="q.select_item.min" :max="q.select_item.max"
@end="onValueChange"></u-slider>
<text>{{ answers[index] || q.select_item.min }}</text>
</view> -->
<!-- 日期题 -->
<u-input v-if="q.edit_input === 'date'" v-model="q.value" type="text"
:placeholder="q.help||'请选择日期'" @click="openDatePicker(index)" />
<u-input v-if="q.edit_input === 'datetime'" v-model="q.value" type="text"
:placeholder="q.help||'请选择日期时间'" @click="openTimePicker(index)" />
</view>
</view>
</view>
<!-- 提交区域 -->
<view class="submit-section">
<!-- <u-button type="primary" shape="circle" @click="submitSurvey">
<u-icon name="send" class="btn-icon"></u-icon>
提交问卷
</u-button> -->
<view @click="submitSurvey" type="primary">提交</view>
</view>
</view>
<!-- 日期选择器 -->
<u-picker v-model="showDatePicker" mode="time" @confirm="confirmDate"></u-picker>
<!-- 日期选择器 -->
<u-picker v-model="showTimePicker" mode="time" @confirm="confirmTime" :params="params"></u-picker>
</view>
</template>
<script>
export default {
data() {
return {
id: '',
survey: {},
questionList: [],
answers: [],
isSubmit:false,
showDatePicker: false,
showTimePicker: false,
currentDateIndex: -1,
answeredCount: 0,
course_id:false,
params: {
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true
},
};
},
computed: {
progressPercent() {
if (!this.questionList.length) return 0;
return (this.answeredCount / this.questionList.length) * 100;
}
},
onLoad(options) {
// 获取页面参数
this.id = options.id
this.course_id = options.course_id
console.log("页面参数:", { id: this.id, course_id: this.course_id })
this.getDetail(this.id)
this.updateProgress();
},
methods: {
// 获取
async getDetail(id) {
// 检查传入的参数类型
// if (this.course_id) {
// // 如果参数是course_id使用courseDetail接口
// const res = await this.$u.api.courseDetail({
// course_id: this.course_id
// })
// console.log("courseDetail res", res)
// this.survey = res
// } else {
// // 如果不是course_id按之前的方式使用courseContentDetail接口
// const res = await this.$u.api.courseContentDetail({
// course_content_id: id
// })
// console.log("courseContentDetail res", res)
// this.survey = res
// }
const res = await this.$u.api.courseEvaluationDetail({
course_content_evaluation_id:id
})
console.log("courseEvaluationDetail res", res)
this.survey = res
// 检查是否有问卷调查数据
console.log("courseEvaluationDetail res", res.course_content_evaluation_asks)
if (res && res.course_content_evaluation_asks) {
this.questionList = res.course_content_evaluation_asks
} else {
this.questionList = []
console.warn("未找到问卷调查数据")
return
}
// 初始化答案数组
this.questionList.map(q => {
q.value = q.value?q.value:''
if (q.edit_input === 'checkbox') {
q.select_item.map(item=>{
item.checked = false
})
console.log("res", q)
};
if (q.allow_input) return q.allow_input_text = q.allow_input_text?q.allow_input_text:'';
});
},
updateProgress() {
let count = 0;
for (let i = 0; i < this.questionList.length; i++) {
const answer = this.questionList[i].value;
if (Array.isArray(answer) && answer.length > 0) {
count++;
} else if (!Array.isArray(answer) && answer !== '' && answer !== null && answer !== undefined) {
count++;
}
}
this.answeredCount = count;
},
onValueChange(e, item) {
console.log("value", e,item)
if(item){
if (e.detail.value.length > 0) {
item.value = e.detail.value.join(",")
}
}
// 在下一个事件循环更新进度确保v-model生效
this.$nextTick(() => {
this.updateProgress();
});
},
openDatePicker(index) {
this.currentDateIndex = index;
this.showDatePicker = true;
},
confirmDate(e) {
console.log("e", e)
if (e) {
if (this.currentDateIndex !== -1) {
this.questionList[this.currentDateIndex].value = e.year + '-' + e.month + '-' + e.day
this.onValueChange();
}
}
},
openTimePicker(index) {
this.currentDateIndex = index;
this.showTimePicker = true;
},
confirmTime(e) {
console.log("e", e)
if (e) {
if (this.currentDateIndex !== -1) {
this.questionList[this.currentDateIndex].value = e.year + '-' + e.month + '-' + e.day + ' ' + e
.hour + ':' + e.minute + ':' + e.second
this.onValueChange();
}
}
},
validateForm() {
console.log("this.questionList[i]", this.questionList)
// return
// for (let i = 0; i < this.questionList.length; i++) {
// const q = this.questionList[i];
// const answer = this.answers[i];
// if (q.required) {
// const isEmpty = Array.isArray(answer) ? answer.length === 0 : (answer === '' || answer === null ||
// answer === undefined);
// if (isEmpty) {
// uni.showToast({
// title: `请完成第 ${i + 1} 题`,
// icon: 'none'
// });
// return false;
// }
// }
// }
let errorCount = 0
this.questionList.map(item => {
if (item.rule) {
// 不能为空
if (item.rule.indexOf('required') !== -1) {
if (this.base.isNull(item.value)) {
this.base.toast(`${item.name}不能为空`)
errorCount++
return
}
}
// 手机号
if (!this.base.isNull(item.value) && item.rule.indexOf('mobile') !== -1) {
if (!this.base.isMobile(item.value)) {
this.base.toast(`${item.name}不正确`)
errorCount++
return
}
}
// 身份证
if (!this.base.isNull(item.value) && item.rule.indexOf('idcard') !== -1) {
if (!this.$u.test.idCard(item.value)) {
this.base.toast(`${item.name}不正确`)
errorCount++
return
}
}
// 邮箱
if (item.rule.indexOf('email') !== -1) {
if (!this.base.isNull(item.value) && !this.base.isMail(item.value)) {
this.base.toast(`${item.name}不正确`)
errorCount++
return
}
}
// 整数
if (item.rule.indexOf('integer') !== -1) {
if (!this.base.isNull(item.value) && !this.base.isInteger(item.value)) {
this.base.toast(`${item.name}必须为整数`)
errorCount++
return
}
}
// 数字
if (item.rule.indexOf('numeric') !== -1) {
if (!this.base.isNull(item.value) && !this.base.isNumber(item.value)) {
this.base.toast(`${item.name}必须为数字`)
errorCount++
return
}
}
}
})
if (errorCount > 0) {
return
}
return true;
},
submitSurvey() {
if (!this.validateForm()) {
return;
}
let that = this
if(this.isSubmit){
return
}
this.isSubmit = true
uni.showModal({
title: '提交确认',
content: '确定要提交问卷吗?',
success: (res) => {
if (res.confirm) {
that.$u.api.courseContentForm({
course_content_evaluation_id:that.id,
data:that.questionList
}).then(res=>{
that.base.toast('提交成功',1500,function(){
that.isSubmit = false
uni.navigateBack(-1)
})
}).catch(err=>{
that.isSubmit = false
})
}
}
});
}
}
};
</script>
<style scoped lang="scss">
.survey-fill-page {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
// background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
height: 100vh;
overflow: scroll;
}
.cbg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100vh;
}
.survey-container {
margin: 0 auto;
padding: 30rpx;
padding-top: 100rpx;
position: relative;
}
.survey-header {
background: white;
border-radius: 24rpx;
padding: 40rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
font-size: 28rpx;
padding-bottom: 20rpx;
&-item {
color: #666;
&>view {
display: flex;
margin-bottom: 40rpx;
&>span:first-child {
color: #000;
margin-right: 20rpx;
}
}
}
}
.survey-title {
font-size: 44rpx;
font-weight: 700;
margin-bottom: 24rpx;
text-align: center;
}
.survey-description {
font-size: 28rpx;
color: #6c757d;
line-height: 1.6;
margin-bottom: 30rpx;
}
.survey-meta {
display: flex;
justify-content: center;
gap: 30rpx;
flex-wrap: wrap;
font-size: 24rpx;
color: #6c757d;
}
.meta-item {
display: flex;
align-items: center;
gap: 8rpx;
}
.progress-bar-container {
background: white;
padding: 20rpx 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
position: fixed;
width: 100%;
top: 0;
left: 0;
z-index: 99;
}
.progress-info {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 24rpx;
color: #2018a0;
&-progress {
width: calc(100% - 50rpx)
}
}
.survey-form {}
.question-item {
// padding: 30rpx 0;
// border-bottom: 1rpx solid #e9ecef;
background: white;
border-radius: 24rpx;
padding: 40rpx 20rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
font-size: 28rpx;
}
.question-item:last-child {
border-bottom: none;
}
.question-header {
display: flex;
align-items: center;
gap: 20rpx;
margin-bottom: 24rpx;
}
.question-number {
background: #bf976e;
color: white;
width: 60rpx;
height: 60rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 600;
flex-shrink: 0;
}
.question-title {
font-size: 28rpx;
font-weight: 600;
color: #333;
line-height: 1.4;
flex: 1;
}
.required-mark {
color: #e74c3c;
margin-left: 8rpx;
}
.question-content {
// padding-left: 64rpx;
}
.scale-container {
display: flex;
align-items: center;
gap: 20rpx;
color: #666;
}
.submit-section {
width: 100%;
position: relative;
padding: 60rpx 0;
&>view {
width: 70%;
text-align: center;
margin: 0 auto;
color: #fff;
background: linear-gradient(to right, #5e5fbc, #0d0398);
border-radius: 30rpx;
padding: 20rpx;
}
}
.btn-icon {
margin-right: 10rpx;
}
</style>