Skip to content

问诊室消息收发(二) ​

本页对应 问诊室消息收发,共 6 段视频,约 56 分钟。

学习目标 ​

  • 能够根据订单ID调用订单详情接口,并从返回数据中提取医生ID、订单ID及订单状态,完成评价前参数准备。
  • 能够按项目规范在 service 层封装“获取订单详情”和“提交医生评价”API,并在页面或组件中正确导入调用。
  • 能够通过 props 将 orderId、doctorId、isCommented、score、content 等数据从父组件传入评价组件,并在子组件中声明接收与默认值。
  • 能够点击提交评价时携带医生ID、订单ID、评分、评价内容、是否匿名调用评价接口,并根据返回 code 给出成功或失败提示。
  • 能够根据评价状态控制提交按钮和匿名评价区域的显示,并在评价成功后更新状态以隐藏评价入口。
  • 能够为已评价订单传递评价数据,利用 v-model 回显星级和评价内容,并通过监听订单状态变化事件重新获取订单详情以刷新页面状态。

知识点 ​

先明确目标:评价不是立刻能提交 ​

为什么需要:点击“评价”按钮时,后端必须知道“评价哪个医生、对应哪个订单”。只拿到页面上的星星和文字还不够。
怎么想:评价接口至少需要医生 ID、订单 ID、分数、内容、是否匿名五类参数。医生 ID 和订单 ID 要先从订单详情里取。
怎么做:先调订单详情接口,从返回数据中找 doctorInfo.id 和订单 ID;再把它们传给评价组件。
易错点:转写稿里“order 就解释错了”“aler detail”都是口误/同音,实际应理解为订单详情 orderDetail;不要凭空写字段,先看接口返回值。原始笔记未附图片,这里不补造图片。

获取订单详情,拿到医生 ID ​

为什么需要:页面加载时只有订单 ID,医生 ID 在订单详情里。
怎么想:沿用“先封装 API,再在页面调用,最后保存数据”的老套路。
怎么做:在问诊相关 service 中封装 orderDetailAPI,在问诊室页面写 getOrderDetail,调用后判断 code !== 1 则提示 message,否则把 data 存到 orderDetail。
易错点:调用详情接口必须传订单 ID;转写稿调试时先没传参导致失败,补上 props.orderId 后才成功。关键片段示意:

js
const res = await orderDetailAPI({ orderId: props.orderId })
if (res.code !== 1) return ElMessage.error(res.message)
orderDetail.value = res.data

把医生 ID 和订单 ID 传入评价组件 ​

为什么需要:评价请求在子组件里发,但医生 ID、订单 ID 在父页面里。
怎么想:父传子用 props;子组件先接收,再在提交时使用。
怎么做:父组件给评价组件传 doctorId、orderId;子组件用 props 接收。
易错点:orderDetail 初始是空对象,直接写 orderDetail.doctorInfo.id 会报错。转写稿中通过可选链/问号屏蔽,如 orderDetail?.doctorInfo?.id。调试时先看请求载荷,发现只传了 3 个参数,缺订单 ID,补传后才成功。

提交评价:封装接口并传五个参数 ​

为什么需要:用户点提交按钮时要真正调用评价接口。
怎么想:先封装评价 API,再监听按钮点击,最后把表单数据和两个 ID 一起传过去。
怎么做:点击事件里 await 调接口;参数用 ...formData.value 展开分数、内容、匿名状态,再补 doctorId、orderId。
易错点:漏传订单 ID 时后端会提示“orderId 是必须的”;不要只传表单三项。成功后要提示“感谢您的评价”。

控制评价按钮:只允许评价一次 ​

为什么需要:评价成功后再显示提交按钮,用户可能重复评价。
怎么想:加一个“是否已评价”的状态变量,成功后置为 true,用 v-if 控制按钮和匿名评价区域。
怎么做:定义 hasComment = ref(false);接口成功后设为 true;模板中写 v-if="!hasComment"。
易错点:判断方向别写反;已评价时按钮应隐藏,未评价时才显示。

