|
|
@@ -0,0 +1,443 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="zh-CN">
|
|
|
+<head>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <title>Shadcn 管理后台</title>
|
|
|
+ <!-- 引入 Tailwind CSS(Shadcn 依赖) -->
|
|
|
+ <script src="https://cdn.tailwindcss.com"></script>
|
|
|
+ <!-- 引入 Font Awesome(图标支持) -->
|
|
|
+ <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
|
|
+ <!-- 引入 Juris 框架 -->
|
|
|
+ <script src="https://unpkg.com/juris"></script>
|
|
|
+
|
|
|
+ <!-- Tailwind 配置(匹配 Shadcn 主题) -->
|
|
|
+ <script>
|
|
|
+ tailwind.config = {
|
|
|
+ theme: {
|
|
|
+ extend: {
|
|
|
+ colors: {
|
|
|
+ primary: '#3b82f6', // Shadcn 蓝色主色
|
|
|
+ secondary: '#1e293b', // 侧边栏深色
|
|
|
+ neutral: '#f1f5f9', // 主内容区背景
|
|
|
+ },
|
|
|
+ fontFamily: {
|
|
|
+ inter: ['Inter', 'system-ui', 'sans-serif'],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+ </script>
|
|
|
+
|
|
|
+ <!-- 自定义工具类(匹配 Shadcn 组件样式) -->
|
|
|
+ <style type="text/tailwindcss">
|
|
|
+ @layer utilities {
|
|
|
+ .content-auto { content-visibility: auto; }
|
|
|
+ .sidebar-item-active {
|
|
|
+ background-color: rgb(59 130 246 / 0.1);
|
|
|
+ color: rgb(59 130 246);
|
|
|
+ border-left-width: 4px;
|
|
|
+ border-left-color: rgb(59 130 246);
|
|
|
+ }
|
|
|
+ .card-shadow {
|
|
|
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
|
+ }
|
|
|
+ .card-shadow:hover {
|
|
|
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+</head>
|
|
|
+
|
|
|
+<body class="font-inter bg-neutral min-h-screen">
|
|
|
+ <div id="app" class="flex h-screen overflow-hidden"></div>
|
|
|
+
|
|
|
+ <script>
|
|
|
+ // 1. 模拟后台数据
|
|
|
+ const mockData = {
|
|
|
+ stats: { user: 1280, order: 3650, revenue: 156800, product: 240 },
|
|
|
+ tableData: [
|
|
|
+ { id: 1, name: "张三", role: "管理员", status: "正常", date: "2024-01-15" },
|
|
|
+ { id: 2, name: "李四", role: "编辑", status: "正常", date: "2024-02-20" },
|
|
|
+ { id: 3, name: "王五", role: "访客", status: "禁用", date: "2024-03-10" },
|
|
|
+ { id: 4, name: "赵六", role: "编辑", status: "正常", date: "2024-04-05" }
|
|
|
+ ],
|
|
|
+ activeMenu: "dashboard"
|
|
|
+ };
|
|
|
+
|
|
|
+ // 2. 状态标签组件(Shadcn 风格)
|
|
|
+ function StatusBadge(status) {
|
|
|
+ const base = "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium";
|
|
|
+ if (status === "正常") return `${base} bg-green-100 text-green-800`;
|
|
|
+ if (status === "禁用") return `${base} bg-red-100 text-red-800`;
|
|
|
+ return `${base} bg-gray-100 text-gray-800`;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 表格渲染函数(Shadcn 表格样式)
|
|
|
+ function renderTable(app) {
|
|
|
+ const data = app.getState("tableData");
|
|
|
+
|
|
|
+ // 创建表行
|
|
|
+ const tableRows = data.map(item => ({
|
|
|
+ tr: {
|
|
|
+ class: "border-b hover:bg-gray-50 transition-colors",
|
|
|
+ children: [
|
|
|
+ { td: { class: "px-6 py-4 font-medium text-gray-900", text: item.id.toString() } },
|
|
|
+ { td: { class: "px-6 py-4", text: item.name } },
|
|
|
+ { td: { class: "px-6 py-4", text: item.role } },
|
|
|
+ { td: { class: "px-6 py-4", children: [
|
|
|
+ { span: { class: StatusBadge(item.status), text: item.status } }
|
|
|
+ ] } },
|
|
|
+ { td: { class: "px-6 py-4", text: item.date } },
|
|
|
+ { td: { class: "px-6 py-4 text-right", children: [
|
|
|
+ // 编辑按钮(Shadcn 主色)
|
|
|
+ {
|
|
|
+ tag: "button",
|
|
|
+ class: "mr-2 inline-flex items-center px-3 py-1.5 text-sm font-medium text-white bg-primary rounded-md hover:bg-primary/90 transition-colors",
|
|
|
+ text: "编辑",
|
|
|
+ onclick: () => alert(`编辑用户:${item.name}`),
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "mr-1 fa fa-pencil" }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ // 删除按钮(Shadcn 危险色)
|
|
|
+ {
|
|
|
+ tag: "button",
|
|
|
+ class: "inline-flex items-center px-3 py-1.5 text-sm font-medium text-white bg-red-500 rounded-md hover:bg-red-600 transition-colors",
|
|
|
+ text: "删除",
|
|
|
+ onclick: () => {
|
|
|
+ if (confirm(`确定删除用户 ${item.name} 吗?`)) {
|
|
|
+ const newData = data.filter(row => row.id !== item.id);
|
|
|
+ app.setState("tableData", newData);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "mr-1 fa fa-trash" }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ] } }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }));
|
|
|
+
|
|
|
+ return {
|
|
|
+ tag: "div",
|
|
|
+ class: "overflow-hidden rounded-lg border bg-white shadow",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: "table",
|
|
|
+ class: "w-full text-sm text-left text-gray-500",
|
|
|
+ children: [
|
|
|
+ // 表头(Shadcn 风格)
|
|
|
+ {
|
|
|
+ tag: "thead",
|
|
|
+ class: "bg-gray-50 text-xs uppercase text-gray-700",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: "tr",
|
|
|
+ children: [
|
|
|
+ { tag: "th", class: "px-6 py-3", text: "ID" },
|
|
|
+ { tag: "th", class: "px-6 py-3", text: "用户名" },
|
|
|
+ { tag: "th", class: "px-6 py-3", text: "角色" },
|
|
|
+ { tag: "th", class: "px-6 py-3", text: "状态" },
|
|
|
+ { tag: "th", class: "px-6 py-3", text: "创建时间" },
|
|
|
+ { tag: "th", class: "px-6 py-3 text-right", text: "操作" }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ // 表体
|
|
|
+ {
|
|
|
+ tag: "tbody",
|
|
|
+ children: tableRows
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 初始化 Juris 应用
|
|
|
+ const app = new Juris({
|
|
|
+ states: {
|
|
|
+ stats: mockData.stats,
|
|
|
+ tableData: mockData.tableData,
|
|
|
+ activeMenu: mockData.activeMenu
|
|
|
+ },
|
|
|
+ layout: {
|
|
|
+ tag: "div",
|
|
|
+ class: "flex h-screen overflow-hidden",
|
|
|
+ children: [
|
|
|
+ // 侧边栏(Shadcn 深色风格)
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "w-64 bg-secondary text-white flex-shrink-0",
|
|
|
+ children: [
|
|
|
+ // 侧边栏标题
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "p-4 border-b border-gray-700",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: "h1",
|
|
|
+ class: "text-xl font-bold",
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "mr-2 fa fa-cogs" },
|
|
|
+ "管理后台"
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ // 侧边栏菜单
|
|
|
+ {
|
|
|
+ tag: "nav",
|
|
|
+ class: "p-4 space-y-1",
|
|
|
+ children: [
|
|
|
+ // 数据概览
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: () => app.getState("activeMenu") === "dashboard" ? "sidebar-item-active px-3 py-2 rounded-md cursor-pointer" : "px-3 py-2 text-gray-300 rounded-md hover:bg-gray-700 cursor-pointer transition-colors",
|
|
|
+ onclick: () => app.setState("activeMenu", "dashboard"),
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "mr-2 fa fa-dashboard" },
|
|
|
+ "数据概览"
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ // 用户管理
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: () => app.getState("activeMenu") === "user" ? "sidebar-item-active px-3 py-2 rounded-md cursor-pointer" : "px-3 py-2 text-gray-300 rounded-md hover:bg-gray-700 cursor-pointer transition-colors",
|
|
|
+ onclick: () => app.setState("activeMenu", "user"),
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "mr-2 fa fa-users" },
|
|
|
+ "用户管理"
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ // 订单管理
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: () => app.getState("activeMenu") === "order" ? "sidebar-item-active px-3 py-2 rounded-md cursor-pointer" : "px-3 py-2 text-gray-300 rounded-md hover:bg-gray-700 cursor-pointer transition-colors",
|
|
|
+ onclick: () => app.setState("activeMenu", "order"),
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "mr-2 fa fa-shopping-cart" },
|
|
|
+ "订单管理"
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ // 商品管理
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: () => app.getState("activeMenu") === "product" ? "sidebar-item-active px-3 py-2 rounded-md cursor-pointer" : "px-3 py-2 text-gray-300 rounded-md hover:bg-gray-700 cursor-pointer transition-colors",
|
|
|
+ onclick: () => app.setState("activeMenu", "product"),
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "mr-2 fa fa-cube" },
|
|
|
+ "商品管理"
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+
|
|
|
+ // 主内容区(Shadcn 浅色风格)
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "flex-1 overflow-y-auto bg-neutral p-6",
|
|
|
+ children: [
|
|
|
+ () => {
|
|
|
+ const active = app.getState("activeMenu");
|
|
|
+ // 数据概览页面
|
|
|
+ if (active === "dashboard") {
|
|
|
+ return {
|
|
|
+ tag: "div",
|
|
|
+ children: [
|
|
|
+ // 页面标题
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "mb-6",
|
|
|
+ children: [
|
|
|
+ { tag: "h2", class: "text-2xl font-bold text-gray-800", text: "数据概览" },
|
|
|
+ { tag: "p", class: "text-gray-500", text: "查看系统关键指标与最新数据" }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+
|
|
|
+ // 数据卡片组(Shadcn 卡片风格)
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8",
|
|
|
+ children: [
|
|
|
+ // 用户数卡片
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "card-shadow bg-white rounded-lg p-6",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "flex items-center text-gray-500 mb-2",
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "fa fa-users mr-2 text-primary" },
|
|
|
+ { tag: "span", text: "总用户数" }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ { tag: "div", class: "text-3xl font-bold text-gray-900", text: app.getState("stats").user.toString() },
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "mt-2 text-green-500 text-sm",
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "fa fa-arrow-up mr-1" },
|
|
|
+ { tag: "span", text: "12% 较上月" }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+
|
|
|
+ // 订单数卡片
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "card-shadow bg-white rounded-lg p-6",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "flex items-center text-gray-500 mb-2",
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "fa fa-shopping-cart mr-2 text-primary" },
|
|
|
+ { tag: "span", text: "总订单数" }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ { tag: "div", class: "text-3xl font-bold text-gray-900", text: app.getState("stats").order.toString() },
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "mt-2 text-green-500 text-sm",
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "fa fa-arrow-up mr-1" },
|
|
|
+ { tag: "span", text: "8% 较上月" }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+
|
|
|
+ // 营收卡片
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "card-shadow bg-white rounded-lg p-6",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "flex items-center text-gray-500 mb-2",
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "fa fa-rmb mr-2 text-primary" },
|
|
|
+ { tag: "span", text: "总营收(元)" }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ { tag: "div", class: "text-3xl font-bold text-gray-900", text: app.getState("stats").revenue.toString() },
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "mt-2 text-green-500 text-sm",
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "fa fa-arrow-up mr-1" },
|
|
|
+ { tag: "span", text: "23% 较上月" }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+
|
|
|
+ // 商品数卡片
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "card-shadow bg-white rounded-lg p-6",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "flex items-center text-gray-500 mb-2",
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "fa fa-cube mr-2 text-primary" },
|
|
|
+ { tag: "span", text: "商品总数" }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ { tag: "div", class: "text-3xl font-bold text-gray-900", text: app.getState("stats").product.toString() },
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "mt-2 text-red-500 text-sm",
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "fa fa-arrow-down mr-1" },
|
|
|
+ { tag: "span", text: "3% 较上月" }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+
|
|
|
+ // 最近用户表格
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ children: [
|
|
|
+ { tag: "h3", class: "mb-4 text-xl font-semibold text-gray-800", text: "最近用户" },
|
|
|
+ renderTable(app)
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 用户管理页面
|
|
|
+ else if (active === "user") {
|
|
|
+ return {
|
|
|
+ tag: "div",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "mb-6",
|
|
|
+ children: [
|
|
|
+ { tag: "h2", class: "text-2xl font-bold text-gray-800", text: "用户管理" },
|
|
|
+ { tag: "p", class: "text-gray-500", text: "管理系统所有用户账号" }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ renderTable(app)
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // 其他页面(默认显示数据概览)
|
|
|
+ else {
|
|
|
+ return {
|
|
|
+ tag: "div",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "mb-6",
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ tag: "h2",
|
|
|
+ class: "text-2xl font-bold text-gray-800",
|
|
|
+ text: `${active === "order" ? "订单" : "商品"}管理`
|
|
|
+ },
|
|
|
+ {
|
|
|
+ tag: "p",
|
|
|
+ class: "text-gray-500",
|
|
|
+ text: `管理系统所有${active === "order" ? "订单" : "商品"}数据`
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ tag: "div",
|
|
|
+ class: "bg-white p-8 rounded-lg shadow text-center text-gray-500",
|
|
|
+ children: [
|
|
|
+ { tag: "i", class: "fa fa-file-text-o text-4xl mb-4" },
|
|
|
+ { tag: "h3", class: "text-xl font-semibold mb-2", text: "功能开发中" },
|
|
|
+ { tag: "p", text: "该模块功能正在开发,敬请期待~" }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 5. 渲染应用
|
|
|
+ app.render('#app');
|
|
|
+ </script>
|
|
|
+</body>
|
|
|
+</html>
|