主题
问诊室消息收发(二)
本页对应 问诊室消息收发,共 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 = truehtml
<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出错。
常见错误
现象:提交评价时后端提示
orderId必须传,但前端只传了评分和内容。
→ 原因: 只展开了表单数据,漏传props.orderId/props.doctorId。
→ 修法: 提交前核对接口要求的 5 个参数,显式补齐订单 ID、医生 ID,并检查请求载荷。现象:组件传
doctorId时控制台报错或该参数传不过去,最终评价请求缺医生 ID。
→ 原因: 订单详情初始值为空对象,直接取orderDetail.docInfo.id,数据未回来时属性不存在。
→ 修法: 使用可选链或空值保护,如orderDetail?.docInfo?.id,并确认父组件数据加载完成后再取。现象:评价成功后按钮仍显示,用户还能再次填写评价。
→ 原因: 只调用了评价接口,没有维护“已评价”状态,或模板中v-if条件写反。
→ 修法: 成功回调中更新hasEvaluated,并用v-if="!hasEvaluated"控制提交按钮和匿名评价区域。现象:刷新页面后评价内容消失,或已评价订单仍显示未评价样式。
→ 原因: 未区分msgType23/24,或已评价组件没有接收并回显评分、评价内容。
→ 修法: 23 走未评价、24 走已评价;已评价组件接收score、content等数据并回填到评分组件和文本域/展示区。现象:结束问诊后页面仍可继续发消息,按钮禁用状态不更新。
→ 原因: 订单详情只在页面加载时请求一次,订单状态变化后没有重新获取。
→ 修法: 监听订单状态变化事件,触发后重新调用getOrderDetail,刷新status并驱动禁用逻辑。现象:已评价订单仍显示匿名评价和提交按钮,或仍传
orderId、doctorId。
→ 原因: 已评价和未评价共用模板,但没有通过属性区分,或把评价提交参数也传给了已评价场景。
→ 修法: 给组件传isEvaluated/类似布尔属性,已评价时隐藏提交相关 UI,并只传回显所需数据。
练习
- 在评价提交方法中打印请求参数,核对
doctorId、orderId、评分、内容、是否匿名 5 个字段是否齐全;若缺失,定位是父组件传参问题还是子组件接收问题。 - 将订单详情初始值设为
{},分别测试详情未返回和已返回两种情况下doctorId的取值,补上空值保护并说明为什么需要。 - 模拟评价成功:更新“已评价”状态,使提交按钮、匿名评价区域隐藏;再刷新页面,验证 23/24 两种
msgType下组件表现是否一致。 - 创建新订单并完成医生接诊,观察
status为 3 与不为 3 时输入框禁用状态;再结束问诊,验证监听订单状态变化后页面是否自动刷新状态。 - 为已评价组件补全评分和评价内容回显,要求无评分时显示 0、无内容时做空值兼容,并说明双向绑定回显的初始值来源。
课堂画面






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