@lxzy/code-snippet 0.0.8 → 0.0.10

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.
@@ -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
@@ -1,10 +1,10 @@
1
- import React, { useState } from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import { PageContainer } from '@ant-design/pro-layout';
3
3
  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,14 +1,21 @@
1
- import React, { useRef, useState } from 'react';
2
- import { Button, DatePicker, message, Modal, Select, Space } from 'antd';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import {
3
+ Button,
4
+ DatePicker,
5
+ message,
6
+ Modal,
7
+ notification,
8
+ Select,
9
+ Space,
10
+ } from 'antd';
3
11
  import ProTable, { ActionType } from '@ant-design/pro-table';
4
- import { useNavigate } from 'react-router-dom';
5
12
  import axios from 'axios';
6
13
  import AddDrawer from './add';
14
+ import history from '@/umi';
7
15
 
8
16
  const ipTagOptions = ['品牌A', '品牌B', '品牌C', '品牌D'];
9
17
 
10
18
  const ActivitySystemManagement = () => {
11
- const navigate = useNavigate();
12
19
  const actionRef = useRef<ActionType>();
13
20
  const [drawerVisible, setDrawerVisible] = useState(false);
14
21
  const [editingItem, setEditingItem] = useState(null);
@@ -158,7 +165,11 @@ const ActivitySystemManagement = () => {
158
165
  <Button
159
166
  type="link"
160
167
  size="small"
161
- onClick={() => navigate('/activityCenter/activitySystemManagement/addPages')}
168
+ onClick={() =>
169
+ history.push(
170
+ '/activityCenter/activitySystemManagement/addPages',
171
+ )
172
+ }
162
173
  >
163
174
  添加页面
164
175
  </Button>
@@ -0,0 +1,5 @@
1
+ import React, { useState } from 'react';
2
+
3
+ export default function Home() {
4
+ return <div>home</div>;
5
+ }
@@ -0,0 +1,17 @@
1
+ class Dispatcher {
2
+ data = {};
3
+ callbacks = {};
4
+
5
+ update(namespace) {
6
+ if (this.callbacks[namespace]) {
7
+ this.callbacks[namespace].forEach((cb) => cb(this.data[namespace]));
8
+ }
9
+ }
10
+
11
+ setData(namespace, data) {
12
+ this.data[namespace] = data;
13
+ this.update(namespace);
14
+ }
15
+ }
16
+
17
+ export default new Dispatcher();
@@ -0,0 +1,7 @@
1
+ import { createHashHistory } from 'history-with-query';
2
+ import { useModel, ModelProvider } from './useModel';
3
+
4
+ const history = createHashHistory();
5
+
6
+ export { history, useModel, ModelProvider };
7
+ export default history;
@@ -0,0 +1,52 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import dispatcher from './dispatcher';
3
+
4
+ function useModel(namespace) {
5
+ const [state, setState] = useState(() => dispatcher.data[namespace]);
6
+
7
+ useEffect(() => {
8
+ const handler = (data) => setState(data);
9
+ dispatcher.callbacks[namespace] = dispatcher.callbacks[namespace] || [];
10
+ dispatcher.callbacks[namespace].push(handler);
11
+ return () => {
12
+ dispatcher.callbacks[namespace] = dispatcher.callbacks[namespace].filter(
13
+ (h) => h !== handler,
14
+ );
15
+ };
16
+ }, [namespace]);
17
+
18
+ return state;
19
+ }
20
+
21
+ function Executor(props) {
22
+ const { hook, namespace } = props;
23
+ const data = hook();
24
+ useEffect(() => {
25
+ dispatcher.setData(namespace, data);
26
+ }, [data, namespace]);
27
+ return null;
28
+ }
29
+
30
+ function ModelProvider(props) {
31
+ const { children } = props;
32
+ const modules = import.meta.glob('/src/models/**/*.ts', { eager: true });
33
+ const modelList = Object.entries(modules)
34
+ .filter(([path, module]) => {
35
+ return module && module.default;
36
+ })
37
+ .map(([path, module]) => {
38
+ const namespace = path.replace(/^\/src\/models\//, '').replace(/\.ts$/, '');
39
+ return { namespace, hook: module.default };
40
+ });
41
+
42
+ return (
43
+ <>
44
+ {modelList.map(({ namespace, hook }) => (
45
+ <Executor key={namespace} hook={hook} namespace={namespace} />
46
+ ))}
47
+ {children}
48
+ </>
49
+ );
50
+ }
51
+
52
+ export { useModel, ModelProvider };
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
package/tsconfig.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "esnext",
4
- "module": "esnext",
5
- "moduleResolution": "node",
3
+ "module": "ESNext",
4
+ "target": "ESNext",
5
+ "lib": ["DOM", "ESNext", "DOM.Iterable"],
6
+ "moduleResolution": "bundler",
6
7
  "resolveJsonModule": true,
7
8
  "importHelpers": true,
8
9
  "jsx": "react-jsx",
@@ -12,12 +13,13 @@
12
13
  "strict": false,
13
14
  "noImplicitAny": false,
14
15
  "paths": {
15
- "@/*": ["src/*"]
16
+ "@/*": ["src/*"],
17
+ "umi": ["src/umi"]
16
18
  },
17
19
  "allowSyntheticDefaultImports": true,
18
- "skipLibCheck": true,
19
- "types": ["node"]
20
+ "experimentalDecorators": true,
21
+ "emitDecoratorMetadata": true,
22
+ "skipLibCheck": true
20
23
  },
21
- "include": ["mock/**/*", "src/**/*", "typings.d.ts", "vite.*.ts"],
22
- "exclude": ["node_modules", "lib", "es", "dist", "typings"]
24
+ "include": ["mock/**/*", "src/**/*", "routes/**/*", "typings.d.ts", "vite.*.ts"]
23
25
  }
package/vite.config.ts CHANGED
@@ -4,8 +4,14 @@ import { viteMockServe } from 'vite-plugin-mock';
4
4
  import path from 'path';
5
5
 
6
6
  export default defineConfig(({ command }) => ({
7
+ define: {
8
+ 'process.env': {},
9
+ 'process.env.NODE_ENV': JSON.stringify(
10
+ command === 'serve' ? 'development' : 'production',
11
+ ),
12
+ },
7
13
  plugins: [
8
- react(),
14
+ react({}),
9
15
  viteMockServe({
10
16
  mockPath: 'mock',
11
17
  enable: command === 'serve',
@@ -14,6 +20,7 @@ export default defineConfig(({ command }) => ({
14
20
  resolve: {
15
21
  alias: {
16
22
  '@': path.resolve(__dirname, './src'),
23
+ umi: path.resolve(__dirname, './src/umi'),
17
24
  '~antd': path.resolve(__dirname, './node_modules/antd'),
18
25
  },
19
26
  extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'],
@@ -23,10 +30,14 @@ export default defineConfig(({ command }) => ({
23
30
  less: {
24
31
  javascriptEnabled: true,
25
32
  math: 'always',
33
+ modifyVars: {
34
+ '@root-entry-name': 'default',
35
+ },
26
36
  },
27
37
  },
28
38
  },
29
39
  server: {
30
40
  port: 8000,
41
+ open: true,
31
42
  },
32
43
  }));
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
- }