wlzboy
2025-09-27 c1147646b9ef1d713a202d7ab8cf3ea8d677f142
ruoyi-ui/src/views/evaluation/index.vue
@@ -3,7 +3,7 @@
    <!-- 页面头部 -->
    <div class="evaluation-header">
      <h1>服务评价</h1>
      <p>感谢您使用我们的服务,请对本次服务进行评价</p>
      <p>感谢您使用我们的非120急救医疗转运服务,请对本次服务进行评价!</p>
    </div>
    <!-- 车辆信息 -->
@@ -19,12 +19,41 @@
      <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>
@@ -35,17 +64,16 @@
            <!-- 星级评价 - 标题和评分在同一行 -->
            <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>
@@ -60,8 +88,16 @@
                {{ 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>
@@ -85,6 +121,7 @@
                  placeholder="请输入您的意见或建议"
                  @input="updateDimensionText(dimension.dimensionId, $event)"
                  size="small"
                  :aria-label="`${dimension.dimensionName}评价意见`"
                />
              </div>
            </div>
@@ -118,7 +155,7 @@
</template>
<script>
import { getEvaluationDimensions, submitEvaluation, getWechatUserInfo } from "@/api/evaluation";
import { getEvaluationDimensions, submitEvaluation, getWechatUserInfo, getWechatAuthUrl } from "@/api/evaluation";
export default {
  name: "Evaluation",
@@ -136,6 +173,8 @@
        wechatPhone: '',
        evaluationDetails: []
      },
      // 用于存储选择类型的评价选项
      selectedOptions: {},
      rules: {
        customerName: [
          { required: true, message: '请输入您的姓名', trigger: 'blur' }
@@ -147,7 +186,8 @@
      },
      submitting: false,
      showResult: false,
      resultMessage: ''
      resultMessage: '',
      wechatAuthLoading: false
    };
  },
  created() {
@@ -178,7 +218,10 @@
    // 处理微信授权
    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) {
@@ -187,10 +230,59 @@
            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;
      }
    },
@@ -220,13 +312,37 @@
        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;
    },
    // 更新维度选项
@@ -236,7 +352,16 @@
        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);
    },
    // 获取维度文本
@@ -252,7 +377,8 @@
        detail = { dimensionId, textContent: '' };
        this.evaluationForm.evaluationDetails.push(detail);
      }
      detail.textContent = textContent;
      // 使用Vue.set确保响应式更新
      this.$set(detail, 'textContent', textContent);
    },
    // 获取维度选项配置
@@ -261,6 +387,7 @@
      try {
        return JSON.parse(dimension.options);
      } catch (error) {
        console.error('Error parsing options for', dimension.dimensionName, ':', error);
        return [];
      }
    },
@@ -289,7 +416,7 @@
        // 提交评价
        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 || '提交失败,请重试');
@@ -308,6 +435,7 @@
      this.evaluationForm.customerName = '';
      this.evaluationForm.customerPhone = '';
      this.evaluationForm.evaluationDetails = [];
      this.selectedOptions = {};
      this.$refs.evaluationForm.resetFields();
    }
  }
@@ -430,6 +558,15 @@
  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;
@@ -459,10 +596,139 @@
  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;
}
/* 优化表单项间距 */
@@ -587,6 +853,11 @@
    font-size: 13px;
  }
  
  .dimension-name-fixed {
    width: 120px;
    font-size: 13px;
  }
  .star-rating-content {
    min-width: auto;
    width: 100%;
@@ -628,6 +899,41 @@
    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;
  }
}
/* 超小屏幕适配 */