feat(M08-D): 建立后台运营总览
This commit is contained in:
+41
-11
@@ -10,7 +10,21 @@
|
||||
</div>
|
||||
</div>
|
||||
<nav class="nav-list" aria-label="后台模块">
|
||||
<button class="nav-item active" type="button">
|
||||
<button
|
||||
class="nav-item"
|
||||
:class="{ active: activeModule === 'overview' }"
|
||||
type="button"
|
||||
@click="activeModule = 'overview'"
|
||||
>
|
||||
<LayoutDashboard :size="18" />
|
||||
<span>运营总览</span>
|
||||
</button>
|
||||
<button
|
||||
class="nav-item"
|
||||
:class="{ active: activeModule === 'cleaning' }"
|
||||
type="button"
|
||||
@click="activeModule = 'cleaning'"
|
||||
>
|
||||
<Sparkles :size="18" />
|
||||
<span>保洁运营</span>
|
||||
</button>
|
||||
@@ -32,8 +46,8 @@
|
||||
<section class="workspace">
|
||||
<header class="topbar">
|
||||
<div>
|
||||
<p class="eyebrow">M08-B</p>
|
||||
<h2>保洁任务与结算</h2>
|
||||
<p class="eyebrow">{{ activeModule === 'overview' ? 'M08-D' : 'M08-B' }}</p>
|
||||
<h2>{{ activeModule === 'overview' ? '平台运营总览' : '保洁任务与结算' }}</h2>
|
||||
</div>
|
||||
<div class="token-box">
|
||||
<el-input
|
||||
@@ -50,6 +64,13 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<OperationsOverviewPanel
|
||||
v-if="activeModule === 'overview'"
|
||||
:session="session"
|
||||
@open-cleaning="activeModule = 'cleaning'"
|
||||
/>
|
||||
|
||||
<template v-else>
|
||||
<section class="metric-grid" aria-label="保洁概览">
|
||||
<div class="metric">
|
||||
<span>待验收</span>
|
||||
@@ -198,17 +219,19 @@
|
||||
<CleaningFieldHandoffPanel />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
</section>
|
||||
</main>
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { computed, reactive, ref, watch } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import {
|
||||
ClipboardCheck,
|
||||
Download,
|
||||
LayoutDashboard,
|
||||
ListTodo,
|
||||
RadioTower,
|
||||
RotateCcw,
|
||||
@@ -223,6 +246,7 @@ import CleaningSettlementsPanel from './components/CleaningSettlementsPanel.vue'
|
||||
import CleaningStatisticsPanel from './components/CleaningStatisticsPanel.vue';
|
||||
import CleanersPanel from './components/CleanersPanel.vue';
|
||||
import CleaningFieldHandoffPanel from './components/CleaningFieldHandoffPanel.vue';
|
||||
import OperationsOverviewPanel from './components/OperationsOverviewPanel.vue';
|
||||
import {
|
||||
ApiError,
|
||||
assignCleaningTask,
|
||||
@@ -257,7 +281,9 @@ import type {
|
||||
} from './types';
|
||||
import { money } from './format';
|
||||
|
||||
const tokenDraft = ref(localStorage.getItem('qipai.admin.token') || '');
|
||||
const savedToken = ref(localStorage.getItem('qipai.admin.token') || '');
|
||||
const tokenDraft = ref(savedToken.value);
|
||||
const activeModule = ref<'overview' | 'cleaning'>('overview');
|
||||
const activeTab = ref('tasks');
|
||||
const lastError = ref('');
|
||||
const lastMessage = ref('');
|
||||
@@ -265,7 +291,7 @@ const taskStatus = ref<TaskStatus | ''>('SUBMITTED');
|
||||
const settlementStatus = ref<SettlementStatus | ''>('CONFIRMED');
|
||||
const cleanerStatus = ref<UserStatus | ''>('ACTIVE');
|
||||
const cleanerSearch = ref('');
|
||||
const session = computed(() => ({ token: tokenDraft.value }));
|
||||
const session = computed(() => ({ token: savedToken.value }));
|
||||
const loading = reactive({ tasks: false, settlements: false, statistics: false, cleaners: false });
|
||||
const tasks = reactive<PageResult<CleaningTask>>({ items: [], total: 0, page: 1, pageSize: 20 });
|
||||
const settlements = reactive<PageResult<CleaningSettlement>>({
|
||||
@@ -310,8 +336,14 @@ const operationalQueueTotal = computed(() => (
|
||||
));
|
||||
|
||||
function saveToken() {
|
||||
localStorage.setItem('qipai.admin.token', tokenDraft.value.trim());
|
||||
savedToken.value = tokenDraft.value.trim();
|
||||
localStorage.setItem('qipai.admin.token', savedToken.value);
|
||||
ElMessage.success('已保存');
|
||||
if (activeModule.value === 'cleaning' && savedToken.value) void loadCleaningWorkspace();
|
||||
}
|
||||
|
||||
function loadCleaningWorkspace() {
|
||||
return Promise.all([loadTasks(), loadSettlements(), loadStatistics(), loadCleaners()]);
|
||||
}
|
||||
|
||||
async function runAction(work: () => Promise<void>, success: string) {
|
||||
@@ -659,9 +691,7 @@ async function handleResetCleanerSessions(userId: string) {
|
||||
}, '已重置保洁员会话');
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (session.value.token) {
|
||||
void Promise.all([loadTasks(), loadSettlements(), loadStatistics(), loadCleaners()]);
|
||||
}
|
||||
watch(activeModule, (module) => {
|
||||
if (module === 'cleaning' && session.value.token) void loadCleaningWorkspace();
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user