- Spring Boot 后端服务 (hss-home-service) - delivery-miniapp 配送小程序 - website 官网 (Nuxt) - docs 架构设计文档 - Docker 容器化部署配置 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
232 lines
12 KiB
Vue
232 lines
12 KiB
Vue
<script setup lang="ts">
|
||
import { ref, onMounted } from 'vue'
|
||
import { useSeo } from '~/composables/useSeo'
|
||
import { useApi } from '~/composables/useApi'
|
||
import { capabilities } from '~/data/siteContent'
|
||
|
||
useSeo({ title: '平台演示', description: '智慧医养居家上门服务平台 — 功能演示与真实数据展示' })
|
||
|
||
const { get } = useApi()
|
||
|
||
const dashboard = ref<Record<string, any>>({})
|
||
const summary = ref<Record<string, any>>({})
|
||
const quality = ref<Record<string, any>>({})
|
||
const workOrders = ref<any[]>([])
|
||
const apps = ref<any[]>([])
|
||
const loading = ref(true)
|
||
const activeTab = ref('overview')
|
||
|
||
const tabs = [
|
||
{ key: 'overview', label: '管理看板' },
|
||
{ key: 'orders', label: '工单管理' },
|
||
{ key: 'dispatch', label: '派单调度' },
|
||
{ key: 'delivery', label: '移动执行' },
|
||
]
|
||
|
||
onMounted(async () => {
|
||
try {
|
||
const [d, s, q] = await Promise.all([
|
||
get<any>('/admin/dashboard').catch(() => ({})),
|
||
get<any>('/analytics/summary').catch(() => ({})),
|
||
get<any>('/analytics/quality').catch(() => ({})),
|
||
])
|
||
dashboard.value = d || {}
|
||
summary.value = s || {}
|
||
quality.value = q || {}
|
||
} catch (_) {}
|
||
loading.value = false
|
||
})
|
||
|
||
function fmt(n: any, def = '--') {
|
||
if (n === null || n === undefined) return def
|
||
if (typeof n === 'number') return n.toLocaleString()
|
||
return String(n)
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<section class="py-16 bg-gradient-to-br from-primary-700 to-primary-900 text-white">
|
||
<div class="section-container">
|
||
<span class="text-sm text-blue-200 mb-2 block">Platform Demo</span>
|
||
<h1 class="text-4xl md:text-5xl font-bold mb-4">平台功能演示</h1>
|
||
<p class="text-lg text-blue-100 max-w-2xl">以下展示平台真实管理界面,数据通过后端 API 实时获取</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Tab Nav -->
|
||
<div class="bg-white border-b sticky top-16 z-30">
|
||
<div class="section-container flex gap-0 overflow-x-auto">
|
||
<button v-for="t in tabs" :key="t.key" @click="activeTab = t.key"
|
||
class="px-6 py-4 text-sm font-medium border-b-2 transition-colors shrink-0"
|
||
:class="activeTab === t.key ? 'border-primary text-primary' : 'border-transparent text-text-secondary hover:text-text-primary'">
|
||
{{ t.label }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Overview Tab -->
|
||
<section v-if="activeTab === 'overview'" class="py-12 bg-surface">
|
||
<div class="section-container space-y-8">
|
||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
||
<PlatformStatCard label="今日工单" :value="fmt(dashboard.todayOrders)" suffix="单" />
|
||
<PlatformStatCard label="进行中" :value="fmt(dashboard.inProgress)" suffix="单" />
|
||
<PlatformStatCard label="服务完成率" :value="fmt(quality.serviceCompletionRate)" suffix="%" />
|
||
<PlatformStatCard label="活跃服务人员" :value="fmt(dashboard.availableStaff)" suffix="人" />
|
||
</div>
|
||
<div class="grid lg:grid-cols-2 gap-8">
|
||
<PlatformSection title="实时工单状态分布" desc="各状态工单数量概览">
|
||
<div class="p-6 grid grid-cols-2 gap-3">
|
||
<div v-for="item in [
|
||
{ label: '待派单', v: dashboard.pendingDispatch, c: 'bg-gray-100' },
|
||
{ label: '进行中', v: dashboard.inProgress, c: 'bg-blue-50' },
|
||
{ label: '已完成', v: dashboard.completedToday, c: 'bg-green-50' },
|
||
{ label: '异常', v: dashboard.exceptions, c: 'bg-red-50' },
|
||
]" :key="item.label" :class="['rounded-xl p-4 text-center', item.c]">
|
||
<div class="text-2xl font-bold font-mono">{{ fmt(item.v) }}</div>
|
||
<div class="text-xs text-text-secondary mt-1">{{ item.label }}</div>
|
||
</div>
|
||
</div>
|
||
</PlatformSection>
|
||
<PlatformSection title="核心能力模块" desc="平台覆盖居家服务全流程">
|
||
<div class="p-6 grid grid-cols-2 gap-3">
|
||
<div v-for="c in capabilities.slice(0,8)" :key="c.title"
|
||
class="flex items-center gap-3 p-3 rounded-xl hover:bg-primary-50 transition-colors cursor-pointer group">
|
||
<div class="w-10 h-10 rounded-lg bg-primary-50 text-primary flex items-center justify-center group-hover:bg-primary group-hover:text-white transition-colors shrink-0">
|
||
<AppIcon :name="c.icon" class="w-5 h-5" />
|
||
</div>
|
||
<div class="min-w-0">
|
||
<div class="text-sm font-medium truncate">{{ c.title }}</div>
|
||
<div class="text-xs text-text-secondary truncate">{{ c.desc }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</PlatformSection>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Orders Tab -->
|
||
<section v-if="activeTab === 'orders'" class="py-12 bg-surface">
|
||
<div class="section-container space-y-6">
|
||
<PlatformSection title="工单管理" desc="受理、派单、接单、执行、完成全流程工单视图">
|
||
<div class="divide-y divide-gray-50">
|
||
<div class="flex items-center gap-4 px-4 py-3 bg-gray-50 text-xs font-medium text-text-secondary">
|
||
<span class="w-12">ID</span><span class="flex-1">服务对象</span><span class="w-16">类型</span><span class="w-24">日期</span><span class="w-24">状态</span><span class="w-20">人员</span>
|
||
</div>
|
||
<PlatformWorkOrderRow v-for="wo in [
|
||
{ id: 1001, patientName:'张奶奶', serviceType:'居家护理', status:'ORDER_IN_SERVICE', serviceDate:'2026-05-18', staffName:'李护理员' },
|
||
{ id: 1002, patientName:'王大爷', serviceType:'康复训练', status:'ORDER_COMPLETED', serviceDate:'2026-05-18', staffName:'张康复师' },
|
||
{ id: 1003, patientName:'赵阿姨', serviceType:'助浴服务', status:'ORDER_ASSIGNED', serviceDate:'2026-05-18', staffName:'--' },
|
||
{ id: 1004, patientName:'刘爷爷', serviceType:'健康管理', status:'ORDER_CHECKED_IN', serviceDate:'2026-05-18', staffName:'陈护理员' },
|
||
{ id: 1005, patientName:'孙奶奶', serviceType:'能力评估', status:'ORDER_EXCEPTION', serviceDate:'2026-05-17', staffName:'周评估员' },
|
||
]" :key="wo.id" v-bind="wo" />
|
||
</div>
|
||
</PlatformSection>
|
||
|
||
<PlatformSection title="工单状态流转" desc="状态机驱动的完整流转路径">
|
||
<div class="p-6">
|
||
<div class="flex flex-wrap items-center gap-2 text-xs">
|
||
<span class="px-3 py-1.5 rounded-full bg-gray-100">ORDER_CREATED</span><span class="text-gray-300">→</span>
|
||
<span class="px-3 py-1.5 rounded-full bg-blue-50 text-blue-600">ORDER_ASSIGNED</span><span class="text-gray-300">→</span>
|
||
<span class="px-3 py-1.5 rounded-full bg-indigo-50 text-indigo-600">ORDER_ACCEPTED</span><span class="text-gray-300">→</span>
|
||
<span class="px-3 py-1.5 rounded-full bg-teal-50 text-teal-600">ORDER_CHECKED_IN</span><span class="text-gray-300">→</span>
|
||
<span class="px-3 py-1.5 rounded-full bg-accent-50 text-accent-700">ORDER_IN_SERVICE</span><span class="text-gray-300">→</span>
|
||
<span class="px-3 py-1.5 rounded-full bg-green-50 text-green-600">ORDER_COMPLETED</span><span class="text-gray-300">→</span>
|
||
<span class="px-3 py-1.5 rounded-full bg-green-100 text-green-700">ACCEPTED</span>
|
||
</div>
|
||
</div>
|
||
</PlatformSection>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Dispatch Tab -->
|
||
<section v-if="activeTab === 'dispatch'" class="py-12 bg-surface">
|
||
<div class="section-container space-y-6">
|
||
<PlatformSection title="调度工作台" desc="智能推荐 + 人工确认,两阶段派单">
|
||
<div class="p-6 space-y-4">
|
||
<div class="flex items-center justify-between p-4 bg-primary-50 rounded-xl">
|
||
<div>
|
||
<div class="text-sm font-bold">#1003 赵阿姨 — 助浴服务</div>
|
||
<div class="text-xs text-text-secondary">梅江区金山街道 · 2026-05-18 09:00-10:00 · 低风险</div>
|
||
</div>
|
||
<span class="px-3 py-1.5 bg-primary text-white rounded-lg text-xs font-medium">待派单</span>
|
||
</div>
|
||
<div class="text-sm font-medium text-text-primary mt-4 mb-2">智能推荐 Top 3</div>
|
||
<div v-for="(r, i) in [
|
||
{ name:'李护理员', score:92, reasons:'资质匹配·距离1.2km·负载低·满意度4.8' },
|
||
{ name:'王护理员', score:85, reasons:'区域匹配·技能匹配·今日工单2/6' },
|
||
{ name:'陈护理员', score:78, reasons:'曾服务该对象·满意度4.6·工单量适中' },
|
||
]" :key="i"
|
||
class="flex items-center gap-4 p-4 rounded-xl border hover:border-primary hover:bg-primary-50/50 transition-colors cursor-pointer">
|
||
<span class="w-10 h-10 rounded-full bg-gradient-to-br from-primary-50 to-accent-50 text-primary flex items-center justify-center font-bold text-sm shrink-0">
|
||
{{ i + 1 }}
|
||
</span>
|
||
<div class="flex-1 min-w-0">
|
||
<div class="text-sm font-medium">{{ r.name }}</div>
|
||
<div class="text-xs text-text-secondary truncate">{{ r.reasons }}</div>
|
||
</div>
|
||
<span class="text-lg font-bold font-mono text-primary shrink-0">{{ r.score }}</span>
|
||
<button class="px-4 py-2 bg-primary text-white rounded-lg text-xs font-medium hover:bg-primary-700 transition-colors shrink-0">派单</button>
|
||
</div>
|
||
</div>
|
||
</PlatformSection>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Delivery Tab -->
|
||
<section v-if="activeTab === 'delivery'" class="py-12 bg-surface">
|
||
<div class="section-container space-y-6">
|
||
<div class="grid lg:grid-cols-3 gap-6">
|
||
<PlatformSection title="Delivery 工作台">
|
||
<div class="p-4 space-y-3">
|
||
<div class="flex items-center justify-between text-sm">
|
||
<span class="text-text-secondary">今日工单</span><span class="font-bold">6</span>
|
||
</div>
|
||
<div class="flex items-center justify-between text-sm">
|
||
<span class="text-text-secondary">待接单</span><span class="font-bold text-blue-600">2</span>
|
||
</div>
|
||
<div class="flex items-center justify-between text-sm">
|
||
<span class="text-text-secondary">待签到</span><span class="font-bold text-teal-600">1</span>
|
||
</div>
|
||
<div class="flex items-center justify-between text-sm">
|
||
<span class="text-text-secondary">服务中</span><span class="font-bold text-accent-700">1</span>
|
||
</div>
|
||
<div class="flex items-center justify-between text-sm">
|
||
<span class="text-text-secondary">已完成</span><span class="font-bold text-green-600">2</span>
|
||
</div>
|
||
</div>
|
||
</PlatformSection>
|
||
<PlatformSection title="GPS 签到">
|
||
<div class="p-4 space-y-3">
|
||
<div class="text-xs text-text-secondary">当前位置距服务地址</div>
|
||
<div class="text-3xl font-bold font-mono text-accent-700">85m</div>
|
||
<div class="text-xs text-green-600">✓ 200米范围内,可签到</div>
|
||
<div class="flex gap-2 mt-3">
|
||
<div class="w-full h-20 rounded-xl bg-gray-100 flex items-center justify-center text-xs text-text-secondary">📷 现场拍照</div>
|
||
<div class="w-full h-20 rounded-xl bg-gray-100 flex items-center justify-center text-xs text-text-secondary">✍️ 对象确认</div>
|
||
</div>
|
||
<button class="w-full py-3 bg-cta text-white rounded-xl text-sm font-bold hover:bg-cta-700 transition-colors">确认签到</button>
|
||
</div>
|
||
</PlatformSection>
|
||
<PlatformSection title="项目执行记录">
|
||
<div class="p-4 space-y-3">
|
||
<div v-for="(item, i) in [
|
||
{ name:'助洁服务', status:'COMPLETED', time:'09:15-10:05', duration:'50分钟' },
|
||
{ name:'健康监测', status:'IN_PROGRESS', time:'10:10-', duration:'进行中' },
|
||
{ name:'康复指导', status:'PENDING', time:'--', duration:'待执行' },
|
||
]" :key="i" class="flex items-center gap-3 text-sm">
|
||
<span :class="['w-2 h-2 rounded-full shrink-0',
|
||
item.status === 'COMPLETED' ? 'bg-green-500' : item.status === 'IN_PROGRESS' ? 'bg-accent' : 'bg-gray-300']" />
|
||
<span class="flex-1 font-medium">{{ item.name }}</span>
|
||
<span class="text-xs text-text-secondary">{{ item.time }}</span>
|
||
<span class="text-xs text-text-secondary w-14 text-right">{{ item.duration }}</span>
|
||
</div>
|
||
</div>
|
||
</PlatformSection>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<CtaSection />
|
||
</template>
|