@lxzy/code-snippet 0.0.8 → 0.0.9

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.
@@ -0,0 +1,11 @@
1
+ - ts 类型不需要写详细,不要在 tsx 文件里定义 interface,组件里的方法参数不要写类型定义
2
+ - 组件的 props 不要直接在入参的地方解构,也不要定义 React.FC
3
+
4
+ ```ts
5
+ const AddDrawer: React.FC = ({ a, b, c }) => {}; // 错误
6
+
7
+ const AddDrawer = (props) => {
8
+ // 正确
9
+ const { a, b, c } = props;
10
+ };
11
+ ```
package/README.md CHANGED
@@ -1,15 +1,43 @@
1
- # umi project
2
-
3
- ## Getting Started
4
-
5
- Install dependencies,
6
-
7
- ```bash
8
- $ yarn
9
1
  ```
2
+ {
3
+ // Place your 全局 snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
4
+ // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
5
+ // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
6
+ // used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
7
+ // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
8
+ // Placeholders with the same ids are connected.
9
+ "快速打印": {
10
+ "scope": "javascript,javascriptreact,typescript,typescriptreact",
11
+ "prefix": "clg",
12
+ "body": ["console.log($1);"],
13
+ "description": "快速打印"
14
+ },
15
+ "react组件模版": {
16
+ "scope": "javascript, javascriptreact, typescript, typescriptreact",
17
+ "prefix": "react",
18
+ "body": [
19
+ "import React, {useState} from 'react'",
20
+ "",
21
+ "export default function ${TM_FILENAME_BASE/(.*)/${1:/capitalize}/}() {",
22
+ " return (",
23
+ " <div>",
24
+ " $1",
25
+ " </div>",
26
+ " )",
27
+ "}",
28
+ ],
29
+ "description": "react组件模版"
30
+ },
31
+ "formily模版": {
32
+ "scope": "javascript, javascriptreact, typescript, typescriptreact",
33
+ "prefix": "formily",
34
+ "body": [
35
+ "import { createForm, onFieldInputValueChange } from '@formily/core';",
36
+ "import { Form, FormItem, FormGrid } from '@formily/next';",
37
+ "import { Field } from '@formily/react';"
38
+ ],
39
+ "description": "formily模版"
40
+ }
41
+ }
10
42
 
