| | |
| | | <!-- 页面头部 --> |
| | | <div class="evaluation-header"> |
| | | <h1>服务评价</h1> |
| | | <p>感谢您使用我们的服务,请对本次服务进行评价</p> |
| | | <p>感谢您使用我们的非120急救医疗转运服务,请对本次服务进行评价!</p> |
| | | </div> |
| | | |
| | | <!-- 车辆信息 --> |
| | |
| | | <el-form ref="evaluationForm" :model="evaluationForm" :rules="rules" label-width="80px" size="small"> |
| | | <!-- 客户信息 --> |
| | | <div class="form-section"> |
| | | <h3>客户信息</h3> |
| | | <el-form-item label="姓名" prop="customerName"> |
| | | <h3>客户信息:</h3> |
| | | |
| | | <!-- 微信授权信息显示 --> |
| | | <div v-if="evaluationForm.wechatOpenid" class="wechat-info"> |
| | | <div class="wechat-user"> |
| | | <img v-if="evaluationForm.wechatAvatar" :src="evaluationForm.wechatAvatar" class="wechat-avatar" /> |
| | | <div class="wechat-details"> |
| | | <div class="wechat-nickname">{{ evaluationForm.wechatNickname }}</div> |
| | | <div class="wechat-openid">已授权微信登录</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 微信授权按钮 --> |
| | | <div v-if="isWechatBrowser() && !evaluationForm.wechatOpenid" class="wechat-auth-section"> |
| | | <el-button |
| | | type="primary" |
| | | size="small" |
| | | @click="redirectToWechatAuth" |
| | | icon="el-icon-user" |
| | | :loading="wechatAuthLoading" |
| | | > |
| | | {{ wechatAuthLoading ? '正在跳转...' : '微信一键登录' }} |
| | | </el-button> |
| | | <div class="wechat-tip">点击可自动获取您的微信信息</div> |
| | | </div> |
| | | |
| | | <el-form-item label="称呼" prop="customerName"> |
| | | <el-input v-model="evaluationForm.customerName" placeholder="请输入您的姓名" /> |
| | | </el-form-item> |
| | | <el-form-item label="手机号" prop="customerPhone"> |
| | | <el-input v-model="evaluationForm.customerPhone" placeholder="请输入您的手机号" /> |
| | | <div v-if="evaluationForm.wechatOpenid" class="phone-tip"> |
| | | |
| | | </div> |
| | | </el-form-item> |
| | | </div> |
| | | |
| | |
| | | <!-- 星级评价 - 标题和评分在同一行 --> |
| | | <div v-if="dimension.dimensionType === 'star'" class="star-rating-inline"> |
| | | <div class="dimension-title-inline"> |
| | | <span>{{ dimension.dimensionName }}</span> |
| | | <span class="dimension-name-fixed">{{ dimension.dimensionName }}</span> |
| | | <span v-if="dimension.isRequired === '1'" class="required">*</span> |
| | | </div> |
| | | <div class="star-rating-content"> |
| | | <el-rate |
| | | :value="getDimensionScore(dimension.dimensionId)" |
| | | :max="5" |
| | | show-text |
| | | :texts="['很差', '较差', '一般', '满意', '非常满意']" |
| | | @change="updateDimensionScore(dimension.dimensionId, $event)" |
| | | size="small" |
| | | :aria-label="`评价${dimension.dimensionName}`" |
| | | /> |
| | | </div> |
| | | </div> |
| | |
| | | {{ dimension.dimensionDesc }} |
| | | </div> |
| | | <div class="select-rating"> |
| | | <el-radio-group :value="getDimensionOption(dimension.dimensionId)" @change="updateDimensionOption(dimension.dimensionId, $event)" size="small"> |
| | | <el-radio v-for="option in getDimensionOptions(dimension)" :key="option.value" :label="option.value"> |
| | | <el-radio-group |
| | | v-model="selectedOptions[dimension.dimensionId]" |
| | | @change="(value) => handleOptionChange(dimension.dimensionId, value)" |
| | | size="small" |
| | | :aria-label="`选择${dimension.dimensionName}`"> |
| | | <el-radio |
| | | v-for="option in getDimensionOptions(dimension)" |
| | | :key="option.value" |
| | | :label="option.value" |
| | | :aria-label="option.label"> |
| | | {{ option.label }} |
| | | </el-radio> |
| | | </el-radio-group> |
| | |
| | | placeholder="请输入您的意见或建议" |
| | | @input="updateDimensionText(dimension.dimensionId, $event)" |
| | | size="small" |
| | | :aria-label="`${dimension.dimensionName}评价意见`" |
| | | /> |
| | | </div> |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { getEvaluationDimensions, submitEvaluation, getWechatUserInfo } from "@/api/evaluation"; |
| | | import { getEvaluationDimensions, submitEvaluation, getWechatUserInfo, getWechatAuthUrl } from "@/api/evaluation"; |
| | | |
| | | export default { |
| | | name: "Evaluation", |
| | |
| | | wechatPhone: '', |
| | | evaluationDetails: [] |
| | | }, |
| | | // 用于存储选择类型的评价选项 |
| | | selectedOptions: {}, |
| | | rules: { |
| | | customerName: [ |
| | | { required: true, message: '请输入您的姓名', trigger: 'blur' } |
| | |
| | | }, |
| | | submitting: false, |
| | | showResult: false, |
| | | resultMessage: '' |
| | | resultMessage: '', |
| | | wechatAuthLoading: false |
| | | }; |
| | | }, |
| | | created() { |
| | |
| | | // 处理微信授权 |
| | | async handleWechatAuth() { |
| | | const code = this.$route.query.code; |
| | | const state = this.$route.query.state; |
| | | |
| | | if (code) { |
| | | // 有授权码,获取用户信息 |
| | | try { |
| | | const response = await getWechatUserInfo(code); |
| | | if (response.code === 200) { |
| | |
| | | this.evaluationForm.wechatNickname = userInfo.nickname; |
| | | this.evaluationForm.wechatAvatar = userInfo.headimgurl; |
| | | this.evaluationForm.wechatPhone = userInfo.phone || ''; |
| | | |
| | | // 如果获取到了微信昵称,自动填充到姓名字段 |
| | | if (userInfo.nickname && !this.evaluationForm.customerName) { |
| | | this.evaluationForm.customerName = userInfo.nickname; |
| | | } |
| | | |
| | | this.$message.success('微信授权成功,已自动获取您的信息'); |
| | | } else { |
| | | this.$message.error(response.msg || '获取微信用户信息失败'); |
| | | } |
| | | } catch (error) { |
| | | console.error('获取微信用户信息失败:', error); |
| | | this.$message.error('获取微信用户信息失败,请重试'); |
| | | } |
| | | } else { |
| | | // 没有授权码,检查是否需要跳转到微信授权 |
| | | const hasWechatInfo = this.evaluationForm.wechatOpenid; |
| | | if (!hasWechatInfo) { |
| | | await this.redirectToWechatAuth(); |
| | | } |
| | | } |
| | | }, |
| | | |
| | | // 跳转到微信授权 |
| | | async redirectToWechatAuth() { |
| | | this.wechatAuthLoading = true; |
| | | try { |
| | | // 构建当前页面的完整URL作为回调地址 |
| | | const currentUrl = window.location.origin + window.location.pathname; |
| | | const params = new URLSearchParams(window.location.search); |
| | | params.delete('code'); // 移除可能存在的code参数 |
| | | params.delete('state'); // 移除可能存在的state参数 |
| | | const redirectUri = currentUrl + (params.toString() ? '?' + params.toString() : ''); |
| | | |
| | | console.log('准备生成微信授权URL,回调地址:', redirectUri); |
| | | |
| | | const response = await getWechatAuthUrl(redirectUri, 'evaluation'); |
| | | if (response.code === 200) { |
| | | console.log('微信授权URL生成成功:', response.data); |
| | | console.log('原始回调地址:', response.data.originalRedirectUri); |
| | | console.log('微信AppID:', response.data.appId); |
| | | |
| | | // 跳转到微信授权页面 |
| | | window.location.href = response.data.authUrl; |
| | | } else { |
| | | console.error('生成微信授权URL失败:', response.msg); |
| | | this.$message.error('微信授权服务暂时不可用,请手动填写信息'); |
| | | } |
| | | } catch (error) { |
| | | console.error('跳转微信授权失败:', error); |
| | | this.$message.error('微信授权失败,请手动填写信息'); |
| | | } finally { |
| | | this.wechatAuthLoading = false; |
| | | } |
| | | }, |
| | | |
| | |
| | | detail = { dimensionId, score: 0 }; |
| | | this.evaluationForm.evaluationDetails.push(detail); |
| | | } |
| | | detail.score = score; |
| | | // 使用Vue.set确保响应式更新 |
| | | this.$set(detail, 'score', score); |
| | | }, |
| | | |
| | | // 获取维度选项 |
| | | getDimensionOption(dimensionId) { |
| | | const detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimensionId); |
| | | return detail ? detail.optionValue : ''; |
| | | }, |
| | | |
| | | // 获取维度选项值(用于v-model) |
| | | getDimensionOptionValue(dimensionId) { |
| | | const detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimensionId); |
| | | if (!detail) { |
| | | // 如果不存在,创建一个新的detail对象 |
| | | const newDetail = { dimensionId, optionValue: '' }; |
| | | this.evaluationForm.evaluationDetails.push(newDetail); |
| | | return newDetail; |
| | | } |
| | | return detail; |
| | | }, |
| | | |
| | | // 获取维度选项的v-model对象 |
| | | getDimensionOptionModel(dimensionId) { |
| | | const detail = this.evaluationForm.evaluationDetails.find(d => d.dimensionId === dimensionId); |
| | | if (!detail) { |
| | | const newDetail = { dimensionId, optionValue: '' }; |
| | | this.evaluationForm.evaluationDetails.push(newDetail); |
| | | return newDetail; |
| | | } |
| | | return detail; |
| | | }, |
| | | |
| | | // 更新维度选项 |
| | |
| | | detail = { dimensionId, optionValue: '' }; |
| | | this.evaluationForm.evaluationDetails.push(detail); |
| | | } |
| | | detail.optionValue = optionValue; |
| | | // 使用Vue.set确保响应式更新 |
| | | this.$set(detail, 'optionValue', optionValue); |
| | | }, |
| | | |
| | | // 处理选项变化 |
| | | handleOptionChange(dimensionId, value) { |
| | | // 更新selectedOptions |
| | | this.$set(this.selectedOptions, dimensionId, value); |
| | | // 同时更新evaluationDetails |
| | | this.updateDimensionOption(dimensionId, value); |
| | | }, |
| | | |
| | | // 获取维度文本 |
| | |
| | | detail = { dimensionId, textContent: '' }; |
| | | this.evaluationForm.evaluationDetails.push(detail); |
| | | } |
| | | detail.textContent = textContent; |
| | | // 使用Vue.set确保响应式更新 |
| | | this.$set(detail, 'textContent', textContent); |
| | | }, |
| | | |
| | | // 获取维度选项配置 |
| | |
| | | try { |
| | | return JSON.parse(dimension.options); |
| | | } catch (error) { |
| | | console.error('Error parsing options for', dimension.dimensionName, ':', error); |
| | | return []; |
| | | } |
| | | }, |
| | |
| | | // 提交评价 |
| | | const response = await submitEvaluation(this.evaluationForm); |
| | | if (response.code === 200) { |
| | | this.resultMessage = response.msg; |
| | | this.resultMessage = "感谢您的反馈,您的反馈将促使我们不断进步,我们将继续提供更好的服务"; |
| | | this.showResult = true; |
| | | } else { |
| | | this.$message.error(response.msg || '提交失败,请重试'); |
| | |
| | | this.evaluationForm.customerName = ''; |
| | | this.evaluationForm.customerPhone = ''; |
| | | this.evaluationForm.evaluationDetails = []; |
| | | this.selectedOptions = {}; |
| | | this.$refs.evaluationForm.resetFields(); |
| | | } |
| | | } |
| | |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .dimension-name-fixed { |
| | | display: inline-block; |
| | | width: 100px; |
| | | text-align: left; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .star-rating-content { |
| | | flex: 1; |
| | | min-width: 200px; |
| | |
| | | font-size: 13px; |
| | | } |
| | | |
| | | /* 改善无障碍访问 */ |
| | | .select-rating .el-radio__original { |
| | | position: absolute !important; |
| | | opacity: 0 !important; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | margin: 0 !important; |
| | | padding: 0 !important; |
| | | border: none !important; |
| | | outline: none !important; |
| | | clip: rect(0, 0, 0, 0) !important; |
| | | -webkit-appearance: none !important; |
| | | -moz-appearance: none !important; |
| | | appearance: none !important; |
| | | } |
| | | |
| | | .select-rating .el-radio__input { |
| | | position: relative; |
| | | white-space: nowrap; |
| | | vertical-align: middle; |
| | | outline: none; |
| | | line-height: 1; |
| | | } |
| | | |
| | | .select-rating .el-radio__inner { |
| | | border: 1px solid #dcdfe6; |
| | | border-radius: 100%; |
| | | width: 14px; |
| | | height: 14px; |
| | | background-color: #fff; |
| | | position: relative; |
| | | cursor: pointer; |
| | | display: inline-block; |
| | | box-sizing: border-box; |
| | | transition: border-color 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46), background-color 0.25s cubic-bezier(0.71, -0.46, 0.29, 1.46); |
| | | } |
| | | |
| | | .select-rating .el-radio__inner:hover { |
| | | border-color: #409eff; |
| | | } |
| | | |
| | | .select-rating .el-radio.is-checked .el-radio__inner { |
| | | border-color: #409eff; |
| | | background: #409eff; |
| | | } |
| | | |
| | | .select-rating .el-radio.is-checked .el-radio__inner::after { |
| | | transform: translate(-50%, -50%) scale(1); |
| | | } |
| | | |
| | | .select-rating .el-radio__inner::after { |
| | | width: 4px; |
| | | height: 4px; |
| | | border-radius: 100%; |
| | | background-color: #fff; |
| | | content: ""; |
| | | position: absolute; |
| | | left: 50%; |
| | | top: 50%; |
| | | transform: translate(-50%, -50%) scale(0); |
| | | transition: transform 0.15s ease-in; |
| | | } |
| | | |
| | | /* 优化文本评价显示 */ |
| | | .text-rating .el-textarea__inner { |
| | | font-size: 13px; |
| | | min-height: 60px !important; |
| | | } |
| | | |
| | | /* 微信授权相关样式 */ |
| | | .wechat-info { |
| | | background: #f0f9ff; |
| | | border: 1px solid #b3d8ff; |
| | | border-radius: 6px; |
| | | padding: 12px; |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .wechat-user { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .wechat-avatar { |
| | | width: 40px; |
| | | height: 40px; |
| | | border-radius: 50%; |
| | | margin-right: 12px; |
| | | border: 2px solid #409EFF; |
| | | } |
| | | |
| | | .wechat-details { |
| | | flex: 1; |
| | | } |
| | | |
| | | .wechat-nickname { |
| | | font-weight: bold; |
| | | color: #333; |
| | | font-size: 14px; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .wechat-openid { |
| | | color: #666; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .wechat-auth-section { |
| | | text-align: center; |
| | | padding: 16px; |
| | | background: #f8f9fa; |
| | | border-radius: 6px; |
| | | margin-bottom: 16px; |
| | | border: 1px dashed #ddd; |
| | | } |
| | | |
| | | .wechat-tip { |
| | | color: #666; |
| | | font-size: 12px; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .phone-tip { |
| | | color: #909399; |
| | | font-size: 12px; |
| | | margin-top: 4px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .phone-tip i { |
| | | margin-right: 4px; |
| | | color: #409EFF; |
| | | } |
| | | |
| | | /* 优化表单项间距 */ |
| | |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .dimension-name-fixed { |
| | | width: 120px; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .star-rating-content { |
| | | min-width: auto; |
| | | width: 100%; |
| | |
| | | padding: 8px 24px; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | /* 移动端微信授权样式 */ |
| | | .wechat-info { |
| | | padding: 10px; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .wechat-avatar { |
| | | width: 36px; |
| | | height: 36px; |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .wechat-nickname { |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .wechat-openid { |
| | | font-size: 11px; |
| | | } |
| | | |
| | | .wechat-auth-section { |
| | | padding: 12px; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .wechat-tip { |
| | | font-size: 11px; |
| | | margin-top: 6px; |
| | | } |
| | | |
| | | .phone-tip { |
| | | font-size: 11px; |
| | | margin-top: 3px; |
| | | } |
| | | } |
| | | |
| | | /* 超小屏幕适配 */ |