feat(web): I1 shell and I2 customer/project UI

Vue 3 + Element Plus layout with JWT login, RBAC routes, axios 401
handling with token restore, and Customers/Projects views wired to
platform APIs.

Made-with: Cursor
This commit is contained in:
2026-04-06 21:05:02 +08:00
parent 3f577b34d5
commit 65eb983035
18 changed files with 2939 additions and 0 deletions
@@ -0,0 +1,70 @@
<template>
<el-container class="shell">
<el-aside width="220px" class="aside">
<div class="brand">创飞 · 交付平台</div>
<el-menu router :default-active="route.path" background-color="#001529" text-color="#fff" active-text-color="#ffd04b">
<el-menu-item index="/">
<span>首页</span>
</el-menu-item>
<el-menu-item index="/customers">
<span>客户管理</span>
</el-menu-item>
<el-menu-item index="/projects">
<span>项目管理</span>
</el-menu-item>
</el-menu>
</el-aside>
<el-container>
<el-header class="top">
<span class="user">{{ auth.displayName || "—" }}</span>
<el-button type="danger" link @click="logout">退出</el-button>
</el-header>
<el-main class="main">
<router-view />
</el-main>
</el-container>
</el-container>
</template>
<script setup>
import { useRoute, useRouter } from "vue-router";
import { useAuthStore } from "../stores/auth";
const route = useRoute();
const router = useRouter();
const auth = useAuthStore();
function logout() {
auth.logout();
router.push({ name: "login" });
}
</script>
<style scoped>
.shell {
height: 100vh;
}
.aside {
background: #001529;
color: #fff;
}
.brand {
padding: 16px;
font-weight: 600;
border-bottom: 1px solid #ffffff22;
}
.top {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
border-bottom: 1px solid #ebeef5;
}
.user {
color: #606266;
font-size: 14px;
}
.main {
background: #f0f2f5;
}
</style>