fix(c2): 排班派单页接入当日工单列表接口

后端补 R11 后,将日视图数据源从占位切换为 GET /order?serviceDate=
(管理员视角当日全部工单),移除 NEEDS_CONTEXT 告警横幅,批量推荐的
「待派工单」改由当日 to_assign 工单下拉选择并自动带入老人与时段。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
liuyun 2026-10-14 23:10:23 +08:00
parent 80e2a39190
commit 43b467af3a
2 changed files with 49 additions and 24 deletions

View File

@ -6,8 +6,8 @@ import { http } from '@/api/http'
* - 时间字段(timeSlotStart/End 为 datetime、serviceDate/assignTime 为日期)后端返回毫秒时间戳;
* - 派单冲突(2001)/无待遇(1001)/无计划(1002)/资质提示(1006)由后端以 ApiError.message 返回,前端直接展示。
*
* 注意:后端暂无「按日期列全部工单(管理员视角)」的列表接口,仅有 GET /order/today(当前登录
* 护理员本人当日工单)。排班派单页的「全部当日工单」数据源见 task-5-report(NEEDS_CONTEXT)。
* 注意:管理员视角「按日期列全部工单」用 listOrders(GET /order?serviceDate=,权限 order.detail);
* GET /order/today 仅返回当前登录护理员本人当日工单,不可用于日视图。
*/
/** 工单八态(order_status)。 */
@ -148,6 +148,11 @@ export function getTodayOrders(serviceDate?: string): Promise<Order[]> {
return http.get<Order[]>('/order/today', { params: serviceDate ? { serviceDate } : undefined })
}
/** 按日期列当日工单(管理员视角,租户全部工单;可选按护理员过滤,按 timeSlotStart 排序)。 */
export function listOrders(query: { serviceDate: string; assigneeId?: string }): Promise<Order[]> {
return http.get<Order[]>('/order', { params: query })
}
/** 批量推荐(只读,返回推荐护理员 + 理由,不自动派)。 */
export function batchRecommend(query: BatchRecommendQuery): Promise<BatchRecommendItem[]> {
return http.get<BatchRecommendItem[]>('/order/batch-recommend', { params: query })

View File

@ -9,15 +9,6 @@
</div>
</el-card>
<el-alert
v-if="dataSourceMissing"
class="mt-sm"
type="warning"
:closable="false"
title="后端暂缺「按日期列全部工单(管理员视角)」接口,日视图暂无法加载当日工单"
description="后端仅有 GET /order/today(当前登录护理员本人,管理员视角为空)。待补 GET /order?serviceDate= 后接入 loadOrders()。"
/>
<el-card shadow="never" class="mt-sm schedule-page__grid">
<div v-loading="loading" class="schedule-grid">
<div class="schedule-grid__corner">护理员 \ 时段</div>
@ -110,17 +101,26 @@
</el-table>
<div class="mt-sm flex items-center">
<el-form-item label="待派工单ID" class="mb-0">
<el-input v-model="recommendForm.orderId" placeholder="to_assign 工单 ID" style="width: 320px" />
<el-form-item label="待派工单" class="mb-0">
<el-select
v-model="recommendForm.orderId"
placeholder="选择当日 to_assign 工单"
clearable
filterable
style="width: 320px"
@change="onRecommendOrderChange"
>
<el-option v-for="o in toAssignOrders" :key="o.id" :label="toAssignLabel(o)" :value="o.id" />
</el-select>
</el-form-item>
<span class="ml-xs text-xs text-text-placeholder">确认派单需指定 to_assign 工单(日视图接入后可自动带入)</span>
<span class="ml-xs text-xs text-text-placeholder">选择工单后自动带入老人与时段,逐条确认后才派</span>
</div>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { computed, onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { ApiError } from '@/api/http'
import { listElders, type Elder } from '@/api/elder'
@ -128,6 +128,7 @@ import { listStaff, type Staff } from '@/api/staff'
import {
assignOrder,
batchRecommend,
listOrders,
reassignOrder,
type BatchRecommendItem,
type Order,
@ -146,8 +147,6 @@ const staffList = ref<Staff[]>([])
const elders = ref<Elder[]>([])
const orders = ref<Order[]>([])
const conflictedOrderIds = ref<Set<string>>(new Set())
/** 后端缺「按日期列全部工单」接口时为 true(日视图数据源待补)。 */
const dataSourceMissing = ref(false)
const elderNameMap = ref<Map<string, string>>(new Map())
const staffNameMap = ref<Map<string, string>>(new Map())
@ -165,6 +164,9 @@ const recommending = ref(false)
const recommendations = ref<BatchRecommendItem[]>([])
const recommendForm = reactive({ elderId: '', timeSlotStart: '', timeSlotEnd: '', orderId: '' })
/** 当日待派(to_assign)工单,供「待派工单」下拉选择。 */
const toAssignOrders = computed(() => orders.value.filter((o) => o.orderStatus === 'to_assign'))
function pad(n: number): string {
return String(n).padStart(2, '0')
}
@ -180,6 +182,18 @@ function fmtTime(ms?: number | null): string {
return `${pad(d.getHours())}:${pad(d.getMinutes())}`
}
/** 毫秒时间戳 → 'YYYY-MM-DDTHH:mm:ss'(用于 datetime picker 的 value-format)。 */
function toDateTimeStr(ms?: number | null): string {
if (ms == null) return ''
const d = new Date(ms)
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:00`
}
/** 待派工单下拉项文案:老人 · 时段。 */
function toAssignLabel(o: Order): string {
return `${elderName(o.elderId)} · ${fmtTime(o.timeSlotStart)}–${fmtTime(o.timeSlotEnd)}`
}
/** 工单起始小时落到的时段列 key(超出 08:00–18:00 返回 null)。 */
function slotKeyOf(o: Order): string | null {
if (o.timeSlotStart == null) return null
@ -248,13 +262,9 @@ async function loadElders(): Promise<void> {
elderNameMap.value = new Map(result.list.map((e) => [e.id, e.name]))
}
/** 加载当日工单。后端暂缺「按日期列全部工单(管理员视角)」接口 → NEEDS_CONTEXT。 */
/** 加载当日工单(管理员视角,GET /order?serviceDate=)。 */
async function loadOrders(): Promise<void> {
// 待后端补 GET /order?serviceDate=...(管理员视角全部工单)后,替换为:
// orders.value = await listOrdersByDate(date.value)
// 当前仅有 GET /order/today(当前登录护理员本人,管理员视角返回 []),不可用于日视图。
orders.value = []
dataSourceMissing.value = true
orders.value = await listOrders({ serviceDate: date.value })
computeConflicts()
}
@ -329,10 +339,20 @@ async function loadRecommend(): Promise<void> {
}
}
/** 选中待派工单后,自动带入老人与时段(供批量推荐查询用)。 */
function onRecommendOrderChange(orderId: string): void {
if (!orderId) return
const o = orders.value.find((x) => x.id === orderId)
if (!o) return
recommendForm.elderId = o.elderId
recommendForm.timeSlotStart = toDateTimeStr(o.timeSlotStart)
recommendForm.timeSlotEnd = toDateTimeStr(o.timeSlotEnd)
}
/** 逐条人工确认后才派(batch_recommend),不自动派。 */
async function confirmRecommend(staffId: string, name: string): Promise<void> {
if (!recommendForm.orderId) {
ElMessage.warning('请先填写待派工单 ID')
ElMessage.warning('请先选择待派工单')
return
}
try {