|
|
<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" :class="{ 'survey-form--last-input-focused': lastInputFocused }">
|
|
|
<view v-for="(q, index) in questionList" :key="q.id" :id="'question-'+q.id" class="question-item">
|
|
|
<view class="question-header">
|
|
|
<view class="question-number">{{ index + 1 }}</view>
|
|
|
<view class="question-title">
|
|
|
<view class="question-title-item">
|
|
|
<text>{{ q.name }}</text>
|
|
|
<text v-if="q.rule && q.rule.includes('required')" class="required-mark">*</text>
|
|
|
</view>
|
|
|
<view v-if="q.course_content" class="question-title-theme">
|
|
|
<text>{{ q.course_content.theme }}{{ q.course_content.teacher?' -- '+q.course_content.teacher.name:'' }}</text>
|
|
|
</view>
|
|
|
<!-- <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="'请输入'" :adjust-position="false" :cursor-spacing="80"
|
|
|
@focus="onInputFocus(q)" @blur="onInputBlur" />
|
|
|
</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="'请输入'" :adjust-position="false" :cursor-spacing="80"
|
|
|
@focus="onInputFocus(q)" @blur="onInputBlur" />
|
|
|
</view>
|
|
|
|
|
|
<!-- 多维度题目 -->
|
|
|
<view v-if="q.edit_input === 'multi_dimension'" class="multi-dimension-container">
|
|
|
<view v-for="(dimension, dimIndex) in q.dimensions" :key="dimIndex" class="dimension-item">
|
|
|
<view class="dimension-title">
|
|
|
<text v-if="dimension.need_fill" class="required-mark">*</text>
|
|
|
<text class="dimension-name">{{ dimension.name }}</text>
|
|
|
<text v-if="dimension.help" class="dimension-help">{{ dimension.help }}</text>
|
|
|
</view>
|
|
|
<u-radio-group wrap :value="q.value && q.value[dimension.field] ? q.value[dimension.field] : ''" @change="(val) => onDimensionValueChange(q, dimension.field, val)">
|
|
|
<u-radio active-color="#2018a0" v-for="(opt, optIndex) in dimension.select_item" :key="optIndex"
|
|
|
:name="opt.value">{{ opt.value }}</u-radio>
|
|
|
</u-radio-group>
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
<!-- 文本题 -->
|
|
|
<u-input v-if="q.edit_input === 'text'" v-model="q.value" type="text"
|
|
|
:placeholder="q.help||'请输入'" :adjust-position="false" :cursor-spacing="80"
|
|
|
@input="onValueChange" @focus="onInputFocus(q)" @blur="onInputBlur" />
|
|
|
<!-- 文本域 -->
|
|
|
<u-input v-if="q.edit_input === 'textarea'" v-model="q.value" type="textarea"
|
|
|
:placeholder="q.help||'请输入'" :maxlength="9999" :adjust-position="false" :cursor-spacing="80"
|
|
|
@input="onValueChange" @focus="onInputFocus(q)" @blur="onInputBlur" />
|
|
|
<!-- 评分题 -->
|
|
|
<!-- <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,
|
|
|
lastInputFocused: 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();
|
|
|
},
|
|
|
onShow() {
|
|
|
// 真机上 blur 可能不触发,改用键盘高度变化:键盘收起时去掉底部留白
|
|
|
this._keyboardListener = (res) => {
|
|
|
if (res && res.height === 0) {
|
|
|
this.lastInputFocused = false
|
|
|
}
|
|
|
}
|
|
|
uni.onKeyboardHeightChange(this._keyboardListener)
|
|
|
},
|
|
|
onUnload() {
|
|
|
if (this._keyboardListener) {
|
|
|
uni.offKeyboardHeightChange(this._keyboardListener)
|
|
|
}
|
|
|
},
|
|
|
onShareAppMessage() {
|
|
|
let path = '/packages/surveyFill/index?id=' + this.id
|
|
|
if (this.course_id) path += '&course_id=' + this.course_id
|
|
|
return {
|
|
|
path,
|
|
|
title: this.survey.title || '课程问卷',
|
|
|
imageUrl: '/static/share.jpg'
|
|
|
}
|
|
|
},
|
|
|
onShareTimeline() {
|
|
|
let path = '/packages/surveyFill/index?id=' + this.id
|
|
|
if (this.course_id) path += '&course_id=' + this.course_id
|
|
|
return {
|
|
|
path,
|
|
|
title: this.survey.title || '课程问卷',
|
|
|
imageUrl: '/static/share.jpg'
|
|
|
}
|
|
|
},
|
|
|
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 => {
|
|
|
// 多维度题目初始化
|
|
|
if (q.edit_input === 'multi_dimension') {
|
|
|
// 解析 dimensions(可能是字符串 JSON)
|
|
|
if (q.dimensions && typeof q.dimensions === 'string') {
|
|
|
try {
|
|
|
q.dimensions = JSON.parse(q.dimensions)
|
|
|
} catch (e) {
|
|
|
console.error('解析 dimensions 失败:', e)
|
|
|
q.dimensions = []
|
|
|
}
|
|
|
}
|
|
|
// 解析 value(如果后端返回的是 JSON 字符串,需要解析为对象)
|
|
|
if (q.value && typeof q.value === 'string') {
|
|
|
try {
|
|
|
const parsedValue = JSON.parse(q.value)
|
|
|
if (parsedValue && typeof parsedValue === 'object' && !Array.isArray(parsedValue)) {
|
|
|
q.value = parsedValue
|
|
|
} else {
|
|
|
q.value = {}
|
|
|
}
|
|
|
} catch (e) {
|
|
|
// 如果不是 JSON 字符串,初始化为空对象
|
|
|
q.value = {}
|
|
|
}
|
|
|
}
|
|
|
// 确保 value 是对象
|
|
|
if (!q.value || typeof q.value !== 'object' || Array.isArray(q.value)) {
|
|
|
q.value = {}
|
|
|
}
|
|
|
// 为每个维度初始化字段,使用 $set 确保响应式
|
|
|
if (q.dimensions && Array.isArray(q.dimensions)) {
|
|
|
// 找到 questionList 中的索引
|
|
|
const index = this.questionList.findIndex(item => item.id === q.id);
|
|
|
if (index !== -1) {
|
|
|
const questionItem = this.questionList[index];
|
|
|
q.dimensions.forEach(dim => {
|
|
|
if (dim.field) {
|
|
|
// 如果字段不存在,初始化为空字符串
|
|
|
if (!questionItem.value.hasOwnProperty(dim.field)) {
|
|
|
this.$set(questionItem.value, dim.field, '');
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
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 q = this.questionList[i];
|
|
|
|
|
|
// 多维度题目的完成状态检查
|
|
|
if (q.edit_input === 'multi_dimension') {
|
|
|
if (q.dimensions && Array.isArray(q.dimensions)) {
|
|
|
// 获取所有必填维度
|
|
|
const requiredDims = q.dimensions.filter(dim => dim.need_fill);
|
|
|
|
|
|
if (requiredDims.length === 0) {
|
|
|
// 如果没有必填维度,则至少有一个维度有值就算完成
|
|
|
const answer = q.value;
|
|
|
if (answer && typeof answer === 'object' && !Array.isArray(answer)) {
|
|
|
const hasAny = Object.values(answer).some(val => {
|
|
|
return val !== '' && val !== null && val !== undefined && val !== 'undefined' && val !== 'null';
|
|
|
});
|
|
|
if (hasAny) {
|
|
|
count++;
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
// 所有必填维度都必须有值才算完成
|
|
|
const answer = q.value;
|
|
|
if (answer && typeof answer === 'object' && !Array.isArray(answer)) {
|
|
|
const allFilled = requiredDims.every(dim => {
|
|
|
const dimValue = answer[dim.field];
|
|
|
return dimValue !== '' && dimValue !== null && dimValue !== undefined && dimValue !== 'undefined' && dimValue !== 'null';
|
|
|
});
|
|
|
if (allFilled) {
|
|
|
count++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
const answer = q.value;
|
|
|
if (Array.isArray(answer) && answer.length > 0) {
|
|
|
count++;
|
|
|
} else if (!Array.isArray(answer) && answer !== '' && answer !== null && answer !== undefined && answer !== 'undefined' && answer !== 'null') {
|
|
|
count++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
this.answeredCount = count;
|
|
|
},
|
|
|
onInputFocus(q) {
|
|
|
// 输入框获得焦点时,将题目滚动到可见区域,避免键盘弹起时输入框错位
|
|
|
if (!q || !q.id) return
|
|
|
const isLastInputQuestion = this.isLastInputQuestion(q)
|
|
|
if (isLastInputQuestion) {
|
|
|
this.lastInputFocused = true
|
|
|
}
|
|
|
const query = uni.createSelectorQuery().in(this)
|
|
|
query.select('#question-' + q.id).boundingClientRect((rect) => {
|
|
|
if (rect) {
|
|
|
uni.createSelectorQuery().in(this).selectViewport().scrollOffset((scroll) => {
|
|
|
if (scroll) {
|
|
|
// 最后一题输入框时,多滚动使输入框出现在键盘上方(键盘约300px高)
|
|
|
const offsetFromTop = isLastInputQuestion ? 80 : 120
|
|
|
const targetScrollTop = scroll.scrollTop + rect.top - offsetFromTop
|
|
|
uni.pageScrollTo({
|
|
|
scrollTop: Math.max(0, targetScrollTop),
|
|
|
duration: 200
|
|
|
})
|
|
|
}
|
|
|
}).exec()
|
|
|
}
|
|
|
}).exec()
|
|
|
},
|
|
|
onInputBlur() {
|
|
|
this.lastInputFocused = false
|
|
|
},
|
|
|
isLastInputQuestion(q) {
|
|
|
// 判断是否为最后一个包含输入框的题目
|
|
|
const hasInput = (item) => item.edit_input === 'text' || item.edit_input === 'textarea' || item.allow_input
|
|
|
const inputQuestions = this.questionList.filter(hasInput)
|
|
|
return inputQuestions.length > 0 && inputQuestions[inputQuestions.length - 1].id === q.id
|
|
|
},
|
|
|
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();
|
|
|
});
|
|
|
},
|
|
|
onDimensionValueChange(q, field, value) {
|
|
|
console.log('onDimensionValueChange 触发:', q.id, field, value, '当前q.value:', q.value);
|
|
|
// 找到 questionList 中的索引
|
|
|
const index = this.questionList.findIndex(item => item.id === q.id);
|
|
|
if (index === -1) {
|
|
|
console.error('找不到题目索引:', q.id);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
const questionItem = this.questionList[index];
|
|
|
// 确保 value 是对象
|
|
|
if (!questionItem.value || typeof questionItem.value !== 'object' || Array.isArray(questionItem.value)) {
|
|
|
this.$set(questionItem, 'value', {});
|
|
|
}
|
|
|
|
|
|
// 创建新对象,确保响应式更新
|
|
|
const currentValue = questionItem.value || {};
|
|
|
const newValue = { ...currentValue };
|
|
|
newValue[field] = value;
|
|
|
|
|
|
console.log('更新前:', questionItem.value, '更新后:', newValue);
|
|
|
|
|
|
// 使用 $set 更新整个 value 对象,确保响应式
|
|
|
this.$set(questionItem, 'value', newValue);
|
|
|
|
|
|
// 触发进度更新
|
|
|
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)
|
|
|
let errorCount = 0
|
|
|
for (let i = 0; i < this.questionList.length; i++) {
|
|
|
const item = this.questionList[i];
|
|
|
// 多维度题目的验证
|
|
|
if (item.edit_input === 'multi_dimension') {
|
|
|
if (item.dimensions && Array.isArray(item.dimensions)) {
|
|
|
for (let j = 0; j < item.dimensions.length; j++) {
|
|
|
const dim = item.dimensions[j];
|
|
|
if (dim.need_fill) {
|
|
|
const dimValue = item.value && typeof item.value === 'object' ? item.value[dim.field] : '';
|
|
|
if (!dimValue || dimValue === '' || dimValue === null || dimValue === undefined) {
|
|
|
this.base.toast(`${dim.name}不能为空`)
|
|
|
errorCount++
|
|
|
break; // 跳出内层循环
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (errorCount > 0) {
|
|
|
break; // 如果有错误,跳出外层循环
|
|
|
}
|
|
|
}
|
|
|
} else if (item.rule) {
|
|
|
// 不能为空
|
|
|
if (item.rule.indexOf('required') !== -1) {
|
|
|
if (this.base.isNull(item.value)) {
|
|
|
this.base.toast(`${item.name}不能为空`)
|
|
|
errorCount++
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
// 手机号
|
|
|
if (!this.base.isNull(item.value) && item.rule.indexOf('mobile') !== -1) {
|
|
|
if (!this.base.isMobile(item.value)) {
|
|
|
this.base.toast(`${item.name}不正确`)
|
|
|
errorCount++
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
// 身份证
|
|
|
if (!this.base.isNull(item.value) && item.rule.indexOf('idcard') !== -1) {
|
|
|
if (!this.$u.test.idCard(item.value)) {
|
|
|
this.base.toast(`${item.name}不正确`)
|
|
|
errorCount++
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
// 邮箱
|
|
|
if (item.rule.indexOf('email') !== -1) {
|
|
|
if (!this.base.isNull(item.value) && !this.base.isMail(item.value)) {
|
|
|
this.base.toast(`${item.name}不正确`)
|
|
|
errorCount++
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
// 整数
|
|
|
if (item.rule.indexOf('integer') !== -1) {
|
|
|
if (!this.base.isNull(item.value) && !this.base.isInteger(item.value)) {
|
|
|
this.base.toast(`${item.name}必须为整数`)
|
|
|
errorCount++
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
// 数字
|
|
|
if (item.rule.indexOf('numeric') !== -1) {
|
|
|
if (!this.base.isNull(item.value) && !this.base.isNumber(item.value)) {
|
|
|
this.base.toast(`${item.name}必须为数字`)
|
|
|
errorCount++
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (errorCount > 0) {
|
|
|
return false;
|
|
|
}
|
|
|
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) {
|
|
|
// 准备提交数据,将多维度题目的 value 对象序列化为 JSON 字符串
|
|
|
const submitData = that.questionList.map(q => {
|
|
|
const item = { ...q };
|
|
|
// 多维度题目的 value 对象需要序列化为 JSON 字符串
|
|
|
if (item.edit_input === 'multi_dimension' && item.value && typeof item.value === 'object' && !Array.isArray(item.value)) {
|
|
|
item.value = JSON.stringify(item.value);
|
|
|
}
|
|
|
return item;
|
|
|
});
|
|
|
|
|
|
that.$u.api.courseContentForm({
|
|
|
course_content_evaluation_id:that.id,
|
|
|
data:submitData
|
|
|
}).then(res=>{
|
|
|
that.base.toast('提交成功',1500,function(){
|
|
|
that.isSubmit = false
|
|
|
uni.navigateBack(-1)
|
|
|
})
|
|
|
}).catch(err=>{
|
|
|
that.isSubmit = false
|
|
|
})
|
|
|
} else {
|
|
|
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 {}
|
|
|
.survey-form--last-input-focused { padding-bottom: 450rpx; }
|
|
|
|
|
|
.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;
|
|
|
}
|
|
|
.question-title-theme{
|
|
|
font-size: 24rpx;
|
|
|
color: #6c757d;
|
|
|
line-height: 1.6;
|
|
|
// margin-bottom: 30rpx;
|
|
|
}
|
|
|
.required-mark {
|
|
|
color: #e74c3c;
|
|
|
margin-left: 8rpx;
|
|
|
}
|
|
|
|
|
|
.question-content {
|
|
|
// padding-left: 64rpx;
|
|
|
}
|
|
|
|
|
|
/* 多维度题目样式 */
|
|
|
.multi-dimension-container {
|
|
|
width: 100%;
|
|
|
}
|
|
|
|
|
|
.dimension-item {
|
|
|
margin-bottom: 30rpx;
|
|
|
padding: 20rpx;
|
|
|
background-color: #f8f9fa;
|
|
|
border-radius: 16rpx;
|
|
|
border: 1rpx solid #e9ecef;
|
|
|
}
|
|
|
|
|
|
.dimension-title {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
margin-bottom: 20rpx;
|
|
|
font-size: 28rpx;
|
|
|
font-weight: 600;
|
|
|
color: #2c3e50;
|
|
|
}
|
|
|
|
|
|
.dimension-name {
|
|
|
margin-right: 16rpx;
|
|
|
}
|
|
|
|
|
|
.dimension-help {
|
|
|
font-size: 24rpx;
|
|
|
font-weight: normal;
|
|
|
color: #6c757d;
|
|
|
margin-left: 16rpx;
|
|
|
}
|
|
|
|
|
|
.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> |