已评价与未评价共用模板,用状态区分 ​

为什么需要:刷新后评价区域消失,是因为消息状态从 23(未评价)变成 24(已评价)。
怎么想:同一个评价组件复用于 23 和 24,但传入不同标记:未评价传 false,已评价传 true。
怎么做:组件增加布尔属性,默认 false;父组件在 24 状态传 true,组件内用该属性初始化“是否已评价”。
易错点:只传属性不接收等于白传;子组件必须定义 props。已评价时不再需要传医生 ID、订单 ID 用于提交。

回显已评价的分数和内容 ​

为什么需要:已评价订单要展示用户打了几星、写了什么。
怎么想:分数和内容原本用 v-model 绑定,回显时给初始值即可。
怎么做:从 24 状态消息里取 score、content 传给组件;分数初始值用 props.score || 0,内容用 props.content || ''。
易错点:无内容时做兼容,避免显示 undefined;匿名评价区域在已评价状态下不再处理。

监听订单状态变化,及时刷新详情 ​

为什么需要:订单状态会变,例如结束问诊后输入框应禁用,但页面只加载时取过一次详情。
怎么想:状态变化事件触发后,重新调用 getOrderDetail 获取最新状态。
怎么做:监听订单变化事件,在回调中再次执行 getOrderDetail();输入框用 orderDetail.status !== 3 控制禁用,3 表示问诊中。
易错点:不刷新详情会出现“已结束问诊还能发消息”的假象;不是让用户手动刷新,而是监听后自动重取。

先拿到待评价医生的 ID ​

为什么需要:评价不是只提交“分数和内容”,还必须告诉后端“评价哪个医生、对应哪个订单”。所以提交评价前,先通过订单详情接口拿到 doctorId,同时确认 orderId 已经可用。

怎么想:订单详情里包含 docInfo,医生 ID 在 docInfo.id;订单 ID 在页面里已经通过 props.orderId 拿到。调用接口仍是“先封装 API,再在页面调用,最后保存返回数据”。

怎么做:在问诊相关 service 中追加订单详情 API,在页面加载时调用:

js
// 调用订单详情接口
const getOrderDetail = async () => {
  const { code, data, message } = await orderDetailAPI(props.orderId)
  if (code !== 1) return message // 按项目约定处理错误
  orderDetail.value = data
}

调试时先看网络请求是否发出,再展开返回值,确认 docInfo.id 是否存在。转写稿中“aler detail / do info”应纠正为 orderDetail / docInfo。

易错点:调用订单详情必须传 orderId;初始 orderDetail 是空对象时,直接取 orderDetail.docInfo.id 会报错,模板里要用 orderDetail?.docInfo?.id 这类可选链保护。

提交评价要凑齐 5 个参数 ​

为什么需要:评价接口要求 POST 提交,参数包括医生 ID、订单 ID、分数、内容、是否匿名。少传一个,后端就会报“订单 ID 必须”等错误。

怎么想:表单里已有分数、内容、匿名状态,页面外层已有 orderId 和刚拿到的 doctorId。因此要把外层数据传给评价组件,组件内用 props 接收,再在点击提交时合并参数。

怎么做:父组件传值:

html
<RateInfo
  :order-id="orderId"
  :doctor-id="orderDetail?.docInfo?.id"
/>

组件内接收并提交:

js
const props = defineProps({
  orderId: String,
  doctorId: [String, Number]
})

const onSubmit = async () => {
  const { code, message } = await 评价接口({
    ...formData.value,
    doctorId: props.doctorId,
    orderId: props.orderId
  })
  if (code !== 1) return message
}

易错点:转写稿调试时先只传了 3 个参数,后端提示订单 ID 必须;检查载荷后发现 doctorId/orderId 没传成功。根因是父组件传值时对象为空,访问属性报错,后来用问号屏蔽并补齐参数才成功。

用 has 控制“只评价一次” ​

为什么需要:评价只允许一次。提交成功后如果按钮还在,用户还能继续点,交互不合理。

