neo-cmp-cli 1.3.6 → 1.3.7

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo-cmp-cli",
3
- "version": "1.3.6",
3
+ "version": "1.3.7",
4
4
  "description": "前端脚手架:自定义组件开发工具,支持react 和 vue2.0技术栈。",
5
5
  "keywords": [
6
6
  "neo-cli",
@@ -37,7 +37,7 @@
37
37
  "url": "https://github.com/wibetter/antd-custom-cmp-template/issues"
38
38
  },
39
39
  "dependencies": {
40
- "neo-register": "^1.0.3",
40
+ "neo-register": "^1.0.5",
41
41
  "antd": "4.9.4",
42
42
  "react": "^16.9.0",
43
43
  "react-dom": "^16.9.0"
@@ -47,7 +47,7 @@
47
47
  "@commitlint/config-conventional": "^9.1.1",
48
48
  "@types/react": "^16.9.11",
49
49
  "@types/react-dom": "^16.9.15",
50
- "neo-cmp-cli": "^1.3.5",
50
+ "neo-cmp-cli": "^1.3.7",
51
51
  "husky": "^4.2.5",
52
52
  "lint-staged": "^10.2.9",
53
53
  "prettier": "^2.0.5"
@@ -37,7 +37,7 @@
37
37
  "url": "https://github.com/wibetter/echarts-custom-cmp-template/issues"
38
38
  },
39
39
  "dependencies": {
40
- "neo-register": "^1.0.3",
40
+ "neo-register": "^1.0.5",
41
41
  "react": "^16.9.0",
42
42
  "react-dom": "^16.9.0",
43
43
  "echarts": "^5.5.1"
@@ -47,7 +47,7 @@
47
47
  "@commitlint/config-conventional": "^9.1.1",
48
48
  "@types/react": "^16.9.11",
49
49
  "@types/react-dom": "^16.9.15",
50
- "neo-cmp-cli": "^1.3.5",
50
+ "neo-cmp-cli": "^1.3.7",
51
51
  "husky": "^4.2.5",
52
52
  "lint-staged": "^10.2.9",
53
53
  "prettier": "^2.0.5",
@@ -38,7 +38,7 @@
38
38
  "url": "https://github.com/wibetter/neo-custom-cmp-template/issues"
39
39
  },
40
40
  "dependencies": {
41
- "neo-register": "^1.0.3",
41
+ "neo-register": "^1.0.5",
42
42
  "react": "^16.9.0",
43
43
  "react-dom": "^16.9.0",
44
44
  "axios": "^0.27.2",
@@ -52,7 +52,7 @@
52
52
  "@types/react": "^16.9.11",
53
53
  "@types/react-dom": "^16.9.15",
54
54
  "@types/axios": "^0.14.0",
55
- "neo-cmp-cli": "^1.3.5",
55
+ "neo-cmp-cli": "^1.3.7",
56
56
  "husky": "^4.2.5",
57
57
  "lint-staged": "^10.2.9",
58
58
  "prettier": "^2.0.5"
@@ -0,0 +1 @@
1
+ <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1760606213824" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2396" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M258.133333 128A106.666667 106.666667 0 0 0 362.666667 213.333333h298.666666a106.666667 106.666667 0 0 0 104.533334-85.333333h87.424A128 128 0 0 1 981.333333 255.744v597.845333A127.872 127.872 0 0 1 853.290667 981.333333H170.666667A128 128 0 0 1 42.666667 853.589333V255.744A127.872 127.872 0 0 1 170.709333 128H258.133333zM298.666667 384a42.666667 42.666667 0 1 0 0 85.333333h256a42.666667 42.666667 0 0 0 0-85.333333H298.666667z m0 170.666667a42.666667 42.666667 0 0 0 0 85.333333h426.666666a42.666667 42.666667 0 0 0 0-85.333333H298.666667z m0 170.666666a42.666667 42.666667 0 0 0 0 85.333334h256a42.666667 42.666667 0 0 0 0-85.333334H298.666667zM362.666667 42.666667h298.666666a64 64 0 0 1 0 128h-298.666666a64 64 0 0 1 0-128z" p-id="2397" fill="#0764f5"></path></svg>
@@ -0,0 +1 @@
1
+ <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1759212323849" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3505" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M202.8 408.1c-55 0-99.7 44.7-99.7 99.7s44.7 99.7 99.7 99.7c40.7 0 75.8-24.6 91.3-59.7h639v-80h-639c-15.5-35.1-50.6-59.7-91.3-59.7z m0 157c-31.6 0-57.3-25.7-57.3-57.3 0-31.6 25.7-57.3 57.3-57.3 31.6 0 57.3 25.7 57.3 57.3 0 31.6-25.7 57.3-57.3 57.3zM202.8 739.3c-55 0-99.7 44.7-99.7 99.7s44.7 99.7 99.7 99.7c40.7 0 75.8-24.6 91.3-59.7h639v-80h-639c-15.5-35.1-50.6-59.7-91.3-59.7z m0 157c-31.6 0-57.3-25.7-57.3-57.3 0-31.6 25.7-57.3 57.3-57.3 31.6 0 57.3 25.7 57.3 57.3 0 31.6-25.7 57.3-57.3 57.3zM295.1 149.5c-14.9-36.4-50.6-62.1-92.3-62.1-55 0-99.7 44.7-99.7 99.7s44.7 99.7 99.7 99.7c39.8 0 74.2-23.5 90.2-57.3h640v-80H295.1z m-92.3 95c-31.6 0-57.3-25.7-57.3-57.3 0-31.6 25.7-57.3 57.3-57.3 31.6 0 57.3 25.7 57.3 57.3 0 31.5-25.7 57.3-57.3 57.3zM519.6 641.8H933v80H519.6zM519.6 308.6H933v80H519.6z" fill="#0764f5" p-id="3506"></path></svg>
@@ -37,14 +37,14 @@
37
37
  "url": "https://github.com/wibetter/react-custom-cmp-template/issues"
38
38
  },
