neo-cmp-cli 1.3.7 → 1.3.8

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.
Files changed (30) hide show
  1. package/README.md +5 -5
  2. package/package.json +1 -1
  3. package/src/template/antd-custom-cmp-template/package.json +1 -1
  4. package/src/template/echarts-custom-cmp-template/package.json +1 -1
  5. package/src/template/{react-ts-custom-cmp-template → echarts-custom-cmp-template}/src/components/map-widget/index.tsx +56 -18
  6. package/src/template/echarts-custom-cmp-template/src/utils/url.ts +82 -0
  7. package/src/template/neo-custom-cmp-template/neo.config.js +4 -4
  8. package/src/template/neo-custom-cmp-template/package.json +1 -1
  9. package/src/template/react-custom-cmp-template/package.json +1 -1
  10. package/src/template/react-ts-custom-cmp-template/neo.config.js +4 -4
  11. package/src/template/react-ts-custom-cmp-template/package.json +2 -2
  12. package/src/template/vue2-custom-cmp-template/package.json +1 -1
  13. package/src/template/echarts-custom-cmp-template/src/components/info-card/index.tsx +0 -69
  14. package/src/template/echarts-custom-cmp-template/src/components/info-card/model.ts +0 -78
  15. package/src/template/echarts-custom-cmp-template/src/components/info-card/style.scss +0 -105
  16. package/src/template/neo-custom-cmp-template/src/components/contact-card-list/README.md +0 -61
  17. package/src/template/neo-custom-cmp-template/src/components/contact-card-list/index.tsx +0 -191
  18. package/src/template/neo-custom-cmp-template/src/components/contact-card-list/model.ts +0 -56
  19. package/src/template/neo-custom-cmp-template/src/components/contact-card-list/style.scss +0 -260
  20. package/src/template/neo-custom-cmp-template/src/components/contact-form/README.md +0 -94
  21. package/src/template/neo-custom-cmp-template/src/components/contact-form/index.tsx +0 -249
  22. package/src/template/neo-custom-cmp-template/src/components/contact-form/model.ts +0 -63
  23. package/src/template/neo-custom-cmp-template/src/components/contact-form/style.scss +0 -120
  24. package/src/template/react-ts-custom-cmp-template/src/components/info-card/index.tsx +0 -69
  25. package/src/template/react-ts-custom-cmp-template/src/components/info-card/model.ts +0 -78
  26. package/src/template/react-ts-custom-cmp-template/src/components/info-card/style.scss +0 -105
  27. /package/src/template/{react-ts-custom-cmp-template → echarts-custom-cmp-template}/src/components/map-widget/README.md +0 -0
  28. /package/src/template/{react-ts-custom-cmp-template → echarts-custom-cmp-template}/src/components/map-widget/USAGE.md +0 -0
  29. /package/src/template/{react-ts-custom-cmp-template → echarts-custom-cmp-template}/src/components/map-widget/model.ts +0 -0
  30. /package/src/template/{react-ts-custom-cmp-template → echarts-custom-cmp-template}/src/components/map-widget/style.scss +0 -0