怎么想:增加一个“是否已经评价过”的状态,初始 false;评价成功后改为 true;按钮和匿名评价小图标都用 v-if="!has" 控制。

怎么做:

js
const has = ref(false)

// 评价成功后
has.value = true
html
<button v-if="!has" @click="onSubmit">提交评价</button>
<span v-if="!has">匿名评价</span>

易错点:判断要取反,has === true 表示已评价,此时应隐藏按钮;不要写成 v-if="has" 把逻辑弄反。

已评价与未评价共用模板 ​

为什么需要:刷新后未评价组件消失,是因为消息类型从 23 变成 24。23 表示未评价,24 表示已评价;已评价内容仍要展示,所以要用同一模板再渲染一次。

怎么想:已评价时不再需要提交评价,因此不传 orderId/doctorId,只传 has=true 和评价数据 info。组件内再用 props.has 初始化状态。

怎么做:

html
<!-- 未评价 -->
<RateInfo :has="false" :order-id="orderId" :doctor-id="orderDetail?.docInfo?.id" />
<!-- 已评价 -->
<RateInfo :has="true" :info="msg" />

组件内:

js
const props = defineProps({
  has: { type: Boolean, default: false },
  info: { type: Object, default: () => ({}) }
})

易错点:父组件传了属性,组件内必须定义并接收;否则“传了也白传”。已评价时按钮应隐藏,避免用户再次提交。

回显分数和评价内容 ​

为什么需要:已评价订单要展示“打了几星、写了什么”,否则用户看不到历史评价。

怎么想:分数和内容原来用 v-model 绑定,说明既能取值也能回显;只要给初始值即可。分数取 props.info?.score || 0,内容取 props.info?.content || ''。

怎么做:

js
const score = ref(props.info?.score || 0)
const content = ref(props.info?.content || '')

易错点:没有评价数据时要给默认值,避免 undefined 影响渲染;内容为空时可兼容显示 0 或空串。

监听订单状态,控制能否发消息 ​

为什么需要:只有医生接诊、订单状态为 3(问诊中)时才允许发消息;结束问诊后如果页面不更新状态,仍能输入就是 bug。

怎么想:页面加载时只请求一次订单详情,状态变化后必须重新拉取。输入框用 orderDetail?.status !== 3 控制禁用;同时监听订单状态变化事件,在回调里重新调用 getOrderDetail()。

怎么做:

html
<el-input :disabled="orderDetail?.status !== 3" />
js
// 按项目提供的事件名监听订单状态变化
onOrderStatusChange(() => {
  getOrderDetail()
})

易错点:不要只靠用户手动刷新;订单状态变化后要自动重新请求详情,才能拿到最新 status。转写稿中“状态等于 3 表示问诊中”,不等于 3 就禁用输入。

一、评价前先拿医生ID:订单详情是数据入口 ​

为什么需要:评价接口不能只靠页面上的订单ID,还要知道“评价的是哪个医生”。转写中明确:提交评价需要医生ID和订单ID,而页面当前只有订单ID,所以要先查订单详情。

怎么想:订单详情接口的返回值里既有订单ID,也有 docInfo,医生ID就在 docInfo.id 中。按项目老套路:先封装接口,再在页面加载时调用,最后把结果存到 orderDetail。

怎么做:

js
const getOrderDetail = async () => {
  const { code, data, message } = await orderDetailAPI(props.orderId)
  if (code !== 10000) return ElMessage(message)
  orderDetail.value = data
}

页面加载时调用 getOrderDetail()。转写中第一次调试没传 orderId,请求失败;补上 props.orderId 后,网络面板能看到 docInfo 下张医生的 id 为 1。

易错点:不要忘记给详情接口传订单ID;异步请求要 await;orderDetail 初始是空对象,直接写 orderDetail.docInfo.id 会报错,后续传值要用 orderDetail?.docInfo?.id 这类可选链保护。

二、父传子凑齐评价参数并提交 ​

