@lxzy/code-snippet 0.0.1

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/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@lxzy/code-snippet",
3
+ "version": "0.0.1",
4
+ "description": "none",
5
+ "license": "MIT",
6
+ "author": "ywwb",
7
+ "main": "./dist/esm/index.js",
8
+ "module": "./dist/esm/index.js",
9
+ "types": "./dist/esm/index.d.ts",
10
+ "files": [
11
+ "src",
12
+ "public"
13
+ ],
14
+ "scripts": {
15
+ "build": "father build",
16
+ "prepublishOnly": "",
17
+ "pub": "npm publish"
18
+ },
19
+ "dependencies": {},
20
+ "devDependencies": {},
21
+ "peerDependencies": {},
22
+ "publishConfig": {
23
+ "access": "public",
24
+ "registry": "https://registry.npmjs.org/"
25
+ },
26
+ "authors": []
27
+ }
package/src/index.tsx ADDED
File without changes
@@ -0,0 +1,101 @@
1
+ .page {
2
+ min-height: 100vh;
3
+ background: linear-gradient(135deg, #f5f7fa 0%, #e4ecf7 100%);
4
+ padding: 32px 24px;
5
+ box-sizing: border-box;
6
+ }
7
+
8
+ .header {
9
+ text-align: center;
10
+ margin-bottom: 24px;
11
+
12
+ h1 {
13
+ font-size: 28px;
14
+ font-weight: 700;
15
+ color: #1a1a2e;
16
+ margin: 0 0 8px;
17
+ letter-spacing: 2px;
18
+ }
19
+
20
+ p {
21
+ font-size: 14px;
22
+ color: #888;
23
+ margin: 0;
24
+ }
25
+ }
26
+
27
+ .toolbar {
28
+ max-width: 1400px;
29
+ margin: 0 auto 16px;
30
+ display: flex;
31
+ align-items: center;
32
+ justify-content: space-between;
33
+ flex-wrap: wrap;
34
+ gap: 12px;
35
+ background: #fff;
36
+ border-radius: 12px;
37
+ padding: 14px 20px;
38
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
39
+ }
40
+
41
+ .toolbarLeft {
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 8px;
45
+ }
46
+
47
+ .toolbarRight {
48
+ display: flex;
49
+ align-items: center;
50
+ }
51
+
52
+ .label {
53
+ font-size: 14px;
54
+ color: #555;
55
+ font-weight: 500;
56
+ }
57
+
58
+ .info {
59
+ font-size: 13px;
60
+ color: #666;
61
+ background: #f0f5ff;
62
+ padding: 5px 14px;
63
+ border-radius: 6px;
64
+ border: 1px solid #d6e4ff;
65
+
66
+ strong {
67
+ color: #1677ff;
68
+ font-size: 15px;
69
+ margin: 0 2px;
70
+ }
71
+ }
72
+
73
+ .chartWrapper {
74
+ max-width: 1400px;
75
+ margin: 0 auto;
76
+ background: #fff;
77
+ border-radius: 16px;
78
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.06);
79
+ padding: 24px 16px 16px;
80
+ }
81
+
82
+ .chart {
83
+ width: 100%;
84
+ height: 520px;
85
+ }
86
+
87
+ .tips {
88
+ max-width: 1400px;
89
+ margin: 16px auto 0;
90
+ text-align: center;
91
+
92
+ span {
93
+ display: inline-block;
94
+ background: #fffbe6;
95
+ color: #ad6800;
96
+ font-size: 13px;
97
+ padding: 8px 20px;
98
+ border-radius: 8px;
99
+ border: 1px solid #ffe58f;
100
+ }
101
+ }
@@ -0,0 +1,272 @@
1
+ import { useEffect, useRef, useState, useCallback } from "react";
2
+ import * as echarts from "echarts";
3
+ import { DatePicker } from "antd";
4
+ import dayjs, { Dayjs } from "dayjs";
5
+ import s from "./index.less";
6
+
7
+ const { RangePicker } = DatePicker;
8
+
9
+ // 根据小时生成模拟随机数(带日间波动规律)
10
+ function generateData(startDate: Dayjs, endDate: Dayjs) {
11
+ const xData: string[] = [];
12
+ const temperatureData: number[] = [];
13
+ const humidityData: number[] = [];
14
+ const powerData: number[] = [];
15
+
16
+ const totalDays = endDate.diff(startDate, "day") + 1;
17
+
18
+ for (let d = 0; d < totalDays; d++) {
19
+ const currentDay = startDate.add(d, "day");
20
+ const dateStr = currentDay.format("YYYY-MM-DD");
21
+
22
+ for (let h = 0; h < 24; h++) {
23
+ const hour = h.toString().padStart(2, "0");
24
+ xData.push(`${dateStr} ${hour}:00`);
25
+
26
+ // 温度:夜间低(14-18°C),日间高(24-32°C)
27
+ const tempBase = h >= 8 && h <= 18 ? 24 : 16;
28
+ const tempRange = h >= 8 && h <= 18 ? 8 : 4;
29
+ temperatureData.push(
30
+ +(tempBase + Math.random() * tempRange).toFixed(1)
31
+ );
32
+
33
+ // 湿度:与温度大致相反,夜间高(65-80%),日间低(40-58%)
34
+ const humBase = h >= 8 && h <= 18 ? 40 : 65;
35
+ const humRange = h >= 8 && h <= 18 ? 18 : 15;
36
+ humidityData.push(
37
+ +(humBase + Math.random() * humRange).toFixed(1)
38
+ );
39
+
40
+ // 用电量:工作时间高(300-500kWh),夜间低(80-160kWh)
41
+ const powBase = h >= 8 && h <= 20 ? 300 : 80;
42
+ const powRange = h >= 8 && h <= 20 ? 200 : 80;
43
+ powerData.push(
44
+ +(powBase + Math.random() * powRange).toFixed(0)
45
+ );
46
+ }
47
+ }
48
+
49
+ return { xData, temperatureData, humidityData, powerData };
50
+ }
51
+
52
+ // 默认时间:当前时间前三天
53
+ const defaultRange: [Dayjs, Dayjs] = [
54
+ dayjs().subtract(2, "day").startOf("day"),
55
+ dayjs().startOf("day"),
56
+ ];
57
+
58
+ export default function ChartPage() {
59
+ const chartRef = useRef<HTMLDivElement>(null);
60
+ const chartInstance = useRef<echarts.ECharts | null>(null);
61
+ const [dateRange, setDateRange] = useState<[Dayjs, Dayjs]>(defaultRange);
62
+
63
+ // 构建 ECharts 配置
64
+ const buildOption = useCallback(
65
+ (data: ReturnType<typeof generateData>): echarts.EChartsOption => {
66
+ const totalPoints = data.xData.length;
67
+ // 默认展示约 24 个数据点(1天)的宽度
68
+ const visiblePercent = Math.min(100, (24 / totalPoints) * 100);
69
+
70
+ return {
71
+ title: {
72
+ text: `${dateRange[0].format("MM-DD")} 至 ${dateRange[1].format("MM-DD")} 环境监测统计图`,
73
+ subtext: `共 ${totalPoints} 个数据点 · 温度 / 湿度 / 用电量(每小时采样)`,
74
+ left: "center",
75
+ textStyle: { color: "#333", fontSize: 20, fontWeight: "bold" },
76
+ subtextStyle: { color: "#999", fontSize: 13 },
77
+ top: 16,
78
+ },
79
+ tooltip: {
80
+ trigger: "axis",
81
+ backgroundColor: "rgba(255,255,255,0.96)",
82
+ borderColor: "#eee",
83
+ textStyle: { color: "#333" },
84
+ axisPointer: { type: "cross", crossStyle: { color: "#999" } },
85
+ },
86
+ legend: {
87
+ data: ["温度 (°C)", "湿度 (%)", "用电量 (kWh)"],
88
+ top: 80,
89
+ itemGap: 32,
90
+ textStyle: { fontSize: 13 },
91
+ },
92
+ grid: {
93
+ left: 60,
94
+ right: 60,
95
+ top: 130,
96
+ bottom: 120,
97
+ },
98
+ xAxis: {
99
+ type: "category",
100
+ data: data.xData,
101
+ axisLabel: {
102
+ rotate: 45,
103
+ fontSize: 11,
104
+ interval: Math.max(0, Math.floor(totalPoints / 24) - 1),
105
+ formatter: (value: string) => {
106
+ const parts = value.split(" ");
107
+ return `${parts[0].slice(5)}\n${parts[1]}`;
108
+ },
109
+ },
110
+ axisTick: { alignWithLabel: true },
111
+ boundaryGap: false,
112
+ splitLine: { show: true, lineStyle: { type: "dashed", color: "#eee" } },
113
+ },
114
+ yAxis: [
115
+ {
116
+ type: "value",
117
+ name: "温度(°C) / 湿度(%)",
118
+ position: "left",
119
+ axisLabel: { formatter: "{value}" },
120
+ splitLine: { lineStyle: { type: "dashed", color: "#eee" } },
121
+ },
122
+ {
123
+ type: "value",
124
+ name: "用电量(kWh)",
125
+ position: "right",
126
+ axisLabel: { formatter: "{value}" },
127
+ splitLine: { show: false },
128
+ },
129
+ ],
130
+ dataZoom: [
131
+ {
132
+ type: "slider",
133
+ xAxisIndex: 0,
134
+ start: 0,
135
+ end: visiblePercent,
136
+ bottom: 20,
137
+ height: 30,
138
+ borderColor: "#ddd",
139
+ fillerColor: "rgba(64,136,255,0.15)",
140
+ handleStyle: { color: "#4088ff" },
141
+ textStyle: { fontSize: 11 },
142
+ },
143
+ {
144
+ type: "inside",
145
+ xAxisIndex: 0,
146
+ start: 0,
147
+ end: visiblePercent,
148
+ },
149
+ ],
150
+ series: [
151
+ {
152
+ name: "温度 (°C)",
153
+ type: "line",
154
+ data: data.temperatureData,
155
+ smooth: true,
156
+ symbol: "circle",
157
+ symbolSize: 6,
158
+ lineStyle: { width: 2.5, color: "#ff6b6b" },
159
+ itemStyle: { color: "#ff6b6b" },
160
+ areaStyle: {
161
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
162
+ { offset: 0, color: "rgba(255,107,107,0.25)" },
163
+ { offset: 1, color: "rgba(255,107,107,0.02)" },
164
+ ]),
165
+ },
166
+ },
167
+ {
168
+ name: "湿度 (%)",
169
+ type: "line",
170
+ data: data.humidityData,
171
+ smooth: true,
172
+ symbol: "circle",
173
+ symbolSize: 6,
174
+ lineStyle: { width: 2.5, color: "#4ecdc4" },
175
+ itemStyle: { color: "#4ecdc4" },
176
+ areaStyle: {
177
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
178
+ { offset: 0, color: "rgba(78,205,196,0.25)" },
179
+ { offset: 1, color: "rgba(78,205,196,0.02)" },
180
+ ]),
181
+ },
182
+ },
183
+ {
184
+ name: "用电量 (kWh)",
185
+ type: "line",
186
+ yAxisIndex: 1,
187
+ data: data.powerData,
188
+ smooth: true,
189
+ symbol: "circle",
190
+ symbolSize: 6,
191
+ lineStyle: { width: 2.5, color: "#4088ff" },
192
+ itemStyle: { color: "#4088ff" },
193
+ areaStyle: {
194
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
195
+ { offset: 0, color: "rgba(64,136,255,0.25)" },
196
+ { offset: 1, color: "rgba(64,136,255,0.02)" },
197
+ ]),
198
+ },
199
+ },
200
+ ],
201
+ };
202
+ },
203
+ [dateRange]
204
+ );
205
+
206
+ // 初始化图表
207
+ useEffect(() => {
208
+ if (!chartRef.current) return;
209
+ chartInstance.current = echarts.init(chartRef.current);
210
+
211
+ const handleResize = () => chartInstance.current?.resize();
212
+ window.addEventListener("resize", handleResize);
213
+
214
+ return () => {
215
+ window.removeEventListener("resize", handleResize);
216
+ chartInstance.current?.dispose();
217
+ };
218
+ }, []);
219
+
220
+ // 时间区间变化时更新图表
221
+ useEffect(() => {
222
+ if (!chartInstance.current) return;
223
+ const data = generateData(dateRange[0], dateRange[1]);
224
+ chartInstance.current.setOption(buildOption(data), true);
225
+ }, [dateRange, buildOption]);
226
+
227
+ const onRangeChange = (dates: [Dayjs | null, Dayjs | null] | null) => {
228
+ if (dates && dates[0] && dates[1]) {
229
+ setDateRange([dates[0].startOf("day"), dates[1].startOf("day")]);
230
+ }
231
+ };
232
+
233
+ return (
234
+ <div className={s.page}>
235
+ <div className={s.header}>
236
+ <h1>数据统计看板</h1>
237
+ <p>环境监测数据 · 每小时采样一次 · 拖动下方滑块或鼠标滚轮可浏览全部数据</p>
238
+ </div>
239
+ <div className={s.toolbar}>
240
+ <div className={s.toolbarLeft}>
241
+ <span className={s.label}>时间区间:</span>
242
+ <RangePicker
243
+ value={dateRange}
244
+ onChange={onRangeChange}
245
+ allowClear={false}
246
+ format="YYYY-MM-DD"
247
+ disabledDate={(current) => current && current > dayjs().endOf("day")}
248
+ presets={[
249
+ { label: "近 1 天", value: [dayjs().subtract(0, "day").startOf("day"), dayjs().startOf("day")] },
250
+ { label: "近 3 天", value: [dayjs().subtract(2, "day").startOf("day"), dayjs().startOf("day")] },
251
+ { label: "近 7 天", value: [dayjs().subtract(6, "day").startOf("day"), dayjs().startOf("day")] },
252
+ { label: "近 15 天", value: [dayjs().subtract(14, "day").startOf("day"), dayjs().startOf("day")] },
253
+ { label: "近 30 天", value: [dayjs().subtract(29, "day").startOf("day"), dayjs().startOf("day")] },
254
+ ]}
255
+ />
256
+ </div>
257
+ <div className={s.toolbarRight}>
258
+ <span className={s.info}>
259
+ 共 <strong>{dateRange[1].diff(dateRange[0], "day") + 1}</strong> 天 /
260
+ <strong>{(dateRange[1].diff(dateRange[0], "day") + 1) * 24}</strong> 个数据点
261
+ </span>
262
+ </div>
263
+ </div>
264
+ <div className={s.chartWrapper}>
265
+ <div ref={chartRef} className={s.chart} />
266
+ </div>
267
+ <div className={s.tips}>
268
+ <span>💡 提示:拖动图表下方滑块可左右浏览数据,也可在图表区域内使用鼠标滚轮缩放</span>
269
+ </div>
270
+ </div>
271
+ );
272
+ }