feat: 患者端挂号预约流程改造与就诊人选择

- 挂号预约:register-info 流程重构、确认步骤/患者选择步骤组件、我的预约(myappiont)页对接
- 接口:register.js 补充挂号相关接口,api.js 调整
- 就诊人:claim-patient-modal 复用弹窗
- 医生信息:doctor-detail/doctor-userinfo 配合排班展示
- 规范:新增 Api-Module-Split.mdc 接口模块拆分规则
This commit is contained in:
李琦
2026-08-14 13:27:57 +08:00
parent c681cb916b
commit cc252b5d1a
11 changed files with 564 additions and 95 deletions

View File

@@ -0,0 +1,37 @@
---
description: 接口迁移到 xk-api 后必须拆出独立模块文件,禁止再往 api.js 大文件里塞
alwaysApply: true
---
# API 模块拆分规则(xk-api 迁移必读)
`request/api/api.js`(约 600+ 行大杂烩)是历史遗留的 Yii 接口聚合文件。
**任何迁移到 xk-api 的接口、以及所有新增的 xk-api 接口,一律不得写进 `api.js`**,必须提取/新建到 `request/api/` 下的独立业务模块文件。
## 必须做
1. **按业务域建独立文件**:`request/api/<module>.js`,小驼峰命名(已有先例:`patient.js`、`order.js`、`register.js`、`product.js`、`medicalRecord.js`、`specialPrescription.js`)
2. **统一走 http 封装**:`import { post, get } from './http'`,第三参传 `3`(`HttpUrlMap[3] = '/xkApi'`),不要手拼 `/xkApi` 字符串到 `http()` 老封装上
3. **文件头注释标明后端与取值方式**,每个函数注释标 HTTP 方法与路径,例如:
```js
import { post, get } from './http'
/**
* 就诊人相关接口统一走 xk-api(type=3)
* 取值:unwrapXkApi → code / result / message
*/
/** 就诊人列表 xk-api POST /patient/list */
export async function getPatientListApi(params = {}) {
return await post('/patient/list', params, 3)
}
```
4. **迁移某接口时**(Yii → xk-api):把它从 `api.js` 挪到对应模块文件,`api.js` 里原函数直接删除(调用方改 import),确实来不及改完所有调用方时才允许在 `api.js` 保留一行 re-export 并标 `@deprecated`
5. 页面取值统一 `unwrapXkApi`(见 Api-Response.mdc)
## 禁止做
- 禁止在 `api.js` 中新增任何函数(包括 Yii 接口——新 Yii 接口也应放模块文件)
- 禁止新代码再用 `normalizeXkApiResponse` 这类「把 xk-api 响应抹成 errcode/data」的兼容层;那是存量代码的过渡产物
- 禁止一个模块文件里混装两个后端的接口而不加注释区分;同一文件确需并存时,每个函数注释必须标明 `// xk-api` 或 `// Yii`

View File

@@ -11,3 +11,5 @@ alwaysApply: true
6. 微信小程序 `.vue` 模板(会编译成 WXML)禁止使用 `??`、`?.` 等现代运算符,否则会报 `unexpected token '?'`;模板里用 `||` / 显式判断,脚本里可用 `??`/`?.`
7. 微信小程序模板里 `:class` / `:style` 禁止写 `fn(arg)` 方法调用(如 `:class="sexClass(p)"` 会编译失败);用对象/数组字面量(如 `:class="{ male: p.sex == 1 }"`),或把结果先算进 data/computed 再绑定
8. 接口取值:写代码时先确认接口是 xk-api 还是 Yii,再固定用 `code/result/message` 或 `errcode/data/msg`(可用 `unwrapXkApi` / `unwrapYiiApi`);禁止运行时猜测、禁止 `result || data`(详见 Api-Response.mdc)
9. 卡片强调样式:禁止用左侧竖色条(`border-left` 色条/左侧色块)做卡片强调或分类标识,统一用「1px 同色系边框 + 同色低透明度外发光(box-shadow 微光)」;历史页面暂不强制回改,新增/改动的卡片必须遵守
10. API 模块拆分:迁移到 xk-api 的接口和所有新增接口必须放 `request/api/<module>.js` 独立模块文件,禁止再往 `request/api/api.js` 大文件里新增(详见 Api-Module-Split.mdc)