为什么需要:评价组件在子组件里,医生ID却是在父页面查详情得到的;同时评价接口要五个参数:医生ID、订单ID、分数、内容、是否匿名。

怎么想:父组件把 docId、orderId 传给评价组件,子组件用 props 接收;表单负责分数、内容、匿名;提交时把表单数据和两个ID合并。

怎么做:

vue
<RateInfo
  :doc-id="orderDetail?.docInfo?.id"
  :order-id="props.orderId"
/>

子组件接收:

js
const props = defineProps({
  docId: String,
  orderId: String
})

提交时:

js
const params = {
  ...formData.value,
  docId: props.docId,
  orderId: props.orderId
}

转写中的调试很关键:第一次点提交,载荷只有表单三项,接口报“orderId 是必须的”;检查后发现父组件传 orderDetail.docInfo.id 时因空对象报错,加问号屏蔽后,五个参数才真正传过去,评价成功。

易错点:只传表单三项,漏掉两个ID;父组件传了值,子组件没写 props 接收;参数名与接口文档不一致;空对象访问不加保护。

三、评价成功后隐藏入口:用状态变量控制只评一次 ​

为什么需要:业务规定评价只允许一次。成功后如果按钮还在,用户可能重复提交。

怎么想:定义一个“是否已经评价过”的状态,初始 false;接口成功提示“感谢您的评价”,并把状态改成 true;模板里用 v-if 取反控制按钮和匿名评价小图标。

怎么做:

js
const hasCommented = ref(false)
// 评价成功后
hasCommented.value = true

模板:

vue
<button v-if="!hasCommented">提交评价</button>
<div v-if="!hasCommented">匿名评价</div>

易错点:v-if 条件写反;只隐藏提交按钮,忘了隐藏匿名入口;接口成功后没有更新状态。

四、刷新后评价区消失:msgType 23/24 区分未评价和已评价 ​

为什么需要:刷新后评价组件消失不是bug。转写中查数据发现:未评价消息 msgType 是23,已评价变成24;页面只渲染23时,24自然不显示。

怎么想:同一个评价模板复用两次:23传“未评价”,24传“已评价”。已评价不需要再传 orderId、docId,因为不再提交评价。组件增加 isCommented 属性,默认 false,组件内状态初值等于它。

怎么做:

vue
<RateInfo v-if="msg.msgType === 23" :is-commented="false" ... />
<RateInfo v-if="msg.msgType === 24" :is-commented="true" :info="msg" />

组件内:

js
const props = defineProps({
  isCommented: { type: Boolean, default: false },
  info: { type: Object, default: () => ({}) }
})
const hasCommented = ref(props.isCommented)

调试时传 false 按钮显示,传 true 按钮隐藏,说明状态区分生效。

易错点:23/24写反;已评价仍传评价参数;组件内变量和props同名混淆;忘记给默认值。

五、已评价内容回显:score和content ​

为什么需要:已评价不仅要隐藏按钮,还要把用户打的分和写的内容展示出来。

怎么想:父组件把24消息对象传给子组件,子组件通过 info 接收;分数和内容用 ref 初始化,空值时给默认值。

怎么做:

js
const score = ref(props.info?.score || 0)
const content = ref(props.info?.content || '')

模板绑定分数和内容即可。转写中验证:初始分数设为2会显示两颗星,换成 props.info.score 后显示实际三颗星;内容绑定 content 后回显成功。

易错点:不设默认值导致空内容报错;忘记父传 info;已评价还处理匿名状态;分数层级取错。

六、订单状态变化要监听:状态3才允许发消息 ​

为什么需要:只有订单状态为3(问诊中)才能给医生发消息;页面加载时只取一次详情,结束问诊后状态不会自动更新。

怎么想:用 orderDetail.status !== 3 禁用输入;在首页面注册订单状态变化监听,触发后重新调用 getOrderDetail() 更新状态。

怎么做:

vue
:disabled="orderDetail?.status !== 3"
js
// 首页面:注册“订单状态变化”监听
// 回调中重新执行 getOrderDetail()