@@ -1,249 +0,0 @@
1
- import * as React from 'react';
2
- import { Form, Input, Select, Button, message, Card } from 'antd';
3
- // @ts-ignore
4
- import { xObject } from 'neo-open-api'; // Neo Open API
5
- const { Option } = Select;
6
-
7
- import './style.scss';
8
-
9
- interface ContactFormProps {
10
- title: string;
11
- showSubmitButton?: boolean;
12
- data?: any;
13
- }
14
-
15
- interface ContactFormState {
16
- formData: {
17
- name: string;
18
- entityType?: number;
19
- phone__c: string;
20
- };
21
- entityTypeList: any[];
22
- loading: boolean;
23
- }
24
-
25
- export default class ContactForm extends React.PureComponent<
26
- ContactFormProps,
27
- ContactFormState
28
- > {
29
- private formRef: any;
30
-
31
- constructor(props: ContactFormProps) {
32
- super(props);
33
-
34
- this.state = {
35
- formData: {
36
- name: 'wibetter',
37
- phone__c: '15900000003',
38
- },
39
- entityTypeList: [],
40
- loading: false,
41
- };
42
-
43
- // 获取业务类型列表
44
- xObject.getEntityTypeList('customContact__c').then((res: any) => {
45
- if (res && res.status) {
46
- this.setState({
47
- entityTypeList: res.data || [],
48
- });
49
- }
50
- });
51
-
52
- this.handleInputChange = this.handleInputChange.bind(this);
53
- this.handleSubmit = this.handleSubmit.bind(this);
54
- this.resetForm = this.resetForm.bind(this);
55
- }
56
-
57
- handleInputChange(
58
- field: keyof ContactFormState['formData'],
59
- value: string | number,
60
- ) {
61
- this.setState((prevState) => ({
62
- formData: {
63
- ...prevState.formData,
64
- [field]: value,
65
- },
66
- }));
67
- }
68
-
69
- validateForm() {
70
- const { formData } = this.state;
71
-
72
- if (!formData.name.trim()) {
73
- message.error('请输入联系人姓名');
74
- return false;
75
- }
76
-
77
- if (!formData.phone__c.trim()) {
78
- message.error('请输入手机号');
79
- return false;
80
- }
81
-
82
- // 手机号格式验证
83
- const phoneRegex = /^1[3-9]\d{9}$/;
84
- if (!phoneRegex.test(formData.phone__c)) {
85
- message.error('请输入正确的手机号格式');
86
- return false;
87
- }
88
-
89
- return true;
90
- }
91
-
92
- async handleSubmit() {
93
- if (!this.validateForm()) {
94
- return;
95
- }
96
- this.setState({ loading: true });
97
-
98
- try {
99
- const { formData } = this.state;
100
- // 获取当前用户信息
101
- const curAmisData = this.props.data || {};
102
- const userInfo = curAmisData.__NeoCurrentUser;
103
-
104
- // 准备提交的数据
105
- let submitData = {
106
- name: formData.name.trim(),
107
- phone__c: formData.phone__c.trim(),
108
- entityType: formData.entityType,
109
- };
110
-
111
- if (userInfo && userInfo.id) {
112
- submitData = Object.assign(submitData, {
113
- userId: userInfo.id, // 当前用户ID,非必填
114
- dimDepart: userInfo.departId, // 当前用户所属部门ID,非必填
115
- });
116
- }
117
-
118
- // 调用 API 提交数据
119
- const response: any = await xObject.create('customContact__c', {
120
- data: submitData,
121
- });
122
-
123
- if (response && response.status) {
124
- message.success('联系人创建成功!');
125
- // 成功后重置表单
126
- setTimeout(() => {
127
- this.resetForm();
128
- }, 1000);
129
- } else {
130
- message.error('创建联系人失败:', response.msg);
131
- }
132
- } catch (error: any) {
133
- message.error('创建联系人失败:', error);
134
- } finally {
135
- this.setState({ loading: false });
136
- }
137
- }
138
-
139
- resetForm() {
140
- this.setState({
141
- formData: {
142
- name: '',
143
- phone__c: '',
144
- },
145
- });
146
-
147
- // 重置 Ant Design 表单
148
- if (this.formRef) {
149
- this.formRef.resetFields();
150
- }
151
- }
152
-
153
- render() {
154
- const { title, showSubmitButton } = this.props;
155
- const { formData, loading, entityTypeList } = this.state;
156
- const curAmisData = this.props.data || {};
157
- const systemInfo = curAmisData.__NeoSystemInfo || {};
158
-
159
- return (
160
- <div className="contact-form-container">
161
- <Card
162
- title={title || '创建联系人'}
163
- extra={systemInfo.tenantName ? `【${systemInfo.tenantName}】` : ''}
164
- className="contact-form-card"
165
- >
166
- <Form
167
- ref={(ref) => {
168
- this.formRef = ref;
169
- }}
170
- layout="vertical"
171
- className="contact-form"
172
- initialValues={formData}
173
- >
174
- <Form.Item
175
- label="姓名"
176
- required
177
- rules={[{ required: true, message: '请输入联系人姓名' }]}
178
- >
179
- <Input
180
- value={formData.name}
181
- onChange={(e) => this.handleInputChange('name', e.target.value)}
182
- placeholder="请输入联系人姓名"
183
- disabled={loading}
184
- />
185
- </Form.Item>
186
-
187
- <Form.Item
188
- label="手机号"
189
- required
190
- rules={[
191
- { required: true, message: '请输入手机号' },
192
- { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式' },
193
- ]}
194
- >
195
- <Input
196
- value={formData.phone__c}
197
- onChange={(e) =>
198
- this.handleInputChange('phone__c', e.target.value)
199
- }
200
- placeholder="请输入手机号"
201
- disabled={loading}
202
- />
203
- </Form.Item>
204
-
205
- <Form.Item label="业务类型">
206
- <Select
207
- value={formData.entityType}
208
- onChange={(value) =>
209
- this.handleInputChange('entityType', value)
210
- }
211
- placeholder="请选择业务类型"
212
- disabled={loading}
213
- >
214
- {entityTypeList.map((item) => (
215
- <Option
216
- key={item.apiKey}
217
- value={item.id}
218
- disabled={!item.active}
219
- >
220
- {item.label}
221
- </Option>
222
- ))}
223
- </Select>
224
- </Form.Item>
225
-
226
- {showSubmitButton && (
227
- <Form.Item className="form-actions">
228
- <Button
229
- onClick={this.resetForm}
230
- disabled={loading}
231
- style={{ marginRight: 8 }}
232
- >
233
- 重置
234
- </Button>
235
- <Button
236
- type="primary"
237
- onClick={this.handleSubmit}
238
- loading={loading}
239
- >
240
- 保存联系人
241
- </Button>
242
- </Form.Item>
243
- )}
244
- </Form>
245
- </Card>
246
- </div>
247
- );
248
- }
249
- }
@@ -1,63 +0,0 @@
1
- /**
2
- * @file 自定义组件对接编辑器的描述文件
3
- */
4
- export class ContactFormModel {
5
- /**
6
- * cmpType 为自定义组件名称,用于标识组件的唯一性
7
- * 在构建时根据当前组件目录名称自动生成
8
- */
9
- // cmpType: string = 'contact-form';
10
-
11
- // 组件名称,用于设置在编辑器左侧组件面板中展示的名称
12
- label: string = '联系人表单';
13
-
14
- // 组件描述,用于设置在编辑器左侧组件面板中展示的描述
15
- description: string =
16
- '基于 Ant Design 的联系人表单组件,支持姓名、所有人、业务类型、所属部门、手机号等字段';
17
-
18
- // 分类标签,用于设置在编辑器左侧组件面板哪个分类中展示(可设置多个分类标签)
19
- tags: string[] = ['自定义组件'];
20
-
21
- // 组件图标,用于设置在编辑器左侧组件面板中展示的图标
22
- iconSrc: string = 'https://custom-widgets.bj.bcebos.com/contact-form.svg';
23
-
24
- // 初次插入页面的默认属性数据
25
- defaultComProps = {
26
- title: '创建联系人',
27
- label: '联系人表单',
28
- showSubmitButton: true,
29
- };
30
-
31
- // 设计器端预览时展示的默认数据
32
- previewComProps = {
33
- label: '联系人表单',
34
- };
35
-
36
- /**
37
- * 组件面板配置,用于生成编辑器右侧属性配置面板内容
38
- */
39
- propsSchema = [
40
- {
41
- type: 'textarea',
42
- name: 'title',
43
- label: '表单标题',
44
- value: '创建联系人',
45
- placeholder: '请输入表单标题',
46
- },
47
- {
48
- type: 'switch',
49
- name: 'showSubmitButton',
50
- label: '显示提交按钮',
51
- value: true,
52
- },
53
- ];
54
-
55
- // 支持 函数式写法:propsSchemaCreator,com 为组件实例。优先级比 propsSchema 高
56
- /*
57
- propsSchemaCreator = (com: any) => {
58
- return [];
59
- };
60
- */
61
- }
62
-
63
- export default ContactFormModel;
@@ -1,120 +0,0 @@
1
- .contact-form-container {
2
- .contact-form-card {
3
- .ant-card-head {
4
- border-bottom: 1px solid #f0f0f0;
5
-
6
- .ant-card-head-title {
7
- font-size: 18px;
8
- font-weight: 600;
9
- color: #262626;
10
- }
11
- }
12
-
13
- .contact-form {
14
- .ant-form-item {
15
- margin-bottom: 20px;
16
-
17
- .ant-form-item-label {
18
- padding-bottom: 4px;
19
-
20
- label {
21
- font-weight: 500;
22
- color: #262626;
23
-
24
- &.ant-form-item-required::before {
25
- color: #ff4d4f;
26
- }
27
- }
28
- }
29
-
30
- .ant-input,
31
- .ant-select-selector {
32
- border-radius: 6px;
33
- border-color: #d9d9d9;
34
-
35
- &:hover {
36
- border-color: #40a9ff;
37
- }
38
-
39
- &:focus,
40
- &.ant-select-focused .ant-select-selector {
41
- border-color: #1890ff;
42
- box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
43
- }
44
- }
45
-
46
- .ant-select {
47
- .ant-select-selector {
48
- height: 40px;
49
-
50
- .ant-select-selection-item {
51
- line-height: 38px;
52
- }
53
- }
54
- }
55
-
56
- .ant-input {
57
- height: 40px;
58
- }
59
- }
60
-
61
- .form-actions {
62
- margin-bottom: 0;
63
- padding-top: 16px;
64
- border-top: 1px solid #f0f0f0;
65
- text-align: right;
66
-
67
- .ant-btn {
68
- height: 40px;
69
- padding: 8px 24px;
70
- border-radius: 6px;
71
- font-weight: 500;
72
-
73
- &.ant-btn-primary {
74
- background-color: #1890ff;
75
- border-color: #1890ff;
76
-
77
- &:hover {
78
- background-color: #40a9ff;
79
- border-color: #40a9ff;
80
- }
81
-
82
- &:active {
83
- background-color: #096dd9;
84
- border-color: #096dd9;
85
- }
86
- }
87
-
88
- &:not(.ant-btn-primary) {
89
- color: #262626;
90
- background-color: #fff;
91
- border-color: #d9d9d9;
92
-
93
- &:hover {
94
- color: #1890ff;
95
- border-color: #1890ff;
96
- }
97
- }
98
- }
99
- }
100
- }
101
- }
102
- }
103
-
104
- // 响应式设计
105
- @media (max-width: 768px) {
106
- .contact-form-container {
107
- .contact-form-card {
108
- .contact-form {
109
- .form-actions {
110
- text-align: center;
111
-
112
- .ant-btn {
113
- width: 100%;
114
- margin: 4px 0;
115
- }
116
- }
117
- }
118
- }
119
- }
120
- }
@@ -1,69 +0,0 @@
1
- import * as React from 'react';
2
- import './style.scss'; // 组件内容样式
3
-
4
- interface InfoCardProps {
5
- title: string;
6
- backgroundImage: string;
7
- imgCount: number;
8
- commentCount: number;
9
- data?: any;
10
- }
11
-
12
- export default class InfoCard extends React.PureComponent<InfoCardProps> {
13
- constructor(props: InfoCardProps) {
14
- super(props);
15
- this.agreeDataFormat = this.agreeDataFormat.bind(this);
16
- }
17
-
18
- agreeDataFormat(agreeData: number) {
19
- if (agreeData && agreeData <= 9999) {
20
- return agreeData;
21
- }
22
- if (agreeData && agreeData > 9999) {
23
- return `${Math.floor(agreeData / 1000) / 10}w`;
24
- }
25
- return '';
26
- }
27
-
28
- render() {
29
- const { title, backgroundImage, imgCount, commentCount } = this.props;
30
- console.log('当前自定义组件:', this.props, this);
31
- const curAmisData = this.props.data || {};
32
-
33
- const userInfo = curAmisData.__NeoCurrentUser;
34
- const systemInfo = curAmisData.__NeoSystemInfo || {};
35
-
36
- const curBackgroundImage =
37
- backgroundImage || 'https://neo-widgets.bj.bcebos.com/NeoCRM.jpg';
38
- return (
39
- <div className="info-card-container">
40
- <div className="news-title">
41
- {title ||
42
- '营销服全场景智能CRM,帮助企业搭建数字化客户经营平台,实现业绩高质量增长。'}
43
- {systemInfo.tenantName ? `【${systemInfo.tenantName}】` : ''}
44
- </div>
45
- <div className="item-imgbox">
46
- {userInfo && userInfo.icon && (
47
- <div className="user-info-box">
48
- <img src={userInfo.icon} className="user-icon" />
49
- <span className="user-name">{userInfo.name}</span>
50
- </div>
51
- )}
52
- <div
53
- className="news-img"
54
- style={{ backgroundImage: `url(${curBackgroundImage})` }}
55
- ></div>
56
- {imgCount > 0 && <div className="img-count">{imgCount}</div>}
57
- </div>
58
- <div className="news-info">
59
- <div className="left media-mark">NeoCRM · 低代码平台</div>
60
- {commentCount && commentCount > 0 && (
61
- <div className="cmt-num right">
62
- {this.agreeDataFormat(commentCount)}评
63
- </div>
64
- )}
65
- </div>
66
- </div>
67
- );
68
- }
69
- }
@@ -1,78 +0,0 @@
1
- /**
2
- * @file 自定义组件对接编辑器的描述文件
3
- */
4
- export class InfoCardModel {
5
- /**
6
- * cmpType 为自定义组件名称,用于标识组件的唯一性
7
- * 在构建时根据当前组件目录名称自动生成
8
- */
9
- // cmpType: string = 'info-card';
10
-
11
- // 组件名称,用于设置在编辑器左侧组件面板中展示的名称
12
- label: string = '信息卡片';
13
-
14
- // 组件描述,用于设置在编辑器左侧组件面板中展示的描述
15
- description: string = '信息展示卡片';
16
-
17
- // 分类标签,用于设置在编辑器左侧组件面板哪个分类中展示(可设置多个分类标签)
18
- tags: string[] = ['自定义组件'];
19
-
20
- // 组件图标,用于设置在编辑器左侧组件面板中展示的图标
21
- iconSrc: string = 'https://neo-widgets.bj.bcebos.com/custom-widget.svg';
22
- // iconSrc = 'https://neo-widgets.bj.bcebos.com/favicon.png';
23
-
24
- // 初次插入页面的默认属性数据
25
- defaultComProps = {
26
- title:
27
- '营销服全场景智能CRM,帮助企业搭建数字化客户经营平台,实现业绩高质量增长。',
28
- label: '信息卡片',
29
- backgroundImage: 'https://neo-widgets.bj.bcebos.com/NeoCRM.jpg',
30
- imgCount: 3,
31
- commentCount: 2025,
32
- };
33
-
34
- // 设计器端预览时展示的默认数据
35
- previewComProps = {
36
- label: '信息卡片',
37
- };
38
-
39
- /**
40
- * 组件面板配置,用于生成编辑器右侧属性配置面板内容
41
- */
42
- propsSchema = [
43
- {
44
- type: 'textarea',
45
- name: 'title',
46
- label: '卡片title',
47
- value:
48
- '营销服全场景智能CRM,帮助企业搭建数字化客户经营平台,实现业绩高质量增长。',
49
- },
50
- {
51
- type: 'text',
52
- name: 'backgroundImage',
53
- label: '展示图片',
54
- value: 'https://neo-widgets.bj.bcebos.com/NeoCRM.jpg',
55
- },
56
- {
57
- type: 'number',
58
- name: 'imgCount',
59
- label: '图片数量',
60
- value: 3,
61
- },
62
- {
63
- type: 'number',
64
- name: 'commentCount',
65
- label: '评论数',
66
- value: 2025,
67
- },
68
- ];
69
-
70
- // 支持 函数式写法:propsSchemaCreator,com 为组件实例。优先级比 propsSchema 高
71
- /*
72
- propsSchemaCreator = (com: any) => {
73
- return [];
74
- };
75
- */
76
- }
77
-
78
- export default InfoCardModel;
@@ -1,105 +0,0 @@
1
- :root {
2
- --padding-bottom: 12px;
3
- }
4
-
5
- .info-card-container {
6
- position: relative;
7
- box-sizing: border-box;
8
-
9
- /* border-bottom: 1px solid #ececec; */
10
- margin: 6px 12px;
11
- padding: 6px var(--padding-bottom);
12
- background-color: #fff;
13
-
14
- .news-title {
15
- padding: 6px 0;
16
- font-family: PingFangSC-Regular;
17
- font-size: 16px;
18
- line-height: 22px;
19
- color: #5f5e5e;
20
- }
21
-
22
- .item-imgbox {
23
- position: relative;
24
- height: 395px;
25
- background: #f0f0f0;
26
- cursor: pointer;
27
- box-sizing: border-box;
28
- text-align: center;
29
- overflow: hidden;
30
-
31
- .news-img {
32
- width: 100%;
33
- height: 100%;
34
- box-sizing: border-box;
35
- background-size: contain;
36
- }
37
-
38
- .img-count {
39
- position: absolute;
40
- top: 0;
41
- right: 0;
42
- padding: 6px 8px;
43
- color: #fff;
44
- min-width: 60px;
45
- text-align: center;
46
- line-height: 1.2;
47
- background: rgb(0 0 0 / 40%);
48
- font-size: 25px;
49
- box-sizing: border-box;
50
- overflow: hidden;
51
- }
52
-
53
- .user-info-box {
54
- position: absolute;
55
- top: 10px;
56
- left: 10px;
57
- width: 100px;
58
- min-height: 100px;
59
- padding: 6px 8px;
60
- color: #fff;
61
- min-width: 60px;
62
- text-align: center;
63
- line-height: 1.2;
64
- background: rgb(0 0 0 / 40%);
65
- font-size: 25px;
66
- box-sizing: border-box;
67
- overflow: hidden;
68
- display: flex;
69
- flex-direction: column;
70
- align-items: center;
71
- justify-content: center;
72
-
73
- .user-icon {
74
- width: 64px;
75
- height: 64px;
76
- border-radius: 50%;
77
- }
78
-
79
- .user-name {
80
- font-size: 16px;
81
- font-weight: 600;
82
- margin-top: 10px;
83
- }
84
- }
85
- }
86
-
87
- .news-info {
88
- font-family: PingFangSC-Light;
89
- height: 28px;
90
- box-sizing: border-box;
91
- display: flex;
92
- justify-content: space-between;
93
- align-items: center;
94
- }
95
-
96
- .media-mark,
97
- .cmt-num {
98
- display: inline-block;
99
- height: 28px;
100
- line-height: 28px;
101
- font-family: PingFangSC-Light;
102
- font-size: 18px;
103
- color: #828282;
104
- }
105
- }