create-rue 0.0.7 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle.js +3 -3
- package/package.json +14 -17
- package/template/base/app/pages/Home.tsx +136 -55
- package/template/base/app/pages/Report.tsx +192 -0
- package/template/base/app/pages/TodoApp.tsx +464 -0
- package/template/base/app/pages/components/Layout.tsx +186 -32
- package/template/base/app/router.ts +2 -3
- package/template/base/package-lock.json +352 -350
- package/template/base/package.json +7 -7
- package/template/base/pnpm-lock.yaml +51 -51
- package/template/base/style.css +26 -415
- package/template/base/app/pages/Ecosystem.tsx +0 -47
- package/template/base/app/pages/Guide.tsx +0 -49
- package/template/base/app/pages/Packages.tsx +0 -52
package/bundle.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/*! create-rue v0.0.
|
|
2
|
+
/*! create-rue v0.0.11 | MIT */
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
5
|
import "node:fs";
|
|
@@ -1815,7 +1815,7 @@ var require_ejs = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1815
1815
|
var import_picocolors = require_picocolors();
|
|
1816
1816
|
var import_ejs = /* @__PURE__ */ __toESM(require_ejs(), 1);
|
|
1817
1817
|
const defaultBanner = "Rue.js - The Wasm Framework For Vapor Native DOM";
|
|
1818
|
-
const gradientBanner = "\x1B[38;2;66;211;
|
|
1818
|
+
const gradientBanner = "\x1B[38;2;66;211;146mR\x1B[39m\x1B[38;2;66;211;146mu\x1B[39m\x1B[38;2;66;211;146me\x1B[39m\x1B[38;2;66;211;146m.\x1B[39m\x1B[38;2;66;211;146mj\x1B[39m\x1B[38;2;66;210;147ms\x1B[39m \x1B[38;2;68;206;152m-\x1B[39m \x1B[38;2;69;202;157mT\x1B[39m\x1B[38;2;70;200;160mh\x1B[39m\x1B[38;2;71;198;162me\x1B[39m \x1B[38;2;73;194;167mW\x1B[39m\x1B[38;2;73;192;170ma\x1B[39m\x1B[38;2;74;190;173ms\x1B[39m\x1B[38;2;75;188;175mm\x1B[39m \x1B[38;2;77;184;180mF\x1B[39m\x1B[38;2;77;182;183mr\x1B[39m\x1B[38;2;78;180;185ma\x1B[39m\x1B[38;2;79;178;188mm\x1B[39m\x1B[38;2;80;176;191me\x1B[39m\x1B[38;2;81;174;193mw\x1B[39m\x1B[38;2;82;172;196mo\x1B[39m\x1B[38;2;82;170;198mr\x1B[39m\x1B[38;2;83;168;201mk\x1B[39m \x1B[38;2;85;164;206mF\x1B[39m\x1B[38;2;86;162;209mo\x1B[39m\x1B[38;2;86;160;211mr\x1B[39m \x1B[38;2;88;156;216mV\x1B[39m\x1B[38;2;89;154;219ma\x1B[39m\x1B[38;2;90;152;222mp\x1B[39m\x1B[38;2;90;150;224mo\x1B[39m\x1B[38;2;91;148;227mr\x1B[39m \x1B[38;2;93;144;232mN\x1B[39m\x1B[38;2;94;142;234ma\x1B[39m\x1B[38;2;94;140;237mt\x1B[39m\x1B[38;2;95;138;240mi\x1B[39m\x1B[38;2;96;136;242mv\x1B[39m\x1B[38;2;97;134;245me\x1B[39m \x1B[38;2;98;130;250mD\x1B[39m\x1B[38;2;99;128;252mO\x1B[39m\x1B[38;2;100;126;255mM\x1B[39m";
|
|
1819
1819
|
//#endregion
|
|
1820
1820
|
//#region utils/deepMerge.ts
|
|
1821
1821
|
const isObject = (val) => val && typeof val === "object";
|
|
@@ -2052,7 +2052,7 @@ function inferPackageManager() {
|
|
|
2052
2052
|
//#endregion
|
|
2053
2053
|
//#region package.json
|
|
2054
2054
|
var name = "create-rue";
|
|
2055
|
-
var version = "0.0.
|
|
2055
|
+
var version = "0.0.11";
|
|
2056
2056
|
//#endregion
|
|
2057
2057
|
//#region index.ts
|
|
2058
2058
|
const language = await getLanguage(fileURLToPath(new URL("./locales", import.meta.url)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-rue",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "🛠️ The recommended way to start a Vite-powered Rue project",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/hunzhiwange/create-rue#readme",
|
|
@@ -27,18 +27,6 @@
|
|
|
27
27
|
"access": "public",
|
|
28
28
|
"provenance": false
|
|
29
29
|
},
|
|
30
|
-
"scripts": {
|
|
31
|
-
"prepare": "vp config",
|
|
32
|
-
"format": "vp fmt",
|
|
33
|
-
"format-check": "vp fmt --check",
|
|
34
|
-
"lint": "vp lint . --fix",
|
|
35
|
-
"build": "rolldown -c rolldown.config.ts",
|
|
36
|
-
"test": "pnpm run build && pnpm run test:unit",
|
|
37
|
-
"test:unit": "vp test",
|
|
38
|
-
"preversion": "git fetch && git status -uno | grep -q 'Your branch is up to date'",
|
|
39
|
-
"postversion": "zx ./scripts/postversion.mjs",
|
|
40
|
-
"prepublishOnly": "pnpm run build"
|
|
41
|
-
},
|
|
42
30
|
"devDependencies": {
|
|
43
31
|
"@clack/prompts": "^1.2.0",
|
|
44
32
|
"@tsconfig/node24": "^24.0.4",
|
|
@@ -47,12 +35,21 @@
|
|
|
47
35
|
"picocolors": "^1.1.1",
|
|
48
36
|
"rolldown": "1.0.0-rc.16",
|
|
49
37
|
"rollup-plugin-license": "^3.7.1",
|
|
50
|
-
"vite-plus": "
|
|
51
|
-
"vitest": "
|
|
38
|
+
"vite-plus": "latest",
|
|
39
|
+
"vitest": "npm:@voidzero-dev/vite-plus-test@latest",
|
|
52
40
|
"zx": "^8.8.5"
|
|
53
41
|
},
|
|
54
42
|
"engines": {
|
|
55
43
|
"node": "^20.19.0 || >=22.12.0"
|
|
56
44
|
},
|
|
57
|
-
"
|
|
58
|
-
|
|
45
|
+
"scripts": {
|
|
46
|
+
"format": "vp fmt",
|
|
47
|
+
"format-check": "vp fmt --check",
|
|
48
|
+
"lint": "vp lint . --fix",
|
|
49
|
+
"build": "rolldown -c rolldown.config.ts",
|
|
50
|
+
"test": "pnpm run build && pnpm run test:unit",
|
|
51
|
+
"test:unit": "vp test",
|
|
52
|
+
"preversion": "git fetch && git status -uno | grep -q 'Your branch is up to date'",
|
|
53
|
+
"postversion": "zx ./scripts/postversion.mjs"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -3,80 +3,161 @@ import { RouterLink } from '@rue-js/router'
|
|
|
3
3
|
|
|
4
4
|
const highlights = [
|
|
5
5
|
{
|
|
6
|
-
title: '
|
|
7
|
-
desc: '
|
|
6
|
+
title: 'Vapor Native DOM',
|
|
7
|
+
desc: '延续 Rue 的细粒度更新模型,直接面向原生 DOM,适合构建响应迅速的前端界面。',
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
|
-
title: '
|
|
11
|
-
desc: '
|
|
10
|
+
title: '原生 JSX / TSX',
|
|
11
|
+
desc: '以 JSX 和 TSX 作为一等公民,组件、路由和交互逻辑可以在同一套 TypeScript 工作流内完成。',
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
|
-
title: '
|
|
15
|
-
desc: '
|
|
14
|
+
title: '官方脚手架启动',
|
|
15
|
+
desc: '使用 create-rue 即可生成基于 Vite 的 Rue 应用,适合快速起项目和沉淀模板。',
|
|
16
16
|
},
|
|
17
17
|
]
|
|
18
18
|
|
|
19
|
-
const
|
|
20
|
-
'@
|
|
21
|
-
'@
|
|
22
|
-
'@
|
|
19
|
+
const quickStartCommands = [
|
|
20
|
+
'npm create rue@latest',
|
|
21
|
+
'pnpm create rue@latest',
|
|
22
|
+
'yarn create rue@latest',
|
|
23
|
+
'bun create rue@latest',
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
const nextSteps = [
|
|
27
|
+
'阅读介绍与快速开始,先熟悉 Rue 应用的基本结构。',
|
|
28
|
+
'使用脚手架创建项目后,安装依赖并启动开发服务器。',
|
|
29
|
+
'继续查看路由、状态管理和组件能力,再扩展到你的业务页面。',
|
|
23
30
|
]
|
|
24
31
|
|
|
25
32
|
const Home: FC = () => (
|
|
26
|
-
<div className="
|
|
27
|
-
<section className="hero-
|
|
28
|
-
<div className="hero-
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
<div className="space-y-6 pb-4">
|
|
34
|
+
<section className="hero border border-base-300 bg-base-100/90 shadow-xl">
|
|
35
|
+
<div className="hero-content flex-col items-start gap-8 px-6 py-8 lg:flex-row lg:items-end lg:justify-between">
|
|
36
|
+
<div className="max-w-3xl space-y-4">
|
|
37
|
+
<div className="badge badge-primary badge-outline">Rue.js</div>
|
|
38
|
+
<h1 className="text-4xl font-semibold tracking-tight sm:text-5xl">The Wasm Framework For Vapor Native DOM</h1>
|
|
39
|
+
<p className="max-w-2xl text-base leading-7 text-base-content/70">
|
|
40
|
+
Rue.js 采用原生 JSX / TSX 开发方式,结合细粒度响应式与面向原生 DOM 的渲染模型,适合构建轻量、直接且可维护的前端应用。
|
|
41
|
+
</p>
|
|
42
|
+
<div className="flex flex-wrap gap-3">
|
|
43
|
+
<RouterLink to="/report" className="btn btn-primary">
|
|
44
|
+
查看报表页面
|
|
45
|
+
</RouterLink>
|
|
46
|
+
<RouterLink to="/todo" className="btn btn-outline">
|
|
47
|
+
查看 Todo 示例
|
|
48
|
+
</RouterLink>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div className="stats stats-vertical w-full bg-base-200 shadow sm:stats-horizontal lg:w-auto">
|
|
53
|
+
<div className="stat">
|
|
54
|
+
<div className="stat-title">Node.js</div>
|
|
55
|
+
<div className="stat-value text-primary">>= 22.12</div>
|
|
56
|
+
</div>
|
|
57
|
+
<div className="stat">
|
|
58
|
+
<div className="stat-title">启动方式</div>
|
|
59
|
+
<div className="stat-value text-secondary">create-rue</div>
|
|
60
|
+
</div>
|
|
41
61
|
</div>
|
|
42
|
-
</div>
|
|
43
|
-
<div className="hero-panel">
|
|
44
|
-
<div className="panel-title">入口结构</div>
|
|
45
|
-
<pre className="code-block">{`app/
|
|
46
|
-
├─ main.ts
|
|
47
|
-
├─ app.tsx
|
|
48
|
-
├─ router.ts
|
|
49
|
-
└─ pages/
|
|
50
|
-
|
|
51
|
-
useApp(RootApp)
|
|
52
|
-
.use(router)
|
|
53
|
-
.mount('#app')`}</pre>
|
|
54
62
|
</div>
|
|
55
63
|
</section>
|
|
56
64
|
|
|
57
|
-
<section className="grid-
|
|
65
|
+
<section className="grid gap-4 md:grid-cols-3">
|
|
58
66
|
{highlights.map(item => (
|
|
59
|
-
<article key={item.title} className="
|
|
60
|
-
<
|
|
61
|
-
|
|
67
|
+
<article key={item.title} className="card border border-base-300 bg-base-100 shadow-sm">
|
|
68
|
+
<div className="card-body gap-3">
|
|
69
|
+
<h2 className="text-2xl font-semibold">{item.title}</h2>
|
|
70
|
+
<p className="text-sm leading-7 text-base-content/70">{item.desc}</p>
|
|
71
|
+
</div>
|
|
62
72
|
</article>
|
|
63
73
|
))}
|
|
64
74
|
</section>
|
|
65
75
|
|
|
66
|
-
<section className="
|
|
67
|
-
<
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
<section className="grid gap-6 xl:grid-cols-[1.35fr_0.85fr]">
|
|
77
|
+
<article className="card border border-base-300 bg-base-100 shadow-sm">
|
|
78
|
+
<div className="card-body gap-5">
|
|
79
|
+
<div>
|
|
80
|
+
<div className="badge badge-outline">快速开始</div>
|
|
81
|
+
<h2 className="mt-3 text-2xl font-semibold">创建第一个 Rue 应用</h2>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<div className="mockup-code text-sm">
|
|
85
|
+
{quickStartCommands.map(command => (
|
|
86
|
+
<pre key={command} data-prefix="$">
|
|
87
|
+
<code>{command}</code>
|
|
88
|
+
</pre>
|
|
89
|
+
))}
|
|
90
|
+
<pre data-prefix="$">
|
|
91
|
+
<code>cd <your-project-name></code>
|
|
92
|
+
</pre>
|
|
93
|
+
<pre data-prefix="$">
|
|
94
|
+
<code>npm install</code>
|
|
95
|
+
</pre>
|
|
96
|
+
<pre data-prefix="$">
|
|
97
|
+
<code>npm run dev</code>
|
|
98
|
+
</pre>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<div className="rounded-2xl bg-base-200 p-4 text-sm leading-7 text-base-content/70">
|
|
102
|
+
生成的项目基于 Vite,默认支持 JSX / TSX 组件开发;生产构建使用 npm run build,产物输出到 dist 目录。
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</article>
|
|
106
|
+
|
|
107
|
+
<article className="card border border-base-300 bg-base-100 shadow-sm">
|
|
108
|
+
<div className="card-body gap-5">
|
|
109
|
+
<div>
|
|
110
|
+
<div className="badge badge-outline">下一步</div>
|
|
111
|
+
<h2 className="mt-3 text-2xl font-semibold">继续阅读路线</h2>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<div className="space-y-3">
|
|
115
|
+
{nextSteps.map(step => (
|
|
116
|
+
<div key={step} className="rounded-2xl bg-base-200 p-4 text-sm leading-7 text-base-content/75">
|
|
117
|
+
{step}
|
|
118
|
+
</div>
|
|
119
|
+
))}
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<div className="divider my-0"></div>
|
|
123
|
+
|
|
124
|
+
<div className="flex flex-col gap-3">
|
|
125
|
+
<RouterLink to="/report" className="btn btn-outline w-full justify-between">
|
|
126
|
+
打开报表页
|
|
127
|
+
<span>→</span>
|
|
128
|
+
</RouterLink>
|
|
129
|
+
<RouterLink to="/todo" className="btn btn-outline w-full justify-between">
|
|
130
|
+
打开 Todo 示例
|
|
131
|
+
<span>→</span>
|
|
132
|
+
</RouterLink>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</article>
|
|
136
|
+
</section>
|
|
137
|
+
|
|
138
|
+
<section className="card border border-base-300 bg-base-100 shadow-sm">
|
|
139
|
+
<div className="card-body gap-4">
|
|
140
|
+
<div className="flex items-start justify-between gap-4">
|
|
141
|
+
<div>
|
|
142
|
+
<div className="badge badge-outline">文档入口</div>
|
|
143
|
+
<h2 className="mt-3 text-2xl font-semibold">首页建议保留的核心信息</h2>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div className="grid gap-4 md:grid-cols-3">
|
|
148
|
+
<div className="rounded-2xl bg-base-200 p-5">
|
|
149
|
+
<div className="text-sm text-base-content/60">介绍</div>
|
|
150
|
+
<div className="mt-2 text-lg font-semibold">框架定位与渲染模型</div>
|
|
151
|
+
</div>
|
|
152
|
+
<div className="rounded-2xl bg-base-200 p-5">
|
|
153
|
+
<div className="text-sm text-base-content/60">快速开始</div>
|
|
154
|
+
<div className="mt-2 text-lg font-semibold">脚手架、安装依赖与启动开发环境</div>
|
|
155
|
+
</div>
|
|
156
|
+
<div className="rounded-2xl bg-base-200 p-5">
|
|
157
|
+
<div className="text-sm text-base-content/60">扩展阅读</div>
|
|
158
|
+
<div className="mt-2 text-lg font-semibold">路由、状态管理、组件与工具链</div>
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
80
161
|
</div>
|
|
81
162
|
</section>
|
|
82
163
|
</div>
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { type FC } from '@rue-js/rue'
|
|
2
|
+
import { RouterLink } from '@rue-js/router'
|
|
3
|
+
|
|
4
|
+
type ReportRow = {
|
|
5
|
+
day: string
|
|
6
|
+
orders: number
|
|
7
|
+
revenue: number
|
|
8
|
+
conversion: number
|
|
9
|
+
note: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const rows: ReportRow[] = [
|
|
13
|
+
{ day: '04-21', orders: 42, revenue: 18600, conversion: 7.2, note: '新品投放启动' },
|
|
14
|
+
{ day: '04-22', orders: 55, revenue: 24180, conversion: 8.4, note: '自然流量增长' },
|
|
15
|
+
{ day: '04-23', orders: 61, revenue: 28640, conversion: 9.1, note: '渠道折扣带动' },
|
|
16
|
+
{ day: '04-24', orders: 48, revenue: 20520, conversion: 7.8, note: '高客单回落' },
|
|
17
|
+
{ day: '04-25', orders: 74, revenue: 36440, conversion: 10.6, note: '私域活动峰值' },
|
|
18
|
+
{ day: '04-26', orders: 66, revenue: 30900, conversion: 9.7, note: '成交保持稳定' },
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
const moneyFormatter = new Intl.NumberFormat('zh-CN', {
|
|
22
|
+
style: 'currency',
|
|
23
|
+
currency: 'CNY',
|
|
24
|
+
maximumFractionDigits: 0,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const integerFormatter = new Intl.NumberFormat('zh-CN')
|
|
28
|
+
|
|
29
|
+
const totalRevenue = rows.reduce((sum, row) => sum + row.revenue, 0)
|
|
30
|
+
const totalOrders = rows.reduce((sum, row) => sum + row.orders, 0)
|
|
31
|
+
const avgConversion = rows.reduce((sum, row) => sum + row.conversion, 0) / rows.length
|
|
32
|
+
const peakRow = rows.reduce((max, row) => (row.revenue > max.revenue ? row : max), rows[0])
|
|
33
|
+
const maxRevenue = Math.max(...rows.map(row => row.revenue))
|
|
34
|
+
|
|
35
|
+
const summaryCards = [
|
|
36
|
+
{
|
|
37
|
+
label: '累计成交额',
|
|
38
|
+
value: moneyFormatter.format(totalRevenue),
|
|
39
|
+
detail: '过去 6 天整体表现',
|
|
40
|
+
tone: 'bg-primary text-primary-content',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: '累计订单数',
|
|
44
|
+
value: integerFormatter.format(totalOrders),
|
|
45
|
+
detail: '订单总量',
|
|
46
|
+
tone: 'bg-secondary text-secondary-content',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
label: '平均转化率',
|
|
50
|
+
value: `${avgConversion.toFixed(1)}%`,
|
|
51
|
+
detail: '按日均值计算',
|
|
52
|
+
tone: 'bg-accent text-accent-content',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
label: '峰值日期',
|
|
56
|
+
value: peakRow.day,
|
|
57
|
+
detail: `${moneyFormatter.format(peakRow.revenue)} / ${peakRow.orders} 单`,
|
|
58
|
+
tone: 'bg-neutral text-neutral-content',
|
|
59
|
+
},
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
const Report: FC = () => (
|
|
63
|
+
<div className="space-y-6 pb-4">
|
|
64
|
+
<section className="hero border border-base-300 bg-base-100/90 shadow-xl">
|
|
65
|
+
<div className="hero-content flex-col items-start gap-8 px-6 py-8 lg:flex-row lg:items-end lg:justify-between">
|
|
66
|
+
<div className="max-w-3xl space-y-4">
|
|
67
|
+
<h1 className="text-4xl font-semibold tracking-tight sm:text-5xl">报表页面</h1>
|
|
68
|
+
<div className="flex flex-wrap gap-3">
|
|
69
|
+
<RouterLink to="/" className="btn btn-outline">
|
|
70
|
+
返回首页
|
|
71
|
+
</RouterLink>
|
|
72
|
+
<RouterLink to="/todo" className="btn btn-primary">
|
|
73
|
+
查看 Todo 示例
|
|
74
|
+
</RouterLink>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div className="stats stats-vertical w-full bg-base-200 shadow sm:stats-horizontal lg:w-auto">
|
|
79
|
+
<div className="stat">
|
|
80
|
+
<div className="stat-title">最近窗口</div>
|
|
81
|
+
<div className="stat-value text-primary">6 天</div>
|
|
82
|
+
</div>
|
|
83
|
+
<div className="stat">
|
|
84
|
+
<div className="stat-title">可切换主题</div>
|
|
85
|
+
<div className="stat-value text-secondary">全部</div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</section>
|
|
90
|
+
|
|
91
|
+
<section className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
|
92
|
+
{summaryCards.map(card => (
|
|
93
|
+
<article key={card.label} className={`card shadow-lg ${card.tone}`}>
|
|
94
|
+
<div className="card-body gap-2">
|
|
95
|
+
<p className="text-sm opacity-80">{card.label}</p>
|
|
96
|
+
<h2 className="text-3xl font-semibold">{card.value}</h2>
|
|
97
|
+
<p className="text-sm opacity-80">{card.detail}</p>
|
|
98
|
+
</div>
|
|
99
|
+
</article>
|
|
100
|
+
))}
|
|
101
|
+
</section>
|
|
102
|
+
|
|
103
|
+
<section className="grid gap-6 xl:grid-cols-[1.35fr_0.85fr]">
|
|
104
|
+
<article className="card border border-base-300 bg-base-100 shadow-sm">
|
|
105
|
+
<div className="card-body gap-5">
|
|
106
|
+
<div className="flex items-start justify-between gap-4">
|
|
107
|
+
<div>
|
|
108
|
+
<div className="badge badge-outline">营收走势</div>
|
|
109
|
+
<h2 className="mt-3 text-2xl font-semibold">最近 6 天成交波动</h2>
|
|
110
|
+
</div>
|
|
111
|
+
<div className="text-right text-sm text-base-content/60">
|
|
112
|
+
<div>峰值 {peakRow.day}</div>
|
|
113
|
+
<div>{moneyFormatter.format(peakRow.revenue)}</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<div className="space-y-4">
|
|
118
|
+
{rows.map(row => (
|
|
119
|
+
<div key={row.day} className="grid gap-2">
|
|
120
|
+
<div className="flex items-center justify-between gap-4 text-sm">
|
|
121
|
+
<div className="font-medium">{row.day}</div>
|
|
122
|
+
<div className="text-base-content/60">{moneyFormatter.format(row.revenue)}</div>
|
|
123
|
+
</div>
|
|
124
|
+
<progress className="progress progress-primary w-full" value={row.revenue} max={maxRevenue}></progress>
|
|
125
|
+
<div className="flex items-center justify-between gap-4 text-xs text-base-content/60">
|
|
126
|
+
<span>{row.orders} 单</span>
|
|
127
|
+
<span>转化率 {row.conversion}%</span>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
))}
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
</article>
|
|
134
|
+
|
|
135
|
+
<article className="card border border-base-300 bg-base-100 shadow-sm">
|
|
136
|
+
<div className="card-body gap-5">
|
|
137
|
+
<div>
|
|
138
|
+
<h2 className="text-2xl font-semibold">报表概览</h2>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<div className="divider my-0"></div>
|
|
142
|
+
|
|
143
|
+
<div className="space-y-3">
|
|
144
|
+
<div className="rounded-2xl bg-base-200 p-4">
|
|
145
|
+
<div className="font-medium">左上角按钮可隐藏顶部</div>
|
|
146
|
+
</div>
|
|
147
|
+
<RouterLink to="/todo" className="btn btn-outline w-full justify-between">
|
|
148
|
+
切到 Todo 示例
|
|
149
|
+
<span>→</span>
|
|
150
|
+
</RouterLink>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
</article>
|
|
154
|
+
</section>
|
|
155
|
+
|
|
156
|
+
<section className="card border border-base-300 bg-base-100 shadow-sm">
|
|
157
|
+
<div className="card-body gap-4 overflow-x-auto">
|
|
158
|
+
<div className="flex items-end justify-between gap-4">
|
|
159
|
+
<div>
|
|
160
|
+
<div className="badge badge-outline">明细预览</div>
|
|
161
|
+
<h2 className="mt-3 text-2xl font-semibold">日报明细表</h2>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
<table className="table table-zebra">
|
|
166
|
+
<thead>
|
|
167
|
+
<tr>
|
|
168
|
+
<th>日期</th>
|
|
169
|
+
<th>订单数</th>
|
|
170
|
+
<th>成交额</th>
|
|
171
|
+
<th>转化率</th>
|
|
172
|
+
<th>备注</th>
|
|
173
|
+
</tr>
|
|
174
|
+
</thead>
|
|
175
|
+
<tbody>
|
|
176
|
+
{rows.map(row => (
|
|
177
|
+
<tr key={row.day}>
|
|
178
|
+
<td className="font-medium">{row.day}</td>
|
|
179
|
+
<td>{row.orders}</td>
|
|
180
|
+
<td>{moneyFormatter.format(row.revenue)}</td>
|
|
181
|
+
<td>{row.conversion}%</td>
|
|
182
|
+
<td>{row.note}</td>
|
|
183
|
+
</tr>
|
|
184
|
+
))}
|
|
185
|
+
</tbody>
|
|
186
|
+
</table>
|
|
187
|
+
</div>
|
|
188
|
+
</section>
|
|
189
|
+
</div>
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
export default Report
|