View File

@@ -17,7 +17,7 @@
<script>
import { claimPatientApi } from '@/request/api/patient.js'
import { unwrapXkApi } from '@/utils/api-response.js'
import { registePay } from '@/request/api/api.js'
import { registePay } from '@/request/api/register.js'
/**
* 扫码认领医生创建的就诊人(居中 u-modal)

View File

@@ -1,5 +1,4 @@
import http from './request'
import { get } from './http'
import {
getPatientListApi,
savePatientApi,
@@ -113,11 +112,8 @@ export async function commentListTop(params) {
return data
}
// 医生 挂号信息
export async function registerList(params) {
let data = await http('/oldApi/v1/register/doc-register-info', params)
return data
}
// 挂号域接口(registerList/registerCalendar/registe/registeInfo/registePay/registeUnpay/registeCancle)
// 已按 Api-Module-Split 规则迁至 ./register.js,调用方请从 '@/request/api/register.js' 导入
/** 就诊人列表(xk-api POST /patient/list) */
@@ -174,42 +170,6 @@ export async function userEidtPatient(params) {
return normalizeXkApiResponse(await getPatientHealthInfoApi(data))
}
// 挂号
export async function registe(params) {
let data = await http('/oldApi/v1/register/register', params)
return data
}
// 挂号详情
export async function registeInfo(params) {
let data = await http('/oldApi/v1/register/register-detail', params)
return data
}
// 支付挂号(xk-api register/pay,易票联)
export async function registePay(params) {
let data = await http('/xkApi/register/pay', params)
return normalizeXkApiResponse(data)
}
// 取消挂号
export async function registeUnpay(params) {
let data = await http('/oldApi/v1/register/cancel', params)
return data
}
// 挂号退款
export async function registeCancle(params) {
let data = await http('/oldApi/v1/register/refund', params)
return data
}
// 挂号列表
export async function registeList(params) {
let data = await http('/oldApi/v1/register/list', params)
return data
}
// 设置 服务协议
export async function service(params) {
let data = await http('/oldApi/v1/other/service', params)

View File

@@ -1,8 +1,30 @@
import http from './request'
import {post} from './http'
import { unwrapXkApi } from '@/utils/api-response.js'
/**
* 获取挂号记录列表
* 挂号域接口统一模块(除 registerList 外均为 xk-api)
* 取值:unwrapXkApi → code / result / message
*
* 说明:registe/registeInfo 等函数迁自 api.js,保持「http(url, { method, data })」
* 老签名不动,避免改动全部调用方的传参结构;新增接口请用 post(url, params, 3) 新封装。
*/
/**
* 存量页面兼容:把 xk-api 的 code/result 抹成旧版 errcode/data
* @deprecated 仅供 registePay 的存量调用方(读 res.data.errcode/data)过渡使用,
* 新代码一律直接按 code/result 取值或用 unwrapXkApi,禁止再新增本函数的调用
*/
function normalizeXkApiResponse(res) {
if (res && res.data && (res.data.code === 0 || res.data.code === '0')) {
res.data.errcode = 0;
res.data.data = res.data.result;
}
return res;
}
/**
* 获取挂号记录列表 xk-api POST /register/list
* @param params { patient_id: number, store_id: number, page: number }
* @returns {Promise<*>}
*/
@@ -11,7 +33,7 @@ export async function getRegisterListApi(params) {
}
/**
* 获取待支付挂号列表(首页提醒用)
* 获取待支付挂号列表(首页提醒用) xk-api POST /register/list
* @param params
* @returns {Promise<Array>}
*/
@@ -30,3 +52,69 @@ export async function fetchUnpaidRegisterListApi(params = {}) {
const list = (payload && payload.list) || [];
return list.filter((item) => item.status === 0 && item.is_cancel !== 1);
}
/**
* 医生号源日历 xk-api GET /register/schedule-calendar(登录态)
* 返回 { register_status, register_price, book_days, days[] },days 含每天出诊/时段/余号
* 读值按 xk-api 形态:res.data.code == 0 → res.data.result
*/
export async function registerCalendar(params) {
let data = await http('/xkApi/register/schedule-calendar', params)
return data
}
/**
* 医生号源信息(游客态专用)
* URL 写老 Yii doc-register-info,但 request.js 会在 guest 模式下重写到
* xk-api /guest/guest-doctor/doc-register-info(响应 code/result 形态,result 带 calendar)
* @deprecated 登录态请勿使用(会打到老 Yii),登录态一律走 registerCalendar
*/
export async function registerList(params) {
let data = await http('/oldApi/v1/register/doc-register-info', params)
return data
}
/**
* 挂号建单 xk-api POST /register/create(迁自老 Yii /v1/register/register)
* 入参新增 visit_date(Y-m-d) + slot_id(0=全天兜底);返回 result{register_id, isHas}
* 读值按 xk-api 形态:res.data.code == 0 → res.data.result
*/
export async function registe(params) {
let data = await http('/xkApi/register/create', params)
return data
}
/**
* 挂号详情 xk-api POST /register/detail(迁自老 Yii /v1/register/register-detail)
* 返回 result 为单对象(老接口是 data.list[0]),附 appointment 预约日期/时段信息
*/
export async function registeInfo(params) {
let data = await http('/xkApi/register/detail', params)
return data
}
/**
* 挂号支付 xk-api POST /register/pay(易票联)
* 存量调用方读 errcode/data,这里保留 normalize 过渡;0 元单返回 data.is_paid=1
*/
export async function registePay(params) {
let data = await http('/xkApi/register/pay', params)
return normalizeXkApiResponse(data)
}
/**
* 取消挂号 xk-api POST /register/cancel(仅未支付单,迁自老 Yii /v1/register/cancel)
*/
export async function registeUnpay(params) {
let data = await http('/xkApi/register/cancel', params)
return data
}
/**
* 挂号退款 xk-api POST /register/refund(已支付未接诊单,迁自老 Yii /v1/register/refund)
* 注意:老 Yii refund 同时兼容未付取消,xk-api 拆成 cancel/refund 两个接口,页面按 status 分流
*/
export async function registeCancle(params) {
let data = await http('/xkApi/register/refund', params)
return data
}

View File

@@ -39,7 +39,42 @@
<!-- 到店医生 预约挂号:聊天室只读进入时不展示挂号入口 -->
<view class="appoin" v-if="!readonly">
<view class="title">预约挂号</view>
<view class="list">
<!-- 新版排班日历:日期横条 + 时段选择(数据来自 xk-api 排班日历接口) -->
<view class="list" v-if="calendarDays.length > 0">
<scroll-view scroll-x class="day-scroll" :show-scrollbar="false">
<view class="day-strip">
<view class="day-item" v-for="(day, idx) in calendarDays" :key="day.date"
:class="{ active: idx === selectedDayIndex, disabled: !day.is_work || day.is_full }"
@click="selectDay(idx)">
<view class="day-week">{{day.week}}</view>
<view class="day-date">{{day.date_text}}</view>
<view class="day-state" :class="{ rest: !day.is_work, full: day.is_work && day.is_full }">{{day.state_text}}</view>
</view>
</view>
</scroll-view>
<!-- 时段选择:全天单时段自动选中;上下午/自定义时段展示可选卡片 -->
<view class="slot-list" v-if="selectedDay && selectedDay.is_work && selectedDay.slots.length > 1">
<view class="slot-item" v-for="slot in selectedDay.slots" :key="slot.slot_id"
:class="{ active: slot.slot_id === selectedSlotId, disabled: slot.is_full || slot.is_expired }"
@click="selectSlot(slot)">
<view class="slot-name">{{slot.slot_name}}</view>
<view class="slot-time">{{slot.start_time}}-{{slot.end_time}}</view>
<view class="slot-left" :class="{ full: slot.is_full || slot.is_expired }">{{slot.state_text}}</view>
</view>
</view>
<view class="rest-tip" v-if="selectedDay && !selectedDay.is_work">该日医生休诊,请选择其他日期</view>
<view class="yard book-bar">
<view class="stores">
<view class="times" v-if="selectedSlotLabel">{{selectedSlotLabel}}</view>
<text class="price">{{registList.register_price}}</text>
</view>
<view class="btn" :class="{ active: !canBook }" @click="goAdd">
{{canBook ? '挂号' : '不可约'}}
</view>
</view>
</view>
<!-- 旧版回退:日历加载失败或医生停诊时展示今日余号 -->
<view class="list" v-else>
<view class="yard">
<view class="stores">
<view class="times">{{registList.time}}</view>
@@ -100,10 +135,13 @@
import {
commentList,
doctorDetail,
registerList,
storeChange,
userList
} from '@/request/api/api'
import {
registerCalendar,
registerList
} from '@/request/api/register.js'
import { isGuestMode, isLoggedIn, saveRedirectInfo, buildUrlWithParams } from '@/common/utils/auth.js';
export default {
data() {
@@ -123,8 +161,41 @@
rType: '0', // 挂号类型
// 聊天室等场景只读查看:隐藏挂号按钮区
readonly: false,
// 排班日历:未来 N 天出诊/时段/余号(xk-api schedule-calendar / guest doc-register-info 的 calendar)
calendarDays: [],
selectedDayIndex: 0, // 当前选中日期下标
selectedSlotId: -1, // 当前选中时段ID(-1=未选,0=全天兜底)
}
},
computed: {
/** 当前选中的日期对象 */
selectedDay() {
return this.calendarDays[this.selectedDayIndex] || null;
},
/** 当前选中的时段对象 */
selectedSlot() {
if (!this.selectedDay || this.selectedSlotId < 0) return null;
const list = this.selectedDay.slots || [];
for (let i = 0; i < list.length; i++) {
if (list[i].slot_id === this.selectedSlotId) return list[i];
}
return null;
},
/** 选中信息文案:日期 + 时段名 + 起止时间 */
selectedSlotLabel() {
if (!this.selectedDay) return '';
if (!this.selectedSlot) return this.selectedDay.date_text + ' ' + this.selectedDay.week;
const s = this.selectedSlot;
const timeText = s.start_time === '00:00' && s.end_time === '23:59' ? '' : ' ' + s.start_time + '-' + s.end_time;
return this.selectedDay.date_text + ' ' + this.selectedDay.week + ' ' + s.slot_name + timeText;
},
/** 是否可预约:选中日出诊且所选时段未满未过时 */
canBook() {
if (!this.selectedDay || !this.selectedDay.is_work) return false;
const s = this.selectedSlot;
return !!(s && !s.is_full && !s.is_expired);
},
},
onLoad(e) {
console.log(e, 'e');
this.readonly = e.readonly === '1' || e.readonly === 1;
@@ -185,6 +256,62 @@
url: "/subPackages/doctor/doctor-info?id=" + this.id
})
},
// 选择预约日期:切换后默认选中该日第一个可约时段
selectDay(idx) {
this.selectedDayIndex = idx;
this.autoSelectSlot();
},
// 选择时段:约满/已过时的不可选
selectSlot(slot) {
if (slot.is_full || slot.is_expired) return;
this.selectedSlotId = slot.slot_id;
},
// 自动选中当前日期下第一个可约时段(全天单时段直接选中)
autoSelectSlot() {
this.selectedSlotId = -1;
const day = this.calendarDays[this.selectedDayIndex];
if (!day || !day.is_work) return;
const list = day.slots || [];
for (let i = 0; i < list.length; i++) {
if (!list[i].is_full && !list[i].is_expired) {
this.selectedSlotId = list[i].slot_id;
return;
}
}
},
/**
* 预处理日历数据:补充展示文案(MM-DD、余号/约满/休诊),
* 并默认定位到第一个可约日期。文案预计算是因为小程序模板禁止 :class/插值调方法
*/
applyCalendar(calendar) {
const days = (calendar && calendar.days) || [];
const processed = days.map((day) => {
const dateParts = (day.date || '').split('-');
const dateText = dateParts.length === 3 ? dateParts[1] + '-' + dateParts[2] : day.date;
let stateText = '休诊';
if (day.is_work) {
stateText = day.is_full ? '约满' : '余' + day.left;
}
const slots = (day.slots || []).map((slot) => {
let slotState = '余' + slot.left;
if (slot.is_expired) slotState = '已过时';
else if (slot.is_full) slotState = '约满';
return Object.assign({}, slot, { state_text: slotState });
});
return Object.assign({}, day, { date_text: dateText, state_text: stateText, slots: slots });
});
this.calendarDays = processed;
// 默认选第一个可约日期(出诊且未约满),都不可约时停在今天
let idx = 0;
for (let i = 0; i < processed.length; i++) {
if (processed[i].is_work && !processed[i].is_full) {
idx = i;
break;
}
}
this.selectedDayIndex = idx;
this.autoSelectSlot();
},
// 挂号
goAdd() {
// 只读模式不允许挂号
@@ -206,8 +333,19 @@
});
return;
}
if (this.num == 0) {
// 新版日历:校验所选日期时段可约
if (this.calendarDays.length > 0) {
if (!this.canBook) {
uni.showToast({
title: '该日期暂无可约号源',
duration: 2000,
icon: "none"
});
return
}
} else if (this.num == 0) {
// 旧版回退:仅校验今日余号
uni.showToast({
title: '暂无号源',
duration: 2000,
@@ -223,9 +361,13 @@
return
}
uni.navigateTo({
url: "/subPackages/doctor/doctor-userinfo?id=" + this.doctorID + "&r_type=" + this.rType,
})
// 携带预约日期+时段跳转建单流程(旧回退场景不带参,后端默认今天全天)
let url = "/subPackages/doctor/doctor-userinfo?id=" + this.doctorID + "&r_type=" + this.rType;
if (this.calendarDays.length > 0 && this.selectedDay && this.selectedSlot) {
url += "&visit_date=" + this.selectedDay.date + "&slot_id=" + this.selectedSlot.slot_id
+ "&slot_label=" + encodeURIComponent(this.selectedSlotLabel);
}
uni.navigateTo({ url: url })
},
// 评价
@@ -285,31 +427,70 @@
})
},
// 预约挂号
/**
* 预约挂号号源:登录态走 xk-api 排班日历接口(schedule-calendar),
* 游客态仍调 doc-register-info(请求层自动重写到 xk-api guest 版,响应带 calendar 字段)
* 两者都返回未来 N 天出诊/时段/余号,用 applyCalendar 统一渲染
*/
getRegist() {
registerList({
method: "post",
const isGuest = isGuestMode() && !uni.getStorageSync('token');
if (isGuest) {
// 游客:doc-register-info(xk-api guest 版),code/result 形态,result 带 calendar
registerList({
method: "post",
data: {
service_user_id: this.doctorID,
store_id: uni.getStorageSync('store_id') || '11001',
}
}).then((res) => {
if (res.data.code === 0 || res.data.code === '0') {
const responseData = res.data.result || {};
this.registList = {
time: responseData.time || '',
register_price: responseData.register_price || 0,
left_num: parseInt(responseData.left_num) || 0,
register_num: parseInt(responseData.register_num) || 0,
register_status: responseData.register_status || 1
};
this.num = this.registList.left_num;
if (responseData.register_status == 1 && responseData.calendar) {
this.applyCalendar(responseData.calendar);
} else {
this.calendarDays = [];
}
}
})
return;
}
// 登录:xk-api 排班日历(code/result 形态)
registerCalendar({
method: "get",
data: {
service_user_id: this.doctorID,
doctor_id: this.doctorID,
store_id: uni.getStorageSync('store_id') || '11001',
}
}).then((res) => {
// console.log(res, 'reg');
const isGuest = isGuestMode();
const isNewFormat = isGuest && (res.data.code === 0 || res.data.code === '0');
const isOldFormat = !isGuest && (res.data.errcode === 0 || res.data.errcode === '0');
if (isNewFormat || isOldFormat) {
const responseData = isGuest && res.data.result ? res.data.result : res.data.data;
// 确保所有字段都有默认值,避免显示 undefined
if (res.data.code === 0 || res.data.code === '0') {
const responseData = res.data.result || {};
// 老字段兜底:日历模式下 left_num 汇总所有可约天余号,供旧回退区与 goAdd 老校验使用
let totalLeft = 0;
const days = (responseData.days || []);
for (let i = 0; i < days.length; i++) {
totalLeft += days[i].left || 0;
}
this.registList = {
time: responseData.time || '',
time: '',
register_price: responseData.register_price || 0,
left_num: parseInt(responseData.left_num) || 0,
register_num: parseInt(responseData.register_num) || 0,
register_status: responseData.register_status || 1
left_num: totalLeft,
register_num: 0,
register_status: responseData.register_status || 0
};
this.num = this.registList.left_num;
this.num = totalLeft;
if (responseData.register_status == 1) {
this.applyCalendar(responseData);
} else {
this.calendarDays = [];
}
}
})
},
@@ -574,6 +755,126 @@
background: #E0E1E3;
color: #232323;
}
// 日期横条:横向滚动的未来 N 天卡片
.day-scroll {
width: 670rpx;
white-space: nowrap;
.day-strip {
display: inline-flex;
}
.day-item {
display: inline-flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 128rpx;
padding: 16rpx 0;
margin-right: 16rpx;
border-radius: 12rpx;
border: 2rpx solid #E2E8F0;
background: #FFFFFF;
.day-week {
font-size: 26rpx;
font-weight: 600;
color: #1E293B;
}
.day-date {
font-size: 24rpx;
color: #64748B;
margin: 6rpx 0;
}
.day-state {
font-size: 22rpx;
color: #4175EE;
&.rest {
color: #94A3B8;
}
&.full {
color: #F44336;
}
}
&.active {
border-color: #4175EE;
background: rgba(65, 117, 238, 0.08);
}
&.disabled {
opacity: 0.55;
}
}
}
// 时段卡片:上下午/自定义时段单选
.slot-list {
display: flex;
flex-wrap: wrap;
margin-top: 20rpx;
.slot-item {
display: flex;
flex-direction: column;
align-items: center;
width: 208rpx;
padding: 14rpx 0;
margin: 0 16rpx 16rpx 0;
border-radius: 12rpx;
border: 2rpx solid #E2E8F0;
background: #FFFFFF;
.slot-name {
font-size: 26rpx;
font-weight: 600;
color: #1E293B;
}
.slot-time {
font-size: 22rpx;
color: #64748B;
margin: 4rpx 0;
}
.slot-left {
font-size: 22rpx;
color: #4175EE;
&.full {
color: #94A3B8;
}
}
&.active {
border-color: #4175EE;
background: rgba(65, 117, 238, 0.08);
}
&.disabled {
opacity: 0.55;
}
}
}
.rest-tip {
margin-top: 20rpx;
font-size: 26rpx;
color: #94A3B8;
text-align: center;
padding: 24rpx 0;
}
.book-bar {
margin-top: 20rpx;
padding-top: 20rpx;
border-top: 2rpx solid #F1F5F9;
}
}
}

