Files
medical-mall/services/homeServiceService.uts

993 lines
32 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
HomeServiceAcceptanceType,
HomeServiceAdminApplicationType,
HomeServiceAssessmentType,
HomeServiceApplicationDraftType,
HomeServiceCatalogType,
HomeServiceCaseType,
HomeServiceOverviewCardType,
HomeServicePlanType,
HomeServiceRectificationType,
HomeServiceSettlementType,
HomeServiceTaskType,
HomeServiceTimelineItemType
} from '@/types/home-service.uts'
import {
confirmServiceOrder,
createServiceOrder,
getServiceOrderDetail,
listConsumerServiceOrders,
rejectServiceOrderAcceptance
} from '@/services/serviceOrderService.uts'
import supa from '@/components/supadb/aksupainstance.uts'
import {
getServiceOrderStatusText,
type ServiceOrderStatus,
type ServiceOrderTimelineItemType,
type ServiceOrderType
} from '@/types/service-order.uts'
function plainObject(source: any): any {
return JSON.parse(JSON.stringify(source)) as any
}
function readString(source: any, key: string): string {
const value = plainObject(source)[key]
if (value == null) {
return ''
}
return typeof value == 'string' ? value : String(value)
}
function readNumber(source: any, key: string): number {
const value = plainObject(source)[key]
if (typeof value == 'number') {
return value
}
const parsed = Number(value)
return isNaN(parsed) ? 0 : parsed
}
function readStringArray(source: any, key: string): Array<string> {
const value = plainObject(source)[key]
if (Array.isArray(value)) {
const result = [] as Array<string>
for (let i = 0; i < value.length; i++) {
result.push(typeof value[i] == 'string' ? value[i] : String(value[i]))
}
return result
}
if (typeof value == 'string' && value != '') {
try {
const parsed = JSON.parse(value) as any
if (Array.isArray(parsed)) {
const result = [] as Array<string>
for (let i = 0; i < parsed.length; i++) {
result.push(typeof parsed[i] == 'string' ? parsed[i] : String(parsed[i]))
}
return result
}
} catch (error) {
return [] as Array<string>
}
}
return [] as Array<string>
}
function parseCatalogItem(source: any): HomeServiceCatalogType {
return {
id: readString(source, 'id'),
name: readString(source, 'name'),
category: readString(source, 'category'),
price: readNumber(source, 'price'),
durationText: readString(source, 'duration_text'),
summary: readString(source, 'summary'),
tags: readStringArray(source, 'tags_json'),
suitableFor: readString(source, 'suitable_for')
}
}
function createTimeline(title1: string, title2: string, title3: string): Array<HomeServiceTimelineItemType> {
return [
{
id: 'tl-1',
title: title1,
time: '2026-05-12 09:00',
description: '系统已建立服务申请档案。'
},
{
id: 'tl-2',
title: title2,
time: '2026-05-12 11:30',
description: '评估员已完成初步核对与上门安排。'
},
{
id: 'tl-3',
title: title3,
time: '2026-05-13 08:20',
description: '当前环节已进入待执行状态。'
}
]
}
const CASE_STORE: Array<HomeServiceCaseType> = [
{
id: 'case-001',
caseNo: 'HS202605130001',
status: 'pending_dispatch',
statusText: '待派单',
statusTone: 'warning',
serviceName: '基础上门护理',
serviceTime: '2026-05-14 09:00-11:00',
applicantName: '李晓兰',
elderName: '李奶奶',
age: 78,
phone: '13800138000',
address: '梅州市梅江区学海路 18 号 2 栋 602',
summary: '老人近期行动困难,需要基础照护与生命体征监测。',
currentStep: 3,
totalSteps: 8,
staffName: '待分配',
staffPhone: '待分配',
amount: 168,
timeline: createTimeline('已提交申请', '待上门评估', '待派单')
},
{
id: 'case-002',
caseNo: 'HS202605130002',
status: 'in_service',
statusText: '服务中',
statusTone: 'primary',
serviceName: '慢病健康随访',
serviceTime: '2026-05-13 15:00-16:30',
applicantName: '张春梅',
elderName: '张爷爷',
age: 82,
phone: '13900139000',
address: '梅州市梅县区华侨城康宁路 66 号',
summary: '随访血压血糖,核对用药并记录健康建议。',
currentStep: 6,
totalSteps: 8,
staffName: '陈护理',
staffPhone: '13688886666',
amount: 128,
timeline: createTimeline('已提交申请', '已生成服务方案', '服务执行中')
}
]
const TASK_STORE: Array<HomeServiceTaskType> = [
{
id: 'task-001',
caseId: 'case-001',
caseNo: 'HS202605130001',
status: 'pending_visit',
statusText: '待上门',
statusTone: 'warning',
serviceName: '基础上门护理',
elderName: '李奶奶',
address: '梅州市梅江区学海路 18 号 2 栋 602',
appointmentTime: '2026-05-14 09:00',
checkInStatus: '未签到',
recordSummary: '待填写服务记录',
staffName: '黄护理',
staffPhone: '13777770001',
actionText: '签到开始',
timeline: createTimeline('调度已派单', '护理员已接单', '等待上门签到')
},
{
id: 'task-002',
caseId: 'case-002',
caseNo: 'HS202605130002',
status: 'serving',
statusText: '服务中',
statusTone: 'primary',
serviceName: '慢病健康随访',
elderName: '张爷爷',
address: '梅州市梅县区华侨城康宁路 66 号',
appointmentTime: '2026-05-13 15:00',
checkInStatus: '已签到',
recordSummary: '已完成血压血糖记录,待补充宣教备注。',
staffName: '陈护理',
staffPhone: '13688886666',
actionText: '完成提交',
timeline: createTimeline('调度已派单', '已到岗签到', '服务执行中')
}
]
const ADMIN_APPLICATIONS: Array<HomeServiceAdminApplicationType> = [
{
id: 'admin-app-001',
caseId: 'case-001',
caseNo: 'HS202605130001',
status: 'pending_assessment',
statusText: '待评估',
statusTone: 'warning',
elderName: '李奶奶',
serviceName: '基础上门护理',
preferredTime: '2026-05-14 上午',
assessmentResult: '待评估员上门',
dispatcherName: '刘调度',
staffName: '待分配'
},
{
id: 'admin-app-002',
caseId: 'case-002',
caseNo: 'HS202605130002',
status: 'pending_acceptance',
statusText: '待验收',
statusTone: 'success',
elderName: '张爷爷',
serviceName: '慢病健康随访',
preferredTime: '2026-05-13 下午',
assessmentResult: '评估通过,按标准随访执行',
dispatcherName: '刘调度',
staffName: '陈护理'
}
]
const ADMIN_OVERVIEW: Array<HomeServiceOverviewCardType> = [
{ id: 'overview-1', label: '待评估申请', value: '06', tone: 'warning' },
{ id: 'overview-2', label: '待派单工单', value: '03', tone: 'primary' },
{ id: 'overview-3', label: '服务中任务', value: '08', tone: 'success' },
{ id: 'overview-4', label: '待验收任务', value: '04', tone: 'neutral' }
]
const ADMIN_ASSESSMENTS: Array<HomeServiceAssessmentType> = [
{
caseId: 'case-001',
caseNo: 'HS202605130001',
elderName: '李奶奶',
serviceName: '基础上门护理',
riskLevel: '中风险',
careLevel: '护理二级',
visitTime: '2026-05-14 09:00',
assessmentSummary: '行动缓慢,需重点关注跌倒风险和晨间血压波动。',
requirementTags: ['血压监测', '基础照护', '跌倒风险提醒']
},
{
caseId: 'case-002',
caseNo: 'HS202605130002',
elderName: '张爷爷',
serviceName: '慢病健康随访',
riskLevel: '低风险',
careLevel: '随访管理',
visitTime: '2026-05-13 15:00',
assessmentSummary: '生命体征稳定,重点跟踪慢病用药执行情况。',
requirementTags: ['血糖记录', '用药核对', '家属宣教']
}
]
const ADMIN_PLANS: Array<HomeServicePlanType> = [
{
caseId: 'case-001',
caseNo: 'HS202605130001',
elderName: '李奶奶',
serviceName: '基础上门护理',
planTitle: '基础护理 7 日方案',
serviceFrequency: '每周 3 次',
serviceCycle: '2026-05-14 至 2026-05-21',
executorAdvice: '优先安排熟悉慢病照护的护理员,首次上门同步评估跌倒风险。',
billingSummary: '基础护理 ¥168/次,计划总额 ¥504',
planSummary: '围绕晨间照护、生命体征监测和风险提醒开展服务。'
},
{
caseId: 'case-002',
caseNo: 'HS202605130002',
elderName: '张爷爷',
serviceName: '慢病健康随访',
planTitle: '慢病随访连续方案',
serviceFrequency: '每周 2 次',
serviceCycle: '2026-05-13 至 2026-05-27',
executorAdvice: '执行人员需同步上传血压血糖记录并完成家属宣教。',
billingSummary: '随访服务 ¥128/次,计划总额 ¥512',
planSummary: '持续随访血压血糖、用药和饮食管理情况。'
}
]
const ADMIN_RECTIFICATIONS: Array<HomeServiceRectificationType> = [
{
caseId: 'case-001',
caseNo: 'HS202605130001',
elderName: '李奶奶',
serviceName: '基础上门护理',
issueSummary: '家属要求补充护理动作说明和现场照片留痕。',
deadline: '2026-05-14 18:00',
ownerName: '黄护理',
status: 'pending',
statusText: '待整改'
},
{
caseId: 'case-002',
caseNo: 'HS202605130002',
elderName: '张爷爷',
serviceName: '慢病健康随访',
issueSummary: '记录完整,无需整改。',
deadline: '2026-05-15 12:00',
ownerName: '陈护理',
status: 'closed',
statusText: '已关闭'
}
]
const ADMIN_SETTLEMENTS: Array<HomeServiceSettlementType> = [
{
caseId: 'case-001',
caseNo: 'HS202605130001',
elderName: '李奶奶',
serviceName: '基础上门护理',
billingPeriod: '2026-05-14 至 2026-05-21',
totalAmount: '¥504',
insuranceAmount: '¥300',
selfPayAmount: '¥204',
archiveStatus: 'pending',
archiveStatusText: '待归档'
},
{
caseId: 'case-002',
caseNo: 'HS202605130002',
elderName: '张爷爷',
serviceName: '慢病健康随访',
billingPeriod: '2026-05-13 至 2026-05-27',
totalAmount: '¥512',
insuranceAmount: '¥256',
selfPayAmount: '¥256',
archiveStatus: 'pending',
archiveStatusText: '待归档'
}
]
function delay(): Promise<boolean> {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true)
}, 120)
})
}
function cloneCase(item: HomeServiceCaseType): HomeServiceCaseType {
return {
...item,
timeline: item.timeline.map((log) => ({ ...log }))
}
}
function cloneTask(item: HomeServiceTaskType): HomeServiceTaskType {
return {
...item,
timeline: item.timeline.map((log) => ({ ...log }))
}
}
function cloneAssessment(item: HomeServiceAssessmentType): HomeServiceAssessmentType {
return {
...item,
requirementTags: item.requirementTags.slice(0)
}
}
function clonePlan(item: HomeServicePlanType): HomeServicePlanType {
return {
...item
}
}
function cloneRectification(item: HomeServiceRectificationType): HomeServiceRectificationType {
return {
...item
}
}
function cloneSettlement(item: HomeServiceSettlementType): HomeServiceSettlementType {
return {
...item
}
}
export async function fetchHomeServiceCatalog(): Promise<Array<HomeServiceCatalogType>> {
const response = await supa
.from('hss_service_catalog')
.select('id, name, category, price, duration_text, summary, tags_json, suitable_for, sort_no')
.eq('status', 1)
.is('deleted_at', null)
.order('sort_no', { ascending: true })
.execute()
if (response.error != null || response.data == null || !Array.isArray(response.data)) {
return [] as Array<HomeServiceCatalogType>
}
const result = [] as Array<HomeServiceCatalogType>
for (let i = 0; i < response.data.length; i++) {
result.push(parseCatalogItem(response.data[i]))
}
return result
}
export async function fetchConsumerHomeServiceCases(): Promise<Array<HomeServiceCaseType>> {
const orders = await listConsumerServiceOrders()
const result = [] as Array<HomeServiceCaseType>
for (let i = 0; i < orders.length; i++) {
result.push(mapOrderToCase(orders[i]))
}
return result
}
export async function fetchConsumerHomeServiceCaseDetail(caseId: string): Promise<HomeServiceCaseType | null> {
const detail = await getServiceOrderDetail(caseId)
if (detail != null) {
return mapOrderToCase(detail)
}
return null
}
export async function createHomeServiceApplication(draft: HomeServiceApplicationDraftType): Promise<HomeServiceCaseType | null> {
const catalog = await fetchHomeServiceCatalog()
let matchedService: HomeServiceCatalogType | null = null
for (let i = 0; i < catalog.length; i++) {
if (catalog[i].id == draft.serviceId) {
matchedService = catalog[i]
break
}
}
if (matchedService != null && draft.serviceAddressSnapshot != null) {
const createdOrder = await createServiceOrder({
service: matchedService,
address: {
addressId: draft.serviceAddressSnapshot.addressId,
contactName: draft.serviceAddressSnapshot.contactName,
contactPhone: draft.serviceAddressSnapshot.contactPhone,
province: '',
city: '',
district: '',
detailAddress: draft.serviceAddressSnapshot.addressDetail,
fullAddress: draft.serviceAddressSnapshot.fullAddress,
latitude: draft.serviceAddressSnapshot.latitude,
longitude: draft.serviceAddressSnapshot.longitude,
coordinateType: draft.serviceAddressSnapshot.coordinateType,
remark: draft.serviceAddressSnapshot.remark
},
recipientName: draft.elderName,
recipientPhone: draft.phone,
contactName: draft.applicantName,
contactPhone: draft.phone,
appointmentTime: draft.preferredTime,
remark: draft.demandSummary
})
if (createdOrder != null) {
return mapOrderToCase(createdOrder)
}
}
return null
}
function getCaseStep(status: ServiceOrderStatus): number {
if (status == 'created') return 1
if (status == 'assigned') return 3
if (status == 'accepted') return 4
if (status == 'departed') return 5
if (status == 'arrived' || status == 'in_service') return 6
if (status == 'pending_acceptance') return 7
if (status == 'accepted_by_user' || status == 'reviewed' || status == 'settled') return 8
if (status == 'rejected' || status == 'cancelled' || status == 'exception') return 7
return 2
}
function getCaseTone(status: ServiceOrderStatus): string {
if (status == 'created' || status == 'assigned' || status == 'pending_acceptance') return 'warning'
if (status == 'accepted' || status == 'departed' || status == 'arrived' || status == 'in_service') return 'primary'
if (status == 'accepted_by_user' || status == 'reviewed' || status == 'settled') return 'success'
if (status == 'exception' || status == 'cancelled' || status == 'rejected') return 'danger'
return 'neutral'
}
function getTimelineDescription(log: ServiceOrderTimelineItemType): string {
if (log.remark != '') {
return log.remark
}
if (log.toStatus == 'created') return '平台已接收预约申请,等待后续处理。'
if (log.toStatus == 'assigned') return '系统已完成派单,正在通知服务人员。'
if (log.toStatus == 'accepted') return '服务人员已接单,正在准备上门。'
if (log.toStatus == 'departed') return '服务人员已出发,正在前往服务地点。'
if (log.toStatus == 'arrived') return '服务人员已到达服务地点。'
if (log.toStatus == 'in_service') return '服务已开始执行,请留意后续进度。'
if (log.toStatus == 'completed') return '服务执行已完成,正在整理结果。'
if (log.toStatus == 'pending_acceptance') return '服务记录已提交,等待家属验收。'
if (log.toStatus == 'accepted_by_user') return '家属已确认本次服务结果。'
if (log.toStatus == 'reviewed') return '家属已完成评价反馈。'
if (log.toStatus == 'settled') return '本次服务已完成结算归档。'
if (log.toStatus == 'cancelled') return '服务单已取消。'
if (log.toStatus == 'rejected') return '服务人员未接受该工单。'
return '服务过程状态已更新。'
}
function formatServiceAppointmentText(value: string): string {
if (value == '') {
return ''
}
if (value.indexOf('上午') >= 0 || value.indexOf('下午') >= 0 || value.indexOf('晚上') >= 0) {
return value
}
const parsed = Date.parse(value)
if (!isNaN(parsed)) {
const date = new Date(parsed)
let year = date.getFullYear()
const currentYear = new Date().getFullYear()
if (year < currentYear - 1) {
year = currentYear
}
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hour = String(date.getHours()).padStart(2, '0')
const minute = String(date.getMinutes()).padStart(2, '0')
return year + '-' + month + '-' + day + ' ' + hour + ':' + minute
}
const monthDayMatch = value.match(/(\d{2})\/(\d{2})/)
const timeMatch = value.match(/(\d{2}:\d{2}(\s*-\s*\d{2}:\d{2})?)/)
if (monthDayMatch != null) {
const month = monthDayMatch[1] ?? ''
const day = monthDayMatch[2] ?? ''
const timeText = timeMatch != null ? (timeMatch[1] ?? '') : ''
if (month != '' && day != '') {
return String(new Date().getFullYear()) + '-' + month + '-' + day + (timeText != '' ? ' ' + timeText.replace(/\s+/g, '') : '')
}
}
return value.replace('T', ' ')
}
function mapLogsToTimeline(logs: Array<ServiceOrderTimelineItemType>): Array<HomeServiceTimelineItemType> {
const timeline = [] as Array<HomeServiceTimelineItemType>
for (let i = 0; i < logs.length; i++) {
timeline.push({
id: logs[i].id,
title: getServiceOrderStatusText(logs[i].toStatus),
time: logs[i].createdAt,
description: getTimelineDescription(logs[i])
})
}
return timeline
}
function mapOrderToCase(order: ServiceOrderType): HomeServiceCaseType {
return {
id: order.id,
caseNo: order.orderNo,
status: order.status,
statusText: getServiceOrderStatusText(order.status),
statusTone: getCaseTone(order.status),
serviceName: order.serviceName,
serviceTime: formatServiceAppointmentText(order.appointmentTime),
applicantName: order.contactName,
elderName: order.recipientName,
age: 0,
phone: order.contactPhone,
address: order.addressSnapshot.fullAddress,
summary: order.remark,
currentStep: getCaseStep(order.status),
totalSteps: 8,
staffName: order.staffName == '' ? '待分配' : order.staffName,
staffPhone: order.staffPhone == '' ? '待分配' : order.staffPhone,
amount: order.serviceSnapshot.price,
checkinTime: order.executionRecord != null ? order.executionRecord.checkinTime : '',
checkinAddress: order.executionRecord != null ? order.executionRecord.checkinAddress : '',
serviceStartedAt: order.executionRecord != null ? order.executionRecord.serviceStartedAt : order.serviceStartedAt,
serviceFinishedAt: order.executionRecord != null ? order.executionRecord.serviceFinishedAt : order.completedAt,
executionSummary: order.executionRecord != null ? (order.executionRecord.summary != '' ? order.executionRecord.summary : order.executionRecord.remark) : '',
evidenceCount: order.evidenceFiles.length,
serviceAddressSnapshot: null,
timeline: mapLogsToTimeline(order.logs)
}
}
export async function fetchWorkerTasks(): Promise<Array<HomeServiceTaskType>> {
await delay()
return TASK_STORE.map((item) => cloneTask(item))
}
export async function fetchWorkerTaskDetail(taskId: string): Promise<HomeServiceTaskType | null> {
await delay()
const target = TASK_STORE.find((item) => item.id == taskId)
return target == null ? null : cloneTask(target)
}
export async function advanceWorkerTask(taskId: string): Promise<HomeServiceTaskType | null> {
await delay()
const target = TASK_STORE.find((item) => item.id == taskId)
if (target == null) {
return null
}
if (target.status == 'pending_visit') {
target.status = 'serving'
target.statusText = '服务中'
target.statusTone = 'primary'
target.checkInStatus = '已签到'
target.recordSummary = '已完成签到,请按步骤填写服务记录。'
target.actionText = '完成提交'
target.timeline.unshift({
id: 'tl-' + String(target.timeline.length + 1),
title: '已到岗签到',
time: '2026-05-13 14:55',
description: '护理员已在服务地址完成签到。'
})
} else if (target.status == 'serving') {
target.status = 'completed'
target.statusText = '待验收'
target.statusTone = 'success'
target.recordSummary = '已提交执行记录与服务凭证,等待家属验收。'
target.actionText = '已提交'
target.timeline.unshift({
id: 'tl-' + String(target.timeline.length + 1),
title: '服务完成待验收',
time: '2026-05-13 16:20',
description: '服务记录和凭证已经提交。'
})
}
const relatedCase = CASE_STORE.find((item) => item.id == target.caseId)
if (relatedCase != null) {
if (target.status == 'serving') {
relatedCase.status = 'in_service'
relatedCase.statusText = '服务中'
relatedCase.statusTone = 'primary'
relatedCase.currentStep = 6
relatedCase.staffName = target.staffName
relatedCase.staffPhone = target.staffPhone
relatedCase.timeline.unshift({
id: 'case-log-' + String(relatedCase.timeline.length + 1),
title: '护理员已签到',
time: '2026-05-13 14:55',
description: '执行端已开始上门服务。'
})
} else if (target.status == 'completed') {
relatedCase.status = 'pending_acceptance'
relatedCase.statusText = '待验收'
relatedCase.statusTone = 'success'
relatedCase.currentStep = 7
relatedCase.timeline.unshift({
id: 'case-log-' + String(relatedCase.timeline.length + 1),
title: '执行完成待验收',
time: '2026-05-13 16:20',
description: '家属可查看记录并进行验收反馈。'
})
}
}
const relatedAdmin = ADMIN_APPLICATIONS.find((item) => item.caseId == target.caseId)
if (relatedAdmin != null) {
if (target.status == 'serving') {
relatedAdmin.status = 'in_service'
relatedAdmin.statusText = '服务中'
relatedAdmin.statusTone = 'primary'
relatedAdmin.staffName = target.staffName
} else if (target.status == 'completed') {
relatedAdmin.status = 'pending_acceptance'
relatedAdmin.statusText = '待验收'
relatedAdmin.statusTone = 'success'
}
}
return cloneTask(target)
}
export async function submitWorkerCheckIn(taskId: string, note: string): Promise<HomeServiceTaskType | null> {
await delay()
const target = TASK_STORE.find((item) => item.id == taskId)
if (target == null) {
return null
}
if (target.status == 'pending_visit') {
target.status = 'serving'
target.statusText = '服务中'
target.statusTone = 'primary'
target.checkInStatus = '已签到'
target.recordSummary = note == '' ? '已完成签到,请继续填写服务记录。' : note
target.actionText = '完成提交'
target.timeline.unshift({
id: 'checkin-' + String(target.timeline.length + 1),
title: '到岗签到完成',
time: '2026-05-13 14:40',
description: note == '' ? '护理员已完成签到。' : note
})
}
const relatedCase = CASE_STORE.find((item) => item.id == target.caseId)
if (relatedCase != null) {
relatedCase.status = 'in_service'
relatedCase.statusText = '服务中'
relatedCase.statusTone = 'primary'
relatedCase.currentStep = 6
relatedCase.staffName = target.staffName
relatedCase.staffPhone = target.staffPhone
relatedCase.timeline.unshift({
id: 'case-checkin-' + String(relatedCase.timeline.length + 1),
title: '执行人员已到岗',
time: '2026-05-13 14:40',
description: note == '' ? '已完成签到,开始执行服务。' : note
})
}
const relatedAdmin = ADMIN_APPLICATIONS.find((item) => item.caseId == target.caseId)
if (relatedAdmin != null) {
relatedAdmin.status = 'in_service'
relatedAdmin.statusText = '服务中'
relatedAdmin.statusTone = 'primary'
relatedAdmin.staffName = target.staffName
}
return cloneTask(target)
}
export async function submitWorkerServiceRecord(taskId: string, summary: string): Promise<HomeServiceTaskType | null> {
await delay()
const target = TASK_STORE.find((item) => item.id == taskId)
if (target == null) {
return null
}
target.recordSummary = summary == '' ? target.recordSummary : summary
target.timeline.unshift({
id: 'record-' + String(target.timeline.length + 1),
title: '服务记录已更新',
time: '2026-05-13 15:30',
description: summary == '' ? '已保存服务记录。' : summary
})
const relatedCase = CASE_STORE.find((item) => item.id == target.caseId)
if (relatedCase != null) {
relatedCase.summary = summary == '' ? relatedCase.summary : summary
relatedCase.timeline.unshift({
id: 'case-record-' + String(relatedCase.timeline.length + 1),
title: '执行记录已回传',
time: '2026-05-13 15:30',
description: summary == '' ? '执行端已保存记录。' : summary
})
}
return cloneTask(target)
}
export async function submitWorkerException(taskId: string, exceptionType: string, description: string): Promise<HomeServiceTaskType | null> {
await delay()
const target = TASK_STORE.find((item) => item.id == taskId)
if (target == null) {
return null
}
target.status = 'exception'
target.statusText = '异常上报'
target.statusTone = 'warning'
target.actionText = '已上报'
target.timeline.unshift({
id: 'exception-' + String(target.timeline.length + 1),
title: '异常已上报',
time: '2026-05-13 15:45',
description: exceptionType + '' + description
})
const relatedCase = CASE_STORE.find((item) => item.id == target.caseId)
if (relatedCase != null) {
relatedCase.status = 'exception'
relatedCase.statusText = '异常处理中'
relatedCase.statusTone = 'warning'
relatedCase.timeline.unshift({
id: 'case-exception-' + String(relatedCase.timeline.length + 1),
title: '服务异常待处理',
time: '2026-05-13 15:45',
description: exceptionType + '' + description
})
}
const relatedAdmin = ADMIN_APPLICATIONS.find((item) => item.caseId == target.caseId)
if (relatedAdmin != null) {
relatedAdmin.status = 'exception'
relatedAdmin.statusText = '异常处理中'
relatedAdmin.statusTone = 'warning'
}
return cloneTask(target)
}
export async function fetchAdminAssessmentDetail(caseId: string): Promise<HomeServiceAssessmentType | null> {
await delay()
const target = ADMIN_ASSESSMENTS.find((item) => item.caseId == caseId)
return target == null ? null : cloneAssessment(target)
}
export async function submitAdminAssessment(caseId: string, riskLevel: string, careLevel: string, assessmentSummary: string): Promise<HomeServiceAssessmentType | null> {
await delay()
const target = ADMIN_ASSESSMENTS.find((item) => item.caseId == caseId)
if (target == null) {
return null
}
target.riskLevel = riskLevel
target.careLevel = careLevel
target.assessmentSummary = assessmentSummary
const relatedAdmin = ADMIN_APPLICATIONS.find((item) => item.caseId == caseId)
if (relatedAdmin != null) {
relatedAdmin.status = 'pending_plan'
relatedAdmin.statusText = '待方案'
relatedAdmin.statusTone = 'primary'
relatedAdmin.assessmentResult = careLevel + ' · ' + riskLevel
}
const relatedCase = CASE_STORE.find((item) => item.id == caseId)
if (relatedCase != null) {
relatedCase.currentStep = 2
relatedCase.timeline.unshift({
id: 'case-assessment-' + String(relatedCase.timeline.length + 1),
title: '上门评估完成',
time: '2026-05-13 13:20',
description: assessmentSummary
})
}
return cloneAssessment(target)
}
export async function fetchAdminServicePlanDetail(caseId: string): Promise<HomeServicePlanType | null> {
await delay()
const target = ADMIN_PLANS.find((item) => item.caseId == caseId)
return target == null ? null : clonePlan(target)
}
export async function submitAdminServicePlan(
caseId: string,
planTitle: string,
serviceFrequency: string,
serviceCycle: string,
planSummary: string
): Promise<HomeServicePlanType | null> {
await delay()
const target = ADMIN_PLANS.find((item) => item.caseId == caseId)
if (target == null) {
return null
}
target.planTitle = planTitle
target.serviceFrequency = serviceFrequency
target.serviceCycle = serviceCycle
target.planSummary = planSummary
const relatedAdmin = ADMIN_APPLICATIONS.find((item) => item.caseId == caseId)
if (relatedAdmin != null) {
relatedAdmin.status = 'pending_dispatch'
relatedAdmin.statusText = '待派单'
relatedAdmin.statusTone = 'warning'
relatedAdmin.assessmentResult = target.planTitle + ' · ' + target.serviceFrequency
}
const relatedCase = CASE_STORE.find((item) => item.id == caseId)
if (relatedCase != null) {
relatedCase.currentStep = 3
relatedCase.status = 'pending_dispatch'
relatedCase.statusText = '待派单'
relatedCase.statusTone = 'warning'
relatedCase.timeline.unshift({
id: 'case-plan-' + String(relatedCase.timeline.length + 1),
title: '服务方案已生成',
time: '2026-05-13 14:10',
description: planSummary
})
}
return clonePlan(target)
}
export async function fetchConsumerAcceptanceDetail(caseId: string): Promise<HomeServiceAcceptanceType | null> {
const detail = await getServiceOrderDetail(caseId)
if (detail != null) {
return {
caseId: detail.id,
caseNo: detail.orderNo,
elderName: detail.recipientName,
serviceName: detail.serviceName,
acceptanceStatus: detail.status,
acceptanceStatusText: getServiceOrderStatusText(detail.status),
rating: detail.review != null ? detail.review.rating : 5,
feedback: detail.review != null ? detail.review.content : '',
tags: detail.review != null ? detail.review.tags : [] as Array<string>
}
}
return null
}
export async function submitConsumerAcceptance(
caseId: string,
approved: boolean,
rating: number,
feedback: string,
tags: Array<string>
): Promise<HomeServiceAcceptanceType | null> {
if (approved) {
const result = await confirmServiceOrder(caseId, rating, feedback, tags)
if (result != null) {
return await fetchConsumerAcceptanceDetail(caseId)
}
return null
}
const rejected = await rejectServiceOrderAcceptance(caseId, feedback)
if (rejected != null) {
return await fetchConsumerAcceptanceDetail(caseId)
}
return null
}
export async function fetchAdminRectificationDetail(caseId: string): Promise<HomeServiceRectificationType | null> {
await delay()
const target = ADMIN_RECTIFICATIONS.find((item) => item.caseId == caseId)
return target == null ? null : cloneRectification(target)
}
export async function submitAdminRectification(caseId: string, issueSummary: string): Promise<HomeServiceRectificationType | null> {
await delay()
const target = ADMIN_RECTIFICATIONS.find((item) => item.caseId == caseId)
if (target == null) {
return null
}
target.issueSummary = issueSummary
target.status = 'closed'
target.statusText = '已关闭'
const relatedAdmin = ADMIN_APPLICATIONS.find((item) => item.caseId == caseId)
if (relatedAdmin != null) {
relatedAdmin.status = 'pending_acceptance'
relatedAdmin.statusText = '待复验收'
relatedAdmin.statusTone = 'primary'
}
const relatedCase = CASE_STORE.find((item) => item.id == caseId)
if (relatedCase != null) {
relatedCase.status = 'pending_acceptance'
relatedCase.statusText = '待复验收'
relatedCase.statusTone = 'primary'
relatedCase.timeline.unshift({
id: 'case-rectification-' + String(relatedCase.timeline.length + 1),
title: '整改处理完成',
time: '2026-05-13 18:10',
description: issueSummary
})
}
return cloneRectification(target)
}
export async function fetchAdminSettlementDetail(caseId: string): Promise<HomeServiceSettlementType | null> {
await delay()
const target = ADMIN_SETTLEMENTS.find((item) => item.caseId == caseId)
return target == null ? null : cloneSettlement(target)
}
export async function submitAdminSettlementArchive(caseId: string): Promise<HomeServiceSettlementType | null> {
await delay()
const target = ADMIN_SETTLEMENTS.find((item) => item.caseId == caseId)
if (target == null) {
return null
}
target.archiveStatus = 'archived'
target.archiveStatusText = '已归档'
const relatedCase = CASE_STORE.find((item) => item.id == caseId)
if (relatedCase != null) {
relatedCase.timeline.unshift({
id: 'case-settlement-' + String(relatedCase.timeline.length + 1),
title: '结算归档完成',
time: '2026-05-13 18:30',
description: '结算单和执行材料已完成归档。'
})
}
return cloneSettlement(target)
}
export async function fetchAdminHomeServiceApplications(): Promise<Array<HomeServiceAdminApplicationType>> {
await delay()
return ADMIN_APPLICATIONS.map((item) => ({ ...item }))
}
export async function fetchAdminHomeServiceOverview(): Promise<Array<HomeServiceOverviewCardType>> {
await delay()
return ADMIN_OVERVIEW.map((item) => ({ ...item }))
}