Files
Home-Care/hss-home-service/website/pages/demo.vue
comclib c02029a5f3 feat: 初始化居家上门服务系统完整项目代码
- Spring Boot 后端服务 (hss-home-service)
- delivery-miniapp 配送小程序
- website 官网 (Nuxt)
- docs 架构设计文档
- Docker 容器化部署配置

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 09:04:49 +08:00

232 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>