转写中状态从2变3后,刷新详情确认 status 为3,输入框才可用。

易错点:只加载一次、不监听状态变化;条件写反;status 层级取错;监听没放在首页面。

代码示例 ​

1. 接口封装:src/service/consult.js + src/service/doctor.js ​

js
// src/service/consult.js  —— 问诊相关接口
import request from '@/utils/request'

// 获取订单详情:返回值里有 docInfo.id(医生 id)和 status(订单状态)
export function orderDetailAPI(orderId) {
  return request({
    url: '/consult/order/detail', // 接口地址以接口文档为准
    method: 'get',
    params: { orderId }           // 必须传,否则后端报“orderId 必须”
  })
}
js
// src/service/doctor.js  —— 医生相关接口
import request from '@/utils/request'

// 提交医生评价:POST,5 个参数 docId / orderId / score / content / anonymous
export function rateDoctorAPI(data) {
  return request({
    url: '/doctor/rate',          // 接口地址以接口文档为准
    method: 'post',
    data                          // POST 参数放 data,不能放 params
  })
}

要点

  • 转写稿的原话:调接口是“老三套”——先封装方法,再在页面/组件里调用,最后接收数据。
  • 获取订单详情的接口必须带 orderId,第一次测试就失败并报错“orderId 必须”,原因就是没有传参数。
  • 评价接口是 POST,参数放 data 里,共 5 个:docId、orderId、score、content、anonymous。
  • 按业务分文件:问诊的接口放 consult.js,医生的接口放 doctor.js,不要全部塞到一个文件里。

2. 问诊室页面:src/views/room/index.vue(取医生 id + 监听订单状态) ​

vue
<template>
  <div class="room-page">
    <!-- 消息列表:msgList 为问诊室已接收的消息(前文已完成) -->
    <div class="msg-list">
      <template v-for="msg in msgList" :key="msg.id">
        <!-- 未评价:msgType = 23,需要订单 id 与医生 id -->
        <RateInfo
          v-if="msg.msgType === 23"
          :order-id="orderId"
          :doctor-id="orderDetail.docInfo?.id"
          :has="false"
        />
        <!-- 已评价:msgType = 24,只回显内容,不再传 id -->
        <RateInfo
          v-else-if="msg.msgType === 24"
          :has="true"
          :info="msg.msg"
        />
      </template>
    </div>

    <!-- 底部输入区:只有“问诊中(status === 3)”才允许发消息 -->
    <div class="footer">
      <input
        v-model="content"
        :disabled="orderDetail.status !== 3"
        placeholder="请输入内容"
        @keyup.enter="sendText"
      />
      <button :disabled="orderDetail.status !== 3" @click="sendText">发送</button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { Toast } from 'vant'
import { orderDetailAPI } from '@/service/consult'
import RateInfo from './components/RateInfo.vue'

const route = useRoute()
// 订单 id 来自地址栏参数(前文已获取过)
const orderId = route.query.orderId

const orderDetail = ref({}) // 订单详情,初始给空对象
const msgList = ref([])     // 消息列表(socket 推送,前文已实现)
const content = ref('')

// 获取订单详情:里面有 docInfo.id(医生 id)和 status(订单状态)
const getOrderDetail = async () => {
  const { code, data, message } = await orderDetailAPI(orderId)
  if (code !== 10000) return Toast(message)
  orderDetail.value = data
}

// 发送消息(前文/后文实现,这里只做状态校验)
const sendText = () => {
  if (orderDetail.value.status !== 3) return
  content.value = ''
}

onMounted(() => {
  getOrderDetail()
  // 监听订单状态变化:一旦变化就重新拉一次详情
  // (socket 实例与事件名以项目实际为准,前文已建立连接)
  socket.on('orderStatusChange', () => {
    getOrderDetail()
  })
})
</script>