11
- Start the dev server,
12
-
13
- ```bash
14
- $ yarn start
15
43
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lxzy/code-snippet",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "files": [
5
5
  "*",
6
6
  "!dist",
@@ -62,7 +62,7 @@
62
62
  "wangeditor": "^4.7.11"
63
63
  },
64
64
  "devDependencies": {
65
- "@types/node": "^22.1.0",
65
+ "@types/node": "^22.1.0",
66
66
  "@types/react": "^17.0.0",
67
67
  "@types/react-dom": "^17.0.0",
68
68
  "@vitejs/plugin-react": "^6.0.0",
package/src/App.tsx CHANGED
@@ -5,7 +5,7 @@ import ActivitySystemManagement from '@/pages/activityCenter/activitySystemManag
5
5
  import ActivitySystemManagementAddPages from '@/pages/activityCenter/activitySystemManagement/addPages';
6
6
  import Page404 from '@/pages/404';
7
7
 
8
- const App: React.FC = () => {
8
+ const App = () => {
9
9
  return (
10
10
  <BrowserRouter>
11
11
  <BasicLayout>
@@ -13,7 +13,8 @@ const menuDataRender = (menuList: any[]) => {
13
13
  });
14
14
  };
15
15
 
16
- const BasicLayout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
16
+ const BasicLayout = (props) => {
17
+ const { children } = props;
17
18
  const navigate = useNavigate();
18
19
 
19
20
  return (
package/src/main.tsx CHANGED
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import ReactDOM from 'react-dom';
3
3
  import App from './App';
4
+ import 'antd/dist/antd.css';
4
5
  import './global.css';
5
6
 
6
7
  ReactDOM.render(
@@ -29,19 +29,8 @@ const strategyTagOptions = ['常态化', '拉新', '促活', '促销', '品牌
29
29
  const ipTagOptions = ['品牌A', '品牌B', '品牌C', '品牌D'];
30
30
  const industryTagOptions = ['制造业', '轻工业', '重工业', '服务业', '农业'];
31
31
 
32
- interface AddDrawerProps {
33
- visible: boolean;
34
- editingItem: any;
35
- onClose: () => void;
36
- onSuccess: () => void;
37
- }
38
-
39
- const AddDrawer: React.FC<AddDrawerProps> = ({
40
- visible,
41
- editingItem,
42
- onClose,
43
- onSuccess,
44
- }) => {
32
+ const AddDrawer = (props) => {
33
+ const { visible, editingItem, onClose, onSuccess } = props;
45
34
  const formRef = useRef<any>();
46
35
 
47
36
  const handleSubmit = async (values) => {
@@ -5,23 +5,12 @@ import ProTable from '@ant-design/pro-table';
5
5
  import { ModalForm, ProFormText } from '@ant-design/pro-form';
6
6
  import axios from 'axios';
7
7
 
8
- interface ChannelLinkModalProps {
9
- visible: boolean;
10
- pageName: string;
11
- pageId: number;
12
- onClose: () => void;
13
- }
14
-
15
- const ChannelLinkModal: React.FC<ChannelLinkModalProps> = ({
16
- visible,
17
- pageName,
18
- pageId,
19
- onClose,
20
- }) => {
8
+ const ChannelLinkModal = (props) => {
9
+ const { visible, pageName, pageId, onClose } = props;
21
10
  const actionRef = useRef<any>();
22
11
  const [addVisible, setAddVisible] = useState(false);
23
12
  const [editVisible, setEditVisible] = useState(false);
24
- const [editingItem, setEditingItem] = useState<any>(null);
13
+ const [editingItem, setEditingItem] = useState(null);
25
14
 
26
15
  const handleAdd = async (values) => {
27
16
  await axios.post('/api/activity/channelLink/add', {
@@ -1,39 +1,144 @@
1
- import React from 'react';
2
- import { Button } from 'antd';
1
+ import React, { useRef, useState } from 'react';
2
+ import { Button, Modal, Radio, Input, message, Space } from 'antd';
3
+ import { PlusOutlined } from '@ant-design/icons';
3
4
  import ProTable from '@ant-design/pro-table';
5
+ import { ModalForm } from '@ant-design/pro-form';
4
6
  import axios from 'axios';
5
7
 
6
- const CustomLink: React.FC = () => {
8
+ const CustomLink = () => {
9
+ const actionRef = useRef<any>();
10
+ const [addVisible, setAddVisible] = useState(false);
11
+ const [editVisible, setEditVisible] = useState(false);
12
+ const [editingItem, setEditingItem] = useState(null);
13
+
14
+ const handleAdd = async (values) => {
15
+ await axios.post('/api/activity/customLink/add', values);
16
+ message.success('新增成功');
17
+ setAddVisible(false);
18
+ actionRef.current?.reload();
19
+ return true;
20
+ };
21
+
22
+ const handleEdit = async (values) => {
23
+ await axios.post('/api/activity/customLink/update', {
24
+ ...values,
25
+ id: editingItem?.id,
26
+ });
27
+ message.success('编辑成功');
28
+ setEditVisible(false);
29
+ setEditingItem(null);
30
+ actionRef.current?.reload();
31
+ return true;
32
+ };
33
+
34
+ const handleDelete = async (record) => {
35
+ Modal.confirm({
36
+ title: '确认删除',
37
+ content: '确定要删除这条自定义链接吗?',
38
+ onOk: async () => {
39
+ await axios.post('/api/activity/customLink/delete', { id: record.id });
40
+ message.success('删除成功');
41
+ actionRef.current?.reload();
42
+ },
43
+ });
44
+ };
45
+
46
+ const getTypeName = (type: number) => {
47
+ return type === 1 ? '小程序' : 'H5链接';
48
+ };
49
+
7
50
  return (
8
51
  <div>
9
- <ProTable
52
+ <ProTable<any>
10
53
  headerTitle={false}
11
54
  toolBarRender={() => [
12
- <Button key="add" type="primary">新建自定义链接</Button>,
55
+ <Button
56
+ key="add"
57
+ type="primary"
58
+ icon={<PlusOutlined />}
59
+ onClick={() => setAddVisible(true)}
60
+ >
61
+ 新建自定义链接
62
+ </Button>,
13
63
  ]}
64
+ actionRef={actionRef}
14
65
  rowKey="id"
15
66
  request={async (params) => {
16
67
  const { data: result } = await axios.get('/api/activity/customLinkList', { params });
17
68
  return { data: result.data.list, total: result.data.total, success: result.success };
18
69
  }}
19
70
  columns={[
20
- { title: '跳转类型', dataIndex: 'type' },
71
+ { title: '跳转类型', dataIndex: 'type', render: (_, record) => getTypeName(record.type) },
21
72
  { title: '页面路径', dataIndex: 'path' },
22
73
  { title: '最近更新时间', dataIndex: 'updateTime' },
23
74
  {
24
75
  title: '操作',
25
76
  valueType: 'option',
26
- render: () => (
27
- <>
28
- <Button type="link" size="small">编辑</Button>
29
- <Button type="link" danger size="small">删除</Button>
30
- </>
77
+ render: (_, record) => (
78
+ <Space>
79
+ <Button
80
+ type="link"
81
+ size="small"
82
+ onClick={() => {
83
+ setEditingItem(record);
84
+ setEditVisible(true);
85
+ }}
86
+ >
87
+ 编辑
88
+ </Button>
89
+ <Button type="link" danger size="small" onClick={() => handleDelete(record)}>
90
+ 删除
91
+ </Button>
92
+ </Space>
31
93
  ),
32
94
  },
33
95
  ]}
34
96
  pagination={false}
35
97
  options={false}
98
+ search={false}
36
99
  />
100
+
101
+ <ModalForm
102
+ title="新建自定义链接"
103
+ visible={addVisible}
104
+ onVisibleChange={setAddVisible}
105
+ onFinish={handleAdd}
106
+ modalProps={{ destroyOnClose: true }}
107
+ >
108
+ <div style={{ marginBottom: 24 }}>
109
+ <div style={{ marginBottom: 8, fontWeight: 500 }}><span style={{ color: '#ff4d4f' }}>*</span> 跳转类型</div>
110
+ <Radio.Group name="type" defaultValue={1}>
111
+ <Radio value={1}>小程序</Radio>
112
+ <Radio value={2}>H5链接</Radio>
113
+ </Radio.Group>
114
+ </div>
115
+ <div style={{ marginBottom: 24 }}>
116
+ <div style={{ marginBottom: 8, fontWeight: 500 }}><span style={{ color: '#ff4d4f' }}>*</span> 页面路径</div>
117
+ <Input name="path" placeholder="请输入页面路径" />
118
+ </div>
119
+ </ModalForm>
120
+
121
+ <ModalForm
122
+ title="编辑自定义链接"
123
+ visible={editVisible}
124
+ onVisibleChange={setEditVisible}
125
+ onFinish={handleEdit}
126
+ initialValues={editingItem ? { type: editingItem.type, path: editingItem.path } : {}}
127
+ key={editingItem?.id}
128
+ modalProps={{ destroyOnClose: true }}
129
+ >
130
+ <div style={{ marginBottom: 24 }}>
131
+ <div style={{ marginBottom: 8, fontWeight: 500 }}><span style={{ color: '#ff4d4f' }}>*</span> 跳转类型</div>
132
+ <Radio.Group name="type">
133
+ <Radio value={1}>小程序</Radio>
134
+ <Radio value={2}>H5链接</Radio>
135
+ </Radio.Group>
136
+ </div>
137
+ <div style={{ marginBottom: 24 }}>
138
+ <div style={{ marginBottom: 8, fontWeight: 500 }}><span style={{ color: '#ff4d4f' }}>*</span> 页面路径</div>
139
+ <Input name="path" placeholder="请输入页面路径" />
140
+ </div>
141
+ </ModalForm>
37
142
  </div>
38
143
  );
39
144
  };
@@ -4,9 +4,9 @@ import ProTable from '@ant-design/pro-table';
4
4
  import axios from 'axios';
5
5
  import ChannelLinkModal from './ChannelLinkModal';
6
6
 
7
- const CustomPage: React.FC = () => {
7
+ const CustomPage = () => {
8
8
  const [channelLinkVisible, setChannelLinkVisible] = useState(false);
9
- const [currentPage, setCurrentPage] = useState<any>(null);
9
+ const [currentPage, setCurrentPage] = useState(null);
10
10
 
11
11
  return (
12
12
  <div>
@@ -3,7 +3,7 @@ import { Button } from 'antd';
3
3
  import ProTable from '@ant-design/pro-table';
4
4
  import axios from 'axios';
5
5
 
6
- const SystemPage: React.FC = () => {
6
+ const SystemPage = () => {
7
7
  return (
8
8
  <div>
9
9
  <ProTable
@@ -4,7 +4,7 @@ import SystemPage from './components/SystemPage';
4
4
  import CustomPage from './components/CustomPage';
5
5
  import CustomLink from './components/CustomLink';
6
6
 
7
- const AddPages: React.FC = () => {
7
+ const AddPages = () => {
8
8
  const [activeTab, setActiveTab] = useState('system');
9
9
 
10
10
  const tabContent = {
@@ -1,4 +1,4 @@
1
- import React, { useRef, useState } from 'react';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
2
  import { Button, DatePicker, message, Modal, Select, Space } from 'antd';
3
3
  import ProTable, { ActionType } from '@ant-design/pro-table';
4
4
  import { useNavigate } from 'react-router-dom';
@@ -158,7 +158,11 @@ const ActivitySystemManagement = () => {
158
158
  <Button
159
159
  type="link"
160
160
  size="small"
161
- onClick={() => navigate('/activityCenter/activitySystemManagement/addPages')}
161
+ onClick={() =>
162
+ navigate(
163
+ '/activityCenter/activitySystemManagement/addPages',
164
+ )
165
+ }
162
166
  >
163
167
  添加页面
164
168
  </Button>
package/mock/.gitkeep DELETED
File without changes
@@ -1,101 +0,0 @@
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
- }
@@ -1,272 +0,0 @@
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
- }
@@ -1,43 +0,0 @@
1
- const conditionGroups = [
2
- {
3
- "name": "振动传感器条件组",
4
- "description": "加速度/速度/位移/频率阈值",
5
- "logic": "or",
6
- "alarm_level": "prompt",
7
- "action": "notify",
8
- "conditions": [
9
- {
10
- "field_name": "Acceleration 加速度",
11
- "field_key": "/VibrationSensor/Acceleration",
12
- "field_type": "float",
13
- "operator": ">",
14
- "value": data?.Acceleration,
15
- "unit": ""
16
- },
17
- {
18
- "field_name": "Vibration speed 振动速度",
19
- "field_key": "/VibrationSensor/VibrationSpeed",
20
- "field_type": "float",
21
- "operator": ">",
22
- "value": data?.VibrationSpeed,
23
- "unit": ""
24
- },
25
- {
26
- "field_name": "Vibration displacement 振动位移",
27
- "field_key": "/VibrationSensor/VibrationDisplacement",
28
- "field_type": "float",
29
- "operator": ">",
30
- "value": data?.VibrationDisplacement,
31
- "unit": ""
32
- },
33
- {
34
- "field_name": "Vibration frequency 振动频率",
35
- "field_key": "/VibrationSensor/VibrationFrequency",
36
- "field_type": "float",
37
- "operator": ">",
38
- "value": data?.VibrationFrequency,
39
- "unit": ""
40
- }
41
- ]
42
- }
43
- ]