feat(M08-B): 补任务事件流水
This commit is contained in:
@@ -3,6 +3,7 @@ import type {
|
||||
CleaningSettlementDetail,
|
||||
CleaningStatistics,
|
||||
CleaningTask,
|
||||
CleaningTaskEvent,
|
||||
CleaningTaskMember,
|
||||
ManagedUser,
|
||||
PageResult,
|
||||
@@ -170,6 +171,13 @@ export function listCleaningTaskMembers(session: ApiSession, taskId: string) {
|
||||
);
|
||||
}
|
||||
|
||||
export function listCleaningTaskEvents(session: ApiSession, taskId: string) {
|
||||
return request<CleaningTaskEvent[]>(
|
||||
session,
|
||||
`/cleaning/tasks/${encodeURIComponent(taskId)}/events`
|
||||
);
|
||||
}
|
||||
|
||||
export function addCleaningTaskMember(
|
||||
session: ApiSession,
|
||||
taskId: string,
|
||||
|
||||
@@ -280,6 +280,29 @@
|
||||
<span>提交<strong>{{ shortDate(detailDialog.task.submittedAt) }}</strong></span>
|
||||
<span>完成<strong>{{ shortDate(detailDialog.task.completedAt) }}</strong></span>
|
||||
</div>
|
||||
<section class="stat-block">
|
||||
<header>
|
||||
<h3>操作流水</h3>
|
||||
<span>最近 {{ detailDialog.events.length }} 条</span>
|
||||
</header>
|
||||
<el-table :data="detailDialog.events" size="small" v-loading="detailDialog.loadingEvents">
|
||||
<el-table-column prop="action" label="动作" width="130" />
|
||||
<el-table-column label="状态" width="150">
|
||||
<template #default="{ row }">
|
||||
{{ compactText(row.fromStatus) }} → {{ row.toStatus }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="actorId" label="操作人" width="100">
|
||||
<template #default="{ row }">{{ compactText(row.actorId) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="note" label="备注" min-width="160">
|
||||
<template #default="{ row }">{{ compactText(row.note) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createdAt" label="时间" width="130">
|
||||
<template #default="{ row }">{{ shortDate(row.createdAt) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</section>
|
||||
<div class="photo-grid" v-if="detailDialog.task.photoUrls.length">
|
||||
<el-image
|
||||
v-for="url in detailDialog.task.photoUrls"
|
||||
@@ -316,11 +339,19 @@ import {
|
||||
import { ElMessage } from 'element-plus';
|
||||
import {
|
||||
addCleaningTaskMember,
|
||||
listCleaningTaskEvents,
|
||||
listCleaningTaskMembers,
|
||||
removeCleaningTaskMember
|
||||
} from '../api';
|
||||
import { compactText, money, shortDate } from '../format';
|
||||
import type { CleaningTask, CleaningTaskMember, ManagedUser, PageResult, TaskStatus } from '../types';
|
||||
import type {
|
||||
CleaningTask,
|
||||
CleaningTaskEvent,
|
||||
CleaningTaskMember,
|
||||
ManagedUser,
|
||||
PageResult,
|
||||
TaskStatus
|
||||
} from '../types';
|
||||
|
||||
const props = defineProps<{
|
||||
session: { token: string };
|
||||
@@ -358,9 +389,16 @@ const filterDraft = reactive({ storeId: props.filters.storeId, cleanerUserId: pr
|
||||
const reclaimForm = reactive({ olderThanMinutes: 60, limit: 20 });
|
||||
const assignDialog = reactive({ open: false, taskId: '', cleanerUserId: '', note: '' });
|
||||
const rejectDialog = reactive({ open: false, taskId: '', reason: '' });
|
||||
const detailDialog = reactive<{ open: boolean; task: CleaningTask | null }>({
|
||||
const detailDialog = reactive<{
|
||||
open: boolean;
|
||||
loadingEvents: boolean;
|
||||
task: CleaningTask | null;
|
||||
events: CleaningTaskEvent[];
|
||||
}>({
|
||||
open: false,
|
||||
task: null
|
||||
loadingEvents: false,
|
||||
task: null,
|
||||
events: []
|
||||
});
|
||||
const memberDialog = reactive({
|
||||
open: false,
|
||||
@@ -401,9 +439,18 @@ function submitFilters() {
|
||||
});
|
||||
}
|
||||
|
||||
function openDetail(row: CleaningTask) {
|
||||
async function openDetail(row: CleaningTask) {
|
||||
detailDialog.open = true;
|
||||
detailDialog.task = row;
|
||||
detailDialog.events = [];
|
||||
detailDialog.loadingEvents = true;
|
||||
try {
|
||||
detailDialog.events = await listCleaningTaskEvents(props.session, row.id);
|
||||
} catch (error) {
|
||||
ElMessage.error(error instanceof Error ? error.message : '任务流水加载失败');
|
||||
} finally {
|
||||
detailDialog.loadingEvents = false;
|
||||
}
|
||||
}
|
||||
|
||||
function openAssign(row: CleaningTask) {
|
||||
|
||||
@@ -75,6 +75,18 @@ export interface CleaningTaskMember {
|
||||
settledAt?: string | null;
|
||||
}
|
||||
|
||||
export interface CleaningTaskEvent {
|
||||
id: string;
|
||||
taskId: string;
|
||||
fromStatus: TaskStatus | null;
|
||||
toStatus: TaskStatus;
|
||||
action: string;
|
||||
actorId: string;
|
||||
traceId: string;
|
||||
note: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface CleaningSettlement {
|
||||
id: string;
|
||||
settlementNo: string;
|
||||
|
||||
Reference in New Issue
Block a user