View File

@@ -20,6 +20,9 @@
:register-type-prop="registerType"
:initial-r-info="rInfo"
:delegate-store-id-prop="delegateStoreId"
:visit-date-prop="visitDate"
:slot-id-prop="slotId"
:slot-label-prop="slotLabel"
@register-created="onRegisterCreated"
/>
</view>
@@ -69,6 +72,10 @@ export default {
stepDirection: 'forward',
transitionPhase: '',
isStepTransitioning: false,
// 预约日期(Y-m-d)+ 时段ID + 展示文案:由医生详情页排班日历选择后带入,建单时传给 xk-api
visitDate: '',
slotId: 0,
slotLabel: '',
};
},
computed: {
@@ -172,6 +179,10 @@ export default {
this.isStepTransitioning = false;
this.transitionPhase = '';
this.doctorId = e.id || '';
// 医生详情页排班日历选择的预约日期/时段(不传则后端默认今天全天)
this.visitDate = e.visit_date || '';
this.slotId = Number(e.slot_id || 0);
this.slotLabel = e.slot_label ? decodeURIComponent(e.slot_label) : '';
if (e.r_type) {
this.registerType = e.r_type;
if (e.r_info) {

View File

@@ -51,6 +51,10 @@
<view class="list_name">预约序号</view>
<text>{{item.order_number}}</text>
</view>
<view class="info" v-if="item.appointment && item.appointment.visit_date">
<view class="list_name">预约时间</view>
<text>{{ appointmentText(item.appointment) }}</text>
</view>
<TransferPrescriptionCard
v-if="item.is_from_transfer == 1 && item.transfer_prescription"
:transfer-data="item.transfer_prescription"
@@ -91,6 +95,14 @@
if (status == 7) return '已拒诊'
return ''
},
/** 预约时间文案:日期+时段名,全天时段(00:00-23:59)不显示起止时间 */
appointmentText(appt) {
let text = appt.visit_date + ' ' + (appt.slot_name || '')
if (appt.start_time && appt.end_time && !(appt.start_time === '00:00' && appt.end_time === '23:59')) {
text += ' ' + appt.start_time + '-' + appt.end_time
}
return text
},
getInfo(id) {
uni.navigateTo({
url: '/subPackages/register/register-info?id=' + id + '&type=' + 1

View File

@@ -48,9 +48,12 @@
</view>
<view class="item">
<view class="aapoint">
预计就诊时间
预约时间
</view>
<view class="detail">
<view class="detail" v-if="appointmentText">
{{appointmentText}}
</view>
<view class="detail" v-else>
{{registList.created_at}}
</view>
</view>
@@ -150,10 +153,12 @@
<script>
import {
registeInfo,
registePay,
service
} from '@/request/api/api';
import {
registeInfo,
registePay
} from '@/request/api/register.js';
import { createRoomByDoctorIdApi, sendToUserApi } from '@/request/api/im';
import { checkDev } from '@/utils/utils';
import { genOrderApi } from '@/request/api/order';
@@ -209,6 +214,16 @@
shouldEnablePageBackGuard() {
return !(this.registList && this.registList.is_pay == 1);
},
/** 预约时间文案:占号信息(日期+时段),全天时段不显示起止时间;老单无占号返回空回退创建时间 */
appointmentText() {
const appt = this.registList && this.registList.appointment;
if (!appt || !appt.visit_date) return '';
let text = appt.visit_date + ' ' + (appt.slot_name || '');
if (appt.start_time && appt.end_time && !(appt.start_time === '00:00' && appt.end_time === '23:59')) {
text += ' ' + appt.start_time + '-' + appt.end_time;
}
return text;
},
},
watch: {
'registList.is_pay'(val) {
@@ -460,6 +475,7 @@
getInfo() {
const that = this;
if (!this.register_id) return Promise.resolve();
// 详情已迁 xk-api(POST /register/detail):result 为单对象(老 Yii 是 data.list[0]),附 appointment 预约信息
const p = registeInfo({
method: 'post',
data: {
@@ -467,8 +483,8 @@
register_id: that.register_id
}
}).then((res) => {
if (res.data.errcode == 0 && res.data.data.list && res.data.data.list[0]) {
that.registList = res.data.data.list[0];
if (res.data.code == 0 && res.data.result) {
that.registList = res.data.result;
that.registerType = that.registerMap[that.registList.register_type];
if (that.registList.service_user_id) {
that.applyDoctorNumericId(that.registList.service_user_id);

View File

@@ -10,6 +10,10 @@
<text v-if="showDelegateInfo" class="delegate-info">
委托诊所:{{ delegateStoreName }} 委托医生:{{ delegateDoctorName }}
</text>
<!-- 排班日历选择的预约时段(到店挂号带入) -->
<text v-if="slotLabelProp" class="delegate-info">
预约时段:{{ slotLabelProp }}
</text>
<text class="sub-title">请选择患者信息,以便医生给出更准确的诊疗建议,患者信息仅医生可见</text>
</view>
@@ -182,10 +186,10 @@
import {
userList,
userEidtPatient,
registe,
storeInfo,
doctorDetail,
} from '@/request/api/api.js';
import { registe } from '@/request/api/register.js';
import { getClinicOnlineConsultationInfoApi } from '@/request/api/product';
import { createRegisterInfoApi, saveRegisterInfoApi } from '@/request/api/order';
import request from '@/request/api/request';
@@ -209,6 +213,21 @@ export default {
type: String,
default: '',
},
// 预约日期(Y-m-d,医生详情页排班日历选择,空=后端默认今天)
visitDateProp: {
type: String,
default: '',
},
// 预约时段ID(0=全天兜底)
slotIdProp: {
type: [String, Number],
default: 0,
},
// 预约时段展示文案(如「08-13 周四 上午 08:00-12:00」)
slotLabelProp: {
type: String,
default: '',
},
},
data() {
return {
@@ -570,6 +589,8 @@ export default {
this.registerType === '2' ||
this.registerType === '3' ||
(this.registerType !== '0' && !!this.delegateStoreId);
// 建单已迁 xk-api(POST /register/create),响应按 code/result 读取;
// visit_date/slot_id 由医生详情页排班日历带入,不传则后端默认今天全天
registe({
method: 'post',
data: {
@@ -578,20 +599,22 @@ export default {
store_id: storeId,
origin_store_id: shouldSendOriginStoreId ? originStoreId : 0,
service_user_id: this.Did,
register_type: this.registerType
register_type: this.registerType,
visit_date: this.visitDateProp || '',
slot_id: Number(this.slotIdProp || 0)
}
}).then(async (res) => {
if (res.data.errcode == 0) {
this.register_id = res.data.data.register_id;
if (res.data.code == 0) {
this.register_id = res.data.result.register_id;
if (this.registerType === '3' || this.registerType === '2') {
await this.afterRegisterCreated(followUpRInfo);
return;
}
uni.setStorageSync('register_id', this.register_id);
this.emitRegisterCreated(followUpRInfo, res.data.data.isHas == 1);
this.emitRegisterCreated(followUpRInfo, res.data.result.isHas == 1);
} else {
this.$refs.uToast.show({
title: res.data.msg,
title: res.data.message,
type: 'default',
icon: false
});

View File

@@ -88,9 +88,12 @@
</view>
<view class="item">
<view class="aapoint">
预计就诊时间
预约时间
</view>
<view class="detail">
<view class="detail" v-if="appointmentText">
{{appointmentText}}
</view>
<view class="detail" v-else>
{{registList.created_at}}
</view>
</view>
@@ -172,8 +175,9 @@
import {
registeCancle,
registeInfo,
registePay
} from '../../request/api/api';
registePay,
registeUnpay
} from '../../request/api/register.js';
export default {
data() {
return {
@@ -185,6 +189,18 @@
type: 0,
}
},
computed: {
/** 预约时间文案:占号信息(日期+时段),全天时段不显示起止时间;老单无占号回退创建时间 */
appointmentText() {
const appt = this.registList && this.registList.appointment;
if (!appt || !appt.visit_date) return '';
let text = appt.visit_date + ' ' + (appt.slot_name || '');
if (appt.start_time && appt.end_time && !(appt.start_time === '00:00' && appt.end_time === '23:59')) {
text += ' ' + appt.start_time + '-' + appt.end_time;
}
return text;
},
},
onLoad(e) {
this.register_id = e.id
this.type = e.type
@@ -209,17 +225,21 @@
open() {
this.show = true;
},
// 取消预约
/**
* 取消预约(已迁 xk-api):老 Yii refund 一个接口兼容未付/已付,
* xk-api 拆成 cancel(未付取消)与 refund(已付退款),按订单状态分流
*/
cancel() {
registeCancle({
const isPaid = this.registList && this.registList.is_pay == 1;
const doCancel = isPaid ? registeCancle : registeUnpay;
doCancel({
method: "post",
data: {
store_id: uni.getStorageSync('store_id') || '11001',
register_id: this.register_id
}
}).then((res) => {
// console.log(res, 'tk');
if (res.data.errcode == 0) {
if (res.data.code == 0) {
this.isshow = true
uni.showLoading({
title: "加载中"
@@ -227,7 +247,7 @@
setTimeout(() => {
uni.hideLoading();
uni.showToast({
title: "取消成功",
title: isPaid ? "退款申请成功" : "取消成功",
duration: 1500,
mask: false,
icon: 'success'
@@ -237,7 +257,7 @@
} else {
uni.hideLoading();
this.$refs.uToast.show({
title: res.data.msg,
title: res.data.message,
type: 'default',
icon: false
})
@@ -338,7 +358,7 @@
})
},
// 挂号信息
// 挂号信息(已迁 xk-api POST /register/detail:result 为单对象,老 Yii 是 data.list[0])
getInfo() {
registeInfo({
method: "post",
@@ -347,9 +367,8 @@
register_id: this.register_id
}
}).then((res) => {
// console.log(res, 'ghxq');
if (res.data.errcode == 0) {
this.registList = res.data.data.list[0]
if (res.data.code == 0 && res.data.result) {
this.registList = res.data.result
}
})
},