feat: 初始化居家上门服务系统完整项目代码
- Spring Boot 后端服务 (hss-home-service) - delivery-miniapp 配送小程序 - website 官网 (Nuxt) - docs 架构设计文档 - Docker 容器化部署配置 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
120
hss-home-service/website/pages/platform/index.vue
Normal file
120
hss-home-service/website/pages/platform/index.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { usePlatformAuth } from '~/composables/usePlatformAuth'
|
||||
import { useApi } from '~/composables/useApi'
|
||||
|
||||
definePageMeta({ layout: false })
|
||||
|
||||
const { isLoggedIn, user, logout, switchRole, getAuthHeaders, ROLES } = usePlatformAuth()
|
||||
const { get, post } = useApi()
|
||||
|
||||
const stats = ref<Record<string,any>>({})
|
||||
const recentOrders = ref<any[]>([])
|
||||
const activeMenu = ref('dashboard')
|
||||
|
||||
if (!isLoggedIn.value) { await navigateTo('/platform/login') }
|
||||
|
||||
onMounted(async () => {
|
||||
try { stats.value = await get<any>('/admin/dashboard').catch(() => ({})) } catch {}
|
||||
})
|
||||
|
||||
const menuItems = [
|
||||
{ key: 'dashboard', label: '工作台', icon: 'chart' },
|
||||
{ key: 'applications', label: '服务申请', icon: 'clipboard', href: '/platform/applications' },
|
||||
{ key: 'work-orders', label: '工单管理', icon: 'document', href: '/platform/work-orders' },
|
||||
]
|
||||
|
||||
const roleMenus: Record<string, string[]> = {
|
||||
RECEPTIONIST: ['applications'],
|
||||
ASSESSOR: ['applications'],
|
||||
DISPATCHER: ['work-orders'],
|
||||
STAFF: ['work-orders'],
|
||||
SETTLER: ['dashboard'],
|
||||
SUPERVISOR: ['dashboard'],
|
||||
ADMIN: ['applications', 'work-orders'],
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-screen bg-surface flex">
|
||||
<!-- Sidebar -->
|
||||
<aside class="hidden lg:flex flex-col w-56 bg-white border-r shrink-0">
|
||||
<div class="p-4 border-b">
|
||||
<NuxtLink to="/platform" class="flex items-center gap-2 font-bold text-primary">
|
||||
<div class="w-8 h-8 rounded-lg bg-primary flex items-center justify-center text-white text-xs font-mono">H</div>
|
||||
<span class="text-sm">智慧医养平台</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<nav class="flex-1 p-3 space-y-1">
|
||||
<NuxtLink v-for="m in menuItems" :key="m.key" :to="m.href || '/platform'"
|
||||
class="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm transition-colors"
|
||||
:class="activeMenu === m.key ? 'bg-primary-50 text-primary font-medium' : 'text-text-secondary hover:bg-gray-50'">
|
||||
<AppIcon :name="m.icon" class="w-4 h-4" /> {{ m.label }}
|
||||
</NuxtLink>
|
||||
</nav>
|
||||
<div class="p-3 border-t">
|
||||
<div class="flex items-center gap-2 px-3 py-2 text-sm">
|
||||
<div class="w-7 h-7 rounded-full bg-primary-50 text-primary flex items-center justify-center text-xs font-bold">{{ user?.userName?.charAt(0) }}</div>
|
||||
<div class="min-w-0">
|
||||
<div class="text-xs font-medium truncate">{{ user?.userName }}</div>
|
||||
<select @change="switchRole(($event.target as HTMLSelectElement).value)"
|
||||
class="text-xs text-text-secondary bg-transparent border-none outline-none cursor-pointer">
|
||||
<option v-for="r in ROLES" :key="r.key" :value="r.key" :selected="user?.userRole === r.key">{{ r.label }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<button @click="logout(); navigateTo('/platform/login')"
|
||||
class="w-full mt-2 px-3 py-2 text-xs text-text-secondary hover:text-red-500 transition-colors text-left rounded-lg hover:bg-red-50">退出登录</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="flex-1 overflow-auto">
|
||||
<!-- Mobile header -->
|
||||
<div class="lg:hidden bg-white border-b px-4 py-3 flex items-center justify-between">
|
||||
<NuxtLink to="/platform" class="font-bold text-primary text-sm">智慧医养平台</NuxtLink>
|
||||
<div class="flex items-center gap-2">
|
||||
<select @change="switchRole(($event.target as HTMLSelectElement).value)"
|
||||
class="text-xs border rounded-lg px-2 py-1 outline-none">
|
||||
<option v-for="r in ROLES" :key="r.key" :value="r.key" :selected="user?.userRole === r.key">{{ r.label }}</option>
|
||||
</select>
|
||||
<button @click="logout(); navigateTo('/platform/login')" class="text-xs text-red-500">退出</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 lg:p-8">
|
||||
<h2 class="text-xl font-bold mb-6">工作台 — {{ ROLES.find(r=>r.key===user?.userRole)?.label || user?.userRole }}</h2>
|
||||
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
|
||||
<div class="bg-white rounded-xl p-4 shadow-sm border"><div class="text-2xl font-bold font-mono text-primary">{{ stats.todayOrders || '--' }}</div><div class="text-xs text-text-secondary mt-1">今日工单</div></div>
|
||||
<div class="bg-white rounded-xl p-4 shadow-sm border"><div class="text-2xl font-bold font-mono text-accent-700">{{ stats.inProgress || '--' }}</div><div class="text-xs text-text-secondary mt-1">进行中</div></div>
|
||||
<div class="bg-white rounded-xl p-4 shadow-sm border"><div class="text-2xl font-bold font-mono text-green-600">{{ stats.completedToday || '--' }}</div><div class="text-xs text-text-secondary mt-1">已完成</div></div>
|
||||
<div class="bg-white rounded-xl p-4 shadow-sm border"><div class="text-2xl font-bold font-mono text-red-500">{{ stats.exceptions || '--' }}</div><div class="text-xs text-text-secondary mt-1">异常</div></div>
|
||||
</div>
|
||||
|
||||
<!-- Quick actions based on role -->
|
||||
<div class="grid lg:grid-cols-2 gap-6">
|
||||
<div class="bg-white rounded-2xl shadow-sm border p-6">
|
||||
<h3 class="font-bold mb-4">快捷操作</h3>
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<NuxtLink v-if="['RECEPTIONIST','ADMIN'].includes(user?.userRole||'')" to="/platform/applications"
|
||||
class="p-4 rounded-xl bg-primary-50 text-primary text-sm font-medium hover:bg-primary hover:text-white transition-colors text-center">受理新申请</NuxtLink>
|
||||
<NuxtLink v-if="['DISPATCHER','ADMIN'].includes(user?.userRole||'')" to="/platform/work-orders"
|
||||
class="p-4 rounded-xl bg-accent-50 text-accent-700 text-sm font-medium hover:bg-accent hover:text-white transition-colors text-center">查看工单</NuxtLink>
|
||||
<NuxtLink to="/demo" class="p-4 rounded-xl bg-gray-50 text-text-secondary text-sm font-medium hover:bg-gray-100 transition-colors text-center">平台演示</NuxtLink>
|
||||
<NuxtLink to="/" class="p-4 rounded-xl bg-gray-50 text-text-secondary text-sm font-medium hover:bg-gray-100 transition-colors text-center">返回官网</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-2xl shadow-sm border p-6">
|
||||
<h3 class="font-bold mb-4">当前角色权限</h3>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between py-2 border-b border-gray-50"><span class="text-text-secondary">角色</span><span class="font-medium">{{ ROLES.find(r=>r.key===user?.userRole)?.label }}</span></div>
|
||||
<div class="flex justify-between py-2 border-b border-gray-50"><span class="text-text-secondary">可操作模块</span><span class="font-medium">{{ (roleMenus[user?.userRole||'']||['dashboard']).join(', ') }}</span></div>
|
||||
<div class="flex justify-between py-2"><span class="text-text-secondary">数据范围</span><span class="font-medium">本机构</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user