admin.html 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Shadcn 管理后台</title>
  6. <!-- 引入 Tailwind CSS(Shadcn 依赖) -->
  7. <script src="https://cdn.tailwindcss.com"></script>
  8. <!-- 引入 Font Awesome(图标支持) -->
  9. <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
  10. <!-- 引入 Juris 框架 -->
  11. <script src="https://unpkg.com/juris"></script>
  12. <!-- Tailwind 配置(匹配 Shadcn 主题) -->
  13. <script>
  14. tailwind.config = {
  15. theme: {
  16. extend: {
  17. colors: {
  18. primary: '#3b82f6', // Shadcn 蓝色主色
  19. secondary: '#1e293b', // 侧边栏深色
  20. neutral: '#f1f5f9', // 主内容区背景
  21. },
  22. fontFamily: {
  23. inter: ['Inter', 'system-ui', 'sans-serif'],
  24. },
  25. },
  26. }
  27. }
  28. </script>
  29. <!-- 自定义工具类(匹配 Shadcn 组件样式) -->
  30. <style type="text/tailwindcss">
  31. @layer utilities {
  32. .content-auto { content-visibility: auto; }
  33. .sidebar-item-active {
  34. background-color: rgb(59 130 246 / 0.1);
  35. color: rgb(59 130 246);
  36. border-left-width: 4px;
  37. border-left-color: rgb(59 130 246);
  38. }
  39. .card-shadow {
  40. box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  41. }
  42. .card-shadow:hover {
  43. box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
  44. }
  45. }
  46. </style>
  47. </head>
  48. <body class="font-inter bg-neutral min-h-screen">
  49. <div id="app" class="flex h-screen overflow-hidden"></div>
  50. <script>
  51. // 1. 模拟后台数据
  52. const mockData = {
  53. stats: { user: 1280, order: 3650, revenue: 156800, product: 240 },
  54. tableData: [
  55. { id: 1, name: "张三", role: "管理员", status: "正常", date: "2024-01-15" },
  56. { id: 2, name: "李四", role: "编辑", status: "正常", date: "2024-02-20" },
  57. { id: 3, name: "王五", role: "访客", status: "禁用", date: "2024-03-10" },
  58. { id: 4, name: "赵六", role: "编辑", status: "正常", date: "2024-04-05" }
  59. ],
  60. activeMenu: "dashboard"
  61. };
  62. // 2. 状态标签组件(Shadcn 风格)
  63. function StatusBadge(status) {
  64. const base = "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium";
  65. if (status === "正常") return `${base} bg-green-100 text-green-800`;
  66. if (status === "禁用") return `${base} bg-red-100 text-red-800`;
  67. return `${base} bg-gray-100 text-gray-800`;
  68. }
  69. // 3. 表格渲染函数(Shadcn 表格样式)
  70. function renderTable(app) {
  71. const data = app.getState("tableData");
  72. // 创建表行(使用数组格式避免Juris框架的属性名问题)
  73. const tableRows = data.map((item, index) => ({
  74. tr: {
  75. class: "border-b hover:bg-gray-50 transition-colors",
  76. children: [
  77. { td: { class: "px-6 py-4 font-medium text-gray-900", text: item.id.toString() } },
  78. { td: { class: "px-6 py-4", text: item.name } },
  79. { td: { class: "px-6 py-4", text: item.role } },
  80. { td: { class: "px-6 py-4", children: [
  81. { span: { class: StatusBadge(item.status), text: item.status } }
  82. ] } },
  83. { td: { class: "px-6 py-4", text: item.date } },
  84. { td: { class: "px-6 py-4 text-right", children: [
  85. // 编辑按钮(Shadcn 主色)
  86. {
  87. tag: "button",
  88. 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",
  89. text: "编辑",
  90. onclick: () => alert(`编辑用户:${item.name}`),
  91. children: [
  92. { tag: "i", class: "mr-1 fa fa-pencil" }
  93. ]
  94. },
  95. // 删除按钮(Shadcn 危险色)
  96. {
  97. tag: "button",
  98. 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",
  99. text: "删除",
  100. onclick: () => {
  101. if (confirm(`确定删除用户 ${item.name} 吗?`)) {
  102. const newData = data.filter(row => row.id !== item.id);
  103. app.setState("tableData", newData);
  104. }
  105. },
  106. children: [
  107. { tag: "i", class: "mr-1 fa fa-trash" }
  108. ]
  109. }
  110. ] } }
  111. ]
  112. }
  113. }));
  114. return {
  115. tag: "div",
  116. class: "overflow-hidden rounded-lg border bg-white shadow",
  117. children: [
  118. {
  119. tag: "table",
  120. class: "w-full text-sm text-left text-gray-500",
  121. children: [
  122. // 表头(Shadcn 风格)
  123. {
  124. tag: "thead",
  125. class: "bg-gray-50 text-xs uppercase text-gray-700",
  126. children: [
  127. {
  128. tag: "tr",
  129. children: [
  130. { tag: "th", class: "px-6 py-3", text: "ID" },
  131. { tag: "th", class: "px-6 py-3", text: "用户名" },
  132. { tag: "th", class: "px-6 py-3", text: "角色" },
  133. { tag: "th", class: "px-6 py-3", text: "状态" },
  134. { tag: "th", class: "px-6 py-3", text: "创建时间" },
  135. { tag: "th", class: "px-6 py-3 text-right", text: "操作" }
  136. ]
  137. }
  138. ]
  139. },
  140. // 表体
  141. {
  142. tag: "tbody",
  143. children: tableRows
  144. }
  145. ]
  146. }
  147. ]
  148. };
  149. }
  150. // 4. 初始化 Juris 应用
  151. const app = new Juris({
  152. states: {
  153. stats: mockData.stats,
  154. tableData: mockData.tableData,
  155. activeMenu: mockData.activeMenu
  156. },
  157. layout: {
  158. tag: "div",
  159. class: "flex h-screen overflow-hidden",
  160. children: [
  161. // 侧边栏(Shadcn 深色风格)
  162. {
  163. tag: "div",
  164. class: "w-64 bg-secondary text-white flex-shrink-0",
  165. children: [
  166. // 侧边栏标题
  167. {
  168. tag: "div",
  169. class: "p-4 border-b border-gray-700",
  170. children: [
  171. {
  172. tag: "h1",
  173. class: "text-xl font-bold",
  174. children: [
  175. { tag: "i", class: "mr-2 fa fa-cogs" },
  176. "管理后台"
  177. ]
  178. }
  179. ]
  180. },
  181. // 侧边栏菜单
  182. {
  183. tag: "nav",
  184. class: "p-4 space-y-1",
  185. children: [
  186. // 数据概览
  187. {
  188. tag: "div",
  189. 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",
  190. onclick: () => app.setState("activeMenu", "dashboard"),
  191. children: [
  192. { tag: "i", class: "mr-2 fa fa-dashboard" },
  193. "数据概览"
  194. ]
  195. },
  196. // 用户管理
  197. {
  198. tag: "div",
  199. 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",
  200. onclick: () => app.setState("activeMenu", "user"),
  201. children: [
  202. { tag: "i", class: "mr-2 fa fa-users" },
  203. "用户管理"
  204. ]
  205. },
  206. // 订单管理
  207. {
  208. tag: "div",
  209. 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",
  210. onclick: () => app.setState("activeMenu", "order"),
  211. children: [
  212. { tag: "i", class: "mr-2 fa fa-shopping-cart" },
  213. "订单管理"
  214. ]
  215. },
  216. // 商品管理
  217. {
  218. tag: "div",
  219. 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",
  220. onclick: () => app.setState("activeMenu", "product"),
  221. children: [
  222. { tag: "i", class: "mr-2 fa fa-cube" },
  223. "商品管理"
  224. ]
  225. }
  226. ]
  227. }
  228. ]
  229. },
  230. // 主内容区(Shadcn 浅色风格)
  231. {
  232. tag: "div",
  233. class: "flex-1 overflow-y-auto bg-neutral p-6",
  234. children: [
  235. () => {
  236. const active = app.getState("activeMenu");
  237. // 数据概览页面
  238. if (active === "dashboard") {
  239. return {
  240. tag: "div",
  241. children: [
  242. // 页面标题
  243. {
  244. tag: "div",
  245. class: "mb-6",
  246. children: [
  247. { tag: "h2", class: "text-2xl font-bold text-gray-800", text: "数据概览" },
  248. { tag: "p", class: "text-gray-500", text: "查看系统关键指标与最新数据" }
  249. ]
  250. },
  251. // 数据卡片组(Shadcn 卡片风格)
  252. {
  253. tag: "div",
  254. class: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8",
  255. children: [
  256. // 用户数卡片
  257. {
  258. tag: "div",
  259. class: "card-shadow bg-white rounded-lg p-6",
  260. children: [
  261. {
  262. tag: "div",
  263. class: "flex items-center text-gray-500 mb-2",
  264. children: [
  265. { tag: "i", class: "fa fa-users mr-2 text-primary" },
  266. { tag: "span", text: "总用户数" }
  267. ]
  268. },
  269. { tag: "div", class: "text-3xl font-bold text-gray-900", text: app.getState("stats").user.toString() },
  270. {
  271. tag: "div",
  272. class: "mt-2 text-green-500 text-sm",
  273. children: [
  274. { tag: "i", class: "fa fa-arrow-up mr-1" },
  275. { tag: "span", text: "12% 较上月" }
  276. ]
  277. }
  278. ]
  279. },
  280. // 订单数卡片
  281. {
  282. tag: "div",
  283. class: "card-shadow bg-white rounded-lg p-6",
  284. children: [
  285. {
  286. tag: "div",
  287. class: "flex items-center text-gray-500 mb-2",
  288. children: [
  289. { tag: "i", class: "fa fa-shopping-cart mr-2 text-primary" },
  290. { tag: "span", text: "总订单数" }
  291. ]
  292. },
  293. { tag: "div", class: "text-3xl font-bold text-gray-900", text: app.getState("stats").order.toString() },
  294. {
  295. tag: "div",
  296. class: "mt-2 text-green-500 text-sm",
  297. children: [
  298. { tag: "i", class: "fa fa-arrow-up mr-1" },
  299. { tag: "span", text: "8% 较上月" }
  300. ]
  301. }
  302. ]
  303. },
  304. // 营收卡片
  305. {
  306. tag: "div",
  307. class: "card-shadow bg-white rounded-lg p-6",
  308. children: [
  309. {
  310. tag: "div",
  311. class: "flex items-center text-gray-500 mb-2",
  312. children: [
  313. { tag: "i", class: "fa fa-rmb mr-2 text-primary" },
  314. { tag: "span", text: "总营收(元)" }
  315. ]
  316. },
  317. { tag: "div", class: "text-3xl font-bold text-gray-900", text: app.getState("stats").revenue.toString() },
  318. {
  319. tag: "div",
  320. class: "mt-2 text-green-500 text-sm",
  321. children: [
  322. { tag: "i", class: "fa fa-arrow-up mr-1" },
  323. { tag: "span", text: "23% 较上月" }
  324. ]
  325. }
  326. ]
  327. },
  328. // 商品数卡片
  329. {
  330. tag: "div",
  331. class: "card-shadow bg-white rounded-lg p-6",
  332. children: [
  333. {
  334. tag: "div",
  335. class: "flex items-center text-gray-500 mb-2",
  336. children: [
  337. { tag: "i", class: "fa fa-cube mr-2 text-primary" },
  338. { tag: "span", text: "商品总数" }
  339. ]
  340. },
  341. { tag: "div", class: "text-3xl font-bold text-gray-900", text: app.getState("stats").product.toString() },
  342. {
  343. tag: "div",
  344. class: "mt-2 text-red-500 text-sm",
  345. children: [
  346. { tag: "i", class: "fa fa-arrow-down mr-1" },
  347. { tag: "span", text: "3% 较上月" }
  348. ]
  349. }
  350. ]
  351. }
  352. ]
  353. },
  354. // 最近用户表格(暂时注释掉以测试渲染问题)
  355. {
  356. tag: "div",
  357. children: [
  358. { tag: "h3", class: "mb-4 text-xl font-semibold text-gray-800", text: "最近用户" },
  359. { tag: "p", class: "text-gray-500", text: "表格功能暂时禁用" }
  360. // renderTable(app)
  361. ]
  362. }
  363. ]
  364. };
  365. }
  366. // 用户管理页面
  367. else if (active === "user") {
  368. return {
  369. tag: "div",
  370. children: [
  371. {
  372. tag: "div",
  373. class: "mb-6",
  374. children: [
  375. { tag: "h2", class: "text-2xl font-bold text-gray-800", text: "用户管理" },
  376. { tag: "p", class: "text-gray-500", text: "管理系统所有用户账号" }
  377. ]
  378. },
  379. // renderTable(app)
  380. { tag: "p", class: "text-gray-500", text: "用户表格功能暂时禁用" }
  381. ]
  382. };
  383. }
  384. // 其他页面(默认显示数据概览)
  385. else {
  386. return {
  387. tag: "div",
  388. children: [
  389. {
  390. tag: "div",
  391. class: "mb-6",
  392. children: [
  393. {
  394. tag: "h2",
  395. class: "text-2xl font-bold text-gray-800",
  396. text: `${active === "order" ? "订单" : "商品"}管理`
  397. },
  398. {
  399. tag: "p",
  400. class: "text-gray-500",
  401. text: `管理系统所有${active === "order" ? "订单" : "商品"}数据`
  402. }
  403. ]
  404. },
  405. {
  406. tag: "div",
  407. class: "bg-white p-8 rounded-lg shadow text-center text-gray-500",
  408. children: [
  409. { tag: "i", class: "fa fa-file-text-o text-4xl mb-4" },
  410. { tag: "h3", class: "text-xl font-semibold mb-2", text: "功能开发中" },
  411. { tag: "p", text: "该模块功能正在开发,敬请期待~" }
  412. ]
  413. }
  414. ]
  415. };
  416. }
  417. }
  418. ]
  419. }
  420. ]
  421. }
  422. });
  423. // 5. 渲染应用
  424. app.render('#app');
  425. </script>
  426. </body>
  427. </html>