继续完善居家服务模块
This commit is contained in:
@@ -42,6 +42,20 @@
|
|||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mall/delivery/orders/route",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "出发与导航",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/mall/delivery/orders/checkin",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "到岗签到",
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/mall/delivery/service-record/index",
|
"path": "pages/mall/delivery/service-record/index",
|
||||||
"style": {
|
"style": {
|
||||||
|
|||||||
@@ -39,8 +39,8 @@
|
|||||||
<text class="stat-label">服务中</text>
|
<text class="stat-label">服务中</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="stat-item">
|
<view class="stat-item">
|
||||||
<text class="stat-value money">{{ incomeText }}</text>
|
<text class="stat-value">{{ dashboard.completedCount }}</text>
|
||||||
<text class="stat-label">预计收入</text>
|
<text class="stat-label">已完成</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -89,7 +89,7 @@ import { computed, ref } from 'vue'
|
|||||||
import { onShow } from '@dcloudio/uni-app'
|
import { onShow } from '@dcloudio/uni-app'
|
||||||
import ServicePageScaffold from '@/components/homeService/ServicePageScaffold.uvue'
|
import ServicePageScaffold from '@/components/homeService/ServicePageScaffold.uvue'
|
||||||
import type { DeliveryInfoType } from '@/types/delivery.uts'
|
import type { DeliveryInfoType } from '@/types/delivery.uts'
|
||||||
import { acceptServiceOrder, getDeliveryDashboardStats, getDeliveryProfile, markDeparted } from '@/services/deliveryService.uts'
|
import { acceptServiceOrder, getDeliveryDashboardStats, getDeliveryProfile } from '@/services/deliveryService.uts'
|
||||||
import { getNextStepText, getPrimaryActionText } from '@/utils/deliveryCareUi.uts'
|
import { getNextStepText, getPrimaryActionText } from '@/utils/deliveryCareUi.uts'
|
||||||
import { requireDeliveryAuth } from '@/utils/deliveryAuth.uts'
|
import { requireDeliveryAuth } from '@/utils/deliveryAuth.uts'
|
||||||
|
|
||||||
@@ -117,7 +117,6 @@ const onlineText = computed((): string => {
|
|||||||
if (profile.value.onlineStatus == 'busy') return '忙碌'
|
if (profile.value.onlineStatus == 'busy') return '忙碌'
|
||||||
return '离线'
|
return '离线'
|
||||||
})
|
})
|
||||||
const incomeText = computed((): string => '¥' + String(dashboard.value.expectedIncome))
|
|
||||||
const nextActionText = computed((): string => dashboard.value.nextOrder == null ? '查看详情' : getPrimaryActionText(dashboard.value.nextOrder!.status))
|
const nextActionText = computed((): string => dashboard.value.nextOrder == null ? '查看详情' : getPrimaryActionText(dashboard.value.nextOrder!.status))
|
||||||
const nextStepText = computed((): string => dashboard.value.nextOrder == null ? '暂无' : getNextStepText(dashboard.value.nextOrder!.status))
|
const nextStepText = computed((): string => dashboard.value.nextOrder == null ? '暂无' : getNextStepText(dashboard.value.nextOrder!.status))
|
||||||
const nextStatusText = computed((): string => dashboard.value.nextOrder == null ? '' : dashboard.value.nextOrder!.statusText)
|
const nextStatusText = computed((): string => dashboard.value.nextOrder == null ? '' : dashboard.value.nextOrder!.statusText)
|
||||||
@@ -172,9 +171,7 @@ async function handleOrderAction(orderId: string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (order.status == 'accepted' || order.status == 'waiting_departure') {
|
if (order.status == 'accepted' || order.status == 'waiting_departure') {
|
||||||
await markDeparted(orderId)
|
uni.navigateTo({ url: '/pages/mall/delivery/orders/route?id=' + orderId })
|
||||||
uni.showToast({ title: '已标记出发', icon: 'success' })
|
|
||||||
loadData()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
goDetail(orderId)
|
goDetail(orderId)
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ async function submitCheckin() {
|
|||||||
checkinMode: 'gps'
|
checkinMode: 'gps'
|
||||||
})
|
})
|
||||||
uni.showToast({ title: '签到成功', icon: 'success' })
|
uni.showToast({ title: '签到成功', icon: 'success' })
|
||||||
uni.navigateTo({ url: '/pages/mall/delivery/orders/execute?id=' + orderId.value })
|
uni.redirectTo({ url: '/pages/mall/delivery/service-record/index?id=' + orderId.value })
|
||||||
} finally {
|
} finally {
|
||||||
submitting.value = false
|
submitting.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,15 +92,10 @@ import ServicePageScaffold from '@/components/homeService/ServicePageScaffold.uv
|
|||||||
import type { DeliveryOrderType } from '@/types/delivery.uts'
|
import type { DeliveryOrderType } from '@/types/delivery.uts'
|
||||||
import {
|
import {
|
||||||
acceptServiceOrder,
|
acceptServiceOrder,
|
||||||
checkInServiceOrder,
|
|
||||||
completeServiceOrder,
|
|
||||||
getServiceOrderDetail,
|
getServiceOrderDetail,
|
||||||
markArrived,
|
rejectServiceOrder
|
||||||
markDeparted,
|
|
||||||
rejectServiceOrder,
|
|
||||||
startServiceOrder
|
|
||||||
} from '@/services/deliveryService.uts'
|
} from '@/services/deliveryService.uts'
|
||||||
import { getNextStepText, getPrimaryActionText, needsServiceRecord } from '@/utils/deliveryCareUi.uts'
|
import { getNextStepText, getPrimaryActionText } from '@/utils/deliveryCareUi.uts'
|
||||||
import { requireDeliveryAuth } from '@/utils/deliveryAuth.uts'
|
import { requireDeliveryAuth } from '@/utils/deliveryAuth.uts'
|
||||||
import { getDeliveryRouteParam } from '@/utils/deliveryRoute.uts'
|
import { getDeliveryRouteParam } from '@/utils/deliveryRoute.uts'
|
||||||
|
|
||||||
@@ -129,7 +124,10 @@ function makePhoneCall(phone: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mockNavigate() {
|
function mockNavigate() {
|
||||||
uni.showToast({ title: '导航为 mock 占位', icon: 'none' })
|
if (order.value == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.navigateTo({ url: '/pages/mall/delivery/orders/route?id=' + order.value!.id })
|
||||||
}
|
}
|
||||||
|
|
||||||
function goException() {
|
function goException() {
|
||||||
@@ -164,27 +162,15 @@ async function handlePrimary() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (status == 'accepted' || status == 'waiting_departure') {
|
if (status == 'accepted' || status == 'waiting_departure') {
|
||||||
await markDeparted(orderId.value)
|
uni.navigateTo({ url: '/pages/mall/delivery/orders/route?id=' + orderId.value })
|
||||||
uni.showToast({ title: '已出发', icon: 'success' })
|
|
||||||
loadData()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (status == 'departed' || status == 'on_the_way') {
|
if (status == 'departed' || status == 'on_the_way') {
|
||||||
await markArrived(orderId.value)
|
uni.navigateTo({ url: '/pages/mall/delivery/orders/route?id=' + orderId.value })
|
||||||
uni.showToast({ title: '已到达', icon: 'success' })
|
|
||||||
loadData()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (status == 'arrived') {
|
if (status == 'arrived') {
|
||||||
await checkInServiceOrder(orderId.value, '详情页签到', null)
|
uni.navigateTo({ url: '/pages/mall/delivery/orders/checkin?id=' + orderId.value })
|
||||||
uni.showToast({ title: '签到成功', icon: 'success' })
|
|
||||||
loadData()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (status == 'checked_in') {
|
|
||||||
await startServiceOrder(orderId.value)
|
|
||||||
uni.showToast({ title: '开始服务', icon: 'success' })
|
|
||||||
loadData()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (status == 'in_service' || status == 'serving' || status == 'completed') {
|
if (status == 'in_service' || status == 'serving' || status == 'completed') {
|
||||||
@@ -192,14 +178,7 @@ async function handlePrimary() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (status == 'pending_confirm' || status == 'pending_acceptance' || status == 'pending_submit') {
|
if (status == 'pending_confirm' || status == 'pending_acceptance' || status == 'pending_submit') {
|
||||||
if (needsServiceRecord(order.value)) {
|
uni.showToast({ title: '已完成服务,等待用户验收', icon: 'none' })
|
||||||
uni.showToast({ title: '请先填写服务记录', icon: 'none' })
|
|
||||||
goRecord()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
await completeServiceOrder(orderId.value)
|
|
||||||
uni.showToast({ title: '服务已完成', icon: 'success' })
|
|
||||||
loadData()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (status == 'abnormal' || status == 'exception_pending') {
|
if (status == 'abnormal' || status == 'exception_pending') {
|
||||||
|
|||||||
@@ -43,15 +43,10 @@ import ServicePageScaffold from '@/components/homeService/ServicePageScaffold.uv
|
|||||||
import type { DeliveryOrderStatus, DeliveryOrderType } from '@/types/delivery.uts'
|
import type { DeliveryOrderStatus, DeliveryOrderType } from '@/types/delivery.uts'
|
||||||
import {
|
import {
|
||||||
acceptServiceOrder,
|
acceptServiceOrder,
|
||||||
checkInServiceOrder,
|
|
||||||
completeServiceOrder,
|
|
||||||
getHistoryServiceOrders,
|
getHistoryServiceOrders,
|
||||||
getPendingServiceOrders,
|
getPendingServiceOrders,
|
||||||
getTodayServiceOrders,
|
getTodayServiceOrders,
|
||||||
markArrived,
|
rejectServiceOrder
|
||||||
markDeparted,
|
|
||||||
rejectServiceOrder,
|
|
||||||
startServiceOrder
|
|
||||||
} from '@/services/deliveryService.uts'
|
} from '@/services/deliveryService.uts'
|
||||||
import { getDeliveryOrderTabs, getPrimaryActionText } from '@/utils/deliveryCareUi.uts'
|
import { getDeliveryOrderTabs, getPrimaryActionText } from '@/utils/deliveryCareUi.uts'
|
||||||
import { requireDeliveryAuth } from '@/utils/deliveryAuth.uts'
|
import { requireDeliveryAuth } from '@/utils/deliveryAuth.uts'
|
||||||
@@ -137,27 +132,15 @@ async function handleAction(orderId: string, status: DeliveryOrderStatus) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (status == 'accepted' || status == 'waiting_departure') {
|
if (status == 'accepted' || status == 'waiting_departure') {
|
||||||
await markDeparted(orderId)
|
uni.navigateTo({ url: '/pages/mall/delivery/orders/route?id=' + orderId })
|
||||||
uni.showToast({ title: '已标记出发', icon: 'success' })
|
|
||||||
loadData()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (status == 'departed' || status == 'on_the_way') {
|
if (status == 'departed' || status == 'on_the_way') {
|
||||||
await markArrived(orderId)
|
uni.navigateTo({ url: '/pages/mall/delivery/orders/route?id=' + orderId })
|
||||||
uni.showToast({ title: '已标记到达', icon: 'success' })
|
|
||||||
loadData()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (status == 'arrived') {
|
if (status == 'arrived') {
|
||||||
await checkInServiceOrder(orderId, '已到达并签到', null)
|
uni.navigateTo({ url: '/pages/mall/delivery/orders/checkin?id=' + orderId })
|
||||||
uni.showToast({ title: '签到成功', icon: 'success' })
|
|
||||||
loadData()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (status == 'checked_in') {
|
|
||||||
await startServiceOrder(orderId)
|
|
||||||
uni.showToast({ title: '已开始服务', icon: 'success' })
|
|
||||||
loadData()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (status == 'in_service' || status == 'serving' || status == 'completed') {
|
if (status == 'in_service' || status == 'serving' || status == 'completed') {
|
||||||
@@ -165,13 +148,7 @@ async function handleAction(orderId: string, status: DeliveryOrderStatus) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (status == 'pending_confirm' || status == 'pending_acceptance' || status == 'pending_submit') {
|
if (status == 'pending_confirm' || status == 'pending_acceptance' || status == 'pending_submit') {
|
||||||
const result = await completeServiceOrder(orderId)
|
uni.showToast({ title: '已完成服务,等待用户验收', icon: 'none' })
|
||||||
if (result == null) {
|
|
||||||
uni.showToast({ title: '请先填写服务记录', icon: 'none' })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
uni.showToast({ title: '服务已完成', icon: 'success' })
|
|
||||||
loadData()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
goDetail(orderId)
|
goDetail(orderId)
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ import { computed, ref } from 'vue'
|
|||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import ServicePageScaffold from '@/components/homeService/ServicePageScaffold.uvue'
|
import ServicePageScaffold from '@/components/homeService/ServicePageScaffold.uvue'
|
||||||
import type { DeliveryOrderType, DeliveryServiceItemType, DeliveryServiceRecordType } from '@/types/delivery.uts'
|
import type { DeliveryOrderType, DeliveryServiceItemType, DeliveryServiceRecordType } from '@/types/delivery.uts'
|
||||||
import { getServiceOrderDetail, submitServiceRecord } from '@/services/deliveryService.uts'
|
import { completeServiceOrder, getServiceOrderDetail, startServiceOrder, submitServiceRecord } from '@/services/deliveryService.uts'
|
||||||
import { requireDeliveryAuth } from '@/utils/deliveryAuth.uts'
|
import { requireDeliveryAuth } from '@/utils/deliveryAuth.uts'
|
||||||
import { getDeliveryRouteParam } from '@/utils/deliveryRoute.uts'
|
import { getDeliveryRouteParam } from '@/utils/deliveryRoute.uts'
|
||||||
|
|
||||||
@@ -145,6 +145,9 @@ async function submitRecordAction() {
|
|||||||
if (!validateRecord()) {
|
if (!validateRecord()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (order.value != null && order.value.status != 'in_service' && order.value.status != 'serving') {
|
||||||
|
await startServiceOrder(orderId.value)
|
||||||
|
}
|
||||||
const record = {
|
const record = {
|
||||||
id: 'record-' + orderId.value,
|
id: 'record-' + orderId.value,
|
||||||
orderId: orderId.value,
|
orderId: orderId.value,
|
||||||
@@ -176,7 +179,8 @@ async function submitRecordAction() {
|
|||||||
updatedAt: new Date().toISOString().replace('T', ' ').substring(0, 19)
|
updatedAt: new Date().toISOString().replace('T', ' ').substring(0, 19)
|
||||||
} as DeliveryServiceRecordType
|
} as DeliveryServiceRecordType
|
||||||
await submitServiceRecord(orderId.value, record)
|
await submitServiceRecord(orderId.value, record)
|
||||||
uni.showToast({ title: '服务记录已提交', icon: 'success' })
|
await completeServiceOrder(orderId.value)
|
||||||
|
uni.showToast({ title: '服务记录已提交,等待验收', icon: 'success' })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.redirectTo({ url: '/pages/mall/delivery/orders/detail?id=' + orderId.value })
|
uni.redirectTo({ url: '/pages/mall/delivery/orders/detail?id=' + orderId.value })
|
||||||
}, 300)
|
}, 300)
|
||||||
|
|||||||
@@ -1,4 +1,16 @@
|
|||||||
import { getDeliveryProfileByUserId, loginDelivery as loginDeliveryApi } from '@/api/delivery.uts'
|
import { getDeliveryProfileByUserId, loginDelivery as loginDeliveryApi } from '@/api/delivery.uts'
|
||||||
|
import {
|
||||||
|
acceptOrder as acceptRealServiceOrder,
|
||||||
|
arriveOrder as arriveRealServiceOrder,
|
||||||
|
checkinOrder as checkinRealServiceOrder,
|
||||||
|
departOrder as departRealServiceOrder,
|
||||||
|
finishOrder as finishRealServiceOrder,
|
||||||
|
getDashboard as getRealDashboard,
|
||||||
|
getOrderDetail as getRealServiceOrderDetail,
|
||||||
|
getOrdersByTab as getRealOrdersByTab,
|
||||||
|
saveServiceRecord as saveRealServiceRecord,
|
||||||
|
startService as startRealService
|
||||||
|
} from '@/services/serviceOrderService.uts'
|
||||||
import {
|
import {
|
||||||
acceptCareOrder,
|
acceptCareOrder,
|
||||||
checkInCareOrder,
|
checkInCareOrder,
|
||||||
@@ -47,7 +59,7 @@ export async function getDeliveryProfile(): Promise<DeliveryInfoType | null> {
|
|||||||
if (!authResult.ok) {
|
if (!authResult.ok) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return getDeliveryCareProfile()
|
return authResult.deliveryInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getDeliveryByUserId(userId: string): Promise<DeliveryInfoType | null> {
|
export async function getDeliveryByUserId(userId: string): Promise<DeliveryInfoType | null> {
|
||||||
@@ -72,21 +84,21 @@ export async function getDeliveryDashboard(): Promise<DeliveryDashboardType> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getDeliveryOrders(params: DeliveryOrderQueryType): Promise<Array<DeliveryOrderType>> {
|
export async function getDeliveryOrders(params: DeliveryOrderQueryType): Promise<Array<DeliveryOrderType>> {
|
||||||
if (params.tab == 'pending' || params.tab == 'pending_assignment' || params.tab == 'pending_accept') {
|
if (params.tab == 'pending' || params.tab == 'pending_assignment') {
|
||||||
return getPendingCareOrders()
|
return await getRealOrdersByTab('pending')
|
||||||
}
|
}
|
||||||
if (params.tab == 'history' || params.tab == 'completed' || params.tab == 'archive') {
|
if (params.tab == 'history' || params.tab == 'completed' || params.tab == 'archive') {
|
||||||
return getHistoryCareOrders()
|
return await getRealOrdersByTab('history')
|
||||||
}
|
}
|
||||||
return getTodayCareOrders()
|
return await getRealOrdersByTab('today')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getDeliveryOrderDetail(id: string): Promise<DeliveryOrderType | null> {
|
export async function getDeliveryOrderDetail(id: string): Promise<DeliveryOrderType | null> {
|
||||||
return getCareOrderDetail(id)
|
return await getRealServiceOrderDetail(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function acceptDeliveryOrder(id: string): Promise<DeliveryOrderType | null> {
|
export async function acceptDeliveryOrder(id: string): Promise<DeliveryOrderType | null> {
|
||||||
return acceptCareOrder(id)
|
return await acceptRealServiceOrder(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function rejectDeliveryOrder(id: string, reason: string): Promise<DeliveryOrderType | null> {
|
export async function rejectDeliveryOrder(id: string, reason: string): Promise<DeliveryOrderType | null> {
|
||||||
@@ -94,27 +106,19 @@ export async function rejectDeliveryOrder(id: string, reason: string): Promise<D
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function startDepart(id: string, location: DeliveryLocationType): Promise<DeliveryOrderType | null> {
|
export async function startDepart(id: string, location: DeliveryLocationType): Promise<DeliveryOrderType | null> {
|
||||||
const order = markCareOrderDeparted(id)
|
return await departRealServiceOrder(id, location)
|
||||||
if (order != null) {
|
|
||||||
order.lastLocation = location
|
|
||||||
}
|
|
||||||
return order
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function arriveOrder(id: string, location: DeliveryLocationType): Promise<DeliveryOrderType | null> {
|
export async function arriveOrder(id: string, location: DeliveryLocationType): Promise<DeliveryOrderType | null> {
|
||||||
const order = markCareOrderArrived(id)
|
return await arriveRealServiceOrder(id, location)
|
||||||
if (order != null) {
|
|
||||||
order.lastLocation = location
|
|
||||||
}
|
|
||||||
return order
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkinOrder(id: string, payload: DeliveryCheckinPayloadType): Promise<DeliveryOrderType | null> {
|
export async function checkinOrder(id: string, payload: DeliveryCheckinPayloadType): Promise<DeliveryOrderType | null> {
|
||||||
return checkInCareOrder(id, payload.location, payload.note)
|
return await checkinRealServiceOrder(id, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function startService(id: string): Promise<DeliveryOrderType | null> {
|
export async function startService(id: string): Promise<DeliveryOrderType | null> {
|
||||||
return startCareService(id)
|
return await startRealService(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveServiceProgress(id: string, payload: DeliveryProgressPayloadType): Promise<DeliveryOrderType | null> {
|
export async function saveServiceProgress(id: string, payload: DeliveryProgressPayloadType): Promise<DeliveryOrderType | null> {
|
||||||
@@ -194,27 +198,27 @@ export async function updateDeliveryOnlineStatus(status: string): Promise<Delive
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getDeliveryDashboardStats(): Promise<DeliveryDashboardType> {
|
export async function getDeliveryDashboardStats(): Promise<DeliveryDashboardType> {
|
||||||
return getDeliveryCareDashboard()
|
return await getRealDashboard()
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getPendingServiceOrders(): Promise<Array<DeliveryOrderType>> {
|
export async function getPendingServiceOrders(): Promise<Array<DeliveryOrderType>> {
|
||||||
return getPendingCareOrders()
|
return await getRealOrdersByTab('pending')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getTodayServiceOrders(): Promise<Array<DeliveryOrderType>> {
|
export async function getTodayServiceOrders(): Promise<Array<DeliveryOrderType>> {
|
||||||
return getTodayCareOrders()
|
return await getRealOrdersByTab('today')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getHistoryServiceOrders(): Promise<Array<DeliveryOrderType>> {
|
export async function getHistoryServiceOrders(): Promise<Array<DeliveryOrderType>> {
|
||||||
return getHistoryCareOrders()
|
return await getRealOrdersByTab('history')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getServiceOrderDetail(orderId: string): Promise<DeliveryOrderType | null> {
|
export async function getServiceOrderDetail(orderId: string): Promise<DeliveryOrderType | null> {
|
||||||
return getCareOrderDetail(orderId)
|
return await getRealServiceOrderDetail(orderId)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function acceptServiceOrder(orderId: string): Promise<DeliveryOrderType | null> {
|
export async function acceptServiceOrder(orderId: string): Promise<DeliveryOrderType | null> {
|
||||||
return acceptCareOrder(orderId)
|
return await acceptRealServiceOrder(orderId)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function rejectServiceOrder(orderId: string, reason: string): Promise<DeliveryOrderType | null> {
|
export async function rejectServiceOrder(orderId: string, reason: string): Promise<DeliveryOrderType | null> {
|
||||||
@@ -222,27 +226,35 @@ export async function rejectServiceOrder(orderId: string, reason: string): Promi
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function markDeparted(orderId: string): Promise<DeliveryOrderType | null> {
|
export async function markDeparted(orderId: string): Promise<DeliveryOrderType | null> {
|
||||||
return markCareOrderDeparted(orderId)
|
return await departRealServiceOrder(orderId, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function markArrived(orderId: string): Promise<DeliveryOrderType | null> {
|
export async function markArrived(orderId: string): Promise<DeliveryOrderType | null> {
|
||||||
return markCareOrderArrived(orderId)
|
return await arriveRealServiceOrder(orderId, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkInServiceOrder(orderId: string, note: string, location: DeliveryLocationType | null = null): Promise<DeliveryOrderType | null> {
|
export async function checkInServiceOrder(orderId: string, note: string, location: DeliveryLocationType | null = null): Promise<DeliveryOrderType | null> {
|
||||||
return checkInCareOrder(orderId, location, note)
|
if (location == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return await checkinRealServiceOrder(orderId, {
|
||||||
|
location,
|
||||||
|
note,
|
||||||
|
photos: [] as Array<string>,
|
||||||
|
checkinMode: 'gps'
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function startServiceOrder(orderId: string): Promise<DeliveryOrderType | null> {
|
export async function startServiceOrder(orderId: string): Promise<DeliveryOrderType | null> {
|
||||||
return startCareService(orderId)
|
return await startRealService(orderId)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function submitServiceRecord(orderId: string, record: DeliveryServiceRecordType): Promise<DeliveryOrderType | null> {
|
export async function submitServiceRecord(orderId: string, record: DeliveryServiceRecordType): Promise<DeliveryOrderType | null> {
|
||||||
return submitCareServiceRecord(orderId, record)
|
return await saveRealServiceRecord(orderId, record)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function completeServiceOrder(orderId: string): Promise<DeliveryOrderType | null> {
|
export async function completeServiceOrder(orderId: string): Promise<DeliveryOrderType | null> {
|
||||||
return completeCareOrder(orderId)
|
return await finishRealServiceOrder(orderId)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function submitAbnormalReport(orderId: string, report: DeliveryExceptionPayloadType): Promise<DeliveryOrderType | null> {
|
export async function submitAbnormalReport(orderId: string, report: DeliveryExceptionPayloadType): Promise<DeliveryOrderType | null> {
|
||||||
|
|||||||
500
services/serviceOrderService.uts
Normal file
500
services/serviceOrderService.uts
Normal file
@@ -0,0 +1,500 @@
|
|||||||
|
import supa from '@/components/supadb/aksupainstance.uts'
|
||||||
|
import { getCurrentUserId } from '@/utils/store.uts'
|
||||||
|
import { getDeliveryProfileByUserId } from '@/api/delivery.uts'
|
||||||
|
import { getServiceOrderStatusText, normalizeServiceOrderStatus, type ServiceOrderStatus } from '@/types/service-order.uts'
|
||||||
|
import type {
|
||||||
|
DeliveryCheckinPayloadType,
|
||||||
|
DeliveryDashboardType,
|
||||||
|
DeliveryLocationType,
|
||||||
|
DeliveryOrderType,
|
||||||
|
DeliveryServiceRecordType
|
||||||
|
} from '@/types/delivery.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')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getCurrentStaffId(): Promise<string> {
|
||||||
|
const userId = getCurrentUserId()
|
||||||
|
if (userId == '') {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
const profile = await getDeliveryProfileByUserId(userId)
|
||||||
|
return profile != null ? profile.id : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
async function insertStatusLog(orderId: string, fromStatus: string, toStatus: ServiceOrderStatus, remark: string): Promise<void> {
|
||||||
|
const userId = getCurrentUserId()
|
||||||
|
await supa.from('hss_service_order_status_logs').insert({
|
||||||
|
id: buildId('slog'),
|
||||||
|
order_id: orderId,
|
||||||
|
from_status: fromStatus,
|
||||||
|
to_status: toStatus,
|
||||||
|
operator_id: userId == '' ? null : userId,
|
||||||
|
operator_role: 'delivery',
|
||||||
|
remark,
|
||||||
|
created_at: nowIso()
|
||||||
|
}).execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
function emptyOrder(): DeliveryOrderType {
|
||||||
|
return {
|
||||||
|
id: '',
|
||||||
|
orderNo: '',
|
||||||
|
serviceType: '',
|
||||||
|
serviceName: '',
|
||||||
|
serviceCategory: '',
|
||||||
|
serviceItems: [] as Array<any>,
|
||||||
|
elderId: '',
|
||||||
|
elderName: '',
|
||||||
|
elderNameMasked: '',
|
||||||
|
elderGender: '',
|
||||||
|
elderAge: 0,
|
||||||
|
elderPhone: '',
|
||||||
|
elderPhoneMasked: '',
|
||||||
|
fullElderName: '',
|
||||||
|
fullPhone: '',
|
||||||
|
contactRelation: '家属',
|
||||||
|
addressSummary: '',
|
||||||
|
address: '',
|
||||||
|
addressDetail: '',
|
||||||
|
fullAddress: '',
|
||||||
|
latitude: 0,
|
||||||
|
longitude: 0,
|
||||||
|
appointmentTime: '',
|
||||||
|
appointmentStartTime: '',
|
||||||
|
appointmentEndTime: '',
|
||||||
|
duration: 90,
|
||||||
|
estimatedDuration: 90,
|
||||||
|
price: 0,
|
||||||
|
staffIncome: 0,
|
||||||
|
distance: '',
|
||||||
|
actualStartTime: '',
|
||||||
|
actualEndTime: '',
|
||||||
|
status: 'pending_assignment' as any,
|
||||||
|
statusText: '',
|
||||||
|
statusTone: 'warning',
|
||||||
|
riskTags: [] as Array<string>,
|
||||||
|
healthTags: [] as Array<string>,
|
||||||
|
careLevel: '',
|
||||||
|
needFamilyPresent: false,
|
||||||
|
needMaterials: false,
|
||||||
|
remark: '',
|
||||||
|
merchantId: '',
|
||||||
|
merchantName: '',
|
||||||
|
deliveryStaffId: '',
|
||||||
|
deliveryStaffName: '',
|
||||||
|
acceptTime: '',
|
||||||
|
departTime: '',
|
||||||
|
arriveTime: '',
|
||||||
|
checkinTime: '',
|
||||||
|
finishTime: '',
|
||||||
|
cancelReason: '',
|
||||||
|
exceptionType: '',
|
||||||
|
exceptionDesc: '',
|
||||||
|
evidenceList: [] as Array<any>,
|
||||||
|
signatureUrl: '',
|
||||||
|
signatureName: '',
|
||||||
|
satisfactionStatus: '',
|
||||||
|
settlementStatus: '',
|
||||||
|
archiveStatus: '',
|
||||||
|
createdAt: '',
|
||||||
|
updatedAt: '',
|
||||||
|
contactName: '',
|
||||||
|
contactPhone: '',
|
||||||
|
notices: [] as Array<string>,
|
||||||
|
timeline: [] as Array<any>,
|
||||||
|
statusLog: [] as Array<any>,
|
||||||
|
serviceSummary: '',
|
||||||
|
progressNote: '',
|
||||||
|
distanceKm: '',
|
||||||
|
allowCheckinRadiusMeters: 100,
|
||||||
|
lastLocation: null,
|
||||||
|
trackPoints: [] as Array<any>,
|
||||||
|
serviceRecord: null,
|
||||||
|
abnormalReport: null
|
||||||
|
} as DeliveryOrderType
|
||||||
|
}
|
||||||
|
|
||||||
|
function safeJsonField(source: any, key: string): string {
|
||||||
|
const plain = JSON.parse(JSON.stringify(source)) as any
|
||||||
|
const value = plain[key]
|
||||||
|
if (value == null) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return JSON.stringify(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function statusToDeliveryStatus(status: ServiceOrderStatus): string {
|
||||||
|
if (status == 'assigned') return 'pending_assignment'
|
||||||
|
if (status == 'accepted') return 'accepted'
|
||||||
|
if (status == 'departed') return 'departed'
|
||||||
|
if (status == 'arrived') return 'arrived'
|
||||||
|
if (status == 'in_service') return 'in_service'
|
||||||
|
if (status == 'pending_acceptance') return 'pending_acceptance'
|
||||||
|
if (status == 'reviewed' || status == 'accepted_by_user' || status == 'settled') return 'completed'
|
||||||
|
if (status == 'rejected') return 'rejected'
|
||||||
|
if (status == 'cancelled') return 'cancelled'
|
||||||
|
if (status == 'exception') return 'abnormal'
|
||||||
|
return 'pending_assignment'
|
||||||
|
}
|
||||||
|
|
||||||
|
function statusTone(status: ServiceOrderStatus): string {
|
||||||
|
if (status == 'pending_acceptance' || status == 'assigned') 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 == 'rejected' || status == 'cancelled' || status == 'exception') return 'danger'
|
||||||
|
return 'warning'
|
||||||
|
}
|
||||||
|
|
||||||
|
async function parseDeliveryOrder(orderId: string, item: any): Promise<DeliveryOrderType> {
|
||||||
|
const order = emptyOrder()
|
||||||
|
const obj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
|
||||||
|
const addressRaw = safeJsonField(item, 'address_snapshot_json')
|
||||||
|
const serviceRaw = safeJsonField(item, 'service_snapshot_json')
|
||||||
|
const addressObj = JSON.parse(addressRaw == '' ? '{}' : addressRaw) as UTSJSONObject
|
||||||
|
const serviceObj = JSON.parse(serviceRaw == '' ? '{}' : serviceRaw) as UTSJSONObject
|
||||||
|
const normalizedStatus = normalizeServiceOrderStatus(obj.getString('status') ?? '')
|
||||||
|
order.id = obj.getString('id') ?? ''
|
||||||
|
order.orderNo = obj.getString('order_no') ?? ''
|
||||||
|
order.serviceType = serviceObj.getString('category') ?? '居家服务'
|
||||||
|
order.serviceName = obj.getString('service_name') ?? ''
|
||||||
|
order.serviceCategory = serviceObj.getString('category') ?? ''
|
||||||
|
order.elderName = obj.getString('recipient_name') ?? ''
|
||||||
|
order.elderNameMasked = order.elderName
|
||||||
|
order.fullElderName = order.elderName
|
||||||
|
order.elderPhone = obj.getString('recipient_phone') ?? ''
|
||||||
|
order.elderPhoneMasked = order.elderPhone
|
||||||
|
order.fullPhone = order.elderPhone
|
||||||
|
order.contactName = obj.getString('contact_name') ?? ''
|
||||||
|
order.contactPhone = obj.getString('contact_phone') ?? ''
|
||||||
|
order.contactRelation = '家属'
|
||||||
|
order.address = addressObj.getString('fullAddress') ?? ''
|
||||||
|
order.addressDetail = addressObj.getString('detailAddress') ?? ''
|
||||||
|
order.fullAddress = order.address
|
||||||
|
order.latitude = addressObj.getNumber('latitude') ?? 0
|
||||||
|
order.longitude = addressObj.getNumber('longitude') ?? 0
|
||||||
|
order.appointmentTime = obj.getString('appointment_time') ?? ''
|
||||||
|
order.appointmentStartTime = order.appointmentTime
|
||||||
|
order.appointmentEndTime = order.appointmentTime
|
||||||
|
order.duration = 90
|
||||||
|
order.estimatedDuration = 90
|
||||||
|
order.price = serviceObj.getNumber('price') ?? 0
|
||||||
|
order.staffIncome = order.price
|
||||||
|
order.status = statusToDeliveryStatus(normalizedStatus) as any
|
||||||
|
order.statusText = getServiceOrderStatusText(normalizedStatus)
|
||||||
|
order.statusTone = statusTone(normalizedStatus)
|
||||||
|
order.remark = obj.getString('remark') ?? ''
|
||||||
|
order.deliveryStaffId = obj.getString('current_staff_id') ?? ''
|
||||||
|
order.acceptTime = obj.getString('accepted_at') ?? ''
|
||||||
|
order.departTime = obj.getString('departed_at') ?? ''
|
||||||
|
order.arriveTime = obj.getString('arrived_at') ?? ''
|
||||||
|
order.actualStartTime = obj.getString('service_started_at') ?? ''
|
||||||
|
order.startServiceTime = order.actualStartTime
|
||||||
|
order.finishTime = obj.getString('completed_at') ?? ''
|
||||||
|
order.createdAt = obj.getString('created_at') ?? ''
|
||||||
|
order.updatedAt = obj.getString('updated_at') ?? ''
|
||||||
|
order.allowCheckinRadiusMeters = 100
|
||||||
|
const logsResponse = await supa.from('hss_service_order_status_logs').select('*').eq('order_id', orderId).order('created_at', { ascending: false }).execute()
|
||||||
|
if (logsResponse.data != null) {
|
||||||
|
const rawLogs = logsResponse.data as any[]
|
||||||
|
for (let i = 0; i < rawLogs.length; i++) {
|
||||||
|
const logObj = JSON.parse(JSON.stringify(rawLogs[i])) as UTSJSONObject
|
||||||
|
order.timeline.push({
|
||||||
|
id: logObj.getString('id') ?? '',
|
||||||
|
title: getServiceOrderStatusText(normalizeServiceOrderStatus(logObj.getString('to_status') ?? 'created')),
|
||||||
|
time: logObj.getString('created_at') ?? '',
|
||||||
|
description: logObj.getString('remark') ?? ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const recordResponse = await supa.from('hss_service_execution_records').select('*').eq('order_id', orderId).order('created_at', { ascending: false }).execute()
|
||||||
|
if (recordResponse.data != null) {
|
||||||
|
const raw = recordResponse.data as any[]
|
||||||
|
if (raw.length > 0) {
|
||||||
|
const recordObj = JSON.parse(JSON.stringify(raw[0])) as UTSJSONObject
|
||||||
|
order.checkinTime = recordObj.getString('checkin_time') ?? ''
|
||||||
|
order.serviceRecord = {
|
||||||
|
id: recordObj.getString('id') ?? '',
|
||||||
|
orderId: orderId,
|
||||||
|
startTime: recordObj.getString('service_started_at') ?? '',
|
||||||
|
endTime: recordObj.getString('service_finished_at') ?? '',
|
||||||
|
actualDurationMinutes: recordObj.getNumber('actual_duration_minutes') ?? 0,
|
||||||
|
serviceItems: [] as Array<any>,
|
||||||
|
serviceContent: [] as Array<string>,
|
||||||
|
processNote: recordObj.getString('summary') ?? '',
|
||||||
|
elderStatus: '',
|
||||||
|
healthMetrics: { bloodPressure: '', heartRate: '', bloodSugar: '', bloodOxygen: '' },
|
||||||
|
materialsUsed: '',
|
||||||
|
abnormalNote: '',
|
||||||
|
photos: [] as Array<string>,
|
||||||
|
staffRemark: recordObj.getString('remark') ?? '',
|
||||||
|
familyConfirmation: { method: 'none', code: '', signatureName: '', signatureUrl: '', confirmedAt: '' },
|
||||||
|
createdAt: recordObj.getString('created_at') ?? '',
|
||||||
|
updatedAt: recordObj.getString('updated_at') ?? ''
|
||||||
|
} as any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const evidenceResponse = await supa.from('hss_service_evidence_files').select('*').eq('order_id', orderId).order('created_at', { ascending: false }).execute()
|
||||||
|
if (evidenceResponse.data != null) {
|
||||||
|
const rawEvidence = evidenceResponse.data as any[]
|
||||||
|
for (let i = 0; i < rawEvidence.length; i++) {
|
||||||
|
const evidenceObj = JSON.parse(JSON.stringify(rawEvidence[i])) as UTSJSONObject
|
||||||
|
order.evidenceList.push({
|
||||||
|
id: evidenceObj.getString('id') ?? '',
|
||||||
|
orderId: orderId,
|
||||||
|
phase: evidenceObj.getString('phase') ?? '',
|
||||||
|
fileType: evidenceObj.getString('file_type') ?? 'image',
|
||||||
|
name: evidenceObj.getString('storage_path') ?? '',
|
||||||
|
url: evidenceObj.getString('file_url') ?? '',
|
||||||
|
localPath: '',
|
||||||
|
status: 'success',
|
||||||
|
progress: 100,
|
||||||
|
retryable: false,
|
||||||
|
createdAt: evidenceObj.getString('created_at') ?? ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return order
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getDashboard(): Promise<DeliveryDashboardType> {
|
||||||
|
const orders = await getOrdersByTab('all')
|
||||||
|
let pending = 0
|
||||||
|
let today = 0
|
||||||
|
let serving = 0
|
||||||
|
let completed = 0
|
||||||
|
let nextOrder: DeliveryOrderType | null = null
|
||||||
|
for (let i = 0; i < orders.length; i++) {
|
||||||
|
const item = orders[i]
|
||||||
|
if (item.status == 'pending_assignment') pending++
|
||||||
|
if (item.status == 'pending_assignment' || item.status == 'accepted' || item.status == 'departed' || item.status == 'arrived' || item.status == 'in_service') today++
|
||||||
|
if (item.status == 'in_service') serving++
|
||||||
|
if (item.status == 'completed' || item.status == 'pending_acceptance') completed++
|
||||||
|
if (nextOrder == null && item.status != 'completed' && item.status != 'cancelled' && item.status != 'abnormal') {
|
||||||
|
nextOrder = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
pendingAssignmentCount: pending,
|
||||||
|
pendingAcceptCount: pending,
|
||||||
|
todayOrderCount: today,
|
||||||
|
pendingDepartCount: 0,
|
||||||
|
servingCount: serving,
|
||||||
|
completedCount: completed,
|
||||||
|
exceptionCount: 0,
|
||||||
|
expectedIncome: 0,
|
||||||
|
onlineStatus: 'online',
|
||||||
|
nextOrder,
|
||||||
|
recentOrders: orders.slice(0, 5)
|
||||||
|
} as DeliveryDashboardType
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getOrdersByTab(tab: string): Promise<Array<DeliveryOrderType>> {
|
||||||
|
const staffId = await getCurrentStaffId()
|
||||||
|
if (staffId == '') {
|
||||||
|
return [] as Array<DeliveryOrderType>
|
||||||
|
}
|
||||||
|
const response = await supa.from('hss_service_orders').select('*').eq('current_staff_id', staffId).order('created_at', { ascending: false }).execute()
|
||||||
|
if (response.error != null || response.data == null) {
|
||||||
|
return [] as Array<DeliveryOrderType>
|
||||||
|
}
|
||||||
|
const rawOrders = response.data as any[]
|
||||||
|
const result = [] as Array<DeliveryOrderType>
|
||||||
|
for (let i = 0; i < rawOrders.length; i++) {
|
||||||
|
const orderObj = JSON.parse(JSON.stringify(rawOrders[i])) as UTSJSONObject
|
||||||
|
const normalized = normalizeServiceOrderStatus(orderObj.getString('status') ?? '')
|
||||||
|
let matched = true
|
||||||
|
if (tab == 'pending') {
|
||||||
|
matched = normalized == 'assigned'
|
||||||
|
} else if (tab == 'today') {
|
||||||
|
matched = normalized == 'assigned' || normalized == 'accepted' || normalized == 'departed' || normalized == 'arrived' || normalized == 'in_service' || normalized == 'pending_acceptance'
|
||||||
|
} else if (tab == 'history') {
|
||||||
|
matched = normalized == 'pending_acceptance' || normalized == 'accepted_by_user' || normalized == 'reviewed' || normalized == 'settled' || normalized == 'exception' || normalized == 'cancelled'
|
||||||
|
}
|
||||||
|
if (tab == 'all' || matched) {
|
||||||
|
result.push(await parseDeliveryOrder(orderObj.getString('id') ?? '', rawOrders[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getOrderDetail(orderId: string): Promise<DeliveryOrderType | null> {
|
||||||
|
const response = await supa.from('hss_service_orders').select('*').eq('id', orderId).single().execute()
|
||||||
|
if (response.error != null || response.data == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return await parseDeliveryOrder(orderId, response.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateOrderStatus(orderId: string, nextStatus: ServiceOrderStatus, updateData: UTSJSONObject, remark: string): Promise<DeliveryOrderType | null> {
|
||||||
|
const current = await getOrderDetail(orderId)
|
||||||
|
if (current == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const map = JSON.parse('{}') as UTSJSONObject
|
||||||
|
map.set('status', nextStatus)
|
||||||
|
map.set('updated_at', nowIso())
|
||||||
|
const iterator = updateData.keys()
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
const key = iterator.next()
|
||||||
|
map.set(key, updateData.get(key))
|
||||||
|
}
|
||||||
|
const response = await supa.from('hss_service_orders').update(map).eq('id', orderId).execute()
|
||||||
|
if (response.error != null) {
|
||||||
|
console.error('updateOrderStatus failed', response.error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
await insertStatusLog(orderId, normalizeServiceOrderStatus(current.status as string), nextStatus, remark)
|
||||||
|
return await getOrderDetail(orderId)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function acceptOrder(orderId: string): Promise<DeliveryOrderType | null> {
|
||||||
|
const assignmentResponse = await supa.from('hss_service_assignments').select('*').eq('order_id', orderId).order('created_at', { ascending: false }).execute()
|
||||||
|
if (assignmentResponse.data != null) {
|
||||||
|
const raw = assignmentResponse.data as any[]
|
||||||
|
if (raw.length > 0) {
|
||||||
|
const assignmentId = JSON.parse(JSON.stringify(raw[0]))['id'] as string
|
||||||
|
await supa.from('hss_service_assignments').update({ status: 'accepted', accepted_at: nowIso(), updated_at: nowIso() }).eq('id', assignmentId).execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const updateData = JSON.parse('{}') as UTSJSONObject
|
||||||
|
updateData.set('accepted_at', nowIso())
|
||||||
|
return await updateOrderStatus(orderId, 'accepted', updateData, '服务人员接单')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function departOrder(orderId: string, location: DeliveryLocationType | null): Promise<DeliveryOrderType | null> {
|
||||||
|
const updateData = JSON.parse('{}') as UTSJSONObject
|
||||||
|
updateData.set('departed_at', nowIso())
|
||||||
|
return await updateOrderStatus(orderId, 'departed', updateData, location == null ? '服务人员出发' : '服务人员出发:' + location.address)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function arriveOrder(orderId: string, location: DeliveryLocationType | null): Promise<DeliveryOrderType | null> {
|
||||||
|
const updateData = JSON.parse('{}') as UTSJSONObject
|
||||||
|
updateData.set('arrived_at', nowIso())
|
||||||
|
return await updateOrderStatus(orderId, 'arrived', updateData, location == null ? '服务人员到达' : '服务人员到达:' + location.address)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function checkinOrder(orderId: string, payload: DeliveryCheckinPayloadType): Promise<DeliveryOrderType | null> {
|
||||||
|
const current = await getOrderDetail(orderId)
|
||||||
|
if (current == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
let assignmentId = ''
|
||||||
|
const assignmentResponse = await supa.from('hss_service_assignments').select('*').eq('order_id', orderId).order('created_at', { ascending: false }).execute()
|
||||||
|
if (assignmentResponse.data != null) {
|
||||||
|
const rawAssignments = assignmentResponse.data as any[]
|
||||||
|
if (rawAssignments.length > 0) {
|
||||||
|
assignmentId = JSON.parse(JSON.stringify(rawAssignments[0]))['id'] as string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let recordId = buildId('ser')
|
||||||
|
const recordResponse = await supa.from('hss_service_execution_records').select('*').eq('order_id', orderId).order('created_at', { ascending: false }).execute()
|
||||||
|
if (recordResponse.data != null) {
|
||||||
|
const records = recordResponse.data as any[]
|
||||||
|
if (records.length > 0) {
|
||||||
|
recordId = JSON.parse(JSON.stringify(records[0]))['id'] as string
|
||||||
|
await supa.from('hss_service_execution_records').update({
|
||||||
|
checkin_time: nowIso(),
|
||||||
|
checkin_latitude: payload.location.latitude,
|
||||||
|
checkin_longitude: payload.location.longitude,
|
||||||
|
checkin_address: payload.location.address,
|
||||||
|
remark: payload.note,
|
||||||
|
updated_at: nowIso()
|
||||||
|
}).eq('id', recordId).execute()
|
||||||
|
} else {
|
||||||
|
await supa.from('hss_service_execution_records').insert({
|
||||||
|
id: recordId,
|
||||||
|
order_id: orderId,
|
||||||
|
assignment_id: assignmentId,
|
||||||
|
checkin_time: nowIso(),
|
||||||
|
checkin_latitude: payload.location.latitude,
|
||||||
|
checkin_longitude: payload.location.longitude,
|
||||||
|
checkin_address: payload.location.address,
|
||||||
|
remark: payload.note,
|
||||||
|
created_at: nowIso(),
|
||||||
|
updated_at: nowIso()
|
||||||
|
}).execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < payload.photos.length; i++) {
|
||||||
|
await supa.from('hss_service_evidence_files').insert({
|
||||||
|
id: buildId('sef'),
|
||||||
|
order_id: orderId,
|
||||||
|
execution_record_id: recordId,
|
||||||
|
phase: 'checkin',
|
||||||
|
file_type: 'image',
|
||||||
|
storage_path: payload.photos[i],
|
||||||
|
file_url: payload.photos[i],
|
||||||
|
latitude: payload.location.latitude,
|
||||||
|
longitude: payload.location.longitude,
|
||||||
|
captured_at: nowIso(),
|
||||||
|
created_at: nowIso()
|
||||||
|
}).execute()
|
||||||
|
}
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function startService(orderId: string): Promise<DeliveryOrderType | null> {
|
||||||
|
let recordId = ''
|
||||||
|
const recordResponse = await supa.from('hss_service_execution_records').select('*').eq('order_id', orderId).order('created_at', { ascending: false }).execute()
|
||||||
|
if (recordResponse.data != null) {
|
||||||
|
const records = recordResponse.data as any[]
|
||||||
|
if (records.length > 0) {
|
||||||
|
recordId = JSON.parse(JSON.stringify(records[0]))['id'] as string
|
||||||
|
await supa.from('hss_service_execution_records').update({ service_started_at: nowIso(), updated_at: nowIso() }).eq('id', recordId).execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const updateData = JSON.parse('{}') as UTSJSONObject
|
||||||
|
updateData.set('service_started_at', nowIso())
|
||||||
|
return await updateOrderStatus(orderId, 'in_service', updateData, '开始服务')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveServiceRecord(orderId: string, record: DeliveryServiceRecordType): Promise<DeliveryOrderType | null> {
|
||||||
|
let assignmentId = ''
|
||||||
|
const assignmentResponse = await supa.from('hss_service_assignments').select('*').eq('order_id', orderId).order('created_at', { ascending: false }).execute()
|
||||||
|
if (assignmentResponse.data != null) {
|
||||||
|
const assignments = assignmentResponse.data as any[]
|
||||||
|
if (assignments.length > 0) {
|
||||||
|
assignmentId = JSON.parse(JSON.stringify(assignments[0]))['id'] as string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await supa.from('hss_service_execution_records').upsert({
|
||||||
|
id: record.id,
|
||||||
|
order_id: orderId,
|
||||||
|
assignment_id: assignmentId,
|
||||||
|
service_started_at: record.startTime,
|
||||||
|
service_finished_at: record.endTime,
|
||||||
|
actual_duration_minutes: record.actualDurationMinutes,
|
||||||
|
service_items_json: record.serviceItems as any,
|
||||||
|
summary: record.processNote,
|
||||||
|
remark: record.staffRemark,
|
||||||
|
updated_at: nowIso(),
|
||||||
|
created_at: record.createdAt
|
||||||
|
}).execute()
|
||||||
|
for (let i = 0; i < record.photos.length; i++) {
|
||||||
|
await supa.from('hss_service_evidence_files').insert({
|
||||||
|
id: buildId('sef'),
|
||||||
|
order_id: orderId,
|
||||||
|
execution_record_id: record.id,
|
||||||
|
phase: 'service',
|
||||||
|
file_type: 'image',
|
||||||
|
storage_path: record.photos[i],
|
||||||
|
file_url: record.photos[i],
|
||||||
|
captured_at: nowIso(),
|
||||||
|
created_at: nowIso()
|
||||||
|
}).execute()
|
||||||
|
}
|
||||||
|
return await getOrderDetail(orderId)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function finishOrder(orderId: string): Promise<DeliveryOrderType | null> {
|
||||||
|
const updateData = JSON.parse('{}') as UTSJSONObject
|
||||||
|
updateData.set('completed_at', nowIso())
|
||||||
|
updateData.set('pending_acceptance_at', nowIso())
|
||||||
|
return await updateOrderStatus(orderId, 'pending_acceptance', updateData, '服务完成,等待用户验收')
|
||||||
|
}
|
||||||
81
types/service-order.uts
Normal file
81
types/service-order.uts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
export type ServiceOrderStatus =
|
||||||
|
'created' |
|
||||||
|
'paid' |
|
||||||
|
'assigned' |
|
||||||
|
'accepted' |
|
||||||
|
'rejected' |
|
||||||
|
'departed' |
|
||||||
|
'arrived' |
|
||||||
|
'in_service' |
|
||||||
|
'completed' |
|
||||||
|
'pending_acceptance' |
|
||||||
|
'accepted_by_user' |
|
||||||
|
'reviewed' |
|
||||||
|
'settled' |
|
||||||
|
'cancelled' |
|
||||||
|
'exception'
|
||||||
|
|
||||||
|
export const SERVICE_ORDER_STATUS_LIST: Array<ServiceOrderStatus> = [
|
||||||
|
'created',
|
||||||
|
'paid',
|
||||||
|
'assigned',
|
||||||
|
'accepted',
|
||||||
|
'rejected',
|
||||||
|
'departed',
|
||||||
|
'arrived',
|
||||||
|
'in_service',
|
||||||
|
'completed',
|
||||||
|
'pending_acceptance',
|
||||||
|
'accepted_by_user',
|
||||||
|
'reviewed',
|
||||||
|
'settled',
|
||||||
|
'cancelled',
|
||||||
|
'exception'
|
||||||
|
]
|
||||||
|
|
||||||
|
export type ServiceOrderTimelineItemType = {
|
||||||
|
id: string
|
||||||
|
orderId: string
|
||||||
|
fromStatus: string
|
||||||
|
toStatus: ServiceOrderStatus
|
||||||
|
operatorId: string
|
||||||
|
operatorRole: string
|
||||||
|
remark: string
|
||||||
|
createdAt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getServiceOrderStatusText(status: ServiceOrderStatus): string {
|
||||||
|
if (status == 'created') return '待处理'
|
||||||
|
if (status == 'paid') return '已支付'
|
||||||
|
if (status == 'assigned') return '已派单'
|
||||||
|
if (status == 'accepted') return '已接单'
|
||||||
|
if (status == 'rejected') return '已拒单'
|
||||||
|
if (status == 'departed') return '已出发'
|
||||||
|
if (status == 'arrived') return '已到达'
|
||||||
|
if (status == 'in_service') return '服务中'
|
||||||
|
if (status == 'completed') return '已完成'
|
||||||
|
if (status == 'pending_acceptance') return '待验收'
|
||||||
|
if (status == 'accepted_by_user') return '已验收'
|
||||||
|
if (status == 'reviewed') return '已评价'
|
||||||
|
if (status == 'settled') return '已结算'
|
||||||
|
if (status == 'cancelled') return '已取消'
|
||||||
|
return '异常'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeServiceOrderStatus(status: string): ServiceOrderStatus {
|
||||||
|
if (status == 'created' || status == 'submitted') return 'created'
|
||||||
|
if (status == 'paid') return 'paid'
|
||||||
|
if (status == 'assigned' || status == 'pending_dispatch' || status == 'pending_assignment') return 'assigned'
|
||||||
|
if (status == 'accepted' || status == 'pending_accept') return 'accepted'
|
||||||
|
if (status == 'rejected') return 'rejected'
|
||||||
|
if (status == 'departed' || status == 'waiting_departure' || status == 'on_the_way') return 'departed'
|
||||||
|
if (status == 'arrived' || status == 'checked_in') return 'arrived'
|
||||||
|
if (status == 'in_service' || status == 'serving') return 'in_service'
|
||||||
|
if (status == 'completed') return 'completed'
|
||||||
|
if (status == 'pending_acceptance' || status == 'pending_confirm' || status == 'pending_submit') return 'pending_acceptance'
|
||||||
|
if (status == 'accepted_by_user') return 'accepted_by_user'
|
||||||
|
if (status == 'reviewed') return 'reviewed'
|
||||||
|
if (status == 'settled') return 'settled'
|
||||||
|
if (status == 'cancelled') return 'cancelled'
|
||||||
|
return 'exception'
|
||||||
|
}
|
||||||
@@ -14,16 +14,14 @@ export function getDeliveryOrderTabs(): Array<DeliveryTabOptionType> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isHistoryStatus(status: DeliveryOrderStatus): boolean {
|
export function isHistoryStatus(status: DeliveryOrderStatus): boolean {
|
||||||
return status == 'completed' || status == 'rejected' || status == 'cancelled' || status == 'abnormal' || status == 'terminated' || status == 'archived'
|
return status == 'completed' || status == 'pending_acceptance' || status == 'rejected' || status == 'cancelled' || status == 'abnormal' || status == 'terminated' || status == 'archived'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDeliveryStatusLabel(status: DeliveryOrderStatus): string {
|
export function getDeliveryStatusLabel(status: DeliveryOrderStatus): string {
|
||||||
if (status == 'pending_assignment' || status == 'pending_accept') return '待接单'
|
if (status == 'pending_assignment' || status == 'pending_accept') return '待接单'
|
||||||
if (status == 'accepted') return '已接单'
|
if (status == 'accepted') return '已接单'
|
||||||
if (status == 'waiting_departure') return '待出发'
|
|
||||||
if (status == 'departed' || status == 'on_the_way') return '已出发'
|
if (status == 'departed' || status == 'on_the_way') return '已出发'
|
||||||
if (status == 'arrived') return '已到达'
|
if (status == 'arrived') return '已到达'
|
||||||
if (status == 'checked_in') return '已签到'
|
|
||||||
if (status == 'in_service' || status == 'serving') return '服务中'
|
if (status == 'in_service' || status == 'serving') return '服务中'
|
||||||
if (status == 'pending_confirm' || status == 'pending_acceptance' || status == 'pending_submit') return '待确认'
|
if (status == 'pending_confirm' || status == 'pending_acceptance' || status == 'pending_submit') return '待确认'
|
||||||
if (status == 'completed') return '已完成'
|
if (status == 'completed') return '已完成'
|
||||||
@@ -36,12 +34,11 @@ export function getDeliveryStatusLabel(status: DeliveryOrderStatus): string {
|
|||||||
|
|
||||||
export function getPrimaryActionText(status: DeliveryOrderStatus): string {
|
export function getPrimaryActionText(status: DeliveryOrderStatus): string {
|
||||||
if (status == 'pending_assignment' || status == 'pending_accept') return '接单'
|
if (status == 'pending_assignment' || status == 'pending_accept') return '接单'
|
||||||
if (status == 'accepted' || status == 'waiting_departure') return '我已出发'
|
if (status == 'accepted' || status == 'waiting_departure') return '前往服务'
|
||||||
if (status == 'departed' || status == 'on_the_way') return '我已到达'
|
if (status == 'departed' || status == 'on_the_way') return '我已到达'
|
||||||
if (status == 'arrived') return '签到'
|
if (status == 'arrived') return '签到'
|
||||||
if (status == 'checked_in') return '开始服务'
|
|
||||||
if (status == 'in_service' || status == 'serving') return '填写记录'
|
if (status == 'in_service' || status == 'serving') return '填写记录'
|
||||||
if (status == 'pending_confirm' || status == 'pending_acceptance' || status == 'pending_submit') return '完成服务'
|
if (status == 'pending_confirm' || status == 'pending_acceptance' || status == 'pending_submit') return '等待验收'
|
||||||
if (status == 'completed') return '查看记录'
|
if (status == 'completed') return '查看记录'
|
||||||
if (status == 'abnormal' || status == 'exception_pending') return '查看异常'
|
if (status == 'abnormal' || status == 'exception_pending') return '查看异常'
|
||||||
return '查看详情'
|
return '查看详情'
|
||||||
@@ -49,12 +46,11 @@ export function getPrimaryActionText(status: DeliveryOrderStatus): string {
|
|||||||
|
|
||||||
export function getNextStepText(status: DeliveryOrderStatus): string {
|
export function getNextStepText(status: DeliveryOrderStatus): string {
|
||||||
if (status == 'pending_assignment' || status == 'pending_accept') return '确认是否接单'
|
if (status == 'pending_assignment' || status == 'pending_accept') return '确认是否接单'
|
||||||
if (status == 'accepted' || status == 'waiting_departure') return '前往服务对象地址'
|
if (status == 'accepted' || status == 'waiting_departure') return '前往服务对象地址并发起导航'
|
||||||
if (status == 'departed' || status == 'on_the_way') return '到达服务地点'
|
if (status == 'departed' || status == 'on_the_way') return '到达服务地点'
|
||||||
if (status == 'arrived') return '完成签到确认'
|
if (status == 'arrived') return '完成签到确认'
|
||||||
if (status == 'checked_in') return '开始本次上门服务'
|
if (status == 'in_service' || status == 'serving') return '补充服务记录并完成服务'
|
||||||
if (status == 'in_service' || status == 'serving') return '补充服务记录'
|
if (status == 'pending_confirm' || status == 'pending_acceptance' || status == 'pending_submit') return '等待用户确认验收'
|
||||||
if (status == 'pending_confirm' || status == 'pending_acceptance' || status == 'pending_submit') return '确认并完成订单'
|
|
||||||
if (status == 'completed') return '查看历史记录'
|
if (status == 'completed') return '查看历史记录'
|
||||||
if (status == 'abnormal' || status == 'exception_pending') return '跟进异常处置'
|
if (status == 'abnormal' || status == 'exception_pending') return '跟进异常处置'
|
||||||
return '查看订单详情'
|
return '查看订单详情'
|
||||||
|
|||||||
Reference in New Issue
Block a user