39
39
  "dependencies": {
40
- "neo-register": "^1.0.3",
40
+ "neo-register": "^1.0.5",
41
41
  "react": "^16.9.0",
42
42
  "react-dom": "^16.9.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@commitlint/cli": "^8.3.5",
46
46
  "@commitlint/config-conventional": "^9.1.1",
47
- "neo-cmp-cli": "^1.3.5",
47
+ "neo-cmp-cli": "^1.3.7",
48
48
  "husky": "^4.2.5",
49
49
  "lint-staged": "^10.2.9",
50
50
  "prettier": "^2.0.5"
@@ -37,7 +37,7 @@
37
37
  "url": "https://github.com/wibetter/react-ts-custom-cmp-template/issues"
38
38
  },
39
39
  "dependencies": {
40
- "neo-register": "^1.0.3",
40
+ "neo-register": "^1.0.5",
41
41
  "react": "^16.9.0",
42
42
  "react-dom": "^16.9.0"
43
43
  },
@@ -46,7 +46,7 @@
46
46
  "@commitlint/config-conventional": "^9.1.1",
47
47
  "@types/react": "^16.9.11",
48
48
  "@types/react-dom": "^16.9.15",
49
- "neo-cmp-cli": "^1.3.5",
49
+ "neo-cmp-cli": "^1.3.7",
50
50
  "husky": "^4.2.5",
51
51
  "lint-staged": "^10.2.9",
52
52
  "prettier": "^2.0.5"