要点

  • 页面加载时调用 getOrderDetail(),从返回的 data.docInfo.id 拿到医生 id,再通过 :doctor-id 传给评价组件——这就是本节第一件事。
  • 易错点(转写稿中的实际 bug):orderDetail 初始是 {},模板里必须写 orderDetail.docInfo?.id,否则空对象取不到 docInfo,docId 传不过去,提交评价时后端只收到 3 个参数。
  • status === 3 表示问诊中,只有此时才允许发消息,所以写 :disabled="orderDetail.status !== 3"。
  • 只在 onMounted 里取一次详情是不够的:医生结束问诊后状态变了,页面不知道,还能继续聊天。所以要监听订单状态变化事件,变化后重新调用 getOrderDetail(),让状态实时更新。
  • 消息类型要区分:23 = 未评价(传 orderId、doctorId、has=false),24 = 已评价(传 has=true 和 info,不再传两个 id)。

3. 评价组件:src/views/room/components/RateInfo.vue ​

vue
<template>
  <div class="rate-info">
    <p class="title">医生评价</p>

    <!-- 星级:v-model 双向绑定,回显靠“初始值” -->
    <van-rate v-model="formData.score" :count="5" />

    <div class="content-box">
      <textarea
        v-model="formData.content"
        maxlength="100"
        placeholder="请输入评价内容"
      ></textarea>
      <!-- 字数统计做兜底,内容为空时显示 0 -->
      <span class="word-count">{{ (formData.content || '').length }}/100</span>
    </div>

    <!-- 匿名评价:已评价后隐藏 -->
    <van-checkbox v-if="!hasRated" v-model="formData.anonymous">
      匿名评价
    </van-checkbox>

    <!-- 提交按钮:已评价后隐藏,取反 -->
    <van-button v-if="!hasRated" type="primary" block @click="onSubmit">
      提交评价
    </van-button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { Toast } from 'vant'
import { rateDoctorAPI } from '@/service/doctor'

const props = defineProps({
  orderId: { type: [String, Number], default: '' },
  docId: { type: [String, Number], default: '' },
  has: { type: Boolean, default: false },       // 是否已评价过
  info: { type: Object, default: () => ({}) }   // 已评价时的回显数据
})

// 是否已评价:初始值取自 props.has,提交成功后改成 true
// (转写稿里这个 ref 也叫 has,与 props.has 同名容易混,这里改名 hasRated)
const hasRated = ref(props.has)

// 表单数据:初始值来自 info,v-model 才能把分数和内容回显出来
const formData = ref({
  score: props.info?.score || 0,
  content: props.info?.content || '',
  anonymous: false
})

// 提交评价
const onSubmit = async () => {
  const { code, message } = await rateDoctorAPI({
    ...formData.value,      // 展开 score / content / anonymous
    docId: props.docId,     // 医生 id(由页面传进来)
    orderId: props.orderId  // 订单 id(由页面传进来)
  })
  if (code !== 10000) return Toast(message)

  Toast('感谢您的评价')
  hasRated.value = true     // 变更评价状态 -> 按钮和匿名评价一起隐藏
}
</script>

要点

  • 组件用 defineProps 接收 4 个值:orderId、docId、has、info。页面传了、组件没接收,等于白传。
  • 按钮和匿名评价都用 v-if="!hasRated" 控制——取反:没评价过才显示,评价过就藏起来,用户想再评价也点不到。
  • hasRated 的初始值等于 props.has:页面传 true(msgType=24)按钮就不显示,传 false(msgType=23)就显示,同一个模板区分两种状态。
  • 回显靠 v-model 的初始值:score: props.info?.score || 0、content: props.info?.content || '',有值就显示,没值给默认值。
  • 提交时用 ...formData.value 展开三个表单参数,再补上 docId、orderId,正好凑齐后端要的 5 个参数;code !== 10000 时 return Toast(message) 提前中断,不往下改状态。
  • 字数统计写成 (formData.content || '').length,避免内容为空时取 length 出错。

