完善登录逻辑和个人资料完善

This commit is contained in:
2026-05-26 11:29:06 +08:00
parent cecb51a8e2
commit 9680276b3f
27 changed files with 3934 additions and 1572 deletions

View File

@@ -20,6 +20,7 @@ import {
rejectServiceOrderAcceptance
} from '@/services/serviceOrderService.uts'
import supa from '@/components/supadb/aksupainstance.uts'
import { getCurrentUserId } from '@/utils/store.uts'
import {
getServiceOrderStatusText,
type ServiceOrderStatus,
@@ -27,6 +28,14 @@ import {
type ServiceOrderType
} from '@/types/service-order.uts'
function nowIso(): string {
return new Date().toISOString()
}
function buildId(prefix: string): string {
return prefix + '-' + String(Date.now()) + '-' + String(Math.floor(Math.random() * 100000)).padStart(5, '0')
}
function plainObject(source: any): any {
return JSON.parse(JSON.stringify(source)) as any
}
@@ -576,259 +585,500 @@ function mapOrderToCase(order: ServiceOrderType): HomeServiceCaseType {
}
}
function mapOrderToWorkerTask(order: ServiceOrderType): HomeServiceTaskType {
let taskStatus = 'pending_visit'
let taskStatusText = '待上门'
let taskStatusTone = 'warning'
let actionText = '签到开始'
if (order.status == 'arrived' || order.status == 'in_service') {
taskStatus = 'serving'
taskStatusText = '服务中'
taskStatusTone = 'primary'
actionText = '完成提交'
} else if (order.status == 'pending_acceptance' || order.status == 'accepted_by_user' || order.status == 'reviewed' || order.status == 'settled') {
taskStatus = 'completed'
taskStatusText = '待验收'
taskStatusTone = 'success'
actionText = '已提交'
} else if (order.status == 'exception' || order.status == 'rejected' || order.status == 'cancelled') {
taskStatus = 'exception'
taskStatusText = getServiceOrderStatusText(order.status)
taskStatusTone = 'warning'
actionText = '已上报'
}
return {
id: order.id,
caseId: order.id,
caseNo: order.orderNo,
status: taskStatus,
statusText: taskStatusText,
statusTone: taskStatusTone,
serviceName: order.serviceName,
elderName: order.recipientName,
address: order.addressSnapshot.fullAddress,
appointmentTime: formatServiceAppointmentText(order.appointmentTime),
checkInStatus: order.executionRecord != null && order.executionRecord.checkinTime != '' ? '已签到' : '未签到',
recordSummary: order.executionRecord != null ? (order.executionRecord.summary != '' ? order.executionRecord.summary : order.executionRecord.remark) : '待填写服务记录',
staffName: order.staffName == '' ? '待分配' : order.staffName,
staffPhone: order.staffPhone == '' ? '待分配' : order.staffPhone,
actionText,
timeline: mapLogsToTimeline(order.logs)
}
}
async function listWorkerTaskIds(): Promise<Array<string>> {
const userId = getCurrentUserId()
if (userId == '') {
return [] as Array<string>
}
const careTaskResponse = await supa.from('ec_care_tasks').select('id').eq('assigned_to', userId).order('created_at', { ascending: false }).execute()
if (careTaskResponse.error == null && careTaskResponse.data != null) {
const result = [] as Array<string>
const rows = careTaskResponse.data as Array<any>
for (let i = 0; i < rows.length; i++) {
const id = readString(rows[i], 'id')
if (id != '') {
result.push(id)
}
}
if (result.length > 0) {
return result
}
}
const legacyResponse = await supa.from('hss_service_orders').select('id').eq('current_staff_id', userId).order('created_at', { ascending: false }).execute()
if (legacyResponse.error != null || legacyResponse.data == null) {
return [] as Array<string>
}
const legacyIds = [] as Array<string>
const legacyRows = legacyResponse.data as Array<any>
for (let i = 0; i < legacyRows.length; i++) {
const id = readString(legacyRows[i], 'id')
if (id != '') {
legacyIds.push(id)
}
}
return legacyIds
}
async function isCareTask(taskId: string): Promise<boolean> {
const response = await supa.from('ec_care_tasks').select('id').eq('id', taskId).limit(1).execute()
return response.error == null && response.data != null && (response.data as Array<any>).length > 0
}
async function completeWorkerTask(taskId: string): Promise<HomeServiceTaskType | null> {
const completedAt = nowIso()
if (await isCareTask(taskId)) {
await supa.from('ec_care_tasks').update({
status: 'ACCEPTANCE_PENDING',
service_completed_at: completedAt,
acceptance_pending_at: completedAt,
updated_at: completedAt
}).eq('id', taskId).execute()
await supa.from('hc_work_order_events').insert({
id: buildId('hc-event'),
task_id: taskId,
from_status: 'ORDER_IN_SERVICE',
to_status: 'ACCEPTANCE_PENDING',
actor_id: getCurrentUserId(),
actor_role: 'merchant',
action: 'finish_service',
remark: '服务记录和凭证已经提交。',
created_at: completedAt
}).execute()
} else {
await supa.from('hss_service_orders').update({
status: 'pending_acceptance',
completed_at: completedAt,
pending_acceptance_at: completedAt,
updated_at: completedAt
}).eq('id', taskId).execute()
await supa.from('hss_service_order_status_logs').insert({
id: buildId('slog'),
order_id: taskId,
from_status: 'in_service',
to_status: 'pending_acceptance',
operator_id: getCurrentUserId(),
operator_role: 'merchant',
remark: '服务记录和凭证已经提交。',
created_at: completedAt
}).execute()
}
return await fetchWorkerTaskDetail(taskId)
}
const ADMIN_ASSESSMENT_PREFIX = '[admin_assessment]'
const ADMIN_PLAN_PREFIX = '[admin_plan]'
const ADMIN_RECTIFICATION_PREFIX = '[admin_rectification]'
function encodeAdminRemark(prefix: string, payload: any): string {
return prefix + JSON.stringify(payload)
}
function parseAdminRemark(remark: string, prefix: string): any | null {
if (remark == '' || remark.indexOf(prefix) != 0) {
return null
}
const body = remark.substring(prefix.length)
if (body == '') {
return null
}
try {
return JSON.parse(body) as any
} catch (error) {
return null
}
}
function getDefaultCareLevel(order: ServiceOrderType): string {
if (order.serviceName.indexOf('随访') >= 0) {
return '随访管理'
}
if (order.serviceName.indexOf('护理') >= 0) {
return '护理二级'
}
return '护理一级'
}
function getOrderLatestRemark(order: ServiceOrderType): string {
for (let i = 0; i < order.logs.length; i++) {
if (order.logs[i].remark != '') {
return order.logs[i].remark
}
}
return ''
}
async function listAdminEventRows(caseId: string): Promise<Array<any>> {
if (await isCareTask(caseId)) {
const response = await supa.from('hc_work_order_events').select('*').eq('task_id', caseId).order('created_at', { ascending: false }).execute()
return response.data != null ? response.data as Array<any> : [] as Array<any>
}
const response = await supa.from('hss_service_order_status_logs').select('*').eq('order_id', caseId).order('created_at', { ascending: false }).execute()
return response.data != null ? response.data as Array<any> : [] as Array<any>
}
async function readAdminPayload(caseId: string, prefix: string): Promise<any | null> {
const rows = await listAdminEventRows(caseId)
for (let i = 0; i < rows.length; i++) {
const payload = parseAdminRemark(readString(rows[i], 'remark'), prefix)
if (payload != null) {
return payload
}
}
return null
}
async function readLatestExceptionSummary(caseId: string, order: ServiceOrderType): Promise<string> {
if (await isCareTask(caseId)) {
const response = await supa.from('hc_work_order_exceptions').select('description').eq('task_id', caseId).order('created_at', { ascending: false }).limit(1).execute()
if (response.data != null && (response.data as Array<any>).length > 0) {
const rows = response.data as Array<any>
const text = readString(rows[0], 'description')
if (text != '') {
return text
}
}
}
const latestRemark = getOrderLatestRemark(order)
if (latestRemark != '') {
return latestRemark
}
if (order.review != null && order.review.content != '') {
return order.review.content
}
return '待补充整改说明。'
}
function buildAssessmentDetail(order: ServiceOrderType, payload: any | null): HomeServiceAssessmentType {
const requirementTags = payload != null ? readStringArray(payload, 'requirementTags') : [] as Array<string>
return {
caseId: order.id,
caseNo: order.orderNo,
elderName: order.recipientName,
serviceName: order.serviceName,
riskLevel: payload != null && readString(payload, 'riskLevel') != '' ? readString(payload, 'riskLevel') : '中风险',
careLevel: payload != null && readString(payload, 'careLevel') != '' ? readString(payload, 'careLevel') : getDefaultCareLevel(order),
visitTime: formatServiceAppointmentText(order.appointmentTime),
assessmentSummary: payload != null && readString(payload, 'assessmentSummary') != '' ? readString(payload, 'assessmentSummary') : (order.remark != '' ? order.remark : '待补充上门评估结论。'),
requirementTags: requirementTags.length > 0 ? requirementTags : order.serviceSnapshot.tags
}
}
function buildPlanDetail(order: ServiceOrderType, payload: any | null): HomeServicePlanType {
const serviceCycle = payload != null && readString(payload, 'serviceCycle') != '' ? readString(payload, 'serviceCycle') : formatServiceAppointmentText(order.appointmentTime)
const amountText = '¥' + String(order.serviceSnapshot.price)
return {
caseId: order.id,
caseNo: order.orderNo,
elderName: order.recipientName,
serviceName: order.serviceName,
planTitle: payload != null && readString(payload, 'planTitle') != '' ? readString(payload, 'planTitle') : (order.serviceName + '执行方案'),
serviceFrequency: payload != null && readString(payload, 'serviceFrequency') != '' ? readString(payload, 'serviceFrequency') : '按预约执行',
serviceCycle: serviceCycle,
executorAdvice: payload != null && readString(payload, 'executorAdvice') != '' ? readString(payload, 'executorAdvice') : (order.staffName != '' ? ('优先由' + order.staffName + '承接本次服务并补全留痕。') : '优先安排熟悉该服务类型的执行人员。'),
billingSummary: payload != null && readString(payload, 'billingSummary') != '' ? readString(payload, 'billingSummary') : ('本次服务金额 ' + amountText),
planSummary: payload != null && readString(payload, 'planSummary') != '' ? readString(payload, 'planSummary') : (order.remark != '' ? order.remark : '待补充服务目标、执行重点和验收口径。')
}
}
function buildRectificationDetail(order: ServiceOrderType, payload: any | null, issueSummary: string): HomeServiceRectificationType {
const status = payload != null && readString(payload, 'status') != '' ? readString(payload, 'status') : (order.status == 'exception' ? 'pending' : 'closed')
return {
caseId: order.id,
caseNo: order.orderNo,
elderName: order.recipientName,
serviceName: order.serviceName,
issueSummary: payload != null && readString(payload, 'issueSummary') != '' ? readString(payload, 'issueSummary') : issueSummary,
deadline: payload != null && readString(payload, 'deadline') != '' ? readString(payload, 'deadline') : (order.pendingAcceptanceAt != '' ? order.pendingAcceptanceAt : formatServiceAppointmentText(order.appointmentTime)),
ownerName: payload != null && readString(payload, 'ownerName') != '' ? readString(payload, 'ownerName') : (order.staffName != '' ? order.staffName : '待分配'),
status: status,
statusText: status == 'closed' ? '已关闭' : '待整改'
}
}
export async function fetchWorkerTasks(): Promise<Array<HomeServiceTaskType>> {
await delay()
return TASK_STORE.map((item) => cloneTask(item))
const taskIds = await listWorkerTaskIds()
const result = [] as Array<HomeServiceTaskType>
for (let i = 0; i < taskIds.length; i++) {
const detail = await getServiceOrderDetail(taskIds[i])
if (detail != null) {
result.push(mapOrderToWorkerTask(detail))
}
}
return result
}
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)
const detail = await getServiceOrderDetail(taskId)
return detail == null ? null : mapOrderToWorkerTask(detail)
}
export async function advanceWorkerTask(taskId: string): Promise<HomeServiceTaskType | null> {
await delay()
const target = TASK_STORE.find((item) => item.id == taskId)
if (target == null) {
const detail = await fetchWorkerTaskDetail(taskId)
if (detail == 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: '服务记录和凭证已经提交。'
})
if (detail.status == 'serving') {
return await completeWorkerTask(taskId)
}
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)
return detail
}
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
const checkedInAt = nowIso()
if (await isCareTask(taskId)) {
const recordId = buildId('care-checkin')
await supa.from('ec_care_records').insert({
id: recordId,
task_id: taskId,
record_type: 'checkin',
started_at: checkedInAt,
checked_in_at: checkedInAt,
location_text: note,
remark: note,
created_at: checkedInAt,
updated_at: checkedInAt
}).execute()
await supa.from('ec_care_tasks').update({
status: 'ORDER_IN_SERVICE',
checked_in_at: checkedInAt,
service_started_at: checkedInAt,
updated_at: checkedInAt
}).eq('id', taskId).execute()
await supa.from('hc_work_order_events').insert({
id: buildId('hc-event'),
task_id: taskId,
from_status: 'ORDER_ACCEPTED',
to_status: 'ORDER_IN_SERVICE',
actor_id: getCurrentUserId(),
actor_role: 'merchant',
action: 'checkin_task',
remark: note == '' ? '已完成签到,开始执行服务。' : note,
created_at: checkedInAt
}).execute()
} else {
const recordId = buildId('ser')
await supa.from('hss_service_execution_records').upsert({
id: recordId,
order_id: taskId,
assignment_id: '',
checkin_time: checkedInAt,
checkin_address: note,
service_started_at: checkedInAt,
remark: note,
created_at: checkedInAt,
updated_at: checkedInAt
}).execute()
await supa.from('hss_service_orders').update({
status: 'in_service',
arrived_at: checkedInAt,
service_started_at: checkedInAt,
updated_at: checkedInAt
}).eq('id', taskId).execute()
await supa.from('hss_service_order_status_logs').insert({
id: buildId('slog'),
order_id: taskId,
from_status: 'accepted',
to_status: 'in_service',
operator_id: getCurrentUserId(),
operator_role: 'merchant',
remark: note == '' ? '已完成签到,开始执行服务。' : note,
created_at: checkedInAt
}).execute()
}
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)
return await fetchWorkerTaskDetail(taskId)
}
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) {
const detail = await getServiceOrderDetail(taskId)
if (detail == 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
})
const now = nowIso()
const recordId = detail.executionRecord != null && detail.executionRecord.id != '' ? detail.executionRecord.id : buildId('worker-rec')
if (await isCareTask(taskId)) {
await supa.from('ec_care_records').upsert({
id: recordId,
task_id: taskId,
record_type: 'service',
started_at: detail.executionRecord != null ? detail.executionRecord.serviceStartedAt : detail.serviceStartedAt,
summary: summary,
remark: summary,
created_at: detail.executionRecord != null && detail.executionRecord.createdAt != '' ? detail.executionRecord.createdAt : now,
updated_at: now
}).execute()
await supa.from('ec_care_tasks').update({
status: 'ORDER_IN_SERVICE',
updated_at: now
}).eq('id', taskId).execute()
await supa.from('hc_work_order_events').insert({
id: buildId('hc-event'),
task_id: taskId,
from_status: 'ORDER_IN_SERVICE',
to_status: 'ORDER_IN_SERVICE',
actor_id: getCurrentUserId(),
actor_role: 'merchant',
action: 'save_record',
remark: summary == '' ? '已保存服务记录。' : summary,
created_at: now
}).execute()
} else {
await supa.from('hss_service_execution_records').upsert({
id: recordId,
order_id: taskId,
assignment_id: detail.currentAssignmentId,
service_started_at: detail.executionRecord != null ? detail.executionRecord.serviceStartedAt : detail.serviceStartedAt,
summary: summary,
remark: summary,
created_at: detail.executionRecord != null && detail.executionRecord.createdAt != '' ? detail.executionRecord.createdAt : now,
updated_at: now
}).execute()
}
return cloneTask(target)
return await fetchWorkerTaskDetail(taskId)
}
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
const now = nowIso()
if (await isCareTask(taskId)) {
await supa.from('hc_work_order_exceptions').insert({
id: buildId('hc-ex'),
task_id: taskId,
exception_type: exceptionType,
description: description,
occurred_at: now,
created_by: getCurrentUserId(),
created_at: now,
updated_at: now
}).execute()
await supa.from('ec_care_tasks').update({
status: 'ORDER_EXCEPTION',
updated_at: now
}).eq('id', taskId).execute()
await supa.from('hc_work_order_events').insert({
id: buildId('hc-event'),
task_id: taskId,
from_status: '',
to_status: 'ORDER_EXCEPTION',
actor_id: getCurrentUserId(),
actor_role: 'merchant',
action: 'report_exception',
remark: exceptionType + '' + description,
created_at: now
}).execute()
} else {
await supa.from('hss_service_orders').update({
status: 'exception',
updated_at: now
}).eq('id', taskId).execute()
await supa.from('hss_service_order_status_logs').insert({
id: buildId('slog'),
order_id: taskId,
from_status: 'in_service',
to_status: 'exception',
operator_id: getCurrentUserId(),
operator_role: 'merchant',
remark: exceptionType + '' + description,
created_at: now
}).execute()
}
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)
return await fetchWorkerTaskDetail(taskId)
}
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)
const order = await getServiceOrderDetail(caseId)
if (order == null) {
return null
}
const payload = await readAdminPayload(caseId, ADMIN_ASSESSMENT_PREFIX)
return buildAssessmentDetail(order, payload)
}
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) {
const order = await getServiceOrderDetail(caseId)
if (order == 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 payload = {
riskLevel,
careLevel,
assessmentSummary,
requirementTags: order.serviceSnapshot.tags,
updatedAt: nowIso()
}
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
})
if (await isCareTask(caseId)) {
await supa.from('hc_work_order_events').insert({
id: buildId('hc-event'),
task_id: caseId,
from_status: order.status,
to_status: order.status,
actor_id: getCurrentUserId(),
actor_role: 'admin',
action: 'submit_assessment',
remark: encodeAdminRemark(ADMIN_ASSESSMENT_PREFIX, payload),
created_at: nowIso()
}).execute()
} else {
await supa.from('hss_service_order_status_logs').insert({
id: buildId('slog'),
order_id: caseId,
from_status: order.status,
to_status: order.status,
operator_id: getCurrentUserId(),
operator_role: 'admin',
remark: encodeAdminRemark(ADMIN_ASSESSMENT_PREFIX, payload),
created_at: nowIso()
}).execute()
}
return cloneAssessment(target)
return buildAssessmentDetail(order, payload)
}
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)
const order = await getServiceOrderDetail(caseId)
if (order == null) {
return null
}
const payload = await readAdminPayload(caseId, ADMIN_PLAN_PREFIX)
return buildPlanDetail(order, payload)
}
export async function submitAdminServicePlan(
@@ -838,40 +1088,44 @@ export async function submitAdminServicePlan(
serviceCycle: string,
planSummary: string
): Promise<HomeServicePlanType | null> {
await delay()
const target = ADMIN_PLANS.find((item) => item.caseId == caseId)
if (target == null) {
const order = await getServiceOrderDetail(caseId)
if (order == 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 payload = {
planTitle,
serviceFrequency,
serviceCycle,
executorAdvice: order.staffName != '' ? ('优先由' + order.staffName + '承接本次服务并补全留痕。') : '优先安排熟悉该服务类型的执行人员。',
billingSummary: '本次服务金额 ¥' + String(order.serviceSnapshot.price),
planSummary,
updatedAt: nowIso()
}
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
})
if (await isCareTask(caseId)) {
await supa.from('hc_work_order_events').insert({
id: buildId('hc-event'),
task_id: caseId,
from_status: order.status,
to_status: order.status,
actor_id: getCurrentUserId(),
actor_role: 'admin',
action: 'submit_plan',
remark: encodeAdminRemark(ADMIN_PLAN_PREFIX, payload),
created_at: nowIso()
}).execute()
} else {
await supa.from('hss_service_order_status_logs').insert({
id: buildId('slog'),
order_id: caseId,
from_status: order.status,
to_status: order.status,
operator_id: getCurrentUserId(),
operator_role: 'admin',
remark: encodeAdminRemark(ADMIN_PLAN_PREFIX, payload),
created_at: nowIso()
}).execute()
}
return clonePlan(target)
return buildPlanDetail(order, payload)
}
export async function fetchConsumerAcceptanceDetail(caseId: string): Promise<HomeServiceAcceptanceType | null> {
@@ -914,43 +1168,68 @@ export async function submitConsumerAcceptance(
}
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)
const order = await getServiceOrderDetail(caseId)
if (order == null) {
return null
}
const payload = await readAdminPayload(caseId, ADMIN_RECTIFICATION_PREFIX)
const issueSummary = await readLatestExceptionSummary(caseId, order)
return buildRectificationDetail(order, payload, issueSummary)
}
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) {
const order = await getServiceOrderDetail(caseId)
if (order == 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 payload = {
issueSummary,
deadline: order.pendingAcceptanceAt != '' ? order.pendingAcceptanceAt : formatServiceAppointmentText(order.appointmentTime),
ownerName: order.staffName != '' ? order.staffName : '待分配',
status: 'closed',
updatedAt: nowIso()
}
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
})
if (await isCareTask(caseId)) {
const reopenedAt = nowIso()
await supa.from('ec_care_tasks').update({
status: 'ACCEPTANCE_PENDING',
acceptance_pending_at: reopenedAt,
updated_at: reopenedAt
}).eq('id', caseId).execute()
await supa.from('hc_work_order_events').insert({
id: buildId('hc-event'),
task_id: caseId,
from_status: 'ACCEPTANCE_REJECTED',
to_status: 'ACCEPTANCE_PENDING',
actor_id: getCurrentUserId(),
actor_role: 'admin',
action: 'submit_rectification',
remark: encodeAdminRemark(ADMIN_RECTIFICATION_PREFIX, payload),
created_at: reopenedAt
}).execute()
} else {
const reopenedAt = nowIso()
await supa.from('hss_service_orders').update({
status: 'pending_acceptance',
pending_acceptance_at: reopenedAt,
updated_at: reopenedAt
}).eq('id', caseId).execute()
await supa.from('hss_service_order_status_logs').insert({
id: buildId('slog'),
order_id: caseId,
from_status: order.status,
to_status: 'pending_acceptance',
operator_id: getCurrentUserId(),
operator_role: 'admin',
remark: encodeAdminRemark(ADMIN_RECTIFICATION_PREFIX, payload),
created_at: reopenedAt
}).execute()
}
return cloneRectification(target)
const latest = await getServiceOrderDetail(caseId)
if (latest == null) {
return buildRectificationDetail(order, payload, issueSummary)
}
return buildRectificationDetail(latest, payload, issueSummary)
}
export async function fetchAdminSettlementDetail(caseId: string): Promise<HomeServiceSettlementType | null> {