328 lines
9.8 KiB
Plaintext
328 lines
9.8 KiB
Plaintext
<template>
|
|
<ServicePageScaffold title="服务记录" fallback-url="/pages/mall/delivery/orders/detail">
|
|
<view class="page">
|
|
<view class="card">
|
|
<text class="section-title">服务时间</text>
|
|
<input class="field" v-model="startTime" placeholder="服务开始时间,例如 2026-05-20 15:00" />
|
|
<input class="field" v-model="endTime" placeholder="服务结束时间,例如 2026-05-20 16:30" />
|
|
<input class="field" v-model="actualDurationText" placeholder="实际服务时长(分钟)" type="number" />
|
|
</view>
|
|
|
|
<view class="card">
|
|
<text class="section-title">服务内容</text>
|
|
<view v-for="item in serviceItems" :key="item.id" class="item-row">
|
|
<view class="item-top">
|
|
<text class="item-name">{{ item.name }}</text>
|
|
<switch :checked="item.completed" color="#1f7db4" @change="toggleItem(item.id, $event)" />
|
|
</view>
|
|
<input class="field" v-model="item.remark" placeholder="服务过程说明" />
|
|
<input v-if="item.completed == false" class="field" v-model="item.incompleteReason" placeholder="未完成原因" />
|
|
</view>
|
|
</view>
|
|
|
|
<view class="card">
|
|
<text class="section-title">健康与过程记录</text>
|
|
<textarea class="textarea" v-model="processNote" placeholder="服务过程说明"></textarea>
|
|
<input class="field" v-model="elderStatus" placeholder="服务对象状态" />
|
|
<input class="field" v-model="bloodPressure" placeholder="血压" />
|
|
<input class="field" v-model="heartRate" placeholder="心率" />
|
|
<input class="field" v-model="bloodSugar" placeholder="血糖" />
|
|
<input class="field" v-model="bloodOxygen" placeholder="血氧" />
|
|
<input class="field" v-model="materialsUsed" placeholder="耗材使用记录" />
|
|
<input class="field" v-model="abnormalNote" placeholder="异常情况说明" />
|
|
<input class="field" v-model="staffRemark" placeholder="服务人员备注" />
|
|
<view class="placeholder-row">
|
|
<view class="placeholder-btn" @click="mockPhoto"><text class="placeholder-btn-text">服务照片占位</text></view>
|
|
<text class="placeholder-text">{{ photosText }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="card">
|
|
<text class="section-title">家属确认方式</text>
|
|
<view class="confirm-row">
|
|
<view class="confirm-item" :class="confirmMethod == 'sms_code' ? 'confirm-item-active' : ''" @click="confirmMethod = 'sms_code'"><text class="confirm-text">验证码确认</text></view>
|
|
<view class="confirm-item" :class="confirmMethod == 'signature' ? 'confirm-item-active' : ''" @click="confirmMethod = 'signature'"><text class="confirm-text">签字确认</text></view>
|
|
</view>
|
|
<input v-if="confirmMethod == 'sms_code'" class="field" v-model="confirmCode" placeholder="验证码 mock" />
|
|
<input v-else class="field" v-model="signatureName" placeholder="签字人姓名 mock" />
|
|
</view>
|
|
|
|
<view class="action-row">
|
|
<view class="outline-btn" @click="goBack"><text class="outline-btn-text">返回详情</text></view>
|
|
<view class="primary-btn" @click="submitRecord"><text class="primary-btn-text">提交服务记录</text></view>
|
|
</view>
|
|
</view>
|
|
</ServicePageScaffold>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import { computed, ref } from 'vue'
|
|
import { onLoad } from '@dcloudio/uni-app'
|
|
import ServicePageScaffold from '@/components/homeService/ServicePageScaffold.uvue'
|
|
import type { DeliveryOrderType, DeliveryServiceItemType, DeliveryServiceRecordType } from '@/types/delivery.uts'
|
|
import { getServiceOrderDetail, submitServiceRecord } from '@/services/deliveryService.uts'
|
|
import { requireDeliveryAuth } from '@/utils/deliveryAuth.uts'
|
|
import { getDeliveryRouteParam } from '@/utils/deliveryRoute.uts'
|
|
|
|
const orderId = ref('')
|
|
const order = ref<DeliveryOrderType | null>(null)
|
|
const serviceItems = ref([] as Array<DeliveryServiceItemType>)
|
|
const startTime = ref('')
|
|
const endTime = ref('')
|
|
const actualDurationText = ref('90')
|
|
const processNote = ref('')
|
|
const elderStatus = ref('')
|
|
const bloodPressure = ref('')
|
|
const heartRate = ref('')
|
|
const bloodSugar = ref('')
|
|
const bloodOxygen = ref('')
|
|
const materialsUsed = ref('')
|
|
const abnormalNote = ref('')
|
|
const staffRemark = ref('')
|
|
const confirmMethod = ref('sms_code')
|
|
const confirmCode = ref('')
|
|
const signatureName = ref('')
|
|
const photoCount = ref(0)
|
|
|
|
const photosText = computed((): string => '已添加占位照片 ' + String(photoCount.value) + ' 张')
|
|
|
|
function toggleItem(itemId: string, event: any) {
|
|
for (let i = 0; i < serviceItems.value.length; i++) {
|
|
if (serviceItems.value[i].id == itemId) {
|
|
serviceItems.value[i].completed = event.detail.value === true
|
|
serviceItems.value[i].updatedAt = new Date().toISOString().replace('T', ' ').substring(0, 19)
|
|
if (serviceItems.value[i].completed) {
|
|
serviceItems.value[i].incompleteReason = ''
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function mockPhoto() {
|
|
photoCount.value = photoCount.value + 1
|
|
uni.showToast({ title: '已添加照片占位', icon: 'success' })
|
|
}
|
|
|
|
async function loadData() {
|
|
const authResult = await requireDeliveryAuth({ redirectOnFail: true, toastOnFail: true })
|
|
if (!authResult.ok || orderId.value == '') {
|
|
return
|
|
}
|
|
order.value = await getServiceOrderDetail(orderId.value)
|
|
if (order.value != null) {
|
|
serviceItems.value = order.value.serviceItems
|
|
startTime.value = order.value.startServiceTime != null && order.value.startServiceTime != '' ? order.value.startServiceTime : order.value.appointmentTime
|
|
endTime.value = order.value.finishTime
|
|
processNote.value = order.value.serviceSummary
|
|
staffRemark.value = order.value.progressNote
|
|
if (order.value.serviceRecord != null) {
|
|
elderStatus.value = order.value.serviceRecord!.elderStatus
|
|
bloodPressure.value = order.value.serviceRecord!.healthMetrics.bloodPressure
|
|
heartRate.value = order.value.serviceRecord!.healthMetrics.heartRate
|
|
bloodSugar.value = order.value.serviceRecord!.healthMetrics.bloodSugar
|
|
bloodOxygen.value = order.value.serviceRecord!.healthMetrics.bloodOxygen
|
|
materialsUsed.value = order.value.serviceRecord!.materialsUsed
|
|
abnormalNote.value = order.value.serviceRecord!.abnormalNote
|
|
}
|
|
}
|
|
}
|
|
|
|
function validateRecord(): boolean {
|
|
if (startTime.value == '' || endTime.value == '') {
|
|
uni.showToast({ title: '请填写开始和结束时间', icon: 'none' })
|
|
return false
|
|
}
|
|
for (let i = 0; i < serviceItems.value.length; i++) {
|
|
if (serviceItems.value[i].completed == false && serviceItems.value[i].incompleteReason == '') {
|
|
uni.showToast({ title: '未完成项目需要说明原因', icon: 'none' })
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
async function submitRecordAction() {
|
|
if (!validateRecord()) {
|
|
return
|
|
}
|
|
const record = {
|
|
id: 'record-' + orderId.value,
|
|
orderId: orderId.value,
|
|
startTime: startTime.value,
|
|
endTime: endTime.value,
|
|
actualDurationMinutes: parseInt(actualDurationText.value),
|
|
serviceItems: serviceItems.value,
|
|
serviceContent: serviceItems.value.filter((item) => item.completed).map((item) => item.name),
|
|
processNote: processNote.value,
|
|
elderStatus: elderStatus.value,
|
|
healthMetrics: {
|
|
bloodPressure: bloodPressure.value,
|
|
heartRate: heartRate.value,
|
|
bloodSugar: bloodSugar.value,
|
|
bloodOxygen: bloodOxygen.value
|
|
},
|
|
materialsUsed: materialsUsed.value,
|
|
abnormalNote: abnormalNote.value,
|
|
photos: photoCount.value > 0 ? ['mock-photo-' + String(photoCount.value)] : [] as Array<string>,
|
|
staffRemark: staffRemark.value,
|
|
familyConfirmation: {
|
|
method: confirmMethod.value == 'sms_code' ? 'sms_code' : 'signature',
|
|
code: confirmCode.value,
|
|
signatureName: signatureName.value,
|
|
signatureUrl: '',
|
|
confirmedAt: new Date().toISOString().replace('T', ' ').substring(0, 19)
|
|
},
|
|
createdAt: new Date().toISOString().replace('T', ' ').substring(0, 19),
|
|
updatedAt: new Date().toISOString().replace('T', ' ').substring(0, 19)
|
|
} as DeliveryServiceRecordType
|
|
await submitServiceRecord(orderId.value, record)
|
|
uni.showToast({ title: '服务记录已提交', icon: 'success' })
|
|
setTimeout(() => {
|
|
uni.redirectTo({ url: '/pages/mall/delivery/orders/detail?id=' + orderId.value })
|
|
}, 300)
|
|
}
|
|
|
|
function submitRecord() {
|
|
submitRecordAction()
|
|
}
|
|
|
|
function goBack() {
|
|
uni.redirectTo({ url: '/pages/mall/delivery/orders/detail?id=' + orderId.value })
|
|
}
|
|
|
|
onLoad((options) => {
|
|
if (options != null) {
|
|
orderId.value = getDeliveryRouteParam(options as UTSJSONObject, 'id')
|
|
}
|
|
loadData()
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.page {
|
|
padding-bottom: 32rpx;
|
|
}
|
|
|
|
.card {
|
|
margin-bottom: 18rpx;
|
|
padding: 24rpx;
|
|
border-radius: 24rpx;
|
|
background-color: #ffffff;
|
|
box-shadow: 0 10rpx 24rpx rgba(15, 35, 55, 0.06);
|
|
}
|
|
|
|
.section-title,
|
|
.item-name,
|
|
.primary-btn-text,
|
|
.confirm-text {
|
|
font-weight: 700;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 30rpx;
|
|
color: #16324f;
|
|
}
|
|
|
|
.field,
|
|
.textarea {
|
|
margin-top: 16rpx;
|
|
padding: 0 20rpx;
|
|
border-radius: 18rpx;
|
|
background-color: #f4f8fb;
|
|
font-size: 26rpx;
|
|
color: #16324f;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.field {
|
|
height: 84rpx;
|
|
}
|
|
|
|
.textarea {
|
|
width: 100%;
|
|
min-height: 180rpx;
|
|
padding-top: 20rpx;
|
|
padding-bottom: 20rpx;
|
|
}
|
|
|
|
.item-row {
|
|
margin-top: 16rpx;
|
|
padding: 18rpx;
|
|
border-radius: 18rpx;
|
|
background-color: #f7fbfd;
|
|
}
|
|
|
|
.item-top,
|
|
.placeholder-row,
|
|
.confirm-row,
|
|
.action-row {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.item-name {
|
|
font-size: 28rpx;
|
|
color: #16324f;
|
|
}
|
|
|
|
.placeholder-row,
|
|
.action-row {
|
|
margin-top: 16rpx;
|
|
}
|
|
|
|
.placeholder-btn,
|
|
.confirm-item,
|
|
.outline-btn,
|
|
.primary-btn {
|
|
padding: 18rpx 0;
|
|
border-radius: 18rpx;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.placeholder-btn,
|
|
.confirm-item,
|
|
.outline-btn {
|
|
background-color: #eef6fa;
|
|
}
|
|
|
|
.placeholder-btn {
|
|
width: 42%;
|
|
}
|
|
|
|
.placeholder-btn-text,
|
|
.placeholder-text,
|
|
.outline-btn-text {
|
|
font-size: 24rpx;
|
|
color: #5e758c;
|
|
}
|
|
|
|
.confirm-item {
|
|
width: 48%;
|
|
}
|
|
|
|
.confirm-item-active {
|
|
background-color: #d8eef9;
|
|
}
|
|
|
|
.confirm-text {
|
|
font-size: 26rpx;
|
|
color: #176e97;
|
|
}
|
|
|
|
.outline-btn,
|
|
.primary-btn {
|
|
width: 48%;
|
|
}
|
|
|
|
.primary-btn {
|
|
background-color: #1f7db4;
|
|
}
|
|
|
|
.primary-btn-text {
|
|
font-size: 26rpx;
|
|
color: #ffffff;
|
|
}
|
|
</style> |