常见错误 ​

  1. 现象:提交评价时后端提示 orderId 必须传,但前端只传了评分和内容。
    → 原因: 只展开了表单数据,漏传 props.orderId / props.doctorId。
    → 修法: 提交前核对接口要求的 5 个参数,显式补齐订单 ID、医生 ID,并检查请求载荷。

  2. 现象:组件传 doctorId 时控制台报错或该参数传不过去,最终评价请求缺医生 ID。
    → 原因: 订单详情初始值为空对象,直接取 orderDetail.docInfo.id,数据未回来时属性不存在。
    → 修法: 使用可选链或空值保护,如 orderDetail?.docInfo?.id,并确认父组件数据加载完成后再取。

  3. 现象:评价成功后按钮仍显示,用户还能再次填写评价。
    → 原因: 只调用了评价接口,没有维护“已评价”状态,或模板中 v-if 条件写反。
    → 修法: 成功回调中更新 hasEvaluated,并用 v-if="!hasEvaluated" 控制提交按钮和匿名评价区域。

  4. 现象:刷新页面后评价内容消失,或已评价订单仍显示未评价样式。
    → 原因: 未区分 msgType 23/24,或已评价组件没有接收并回显评分、评价内容。
    → 修法: 23 走未评价、24 走已评价;已评价组件接收 score、content 等数据并回填到评分组件和文本域/展示区。

  5. 现象:结束问诊后页面仍可继续发消息,按钮禁用状态不更新。
    → 原因: 订单详情只在页面加载时请求一次,订单状态变化后没有重新获取。
    → 修法: 监听订单状态变化事件,触发后重新调用 getOrderDetail,刷新 status 并驱动禁用逻辑。

  6. 现象:已评价订单仍显示匿名评价和提交按钮,或仍传 orderId、doctorId。
    → 原因: 已评价和未评价共用模板,但没有通过属性区分,或把评价提交参数也传给了已评价场景。
    → 修法: 给组件传 isEvaluated/类似布尔属性,已评价时隐藏提交相关 UI,并只传回显所需数据。

练习 ​

  1. 在评价提交方法中打印请求参数,核对 doctorId、orderId、评分、内容、是否匿名 5 个字段是否齐全;若缺失,定位是父组件传参问题还是子组件接收问题。
  2. 将订单详情初始值设为 {},分别测试详情未返回和已返回两种情况下 doctorId 的取值,补上空值保护并说明为什么需要。
  3. 模拟评价成功:更新“已评价”状态,使提交按钮、匿名评价区域隐藏;再刷新页面,验证 23/24 两种 msgType 下组件表现是否一致。
  4. 创建新订单并完成医生接诊,观察 status 为 3 与不为 3 时输入框禁用状态;再结束问诊,验证监听订单状态变化后页面是否自动刷新状态。
  5. 为已评价组件补全评分和评价内容回显,要求无评分时显示 0、无内容时做空值兼容,并说明双向绑定回显的初始值来源。

课堂画面 ​

课堂画面 01

课堂画面 02

课堂画面 03

课堂画面 04

课堂画面 05

课堂画面 06

原视频对照 ​

#视频时长
1优医咨询-获取待评价医生的id08:18
2优医咨询-问诊室评价医生-111:38
3优医咨询-问诊室医生评价状态05:55
4优医咨询-问诊室医生已评价10:06
5优医咨询-问诊室医生已评价数据回显11:46
6优医咨询-监听问诊订单状态变化09:05

小结 ​

  1. 评价提交不是只提交表单,必须同时具备订单 ID、医生 ID、评分、内容和匿名标识。
  2. 订单详情是医生 ID 和订单状态的重要数据源,取嵌套字段时必须考虑数据未加载完成的空值场景。
  3. 未评价与已评价应共用模板但明确区分状态,23/24 不能混用。
  4. 评价成功后要同步更新本地状态,隐藏提交入口,避免重复评价。
  5. 已评价场景重点从“提交评价”切换为“回显评价”,不再需要提交评价所需的 ID 参数。
  6. 订单状态会动态变化,页面不能只依赖首次加载数据,必须监听变化并重新拉取详情。
  7. 所有提交类功能都要同时检查请求参数、接口返回 code、用户提示和后续 UI 状态。