@@ -0,0 +1 @@
1
+ <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1760670196857" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4651" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M485.888 626.496 512 663.488l26.112-36.992c1.088-1.472 107.392-151.68 140.864-189.184C715.776 396.224 736 343.168 736 288 736 164.544 635.52 64 512 64s-224 100.48-224 224c0 55.232 20.224 108.288 57.088 149.376C378.624 474.816 484.8 625.024 485.888 626.496zM512 128c88.256 0 160 71.808 160 160 0 39.424-14.464 77.312-40.768 106.688C606.016 422.912 546.624 504.64 512 552.896 477.44 504.64 418.048 422.912 392.768 394.688 366.528 365.376 352 327.488 352 288 352 199.808 423.744 128 512 128zM512 384c52.928 0 96-43.072 96-96S564.928 192 512 192 416 235.072 416 288 459.072 384 512 384zM512 256c17.6 0 32 14.336 32 32S529.6 320 512 320 480 305.664 480 288 494.4 256 512 256zM960 129.024l0 703.168L680 960 384 832l-320 127.36L64 258.176l168.256-67.904C227.264 211.456 224 233.28 224 256c0 2.176 0.512 4.224 0.576 6.4L128 301.376l0 563.648 192-76.416L320 476.032c18.048 23.36 41.472 55.104 64 86.144l0 200.96 1.024-0.384 24.384 10.56L640 872.96 640 562.304c22.976-31.616 46.208-63.168 64-86.144l0 402.56 192-87.68L896 228.608l-97.536 44.544C798.784 267.392 800 261.76 800 256c0-17.664-2.176-34.752-5.184-51.584L960 129.024z" p-id="4652" fill="#0764f5"></path></svg>
@@ -0,0 +1,125 @@
1
+ # 地图展示组件
2
+
3
+ 地图展示组件,支持传入地理坐标或位置名称来展示地图区域,并标注当前位置。
4
+
5
+ ## 功能特性
6
+
7
+ - ✅ 支持通过经纬度坐标定位
8
+ - ✅ 支持通过地址名称定位(自动地理编码)
9
+ - ✅ 支持自定义缩放级别
10
+ - ✅ 支持自定义标记点标题
11
+ - ✅ 支持点击标记查看详细地址
12
+ - ✅ 支持自定义地图高度
13
+ - ✅ 响应式设计,适配移动端
14
+ - ✅ 优雅的加载和错误状态提示
15
+
16
+ ## 使用方式
17
+
18
+ ### 1. 通过经纬度定位
19
+
20
+ ```tsx
21
+ <MapWidget
22
+ longitude={116.397428}
23
+ latitude={39.90923}
24
+ markerTitle="北京天安门"
25
+ zoom={15}
26
+ height={400}
27
+ />
28
+ ```
29
+
30
+ ### 2. 通过地址名称定位
31
+
32
+ ```tsx
33
+ <MapWidget
34
+ locationName="北京市天安门广场"
35
+ markerTitle="天安门广场"
36
+ zoom={15}
37
+ height={400}
38
+ />
39
+ ```
40
+
41
+ ## 属性说明
42
+
43
+ | 属性名 | 类型 | 默认值 | 说明 |
44
+ |--------|------|--------|------|
45
+ | longitude | number | 116.397428 | 经度(-180 到 180)|
46
+ | latitude | number | 39.90923 | 纬度(-90 到 90)|
47
+ | locationName | string | - | 位置名称(优先级高于经纬度)|
48
+ | zoom | number | 14 | 地图缩放级别(3-18)|
49
+ | markerTitle | string | '当前位置' | 标记点标题 |
50
+ | height | number | 400 | 地图容器高度(像素)|
51
+
52
+ ## 注意事项
53
+
54
+ 1. **地图脚本配置**:
55
+ - 当前使用的是企业内部部署的高德地图脚本:`https://neors.ingageapp.com/base/js/amap_2.0.5.21.js`
56
+ - 参考了 `neo-ui-component-web` 项目的实现方式
57
+ - 如需使用高德官方 API,可以:
58
+ - 前往[高德开放平台](https://lbs.amap.com/)申请 Web 端 API Key
59
+ - 在 `index.tsx` 的 `loadAMapScript` 方法中取消注释备用方案代码
60
+ - 替换 `amapKey` 为你的 API Key
61
+
62
+ 2. **定位方式优先级**:
63
+ - 如果同时提供了 `locationName` 和经纬度,优先使用 `locationName`
64
+ - 如果都未提供,默认显示北京天安门位置
65
+
66
+ 3. **地理编码说明**:
67
+ - 使用 `locationName` 时,会自动调用高德地图的地理编码服务
68
+ - 建议提供完整的地址信息以提高解析准确度
69
+ - 地理编码仅支持中国大陆地区
70
+
71
+ 4. **性能优化**:
72
+ - 地图脚本采用动态加载方式,不会影响页面初始加载速度
73
+ - 地图实例在组件销毁时会自动清理,避免内存泄漏
74
+ - 已加载的脚本会被缓存,重复使用不会重复加载
75
+
76
+ ## 示例场景
77
+
78
+ ### 场景1:展示公司地址
79
+ ```tsx
80
+ <MapWidget
81
+ locationName="上海市浦东新区世纪大道XXX号"
82
+ markerTitle="公司总部"
83
+ zoom={16}
84
+ height={500}
85
+ />
86
+ ```
87
+
88
+ ### 场景2:展示多个城市坐标
89
+ ```tsx
90
+ // 北京
91
+ <MapWidget longitude={116.397428} latitude={39.90923} markerTitle="北京" />
92
+
93
+ // 上海
94
+ <MapWidget longitude={121.473701} latitude={31.230416} markerTitle="上海" />
95
+
96
+ // 深圳
97
+ <MapWidget longitude={114.057868} latitude={22.543099} markerTitle="深圳" />
98
+ ```
99
+
100
+ ### 场景3:移动端展示
101
+ 组件已自动适配移动端,会根据屏幕尺寸调整样式和布局。
102
+
103
+ ## 技术实现
104
+
105
+ - 基于高德地图 Web API 2.0
106
+ - 使用 React Class Component
107
+ - TypeScript 类型支持
108
+ - SCSS 样式预处理
109
+ - 动态脚本加载
110
+
111
+ ## 浏览器兼容性
112
+
113
+ - Chrome >= 60
114
+ - Firefox >= 60
115
+ - Safari >= 11
116
+ - Edge >= 79
117
+
118
+ ## 更新日志
119
+
120
+ ### v1.0.0 (2025-10-17)
121
+ - ✨ 初始版本发布
122
+ - ✨ 支持经纬度和地址名称定位
123
+ - ✨ 支持标记点和信息窗体
124
+ - ✨ 响应式设计
125
+
@@ -0,0 +1,190 @@
1
+ # 地图组件快速使用指南
2
+
3
+ ## 快速开始
4
+
5
+ ### 1. 基本使用(经纬度定位)
6
+
7
+ ```tsx
8
+ import MapWidget from './components/map-widget';
9
+
10
+ // 在你的页面或组件中使用
11
+ <MapWidget
12
+ longitude={116.397428}
13
+ latitude={39.90923}
14
+ markerTitle="北京天安门"
15
+ zoom={15}
16
+ height={400}
17
+ />
18
+ ```
19
+
20
+ ### 2. 使用地址名称定位
21
+
22
+ ```tsx
23
+ <MapWidget
24
+ locationName="北京市天安门广场"
25
+ markerTitle="天安门广场"
26
+ zoom={15}
27
+ height={500}
28
+ />
29
+ ```
30
+
31
+ ### 3. 在 Neo 平台中使用
32
+
33
+ 在 Neo 低代码平台的页面编辑器中:
34
+
35
+ 1. 从左侧组件面板找到「地图组件」
36
+ 2. 拖拽到页面中
37
+ 3. 在右侧属性面板配置:
38
+ - **位置名称**:输入地址(如"上海市浦东新区世纪大道")
39
+ - **或使用经纬度**:
40
+ - 经度:如 121.473701
41
+ - 纬度:如 31.230416
42
+ - **标记点标题**:设置标记点显示的文字
43
+ - **缩放级别**:3-18,推荐 14-16
44
+ - **地图高度**:默认 400px,可自定义
45
+
46
+ ## 常用城市坐标
47
+
48
+ | 城市 | 经度 | 纬度 |
49
+ |------|------|------|
50
+ | 北京 | 116.397428 | 39.90923 |
51
+ | 上海 | 121.473701 | 31.230416 |
52
+ | 广州 | 113.264385 | 23.129112 |
53
+ | 深圳 | 114.057868 | 22.543099 |
54
+ | 杭州 | 120.155070 | 30.274084 |
55
+ | 成都 | 104.065735 | 30.659462 |
56
+ | 西安 | 108.948024 | 34.263161 |
57
+ | 武汉 | 114.298572 | 30.584355 |
58
+ | 南京 | 118.767413 | 32.041544 |
59
+ | 重庆 | 106.504962 | 29.533155 |
60
+
61
+ ## 配置说明
62
+
63
+ ### 优先级规则
64
+
65
+ 1. 如果同时设置了「位置名称」和「经纬度」,优先使用「位置名称」
66
+ 2. 如果都未设置,默认显示北京天安门
67
+
68
+ ### 地址搜索提示
69
+
70
+ 使用「位置名称」进行定位时,建议提供完整地址以提高准确度:
71
+
72
+ ✅ **好的示例**:
73
+ - "北京市朝阳区建国门外大街1号"
74
+ - "上海市浦东新区世纪大道88号"
75
+ - "广州市天河区珠江新城花城大道"
76
+
77
+ ❌ **不好的示例**:
78
+ - "建国门" (太模糊)
79
+ - "天河" (太宽泛)
80
+ - "世纪大道" (没有城市信息)
81
+
82
+ ### 缩放级别参考
83
+
84
+ - **3-7**:省级/国家级视图
85
+ - **8-11**:城市级视图
86
+ - **12-14**:区县级视图(默认)
87
+ - **15-16**:街道级视图
88
+ - **17-18**:建筑物级视图
89
+
90
+ ## 常见问题
91
+
92
+ ### Q1: 地图无法显示?
93
+
94
+ **可能原因**:
95
+ 1. 网络连接问题
96
+ 2. 地图脚本加载失败
97
+ 3. 提供的地址无法解析
98
+
99
+ **解决方案**:
100
+ - 检查网络连接
101
+ - 查看浏览器控制台错误信息
102
+ - 尝试使用经纬度而不是地址名称
103
+ - 确认地址格式正确
104
+
105
+ ### Q2: 地址定位不准确?
106
+
107
+ **解决方案**:
108
+ - 提供更完整的地址信息
109
+ - 包含省市区县信息
110
+ - 使用标准地址格式
111
+ - 或直接使用经纬度坐标
112
+
113
+ ### Q3: 如何获取某个地点的经纬度?
114
+
115
+ **方法**:
116
+ 1. 访问 [高德地图坐标拾取器](https://lbs.amap.com/tools/picker)
117
+ 2. 搜索或点击地图上的位置
118
+ 3. 复制显示的经纬度坐标
119
+ 4. 注意:高德地图的顺序是 [经度, 纬度]
120
+
121
+ ### Q4: 支持国外地址吗?
122
+
123
+ **说明**:
124
+ - 当前使用高德地图,主要支持中国大陆地区
125
+ - 国外地址可能无法准确定位
126
+ - 如需支持国外地址,需要切换到谷歌地图或其他国际地图服务
127
+
128
+ ## 进阶使用
129
+
130
+ ### 动态更新位置
131
+
132
+ 如果需要根据用户输入或数据动态更新地图位置,可以通过修改组件的 props 来实现:
133
+
134
+ ```tsx
135
+ class MyPage extends React.Component {
136
+ state = {
137
+ longitude: 116.397428,
138
+ latitude: 39.90923,
139
+ };
140
+
141
+ updateLocation = (lng, lat) => {
142
+ this.setState({
143
+ longitude: lng,
144
+ latitude: lat,
145
+ });
146
+ };
147
+
148
+ render() {
149
+ return (
150
+ <div>
151
+ <button onClick={() => this.updateLocation(121.473701, 31.230416)}>
152
+ 定位到上海
153
+ </button>
154
+ <MapWidget
155
+ longitude={this.state.longitude}
156
+ latitude={this.state.latitude}
157
+ markerTitle="当前位置"
158
+ zoom={15}
159
+ />
160
+ </div>
161
+ );
162
+ }
163
+ }
164
+ ```
165
+
166
+ ### 自定义地图样式
167
+
168
+ 如果需要自定义地图的外观,可以修改 `style.scss` 文件:
169
+
170
+ ```scss
171
+ // 修改标题栏颜色
172
+ .map-widget-header {
173
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
174
+ // 改为你喜欢的颜色
175
+ }
176
+
177
+ // 修改信息窗体样式
178
+ .map-info-window {
179
+ padding: 12px;
180
+ // 自定义样式
181
+ }
182
+ ```
183
+
184
+ ## 技术支持
185
+
186
+ 如有问题,请参考:
187
+ - [高德地图 Web API 文档](https://lbs.amap.com/api/javascript-api/summary)
188
+ - [React 组件开发文档](https://react.docschina.org/)
189
+ - [TypeScript 手册](https://www.typescriptlang.org/docs/)
190
+
@@ -0,0 +1,347 @@
1
+ import * as React from 'react';
2
+ import './style.scss';
3
+
4
+ // 扩展 Window 接口以支持 AMap
5
+ declare global {
6
+ interface Window {
7
+ AMap: any;
8
+ }
9
+ }
10
+
11
+ interface MapWidgetProps {
12
+ // 经度
13
+ longitude?: number;
14
+ // 纬度
15
+ latitude?: number;
16
+ // 位置名称(支持地址搜索)
17
+ locationName?: string;
18
+ // 地图缩放级别 (3-18)
19
+ zoom?: number;
20
+ // 标记点标题
21
+ markerTitle?: string;
22
+ // 地图高度
23
+ height?: number;
24
+ data?: any;
25
+ }
26
+
27
+ interface MapWidgetState {
28
+ isLoading: boolean;
29
+ error?: string;
30
+ currentAddress?: string;
31
+ }
32
+
33
+ /**
34
+ * 地图展示组件
35
+ * 支持传入经纬度坐标或位置名称,展示对应的地图区域并标注当前位置
36
+ * 基于高德地图API实现
37
+ */
38
+ export default class MapWidget extends React.PureComponent<
39
+ MapWidgetProps,
40
+ MapWidgetState
41
+ > {
42
+ private map: any = null;
43
+
44
+ private AMap: any = null;
45
+
46
+ private marker: any = null;
47
+
48
+ private mapContainer: string = 'map-widget-container';
49
+
50
+ constructor(props: MapWidgetProps) {
51
+ super(props);
52
+ this.state = {
53
+ isLoading: true,
54
+ error: undefined,
55
+ currentAddress: '',
56
+ };
57
+ }
58
+
59
+ componentDidMount() {
60
+ this.loadAMapScript();
61
+ }
62
+
63
+ componentDidUpdate(
64
+ prevProps: Readonly<MapWidgetProps>,
65
+ prevState: Readonly<MapWidgetState>,
66
+ snapshot?: any,
67
+ ): void {
68
+ const { longitude, latitude, locationName, zoom = 14 } = this.props;
69
+ const {
70
+ longitude: prevLongitude,
71
+ latitude: prevLatitude,
72
+ locationName: prevLocationName,
73
+ zoom: prevZoom = 14,
74
+ } = prevProps;
75
+ if (
76
+ longitude !== prevLongitude ||
77
+ latitude !== prevLatitude ||
78
+ locationName !== prevLocationName ||
79
+ zoom !== prevZoom
80
+ ) {
81
+ this.initMap();
82
+ }
83
+ }
84
+
85
+ componentWillUnmount() {
86
+ if (this.map) {
87
+ this.map.destroy();
88
+ this.map = null;
89
+ }
90
+ }
91
+
92
+ /**
93
+ * 动态加载高德地图脚本
94
+ */
95
+ loadAMapScript = () => {
96
+ // 检查是否已加载
97
+ if (window.AMap) {
98
+ this.AMap = window.AMap;
99
+ this.initMap();
100
+ return;
101
+ }
102
+
103
+ // 使用 NeoCRM 部署的高德地图脚本: 使用企业内部部署的高德地图脚本,无需单独申请 API Key
104
+ const scriptUrl = 'https://neors.ingageapp.com/base/js/amap_2.0.5.21.js';
105
+ // 备用方案:使用高德官方API(需要申请key)
106
+ // const amapKey = 'your-amap-key-here';
107
+ // const scriptUrl = `https://webapi.amap.com/maps?v=2.0&key=${amapKey}&plugin=AMap.Geocoder,AMap.Marker`;
108
+
109
+ const script = document.createElement('script');
110
+ script.type = 'text/javascript';
111
+ script.src = scriptUrl;
112
+ script.async = true;
113
+
114
+ script.onload = () => {
115
+ this.AMap = window.AMap;
116
+ this.initMap();
117
+ };
118
+
119
+ script.onerror = () => {
120
+ this.setState({
121
+ isLoading: false,
122
+ error: '地图加载失败,请检查网络连接或配置地图API Key',
123
+ });
124
+ };
125
+
126
+ document.head.appendChild(script);
127
+ };
128
+
129
+ /**
130
+ * 初始化地图
131
+ */
132
+ initMap = () => {
133
+ const { longitude, latitude, locationName, zoom = 14 } = this.props;
134
+
135
+ // 如果提供了位置名称,先进行地理编码
136
+ if (locationName) {
137
+ this.geocodeAddress(locationName, zoom);
138
+ }
139
+ // 如果提供了经纬度,直接初始化地图
140
+ else if (longitude !== undefined && latitude !== undefined) {
141
+ this.createMap([longitude, latitude], zoom);
142
+ }
143
+ // 默认显示北京天安门
144
+ else {
145
+ this.createMap([116.397428, 39.90923], zoom);
146
+ }
147
+ };
148
+
149
+ /**
150
+ * 地理编码:先将地址转换为经纬度,再创建地图
151
+ */
152
+ geocodeAddress = (address: string, zoom: number) => {
153
+ if (!this.AMap) {
154
+ return;
155
+ }
156
+
157
+ // 动态加载 Geocoder 插件
158
+ this.AMap.plugin('AMap.Geocoder', () => {
159
+ const geocoder = new this.AMap.Geocoder();
160
+
161
+ geocoder.getLocation(address, (status: string, result: any) => {
162
+ if (status === 'complete' && result.geocodes.length > 0) {
163
+ const location = result.geocodes[0].location;
164
+ this.createMap([location.lng, location.lat], zoom);
165
+ this.setState({
166
+ currentAddress: result.geocodes[0].formattedAddress,
167
+ });
168
+ } else {
169
+ this.setState({
170
+ isLoading: false,
171
+ error: `地址解析失败: ${address}`,
172
+ });
173
+ // 使用默认位置
174
+ this.createMap([116.397428, 39.90923], zoom);
175
+ }
176
+ });
177
+ });
178
+ };
179
+
180
+ /**
181
+ * 创建地图实例
182
+ */
183
+ createMap = (center: [number, number], zoom: number) => {
184
+ if (!this.AMap) {
185
+ return;
186
+ }
187
+
188
+ try {
189
+ // 创建地图实例
190
+ this.map = new this.AMap.Map(this.mapContainer, {
191
+ zoom,
192
+ center,
193
+ resizeEnable: true,
194
+ viewMode: '2D',
195
+ });
196
+
197
+ // 添加标记点
198
+ this.addMarker(center);
199
+
200
+ // 获取当前位置的地址信息
201
+ this.getAddressByLocation(center);
202
+
203
+ this.setState({
204
+ isLoading: false,
205
+ });
206
+ } catch (error) {
207
+ console.log('地图初始化失败 / error:', error);
208
+ this.setState({
209
+ isLoading: false,
210
+ error: '地图初始化失败',
211
+ });
212
+ }
213
+ };
214
+
215
+ /**
216
+ * 添加标记点
217
+ */
218
+ addMarker = (position: [number, number]) => {
219
+ if (!this.AMap || !this.map) {
220
+ return;
221
+ }
222
+
223
+ const { markerTitle } = this.props;
224
+
225
+ // 移除已存在的标记
226
+ if (this.marker) {
227
+ this.map.remove(this.marker);
228
+ }
229
+
230
+ // 创建自定义红色图标
231
+ const redIcon = new this.AMap.Icon({
232
+ size: new this.AMap.Size(50, 68),
233
+ image:
234
+ '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-red.png',
235
+ imageSize: new this.AMap.Size(50, 68),
236
+ });
237
+
238
+ // 创建标记点(红色)
239
+ this.marker = new this.AMap.Marker({
240
+ position,
241
+ title: markerTitle || '当前位置',
242
+ map: this.map,
243
+ anchor: 'bottom-center',
244
+ icon: redIcon,
245
+ });
246
+
247
+ // 点击标记显示信息窗体
248
+ this.marker.on('click', () => {
249
+ const infoWindow = new this.AMap.InfoWindow({
250
+ content: `<div class="map-info-window">
251
+ <div class="info-title">${markerTitle || '当前位置'}</div>
252
+ <div class="info-address">${
253
+ this.state.currentAddress || '正在获取地址...'
254
+ }</div>
255
+ </div>`,
256
+ offset: new this.AMap.Pixel(0, -30),
257
+ });
258
+ infoWindow.open(this.map, position);
259
+ });
260
+ };
261
+
262
+ /**
263
+ * 逆地理编码:根据经纬度获取地址信息
264
+ */
265
+ getAddressByLocation = (location: [number, number]) => {
266
+ if (!this.AMap) {
267
+ return;
268
+ }
269
+
270
+ // 动态加载 Geocoder 插件
271
+ this.AMap.plugin('AMap.Geocoder', () => {
272
+ const geocoder = new this.AMap.Geocoder();
273
+
274
+ geocoder.getAddress(location, (status: string, result: any) => {
275
+ if (status === 'complete' && result.regeocode) {
276
+ this.setState({
277
+ currentAddress: result.regeocode.formattedAddress,
278
+ });
279
+ }
280
+ });
281
+ });
282
+ };
283
+
284
+ render() {
285
+ const { height = 400, data } = this.props;
286
+ const { isLoading, error } = this.state;
287
+
288
+ const curAmisData = data || {};
289
+ const systemInfo = curAmisData.__NeoSystemInfo || {};
290
+
291
+ console.log('this.props:', this.props);
292
+
293
+ return (
294
+ <div className="map-widget-wrapper">
295
+ {/*
296
+ // 地图头部: 显示地图标题和当前位置地址
297
+ <div className="map-widget-header">
298
+ <h3 className="map-widget-title">
299
+ 地图展示
300
+ {systemInfo.tenantName ? `【${systemInfo.tenantName}】` : ''}
301
+ </h3>
302
+ {this.state.currentAddress && (
303
+ <div className="map-widget-address">
304
+ <span className="address-icon">📍</span>
305
+ <span className="address-text">{this.state.currentAddress}</span>
306
+ </div>
307
+ )}
308
+ </div>
309
+ */}
310
+ <div className="map-widget-container-wrapper" style={{ height }}>
311
+ {isLoading && (
312
+ <div className="map-loading">
313
+ <div className="loading-spinner"></div>
314
+ <div className="loading-text">地图加载中...</div>
315
+ </div>
316
+ )}
317
+
318
+ {error && (
319
+ <div className="map-error">
320
+ <div className="error-icon">⚠️</div>
321
+ <div className="error-text">{error}</div>
322
+ </div>
323
+ )}
324
+
325
+ <div
326
+ id={this.mapContainer}
327
+ className="map-widget-container"
328
+ style={{ display: isLoading || error ? 'none' : 'block' }}
329
+ ></div>
330
+ </div>
331
+
332
+ <div className="map-widget-footer">
333
+ <div className="map-info">
334
+ <span className="info-label">经度:</span>
335
+ <span className="info-value">{this.props.longitude || '-'}</span>
336
+ <span className="info-separator">|</span>
337
+ <span className="info-label">纬度:</span>
338
+ <span className="info-value">{this.props.latitude || '-'}</span>
339
+ <span className="info-separator">|</span>
340
+ <span className="info-label">缩放:</span>
341
+ <span className="info-value">{this.props.zoom || 14}</span>
342
+ </div>
343
+ </div>
344
+ </div>
345
+ );
346
+ }
347
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * @file 地图组件对接编辑器的描述文件
3
+ */
4
+ export class MapWidgetModel {
5
+ /**
6
+ * cmpType 为自定义组件名称,用于标识组件的唯一性
7
+ * 在构建时根据当前组件目录名称自动生成
8
+ */
9
+ // cmpType: string = 'map-widget';
10
+
11
+ // 组件名称,用于设置在编辑器左侧组件面板中展示的名称
12
+ label: string = '地图组件';
13
+
14
+ // 组件描述,用于设置在编辑器左侧组件面板中展示的描述
15
+ description: string = '地图展示组件,支持传入经纬度或地址名称';
16
+
17
+ // 分类标签,用于设置在编辑器左侧组件面板哪个分类中展示(可设置多个分类标签)
18
+ tags: string[] = ['自定义组件'];
19
+
20
+ // 组件图标,用于设置在编辑器左侧组件面板中展示的图标
21
+ iconSrc: string = 'https://custom-widgets.bj.bcebos.com/map.svg';
22
+
23
+ // 初次插入页面的默认属性数据
24
+ defaultComProps = {
25
+ label: '地图组件',
26
+ // longitude: 116.397428, // 北京天安门经度
27
+ // latitude: 39.90923, // 北京天安门纬度
28
+ locationName: '北京市天安门广场', // 位置名称(可选)
29
+ zoom: 14, // 缩放级别
30
+ markerTitle: '当前位置', // 标记点标题
31
+ height: 400, // 地图高度
32
+ };
33
+
34
+ // 设计器端预览时展示的默认数据
35
+ previewComProps = {
36
+ label: '地图组件',
37
+ };
38
+
39
+ /**
40
+ * 组件面板配置,用于生成编辑器右侧属性配置面板内容
41
+ */
42
+ propsSchema = [
43
+ {
44
+ type: 'text',
45
+ name: 'locationName',
46
+ label: '位置名称',
47
+ placeholder: '例如:北京市天安门广场',
48
+ description: '输入地址名称自动定位(优先级高于经纬度)',
49
+ },
50
+ {
51
+ type: 'number',
52
+ name: 'longitude',
53
+ label: '经度',
54
+ // value: 116.397428,
55
+ min: -180,
56
+ max: 180,
57
+ step: 0.000001,
58
+ precision: 6,
59
+ },
60
+ {
61
+ type: 'number',
62
+ name: 'latitude',
63
+ label: '纬度',
64
+ // value: 39.90923,
65
+ min: -90,
66
+ max: 90,
67
+ step: 0.000001,
68
+ precision: 6,
69
+ },
70
+ {
71
+ type: 'text',
72
+ name: 'markerTitle',
73
+ label: '标记点标题',
74
+ value: '当前位置',
75
+ },
76
+ {
77
+ type: 'number',
78
+ name: 'zoom',
79
+ label: '缩放级别',
80
+ value: 14,
81
+ min: 3,
82
+ max: 18,
83
+ description: '地图缩放级别,3-18之间,数值越大越详细',
84
+ },
85
+ {
86
+ type: 'number',
87
+ name: 'height',
88
+ label: '地图高度',
89
+ value: 400,
90
+ min: 200,
91
+ max: 800,
92
+ step: 50,
93
+ description: '地图容器的高度(像素)',
94
+ },
95
+ ];
96
+
97
+ // 支持 函数式写法:propsSchemaCreator,com 为组件实例。优先级比 propsSchema 高
98
+ /*
99
+ propsSchemaCreator = (com: any) => {
100
+ return [];
101
+ };
102
+ */
103
+ }
104
+
105
+ export default MapWidgetModel;
@@ -0,0 +1,192 @@
1
+ // 地图组件样式文件
2
+ .map-widget-wrapper {
3
+ width: 100%;
4
+ background: #fff;
5
+ border-radius: 8px;
6
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
7
+ overflow: hidden;
8
+
9
+ .map-widget-header {
10
+ padding: 16px 20px;
11
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
12
+ color: #fff;
13
+
14
+ .map-widget-title {
15
+ margin: 0 0 8px 0;
16
+ font-size: 18px;
17
+ font-weight: 600;
18
+ }
19
+
20
+ .map-widget-address {
21
+ display: flex;
22
+ align-items: center;
23
+ font-size: 14px;
24
+ opacity: 0.95;
25
+
26
+ .address-icon {
27
+ margin-right: 6px;
28
+ font-size: 16px;
29
+ }
30
+
31
+ .address-text {
32
+ flex: 1;
33
+ overflow: hidden;
34
+ text-overflow: ellipsis;
35
+ white-space: nowrap;
36
+ }
37
+ }
38
+ }
39
+
40
+ .map-widget-container-wrapper {
41
+ position: relative;
42
+ background: #f5f5f5;
43
+
44
+ .map-widget-container {
45
+ width: 100%;
46
+ height: 100%;
47
+ }
48
+
49
+ .map-loading {
50
+ display: flex;
51
+ flex-direction: column;
52
+ align-items: center;
53
+ justify-content: center;
54
+ height: 100%;
55
+ background: #fafafa;
56
+
57
+ .loading-spinner {
58
+ width: 40px;
59
+ height: 40px;
60
+ border: 4px solid #e0e0e0;
61
+ border-top-color: #667eea;
62
+ border-radius: 50%;
63
+ animation: spin 1s linear infinite;
64
+ }
65
+
66
+ .loading-text {
67
+ margin-top: 16px;
68
+ color: #666;
69
+ font-size: 14px;
70
+ }
71
+ }
72
+
73
+ .map-error {
74
+ display: flex;
75
+ flex-direction: column;
76
+ align-items: center;
77
+ justify-content: center;
78
+ height: 100%;
79
+ background: #fff5f5;
80
+
81
+ .error-icon {
82
+ font-size: 48px;
83
+ margin-bottom: 16px;
84
+ }
85
+
86
+ .error-text {
87
+ color: #f56c6c;
88
+ font-size: 14px;
89
+ text-align: center;
90
+ padding: 0 20px;
91
+ }
92
+ }
93
+ }
94
+
95
+ .map-widget-footer {
96
+ padding: 12px 20px;
97
+ background: #fafafa;
98
+ border-top: 1px solid #e8e8e8;
99
+
100
+ .map-info {
101
+ display: flex;
102
+ align-items: center;
103
+ justify-content: center;
104
+ font-size: 12px;
105
+ color: #666;
106
+
107
+ .info-label {
108
+ color: #999;
109
+ margin-right: 4px;
110
+ }
111
+
112
+ .info-value {
113
+ color: #333;
114
+ font-weight: 500;
115
+ }
116
+
117
+ .info-separator {
118
+ margin: 0 12px;
119
+ color: #d9d9d9;
120
+ }
121
+ }
122
+ }
123
+
124
+ // 信息窗体样式
125
+ .map-info-window {
126
+ padding: 12px;
127
+ min-width: 200px;
128
+
129
+ .info-title {
130
+ font-size: 14px;
131
+ font-weight: 600;
132
+ color: #333;
133
+ margin-bottom: 8px;
134
+ }
135
+
136
+ .info-address {
137
+ font-size: 12px;
138
+ color: #666;
139
+ line-height: 1.5;
140
+ }
141
+ }
142
+ }
143
+
144
+ // 加载动画
145
+ @keyframes spin {
146
+ 0% {
147
+ transform: rotate(0deg);
148
+ }
149
+ 100% {
150
+ transform: rotate(360deg);
151
+ }
152
+ }
153
+
154
+ // 响应式适配
155
+ @media (max-width: 768px) {
156
+ .map-widget-wrapper {
157
+ .map-widget-header {
158
+ padding: 12px 16px;
159
+
160
+ .map-widget-title {
161
+ font-size: 16px;
162
+ }
163
+
164
+ .map-widget-address {
165
+ font-size: 12px;
166
+ }
167
+ }
168
+
169
+ .map-widget-footer {
170
+ padding: 10px 16px;
171
+
172
+ .map-info {
173
+ font-size: 11px;
174
+
175
+ .info-separator {
176
+ margin: 0 8px;
177
+ }
178
+ }
179
+ }
180
+ }
181
+ }
182
+
183
+ // 高德地图样式覆盖
184
+ .amap-logo,
185
+ .amap-copyright {
186
+ display: none !important;
187
+ }
188
+
189
+ .amap-marker-label {
190
+ border: none;
191
+ background-color: transparent;
192
+ }
@@ -37,14 +37,14 @@
37
37
  "url": "https://github.com/wibetter/vue2-custom-cmp-template/issues"
38
38
  },
39
39
  "dependencies": {
40
- "neo-register": "^1.0.3",
40
+ "neo-register": "^1.0.5",
41
41
  "vue": "^2.6.14",
42
42
  "element-ui": "^2.15.12"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@commitlint/cli": "^8.3.5",
46
46
  "@commitlint/config-conventional": "^9.1.1",
47
- "neo-cmp-cli": "^1.3.5",
47
+ "neo-cmp-cli": "^1.3.7",
48
48
  "husky": "^4.2.5",
49
49
  "lint-staged": "^10.2.9",
50
50
  "prettier": "^2.0.5",