@cqsjjb/jjb-react-admin-component 3.3.0-beta.7 → 3.3.1-beta.0
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/AdaptiveTree/index.d.ts +29 -0
- package/AdaptiveTree/index.js +185 -0
- package/BMap/README.md +1 -1
- package/BMap/index.less +32 -31
- package/ControlWrapper/index.less +38 -0
- package/Table/index.js +2 -2
- package/Table/utils.js +4 -0
- package/package.json +1 -1
- package/AMap/README.md +0 -58
- package/AMap/index.d.ts +0 -40
- package/AMap/index.js +0 -372
- package/AMap/index.less +0 -19
- package/tools/index.js +0 -87
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TreeProps, CheckInfo } from 'antd/es/tree';
|
|
3
|
+
|
|
4
|
+
export interface TitleActionItem<NodeType = any> {
|
|
5
|
+
/** 按钮内容(文本或元素) */
|
|
6
|
+
content: React.ReactNode;
|
|
7
|
+
/** 点击事件回调 */
|
|
8
|
+
onClick?: (node: NodeType) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface AdaptiveTreeProps<NodeType = any> extends Omit<TreeProps<NodeType>, 'onCheck' | 'titleRender' | 'draggable'> {
|
|
12
|
+
/** 节点操作按钮生成函数 */
|
|
13
|
+
titleAction?: (node: NodeType) => TitleActionItem<NodeType>[];
|
|
14
|
+
|
|
15
|
+
/** 节点标题图标生成函数 */
|
|
16
|
+
titleIcon?: (node: NodeType) => React.ReactNode;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 节点选中时的回调函数
|
|
20
|
+
* @param ids 选中节点及其所有父节点id(二维数组)
|
|
21
|
+
* @param nodes 选中的节点数据(一维数组)
|
|
22
|
+
* @param info 选中信息(继承自Ant Design Tree的CheckInfo)
|
|
23
|
+
*/
|
|
24
|
+
onCheck?: (ids: string[][], nodes: NodeType[], info: CheckInfo<NodeType>) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
declare const AdaptiveTree: React.FC<AdaptiveTreeProps>;
|
|
28
|
+
|
|
29
|
+
export default AdaptiveTree;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
/**
|
|
3
|
+
* 自适应树组件
|
|
4
|
+
* @param {Object} props - 组件属性
|
|
5
|
+
* @param {Function} [props.titleAction] - 节点操作按钮生成函数
|
|
6
|
+
* @param {Object} node - 当前节点数据
|
|
7
|
+
* @returns {Array} 操作按钮配置数组,每项包含:
|
|
8
|
+
* @property {ReactNode} content - 按钮内容(文本或元素)
|
|
9
|
+
* @property {Function} onClick - 点击事件回调
|
|
10
|
+
* @param {Function} [props.titleIcon] - 节点标题图标生成函数
|
|
11
|
+
* @param {Object} node - 当前节点数据
|
|
12
|
+
* @returns {ReactNode} 图标元素(如 img、Icon 组件等)
|
|
13
|
+
*
|
|
14
|
+
* @note 说明:
|
|
15
|
+
* 1. 自动继承全局 Ant Design 前缀配置(window.process.env.app.antd['ant-prefix'])
|
|
16
|
+
* 2. 节点容器默认占满父元素空间,支持纵向滚动
|
|
17
|
+
* 3. 节点标题超长自动换行,且不会挤压标题图标和操作图标的空间
|
|
18
|
+
* 4. 节点选中时,返回的节点数据为当前节点及其所有父节点id(二维数组)、选中的节点数据(一维数组)
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* <AdaptiveTree
|
|
22
|
+
* treeData={[]}
|
|
23
|
+
* fieldNames={{
|
|
24
|
+
* title: 'name',
|
|
25
|
+
* key: 'id'
|
|
26
|
+
* }}
|
|
27
|
+
* titleAction={(node) => [
|
|
28
|
+
* {
|
|
29
|
+
* content: '添加',
|
|
30
|
+
* onClick: (node) => {
|
|
31
|
+
* console.warn("添加", node)
|
|
32
|
+
* }
|
|
33
|
+
* },
|
|
34
|
+
* {
|
|
35
|
+
* content: '编辑',
|
|
36
|
+
* onClick: (node) => {
|
|
37
|
+
* console.warn("编辑", node)
|
|
38
|
+
* }
|
|
39
|
+
* }
|
|
40
|
+
* ]}
|
|
41
|
+
* titleIcon={(node) => <FolderOpenOutlined />}
|
|
42
|
+
* />
|
|
43
|
+
*/
|
|
44
|
+
import React from 'react';
|
|
45
|
+
import { Tree, Space } from "antd";
|
|
46
|
+
import { styled } from 'styled-components';
|
|
47
|
+
export default props => {
|
|
48
|
+
const {
|
|
49
|
+
titleAction,
|
|
50
|
+
titleIcon,
|
|
51
|
+
draggable,
|
|
52
|
+
...rest
|
|
53
|
+
} = props;
|
|
54
|
+
const prefixCls = window.process.env.app.antd['ant-prefix'];
|
|
55
|
+
const StyledAntdComponents = styled.div`
|
|
56
|
+
.${prefixCls}-tree {
|
|
57
|
+
width: 100%;
|
|
58
|
+
height: 100%;
|
|
59
|
+
overflow-y: auto;
|
|
60
|
+
}
|
|
61
|
+
.${prefixCls}-tree-switcher {
|
|
62
|
+
align-items: flex-start !important;
|
|
63
|
+
padding-top: 13px;
|
|
64
|
+
}
|
|
65
|
+
.${prefixCls}-tree-checkbox {
|
|
66
|
+
margin-top: 11px;
|
|
67
|
+
margin-left: 4px;
|
|
68
|
+
align-self: flex-start;
|
|
69
|
+
}
|
|
70
|
+
.${prefixCls}-tree-treenode {
|
|
71
|
+
width: 100%;
|
|
72
|
+
display: flex;
|
|
73
|
+
.${prefixCls}-tree-node-content-wrapper {
|
|
74
|
+
flex: 1
|
|
75
|
+
}
|
|
76
|
+
.${prefixCls}-tree-switcher {
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
justify-content: flex-end;
|
|
80
|
+
}
|
|
81
|
+
.${prefixCls}-tree-switcher::before {
|
|
82
|
+
display: none;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
.adaptive-tree-title {
|
|
86
|
+
width: 100%;
|
|
87
|
+
display: flex;
|
|
88
|
+
justify-content: space-between;
|
|
89
|
+
gap: 8px;
|
|
90
|
+
align-items: flex-start;
|
|
91
|
+
padding: 6px 0;
|
|
92
|
+
font-weight: bold;
|
|
93
|
+
transition: none;
|
|
94
|
+
cursor: ${props?.draggable ? 'grab' : 'point'};
|
|
95
|
+
.title-left {
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: flex-start;
|
|
98
|
+
gap: 2px;
|
|
99
|
+
.icon {
|
|
100
|
+
width: 14px;
|
|
101
|
+
height: 14px;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
.operation {
|
|
105
|
+
cursor: pointer;
|
|
106
|
+
white-space: nowrap;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
`;
|
|
110
|
+
|
|
111
|
+
// 获得指定索引的节点 ID
|
|
112
|
+
const getLevelIndexNodeIds = (targetIndexArr, key) => {
|
|
113
|
+
const pathNodes = [];
|
|
114
|
+
const pathNodesIds = [];
|
|
115
|
+
let currentData = props.treeData || [];
|
|
116
|
+
for (let i = 0; i < targetIndexArr.length; i++) {
|
|
117
|
+
const index = targetIndexArr[i];
|
|
118
|
+
let nextNode;
|
|
119
|
+
if (i === 0) {
|
|
120
|
+
if (!Array.isArray(currentData) || index < 0 || index >= currentData.length) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
nextNode = currentData[index];
|
|
124
|
+
} else {
|
|
125
|
+
if (!currentData?.children || !Array.isArray(currentData.children) || index < 0 || index >= currentData.children.length) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
nextNode = currentData.children[index];
|
|
129
|
+
}
|
|
130
|
+
pathNodes.push(nextNode);
|
|
131
|
+
pathNodesIds.push(nextNode[key]);
|
|
132
|
+
currentData = nextNode;
|
|
133
|
+
}
|
|
134
|
+
return [pathNodesIds, pathNodes[pathNodes.length - 1]];
|
|
135
|
+
};
|
|
136
|
+
const onCheck = (id, info) => {
|
|
137
|
+
const key = props?.fieldNames?.key || 'key';
|
|
138
|
+
const ids = [];
|
|
139
|
+
const nodes = [];
|
|
140
|
+
info.checkedNodesPositions.map(item => {
|
|
141
|
+
let nodeIndexArr = item.pos.split('-');
|
|
142
|
+
nodeIndexArr.shift();
|
|
143
|
+
const result = getLevelIndexNodeIds(nodeIndexArr, key);
|
|
144
|
+
ids.push(result[0]);
|
|
145
|
+
nodes.push(result[1]);
|
|
146
|
+
});
|
|
147
|
+
console.warn("onCheck", ids, nodes);
|
|
148
|
+
props?.onCheck && props.onCheck(ids, nodes, info);
|
|
149
|
+
};
|
|
150
|
+
const titleRender = node => {
|
|
151
|
+
const {
|
|
152
|
+
title,
|
|
153
|
+
key
|
|
154
|
+
} = props?.fieldNames || {
|
|
155
|
+
title: 'title',
|
|
156
|
+
key: 'key'
|
|
157
|
+
};
|
|
158
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
159
|
+
className: "adaptive-tree-title",
|
|
160
|
+
key: node[key]
|
|
161
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
162
|
+
className: "title-left"
|
|
163
|
+
}, titleIcon ? /*#__PURE__*/React.createElement("div", {
|
|
164
|
+
className: "icon"
|
|
165
|
+
}, titleIcon(node)) : '', /*#__PURE__*/React.createElement("span", {
|
|
166
|
+
style: {
|
|
167
|
+
marginLeft: 6
|
|
168
|
+
}
|
|
169
|
+
}, node[title])), /*#__PURE__*/React.createElement(Space, null, titleAction ? (titleAction(node) || []).map(item => {
|
|
170
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
171
|
+
onClick: () => {
|
|
172
|
+
item.onClick && item.onClick(node);
|
|
173
|
+
},
|
|
174
|
+
className: "operation"
|
|
175
|
+
}, item?.content || '');
|
|
176
|
+
}) : ''));
|
|
177
|
+
};
|
|
178
|
+
return /*#__PURE__*/React.createElement(StyledAntdComponents, null, /*#__PURE__*/React.createElement(Tree, _extends({
|
|
179
|
+
draggable: draggable ? {
|
|
180
|
+
icon: false
|
|
181
|
+
} : false,
|
|
182
|
+
titleRender: titleRender,
|
|
183
|
+
onCheck: onCheck
|
|
184
|
+
}, rest)));
|
|
185
|
+
};
|
package/BMap/README.md
CHANGED
package/BMap/index.less
CHANGED
|
@@ -1,35 +1,36 @@
|
|
|
1
1
|
#_B_MAP_SEARCH_ {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
box-shadow: 1px 2px 1px rgb(0 0 0 / 15%);
|
|
8
|
-
border: none;
|
|
9
|
-
height: 32px;
|
|
10
|
-
line-height: 32px;
|
|
11
|
-
width: 300px;
|
|
12
|
-
padding: 0 10px;
|
|
13
|
-
font-size: 12px;
|
|
14
|
-
outline: none;
|
|
15
|
-
border-radius: 3px;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.tangram-suggestion-main {
|
|
19
|
-
z-index: 1000;
|
|
20
|
-
margin-top: 6px;
|
|
21
|
-
|
|
22
|
-
.tangram-suggestion {
|
|
23
|
-
border: none;
|
|
2
|
+
position: absolute;
|
|
3
|
+
top: 10px;
|
|
4
|
+
right: 10px;
|
|
5
|
+
z-index: 10;
|
|
6
|
+
color: rgb(102 102 102);
|
|
24
7
|
box-shadow: 1px 2px 1px rgb(0 0 0 / 15%);
|
|
8
|
+
border: none;
|
|
9
|
+
height: 32px;
|
|
10
|
+
line-height: 32px;
|
|
11
|
+
width: 300px;
|
|
12
|
+
padding: 0 10px;
|
|
13
|
+
font-size: 12px;
|
|
14
|
+
outline: none;
|
|
25
15
|
border-radius: 3px;
|
|
26
16
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
17
|
+
|
|
18
|
+
.tangram-suggestion-main {
|
|
19
|
+
z-index: 1000;
|
|
20
|
+
margin-top: 6px;
|
|
21
|
+
|
|
22
|
+
.tangram-suggestion {
|
|
23
|
+
border: none;
|
|
24
|
+
box-shadow: 1px 2px 1px rgb(0 0 0 / 15%);
|
|
25
|
+
border-radius: 3px;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#selCityWd {
|
|
30
|
+
box-sizing: content-box;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.city_content_top {
|
|
34
|
+
box-sizing: content-box;
|
|
35
|
+
}
|
|
36
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
@com-prefix-cls: if(isdefined(@ant-prefix), @ant-prefix, ant);
|
|
2
|
+
|
|
3
|
+
.@{com-prefix-cls}-form-item-control-label-wrapper {
|
|
4
|
+
.@{com-prefix-cls}-form-item-control-label-span {
|
|
5
|
+
border: 1px solid #d9d9d9;
|
|
6
|
+
height: 32px;
|
|
7
|
+
line-height: 30px;
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
margin-right: -1px;
|
|
10
|
+
padding: 0 2px 0 8px;
|
|
11
|
+
border-top-left-radius: 4px;
|
|
12
|
+
border-bottom-left-radius: 4px;
|
|
13
|
+
white-space: nowrap;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&.@{com-prefix-cls}-form-item-control-label-has {
|
|
17
|
+
.@{com-prefix-cls}-select-selector, .@{com-prefix-cls}-picker, .@{com-prefix-cls}-input, .@{com-prefix-cls}-input-affix-wrapper {
|
|
18
|
+
border-top-left-radius: 0;
|
|
19
|
+
border-bottom-left-radius: 0;
|
|
20
|
+
border-left-color: transparent !important;
|
|
21
|
+
&:hover, &:focus, &:focus-within{
|
|
22
|
+
border-left-color: @colorPrimary !important;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
&-default {
|
|
28
|
+
.@{com-prefix-cls}-form-item-control-label-span {
|
|
29
|
+
border-color: #d9d9d9;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&-dark {
|
|
34
|
+
.@{com-prefix-cls}-form-item-control-label-span {
|
|
35
|
+
border-color: #424242;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
package/Table/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import { tools } from '@cqsjjb/jjb-common-lib';
|
|
4
4
|
import { ProTable } from '@ant-design/pro-components';
|
|
5
5
|
import { useAntdResizableHeader } from 'use-antd-resizable-header';
|
|
6
|
-
import { antPrefix, setTableSize, getTableSize, getPersistenceKey } from './utils';
|
|
6
|
+
import { antPrefix, setTableSize, getTableSize, getPersistenceKey, isNull } from './utils';
|
|
7
7
|
import './index.less';
|
|
8
8
|
require('use-antd-resizable-header/dist/style.css');
|
|
9
9
|
export default function TablePro(props) {
|
|
@@ -96,7 +96,7 @@ export default function TablePro(props) {
|
|
|
96
96
|
scroll: scroll,
|
|
97
97
|
columns: resizableColumns,
|
|
98
98
|
className: `${antPrefix}-gbs-pro-table`,
|
|
99
|
-
options: {
|
|
99
|
+
options: !isNull(props.options) ? props.options : {
|
|
100
100
|
reload: false,
|
|
101
101
|
fullScreen: true,
|
|
102
102
|
setting: {
|
package/Table/utils.js
CHANGED
|
@@ -25,3 +25,7 @@ export function getTableSize(index) {
|
|
|
25
25
|
export function setTableSize(value, index) {
|
|
26
26
|
return window.localStorage.setItem(getPersistenceKey(index).size, value);
|
|
27
27
|
}
|
|
28
|
+
|
|
29
|
+
export const isNull = (val) => {
|
|
30
|
+
return val === null || val === undefined || val === '';
|
|
31
|
+
}
|
package/package.json
CHANGED
package/AMap/README.md
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
高德地图组件
|
|
2
|
-
|
|
3
|
-
## 代码演示
|
|
4
|
-
|
|
5
|
-
```jsx
|
|
6
|
-
import { useState } from 'react';
|
|
7
|
-
import { Button } from 'antd';
|
|
8
|
-
import AMap from '@cqsjjb/jjb-react-admin-component/AMap';
|
|
9
|
-
|
|
10
|
-
function App() {
|
|
11
|
-
const [ open, setOpen ] = useState(false);
|
|
12
|
-
return (
|
|
13
|
-
<>
|
|
14
|
-
<Button onClick={() => setOpen(true)}>打开地图</Button>
|
|
15
|
-
{open && (
|
|
16
|
-
<AMap
|
|
17
|
-
onOk={data => {
|
|
18
|
-
console.log(data);
|
|
19
|
-
setOpen(false);
|
|
20
|
-
}}
|
|
21
|
-
onCacnel={() => {
|
|
22
|
-
setOpen(false);
|
|
23
|
-
}}
|
|
24
|
-
/>
|
|
25
|
-
)}
|
|
26
|
-
</>
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## API
|
|
32
|
-
|
|
33
|
-
| 属性 | 说明 | 类型 | 默认值 |
|
|
34
|
-
|----------|:-----|:---------------------------------------------------------------------------------------------------------:|--------:|
|
|
35
|
-
| lng | 经度 | `number` | 116.404 |
|
|
36
|
-
| lat | 纬度 | `number` | 39.915 |
|
|
37
|
-
| title | 弹窗标题 | `string` | 高德地图 |
|
|
38
|
-
| width | 弹窗宽度 | `number` | 700 |
|
|
39
|
-
| onOk | 确认回调 | (data: { lng: number, lat: number, comp: <span style="color: red">IComp</span>, compText: Text }) => void | - |
|
|
40
|
-
| onCancel | 取消回调 | `() => void` | 700 |
|
|
41
|
-
|
|
42
|
-
## 确认回调-IComp
|
|
43
|
-
|
|
44
|
-
| 属性 | 说明 | 类型 | 默认值 |
|
|
45
|
-
|--------------|:----|:--------:|----:|
|
|
46
|
-
| province | 省份 | `string` | - |
|
|
47
|
-
| city | 城市 | `string` | - |
|
|
48
|
-
| district | 区县 | `string` | - |
|
|
49
|
-
| street | 街道 | `string` | - |
|
|
50
|
-
| streetNumber | 门牌号 | `string` | - |
|
|
51
|
-
|
|
52
|
-
## 常见问题
|
|
53
|
-
* 加载地图失败,缺少必要的文件!
|
|
54
|
-
|
|
55
|
-
请确认应用public/index.html中是否导入高德地图SDK。
|
|
56
|
-
* onOk确认回调compText为undefined
|
|
57
|
-
|
|
58
|
-
请确认高德地图是否授权Web应用。
|
package/AMap/index.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
|
|
3
|
-
export interface AMapProps {
|
|
4
|
-
/** 初始经度 默认-116.404 */
|
|
5
|
-
lng?: number;
|
|
6
|
-
/** 初始纬度 默认-39.915 */
|
|
7
|
-
lat?: number;
|
|
8
|
-
/** 标题 默认-高德地图 */
|
|
9
|
-
title?: string;
|
|
10
|
-
/** 地图弹窗宽度 默认-700 */
|
|
11
|
-
width?: number;
|
|
12
|
-
/** 确认事件 返回选择的位置信息 */
|
|
13
|
-
onOk?: (data: {
|
|
14
|
-
// 经度
|
|
15
|
-
lng: number;
|
|
16
|
-
// 纬度
|
|
17
|
-
lat: number;
|
|
18
|
-
// 选择的位置信息对象
|
|
19
|
-
comp?: {
|
|
20
|
-
// 省份
|
|
21
|
-
province: string;
|
|
22
|
-
// 城市
|
|
23
|
-
city: string;
|
|
24
|
-
// 区县
|
|
25
|
-
district: string;
|
|
26
|
-
// 街道
|
|
27
|
-
street: string;
|
|
28
|
-
// 门牌号
|
|
29
|
-
streetNumber: string;
|
|
30
|
-
};
|
|
31
|
-
// 选择的位置详细信息文本
|
|
32
|
-
compText?: string;
|
|
33
|
-
}) => void;
|
|
34
|
-
/** 取消事件 */
|
|
35
|
-
onCancel?: () => void;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
declare const AMap: React.FC<AMapProps>;
|
|
39
|
-
|
|
40
|
-
export default AMap;
|
package/AMap/index.js
DELETED
|
@@ -1,372 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState, useCallback } from 'react';
|
|
2
|
-
import { Button, Col, message, Modal, Result, Row } from 'antd';
|
|
3
|
-
import './index.less';
|
|
4
|
-
const _A_MAP_SEARCH_ = '_A_MAP_SEARCH_';
|
|
5
|
-
const _A_MAP_DEFAULT_POINT_ = {
|
|
6
|
-
lng: 116.397437,
|
|
7
|
-
lat: 39.909148
|
|
8
|
-
};
|
|
9
|
-
export default function AMap({
|
|
10
|
-
lng: propLng,
|
|
11
|
-
lat: propLat,
|
|
12
|
-
title = '高德地图',
|
|
13
|
-
width = 700,
|
|
14
|
-
onOk,
|
|
15
|
-
onCancel
|
|
16
|
-
}) {
|
|
17
|
-
const [lng, setLng] = useState(_A_MAP_DEFAULT_POINT_.lng);
|
|
18
|
-
const [lat, setLat] = useState(_A_MAP_DEFAULT_POINT_.lat);
|
|
19
|
-
const GL = useRef(null);
|
|
20
|
-
const mapRef = useRef(null);
|
|
21
|
-
const markerRef = useRef(null);
|
|
22
|
-
const autoRef = useRef(null);
|
|
23
|
-
const placeSearchRef = useRef(null);
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
if (typeof window.AMap === 'undefined') {
|
|
26
|
-
message.error('未导入高德地图文件,生成地图失败!').then(() => null);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
let mounted = true;
|
|
30
|
-
|
|
31
|
-
// 保证传入的初始值是 number(避免 NaN)
|
|
32
|
-
const initLng = Number(propLng) || _A_MAP_DEFAULT_POINT_.lng;
|
|
33
|
-
const initLat = Number(propLat) || _A_MAP_DEFAULT_POINT_.lat;
|
|
34
|
-
|
|
35
|
-
// 等待容器可见且尺寸非 0(Modal 动画或隐藏态时常为 0)
|
|
36
|
-
const waitForVisible = (el, timeout = 3000) => new Promise(resolve => {
|
|
37
|
-
const start = Date.now();
|
|
38
|
-
function check() {
|
|
39
|
-
if (!el) return resolve(false);
|
|
40
|
-
const r = el.getBoundingClientRect();
|
|
41
|
-
if (r.width > 0 && r.height > 0) return resolve(true);
|
|
42
|
-
if (Date.now() - start > timeout) return resolve(false);
|
|
43
|
-
requestAnimationFrame(check);
|
|
44
|
-
}
|
|
45
|
-
check();
|
|
46
|
-
});
|
|
47
|
-
async function init() {
|
|
48
|
-
if (!GL.current) {
|
|
49
|
-
console.warn('AMap container ref not ready');
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
const visible = await waitForVisible(GL.current, 3000);
|
|
53
|
-
if (!visible) {
|
|
54
|
-
// 继续也可,但记录一下。多数情况下等待后再 init 能解决 Pixel(NaN, 0)
|
|
55
|
-
console.warn('AMap container still not visible before init (proceeding anyway).');
|
|
56
|
-
}
|
|
57
|
-
try {
|
|
58
|
-
const map = new window.AMap.Map(GL.current, {
|
|
59
|
-
center: [initLng, initLat],
|
|
60
|
-
zoom: 18,
|
|
61
|
-
viewMode: '3D'
|
|
62
|
-
});
|
|
63
|
-
mapRef.current = map;
|
|
64
|
-
|
|
65
|
-
// 保证 state 与实际中心一致
|
|
66
|
-
setLng(initLng);
|
|
67
|
-
setLat(initLat);
|
|
68
|
-
|
|
69
|
-
// 插件加载、控件创建都做容错
|
|
70
|
-
window.AMap.plugin(['AMap.Scale', 'AMap.ToolBar', 'AMap.Geolocation', 'AMap.AutoComplete', 'AMap.PlaceSearch', 'AMap.Geocoder'], () => {
|
|
71
|
-
try {
|
|
72
|
-
map.addControl(new window.AMap.Scale());
|
|
73
|
-
} catch (e) {
|
|
74
|
-
// 某些构建/版本中可能不存在
|
|
75
|
-
console.warn('Scale control failed', e);
|
|
76
|
-
}
|
|
77
|
-
try {
|
|
78
|
-
map.addControl(new window.AMap.ToolBar({
|
|
79
|
-
position: 'RT'
|
|
80
|
-
}));
|
|
81
|
-
} catch (e) {
|
|
82
|
-
console.warn('ToolBar control failed', e);
|
|
83
|
-
}
|
|
84
|
-
try {
|
|
85
|
-
// 使用合法角落(RB/RT/LB/LT),不要自定义 'BT'
|
|
86
|
-
const geolocation = new window.AMap.Geolocation({
|
|
87
|
-
position: 'RB',
|
|
88
|
-
offset: new window.AMap.Pixel(Number(20), Number(20)),
|
|
89
|
-
showCircle: false,
|
|
90
|
-
showButton: true
|
|
91
|
-
});
|
|
92
|
-
map.addControl(geolocation);
|
|
93
|
-
|
|
94
|
-
// 正确的回调签名 (status, result)
|
|
95
|
-
geolocation.getCurrentPosition((status, result) => {
|
|
96
|
-
if (status !== 'complete') {
|
|
97
|
-
// 不做致命处理,但提示
|
|
98
|
-
message.error('未开启定位,定位失败!');
|
|
99
|
-
} else {
|
|
100
|
-
// 如果需要可以从 result.position 取值
|
|
101
|
-
try {
|
|
102
|
-
const pos = result && result.position;
|
|
103
|
-
if (pos) {
|
|
104
|
-
const px = typeof pos.getLng === 'function' ? pos.getLng() : pos.lng;
|
|
105
|
-
const py = typeof pos.getLat === 'function' ? pos.getLat() : pos.lat;
|
|
106
|
-
if (!Number.isNaN(Number(px)) && !Number.isNaN(Number(py))) {
|
|
107
|
-
setLng(Number(px));
|
|
108
|
-
setLat(Number(py));
|
|
109
|
-
map.setCenter([Number(px), Number(py)]);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
} catch (e) {
|
|
113
|
-
// 忽略
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
} catch (e) {
|
|
118
|
-
console.warn('Geolocation init failed', e);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// 初始 marker 放置
|
|
122
|
-
try {
|
|
123
|
-
markerRef.current = new window.AMap.Marker({
|
|
124
|
-
position: [initLng, initLat],
|
|
125
|
-
map
|
|
126
|
-
});
|
|
127
|
-
} catch (e) {
|
|
128
|
-
console.warn('Marker init failed', e);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// AutoComplete + PlaceSearch
|
|
132
|
-
try {
|
|
133
|
-
placeSearchRef.current = new window.AMap.PlaceSearch({
|
|
134
|
-
map
|
|
135
|
-
});
|
|
136
|
-
autoRef.current = new window.AMap.AutoComplete({
|
|
137
|
-
input: document.getElementById(_A_MAP_SEARCH_)
|
|
138
|
-
});
|
|
139
|
-
autoRef.current.on && autoRef.current.on('select', e => {
|
|
140
|
-
// e.poi 里可能是 AMap.LngLat 实例 / 对象 / 数组,做兼容处理
|
|
141
|
-
const poi = e && e.poi ? e.poi : null;
|
|
142
|
-
let loc = poi && (poi.location || poi.lnglat) || e && (e.location || e.lnglat) || null;
|
|
143
|
-
let foundLng = null;
|
|
144
|
-
let foundLat = null;
|
|
145
|
-
if (loc) {
|
|
146
|
-
if (typeof loc.getLng === 'function' && typeof loc.getLat === 'function') {
|
|
147
|
-
// AMap.LngLat 实例
|
|
148
|
-
foundLng = Number(loc.getLng());
|
|
149
|
-
foundLat = Number(loc.getLat());
|
|
150
|
-
} else if (typeof loc.lng === 'number' && typeof loc.lat === 'number') {
|
|
151
|
-
foundLng = Number(loc.lng);
|
|
152
|
-
foundLat = Number(loc.lat);
|
|
153
|
-
} else if (Array.isArray(loc)) {
|
|
154
|
-
foundLng = Number(loc[0]);
|
|
155
|
-
foundLat = Number(loc[1]);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
if (foundLng != null && foundLat != null && !Number.isNaN(foundLng) && !Number.isNaN(foundLat)) {
|
|
159
|
-
setLng(foundLng);
|
|
160
|
-
setLat(foundLat);
|
|
161
|
-
map.setCenter([foundLng, foundLat]);
|
|
162
|
-
if (markerRef.current) {
|
|
163
|
-
markerRef.current.setPosition([foundLng, foundLat]);
|
|
164
|
-
} else {
|
|
165
|
-
markerRef.current = new window.AMap.Marker({
|
|
166
|
-
position: [foundLng, foundLat],
|
|
167
|
-
map
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
} else {
|
|
171
|
-
// 兜底:用 placeSearch 搜索 name(如果有)
|
|
172
|
-
const name = poi && (poi.name || poi.address) || e && (e.info || e.name);
|
|
173
|
-
if (name && placeSearchRef.current && placeSearchRef.current.search) {
|
|
174
|
-
placeSearchRef.current.search(name, (status, result) => {
|
|
175
|
-
// placeSearch 回调再处理,这里保持原有逻辑或按需增强
|
|
176
|
-
if (status === 'complete' && result && result.poiList && result.poiList.pois && result.poiList.pois.length > 0) {
|
|
177
|
-
const p = result.poiList.pois[0];
|
|
178
|
-
const loc2 = p.location || p.lnglat;
|
|
179
|
-
let x = null,
|
|
180
|
-
y = null;
|
|
181
|
-
if (loc2) {
|
|
182
|
-
if (typeof loc2.getLng === 'function') {
|
|
183
|
-
x = Number(loc2.getLng());
|
|
184
|
-
y = Number(loc2.getLat());
|
|
185
|
-
} else if (typeof loc2.lng === 'number') {
|
|
186
|
-
x = Number(loc2.lng);
|
|
187
|
-
y = Number(loc2.lat);
|
|
188
|
-
} else if (Array.isArray(loc2)) {
|
|
189
|
-
x = Number(loc2[0]);
|
|
190
|
-
y = Number(loc2[1]);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
if (!Number.isNaN(x) && !Number.isNaN(y)) {
|
|
194
|
-
setLng(x);
|
|
195
|
-
setLat(y);
|
|
196
|
-
map.setCenter([x, y]);
|
|
197
|
-
if (markerRef.current) markerRef.current.setPosition([x, y]);else markerRef.current = new window.AMap.Marker({
|
|
198
|
-
position: [x, y],
|
|
199
|
-
map
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
} catch (e) {
|
|
208
|
-
console.warn('AutoComplete / PlaceSearch init failed', e);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// 点击选点
|
|
212
|
-
try {
|
|
213
|
-
map.on && map.on('click', e => {
|
|
214
|
-
const lnglat = e && e.lnglat;
|
|
215
|
-
if (!lnglat) return;
|
|
216
|
-
let clickLng = null;
|
|
217
|
-
let clickLat = null;
|
|
218
|
-
if (typeof lnglat.getLng === 'function') {
|
|
219
|
-
clickLng = Number(lnglat.getLng());
|
|
220
|
-
clickLat = Number(lnglat.getLat());
|
|
221
|
-
} else {
|
|
222
|
-
clickLng = Number(lnglat.lng || Array.isArray(lnglat) && lnglat[0]);
|
|
223
|
-
clickLat = Number(lnglat.lat || Array.isArray(lnglat) && lnglat[1]);
|
|
224
|
-
}
|
|
225
|
-
if (Number.isNaN(clickLng) || Number.isNaN(clickLat)) return;
|
|
226
|
-
setLng(clickLng);
|
|
227
|
-
setLat(clickLat);
|
|
228
|
-
if (markerRef.current) {
|
|
229
|
-
markerRef.current.setPosition([clickLng, clickLat]);
|
|
230
|
-
} else {
|
|
231
|
-
markerRef.current = new window.AMap.Marker({
|
|
232
|
-
position: [clickLng, clickLat],
|
|
233
|
-
map
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
});
|
|
237
|
-
} catch (e) {
|
|
238
|
-
console.warn('map.on click failed', e);
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
} catch (err) {
|
|
242
|
-
console.error('AMap init error', err);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
init();
|
|
246
|
-
|
|
247
|
-
// cleanup
|
|
248
|
-
return () => {
|
|
249
|
-
mounted = false;
|
|
250
|
-
try {
|
|
251
|
-
if (mapRef.current) {
|
|
252
|
-
mapRef.current.destroy();
|
|
253
|
-
mapRef.current = null;
|
|
254
|
-
}
|
|
255
|
-
} catch (e) {
|
|
256
|
-
// ignore
|
|
257
|
-
}
|
|
258
|
-
markerRef.current = null;
|
|
259
|
-
autoRef.current = null;
|
|
260
|
-
placeSearchRef.current = null;
|
|
261
|
-
};
|
|
262
|
-
}, [propLng, propLat]);
|
|
263
|
-
|
|
264
|
-
// 重置、确认等操作(同样做 number guard)
|
|
265
|
-
const onResetMap = useCallback(() => {
|
|
266
|
-
const map = mapRef.current;
|
|
267
|
-
if (!map) return;
|
|
268
|
-
const x = Number(_A_MAP_DEFAULT_POINT_.lng);
|
|
269
|
-
const y = Number(_A_MAP_DEFAULT_POINT_.lat);
|
|
270
|
-
setLng(x);
|
|
271
|
-
setLat(y);
|
|
272
|
-
try {
|
|
273
|
-
map.setCenter([x, y]);
|
|
274
|
-
if (markerRef.current) {
|
|
275
|
-
markerRef.current.setPosition([x, y]);
|
|
276
|
-
} else {
|
|
277
|
-
markerRef.current = new window.AMap.Marker({
|
|
278
|
-
position: [x, y],
|
|
279
|
-
map
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
} catch (e) {
|
|
283
|
-
console.warn('reset map failed', e);
|
|
284
|
-
}
|
|
285
|
-
}, []);
|
|
286
|
-
const handleOk = useCallback(() => {
|
|
287
|
-
if (!mapRef.current) return;
|
|
288
|
-
// 确保 lng/lat 是 number
|
|
289
|
-
const x = Number(lng);
|
|
290
|
-
const y = Number(lat);
|
|
291
|
-
if (Number.isNaN(x) || Number.isNaN(y)) {
|
|
292
|
-
onOk && onOk({
|
|
293
|
-
lng,
|
|
294
|
-
lat,
|
|
295
|
-
comp: undefined,
|
|
296
|
-
compText: undefined
|
|
297
|
-
});
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
window.AMap.plugin('AMap.Geocoder', () => {
|
|
301
|
-
try {
|
|
302
|
-
const geocoder = new window.AMap.Geocoder();
|
|
303
|
-
geocoder.getAddress([x, y], (status, result) => {
|
|
304
|
-
let comp;
|
|
305
|
-
if (status === 'complete' && result && result.regeocode) {
|
|
306
|
-
comp = result.regeocode.addressComponent;
|
|
307
|
-
}
|
|
308
|
-
onOk && onOk({
|
|
309
|
-
lng: x,
|
|
310
|
-
lat: y,
|
|
311
|
-
comp,
|
|
312
|
-
compText: comp && [comp.province, comp.city, comp.district, comp.township, comp.street, comp.streetNumber].filter(Boolean).join('') || undefined
|
|
313
|
-
});
|
|
314
|
-
});
|
|
315
|
-
} catch (e) {
|
|
316
|
-
onOk && onOk({
|
|
317
|
-
lng: x,
|
|
318
|
-
lat: y,
|
|
319
|
-
comp: undefined,
|
|
320
|
-
compText: undefined
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
});
|
|
324
|
-
}, [lng, lat, onOk]);
|
|
325
|
-
const hasMapScript = typeof window.AMap !== 'undefined';
|
|
326
|
-
return /*#__PURE__*/React.createElement(Modal, {
|
|
327
|
-
open: true,
|
|
328
|
-
destroyOnClose: true,
|
|
329
|
-
title: title,
|
|
330
|
-
width: width,
|
|
331
|
-
footer: hasMapScript && /*#__PURE__*/React.createElement(Row, {
|
|
332
|
-
align: "middle",
|
|
333
|
-
justify: "space-between"
|
|
334
|
-
}, /*#__PURE__*/React.createElement(Col, null, "\u5750\u6807\uFF1A", [lng, lat].join('-')), /*#__PURE__*/React.createElement(Col, null, /*#__PURE__*/React.createElement(Button, {
|
|
335
|
-
ghost: true,
|
|
336
|
-
type: "primary",
|
|
337
|
-
style: {
|
|
338
|
-
marginRight: 12
|
|
339
|
-
},
|
|
340
|
-
onClick: onResetMap
|
|
341
|
-
}, "\u91CD\u7F6E\u5730\u56FE"), /*#__PURE__*/React.createElement(Button, {
|
|
342
|
-
type: "primary",
|
|
343
|
-
onClick: handleOk
|
|
344
|
-
}, "\u786E\u8BA4\u5750\u6807"))),
|
|
345
|
-
maskClosable: false,
|
|
346
|
-
onCancel: () => onCancel && onCancel()
|
|
347
|
-
}, hasMapScript ? /*#__PURE__*/React.createElement("div", {
|
|
348
|
-
style: {
|
|
349
|
-
position: 'relative'
|
|
350
|
-
}
|
|
351
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
352
|
-
ref: GL,
|
|
353
|
-
style: {
|
|
354
|
-
height: 500,
|
|
355
|
-
userSelect: 'none'
|
|
356
|
-
}
|
|
357
|
-
}), /*#__PURE__*/React.createElement("input", {
|
|
358
|
-
id: _A_MAP_SEARCH_,
|
|
359
|
-
type: "text",
|
|
360
|
-
maxLength: 30,
|
|
361
|
-
placeholder: "\u8BF7\u8F93\u5165\u5173\u952E\u5B57\u67E5\u8BE2",
|
|
362
|
-
style: {
|
|
363
|
-
position: 'absolute',
|
|
364
|
-
top: 10,
|
|
365
|
-
left: 10,
|
|
366
|
-
zIndex: 1000
|
|
367
|
-
}
|
|
368
|
-
})) : /*#__PURE__*/React.createElement(Result, {
|
|
369
|
-
status: "error",
|
|
370
|
-
title: "\u52A0\u8F7D\u5730\u56FE\u5931\u8D25\uFF0C\u7F3A\u5C11\u5FC5\u8981\u7684\u6587\u4EF6\uFF01"
|
|
371
|
-
}));
|
|
372
|
-
}
|
package/AMap/index.less
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
#_A_MAP_SEARCH_ {
|
|
2
|
-
position: absolute;
|
|
3
|
-
top: 10px;
|
|
4
|
-
right: 10px;
|
|
5
|
-
z-index: 10;
|
|
6
|
-
color: rgb(102 102 102);
|
|
7
|
-
box-shadow: 1px 2px 1px rgb(0 0 0 / 15%);
|
|
8
|
-
border: none;
|
|
9
|
-
height: 32px;
|
|
10
|
-
line-height: 32px;
|
|
11
|
-
width: 300px;
|
|
12
|
-
padding: 0 10px;
|
|
13
|
-
font-size: 12px;
|
|
14
|
-
outline: none;
|
|
15
|
-
border-radius: 3px;
|
|
16
|
-
}
|
|
17
|
-
.amap-sug-result {
|
|
18
|
-
z-index: 10240 !important;
|
|
19
|
-
}
|
package/tools/index.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { tools } from '@cqsjjb/jjb-common-lib';
|
|
2
|
-
|
|
3
|
-
const { toObject } = tools;
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @description 版本1
|
|
7
|
-
* @param v {string}
|
|
8
|
-
* @return {boolean}
|
|
9
|
-
*/
|
|
10
|
-
export function isVersion1(v) {
|
|
11
|
-
return v === 'v1';
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @description 版本2
|
|
16
|
-
* @param v {string}
|
|
17
|
-
* @return {boolean}
|
|
18
|
-
*/
|
|
19
|
-
export function isVersion2(v) {
|
|
20
|
-
return v === 'v2';
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @description 读取token
|
|
25
|
-
* @return {string}
|
|
26
|
-
*/
|
|
27
|
-
export function getToken() {
|
|
28
|
-
return window.sessionStorage.getItem('token');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @description 读取appKey
|
|
33
|
-
* @return {string}
|
|
34
|
-
*/
|
|
35
|
-
export function getAppKey() {
|
|
36
|
-
return toObject(toObject(toObject(window.process).env).app).appKey;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* @description 读取tenantCode
|
|
41
|
-
* @return {string}
|
|
42
|
-
*/
|
|
43
|
-
export function getTenantCode() {
|
|
44
|
-
return window.sessionStorage.getItem('tenantCode');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* @description 获取纵横比
|
|
49
|
-
* @param wh {string}
|
|
50
|
-
* @return {number[]}
|
|
51
|
-
*/
|
|
52
|
-
export function getViewAsp(wh) {
|
|
53
|
-
try {
|
|
54
|
-
return wh.split('*').map(v => parseInt(v));
|
|
55
|
-
} catch (e) {
|
|
56
|
-
return [0, 0];
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* @description http
|
|
62
|
-
* @param v {string}
|
|
63
|
-
* @return {boolean}
|
|
64
|
-
*/
|
|
65
|
-
export function isHttpUrl(v) {
|
|
66
|
-
return /^http[s]?:\/\//.test(v);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* @description 获取前缀
|
|
71
|
-
* @return {string}
|
|
72
|
-
*/
|
|
73
|
-
export function getPrefixCls() {
|
|
74
|
-
return window.process?.env?.app?.antd['ant-prefix'] || 'ant';
|
|
75
|
-
}
|
|
76
|
-
export function getAlgorithm() {
|
|
77
|
-
const value = document.documentElement.style.getPropertyValue(
|
|
78
|
-
'--gbs-var-algorithm'
|
|
79
|
-
);
|
|
80
|
-
return (
|
|
81
|
-
value ?
|
|
82
|
-
value === '#FFF' ?
|
|
83
|
-
'default'
|
|
84
|
-
: 'dark'
|
|
85
|
-
: 'default'
|
|
86
|
-
);
|
|
87
|
-
}
|