neo-cmp-cli 1.13.9 → 1.13.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.
- package/dist/neo/neoLogin.js +1 -1
- package/dist/package.json.js +1 -1
- package/package.json +1 -1
- package/template/neo-web-entity-grid/src/components/createForm__c/index.tsx +9 -4
- package/template/neo-web-entity-grid/src/components/createForm__c/model.ts +4 -2
- package/template/neo-web-entity-grid/src/components/entityGrid3__c/model.ts +2 -2
- package/template/neo-web-entity-grid/src/components/searchForm__c/index.tsx +6 -10
- package/template/neo-web-entity-grid/src/components/searchForm__c/model.ts +1 -1
- package/template/neo-web-entity-grid/src/components/searchForm__c/style.scss +205 -229
- package/template/neo-web-form/.prettierrc.js +12 -0
- package/template/neo-web-form/@types/neo-ui-common.d.ts +36 -0
- package/template/neo-web-form/README.md +99 -0
- package/template/neo-web-form/commitlint.config.js +59 -0
- package/template/neo-web-form/neo.config.js +57 -0
- package/template/neo-web-form/package.json +66 -0
- package/template/neo-web-form/public/css/base.css +283 -0
- package/template/neo-web-form/public/scripts/app/bluebird.js +6679 -0
- package/template/neo-web-form/public/template.html +13 -0
- package/template/neo-web-form/src/assets/css/common.scss +127 -0
- package/template/neo-web-form/src/assets/css/mixin.scss +47 -0
- package/template/neo-web-form/src/assets/img/AIBtn.gif +0 -0
- package/template/neo-web-form/src/assets/img/NeoCRM.jpg +0 -0
- package/template/neo-web-form/src/assets/img/aiLogo.png +0 -0
- package/template/neo-web-form/src/assets/img/card-list.svg +1 -0
- package/template/neo-web-form/src/assets/img/contact-form.svg +1 -0
- package/template/neo-web-form/src/assets/img/custom-form.svg +1 -0
- package/template/neo-web-form/src/assets/img/custom-widget.svg +1 -0
- package/template/neo-web-form/src/assets/img/data-list.svg +1 -0
- package/template/neo-web-form/src/assets/img/detail.svg +1 -0
- package/template/neo-web-form/src/assets/img/favicon.png +0 -0
- package/template/neo-web-form/src/assets/img/map.svg +1 -0
- package/template/neo-web-form/src/assets/img/search.svg +1 -0
- package/template/neo-web-form/src/assets/img/table.svg +1 -0
- package/template/neo-web-form/src/components/batchAddTable__c/index.tsx +1052 -0
- package/template/neo-web-form/src/components/batchAddTable__c/model.ts +90 -0
- package/template/neo-web-form/src/components/batchAddTable__c/style.scss +21 -0
- package/template/neo-web-form/src/components/batchAddTable__c/tableModal.scss +137 -0
- package/template/neo-web-form/src/components/listSummary__c/index.tsx +120 -0
- package/template/neo-web-form/src/components/listSummary__c/model.ts +69 -0
- package/template/neo-web-form/src/components/listSummary__c/style.scss +40 -0
- package/template/neo-web-form/src/utils/axiosFetcher.ts +37 -0
- package/template/neo-web-form/src/utils/queryObjectData.ts +112 -0
- package/template/neo-web-form/src/utils/xobjects.ts +167 -0
- package/template/neo-web-form/tsconfig.json +39 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 批量新增表格组件对接编辑器的描述文件
|
|
3
|
+
* @description 定义组件在 Neo 平台编辑器中的配置信息
|
|
4
|
+
*/
|
|
5
|
+
export class BatchAddTableModel {
|
|
6
|
+
label: string = '批量新增表格';
|
|
7
|
+
|
|
8
|
+
description: string =
|
|
9
|
+
'基于实体数据源的可编辑表格,支持逐行录入与 Excel 批量导入,提交时触发事件';
|
|
10
|
+
|
|
11
|
+
iconUrl: string = 'https://custom-widgets.bj.bcebos.com/table.svg';
|
|
12
|
+
|
|
13
|
+
targetPage: string[] = ['all'];
|
|
14
|
+
|
|
15
|
+
targetDevice: string = 'web';
|
|
16
|
+
|
|
17
|
+
enableDuplicate: boolean = true;
|
|
18
|
+
|
|
19
|
+
defaultComProps = {
|
|
20
|
+
tableTitle: '批量新增数据',
|
|
21
|
+
batchImportButtonTitle: '批量导入',
|
|
22
|
+
batchImportButtonAlign: 'right',
|
|
23
|
+
xObjectDataApi: {
|
|
24
|
+
xObjectApiKey: 'opportunityProduct',
|
|
25
|
+
fields: [],
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
events = [
|
|
30
|
+
{
|
|
31
|
+
apiKey: 'onSubmit',
|
|
32
|
+
label: '点击提交',
|
|
33
|
+
helpText: '点击提交按钮时触发,事件参数包含当前表格中所有行数据',
|
|
34
|
+
eventParams1:
|
|
35
|
+
[{
|
|
36
|
+
"apiKey": "eventParam",
|
|
37
|
+
"children":
|
|
38
|
+
[
|
|
39
|
+
{ "apiKey": "xObjectApiKey", "label": "实体 API Key", "type": "String" },
|
|
40
|
+
{ "apiKey": "rows", "label": "表格数据列表", "type": "Array" }
|
|
41
|
+
],
|
|
42
|
+
"label": "事件入参",
|
|
43
|
+
"type": "Object"
|
|
44
|
+
}],
|
|
45
|
+
eventParams:
|
|
46
|
+
'[{"apiKey":"eventParam","children":[{"apiKey":"xObjectApiKey","label":"实体 API Key","type":"String"},{"apiKey":"rows","label":"表格数据列表","type":"Array"}],"label":"事件入参","type":"Object"}]',
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
propsSchema = [
|
|
51
|
+
{
|
|
52
|
+
type: 'panelInput',
|
|
53
|
+
name: 'batchImportButtonTitle',
|
|
54
|
+
label: '批量导入按钮文案',
|
|
55
|
+
value: '批量导入',
|
|
56
|
+
placeholder: '入口按钮显示文字',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'panelSelect',
|
|
60
|
+
name: 'batchImportButtonAlign',
|
|
61
|
+
label: '批量导入按钮位置',
|
|
62
|
+
value: 'right',
|
|
63
|
+
placeholder: '请选择按钮水平对齐方式',
|
|
64
|
+
options: [
|
|
65
|
+
{ label: '靠左', value: 'left' },
|
|
66
|
+
{ label: '居中', value: 'center' },
|
|
67
|
+
{ label: '靠右', value: 'right' },
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: 'panelInput',
|
|
72
|
+
name: 'tableTitle',
|
|
73
|
+
label: '表格标题',
|
|
74
|
+
value: '批量新增数据',
|
|
75
|
+
placeholder: '请输入表格标题',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
type: 'xObjectDataApi',
|
|
79
|
+
name: 'xObjectDataApi',
|
|
80
|
+
label: '实体数据源',
|
|
81
|
+
placeholder: '请选择实体数据源',
|
|
82
|
+
custom: false,
|
|
83
|
+
showPage: false,
|
|
84
|
+
showPageSize: false,
|
|
85
|
+
showAutoFetchData: false,
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default BatchAddTableModel;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.batchAddTable__c {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
padding: 8px 12px;
|
|
4
|
+
|
|
5
|
+
.batch-add-entry-toolbar {
|
|
6
|
+
display: flex;
|
|
7
|
+
width: 100%;
|
|
8
|
+
|
|
9
|
+
&--left {
|
|
10
|
+
justify-content: flex-start;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
&--center {
|
|
14
|
+
justify-content: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
&--right {
|
|
18
|
+
justify-content: flex-end;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 批量新增表格 — 弹窗(Modal)相关样式
|
|
3
|
+
* 使用 .batch-add-table-modal 根选择器,适配 Modal 挂载到 body 的场景
|
|
4
|
+
*/
|
|
5
|
+
.batch-add-table-modal {
|
|
6
|
+
.ant-modal-content {
|
|
7
|
+
min-height: 350px;
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.ant-modal-header {
|
|
13
|
+
flex-shrink: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.ant-modal-body {
|
|
17
|
+
flex: 1;
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
min-height: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.ant-modal-footer {
|
|
24
|
+
flex-shrink: 0;
|
|
25
|
+
border-top: 1px solid #f0f0f0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.batch-add-modal-layout {
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
flex: 1;
|
|
32
|
+
min-height: 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** 弹窗内顶部操作区:固定高度、按钮靠右 */
|
|
36
|
+
.batch-add-modal-toolbar-wrap {
|
|
37
|
+
flex-shrink: 0;
|
|
38
|
+
box-sizing: border-box;
|
|
39
|
+
height: 64px;
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
justify-content: flex-end;
|
|
43
|
+
padding-bottom: 12px;
|
|
44
|
+
margin-bottom: 12px;
|
|
45
|
+
border-bottom: 1px solid #f0f0f0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** 表格区域:最大高度 600px,超出纵向滚动 */
|
|
49
|
+
.batch-add-modal-table-scroll {
|
|
50
|
+
flex: 1;
|
|
51
|
+
min-height: 0;
|
|
52
|
+
max-height: 600px;
|
|
53
|
+
overflow: auto;
|
|
54
|
+
|
|
55
|
+
.ant-spin-nested-loading {
|
|
56
|
+
min-height: 100%;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.ant-spin-container {
|
|
60
|
+
min-height: 100%;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.batch-add-modal-footer-inner {
|
|
65
|
+
display: flex;
|
|
66
|
+
justify-content: center;
|
|
67
|
+
width: 100%;
|
|
68
|
+
|
|
69
|
+
.ant-space {
|
|
70
|
+
justify-content: center;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.batch-add-submit-btn {
|
|
74
|
+
min-width: 200px;
|
|
75
|
+
padding-left: 40px;
|
|
76
|
+
padding-right: 40px;
|
|
77
|
+
height: 40px;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.table-wrap {
|
|
82
|
+
.ant-table {
|
|
83
|
+
font-size: 12px;
|
|
84
|
+
|
|
85
|
+
.ant-table-thead > tr > th,
|
|
86
|
+
.ant-table-tbody > tr > td {
|
|
87
|
+
font-size: 12px;
|
|
88
|
+
padding: 6px 10px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.ant-table-thead > tr > th {
|
|
92
|
+
background-color: #fafafa;
|
|
93
|
+
font-weight: 600;
|
|
94
|
+
color: #262626;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.batch-add-cell-editor {
|
|
99
|
+
min-width: 120px;
|
|
100
|
+
font-size: 12px;
|
|
101
|
+
|
|
102
|
+
input,
|
|
103
|
+
textarea {
|
|
104
|
+
font-size: 12px;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.ant-select-selector,
|
|
108
|
+
.ant-picker-input > input {
|
|
109
|
+
font-size: 12px !important;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.ant-input-number-input {
|
|
113
|
+
font-size: 12px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.ant-input-number {
|
|
117
|
+
width: 100%;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.ant-picker {
|
|
121
|
+
width: 100%;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.ant-select {
|
|
125
|
+
width: 100%;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.batch-add-copy-btn,
|
|
131
|
+
.batch-add-delete-btn {
|
|
132
|
+
padding: 0 4px;
|
|
133
|
+
font-size: 12px;
|
|
134
|
+
height: auto;
|
|
135
|
+
line-height: 1.4;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 列表汇总组件
|
|
3
|
+
* @description 根据 setListData 传入的列表与配置的数量/金额/单位字段展示汇总
|
|
4
|
+
*/
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
import { BaseCmp, StatusHoc, NeoEvent } from 'neo-ui-common';
|
|
8
|
+
|
|
9
|
+
import './style.scss';
|
|
10
|
+
|
|
11
|
+
interface FieldDescItem {
|
|
12
|
+
value: string;
|
|
13
|
+
label: string;
|
|
14
|
+
type?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ListSummaryProps {
|
|
18
|
+
/** xObjectEntityList 配置的实体 API Key */
|
|
19
|
+
xObjectApiKey?: string;
|
|
20
|
+
/** 计算字段(数量),selectFieldDescApi 单选,存储为描述数组 */
|
|
21
|
+
quantityFieldDesc?: FieldDescItem[];
|
|
22
|
+
amountFieldDesc?: FieldDescItem[];
|
|
23
|
+
summaryTitle?: string;
|
|
24
|
+
data?: any;
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface ListSummaryState {
|
|
29
|
+
listData: any[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getFirstFieldApiKey(desc?: FieldDescItem[] | null): string | undefined {
|
|
33
|
+
if (!desc || !Array.isArray(desc) || desc.length === 0) return undefined;
|
|
34
|
+
const first = desc[0];
|
|
35
|
+
return first?.value;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function toFiniteNumber(raw: any): number {
|
|
39
|
+
if (raw === null || raw === undefined || raw === '') return 0;
|
|
40
|
+
const n = Number(raw);
|
|
41
|
+
return Number.isFinite(n) ? n : 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function sumField(rows: any[], apiKey: string | undefined): number {
|
|
45
|
+
if (!apiKey || !Array.isArray(rows)) return 0;
|
|
46
|
+
return rows.reduce((acc, row) => acc + toFiniteNumber(row?.[apiKey]), 0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class ListSummary extends BaseCmp<ListSummaryProps, ListSummaryState> {
|
|
50
|
+
constructor(props: ListSummaryProps) {
|
|
51
|
+
super(props);
|
|
52
|
+
this.state = {
|
|
53
|
+
listData: [],
|
|
54
|
+
};
|
|
55
|
+
this.setListData = this.setListData.bind(this);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 组件动作:接收列表数据写入 state.listData
|
|
60
|
+
*/
|
|
61
|
+
@NeoEvent.function
|
|
62
|
+
setListData(payload?: any) {
|
|
63
|
+
let list: any[] = [];
|
|
64
|
+
if (Array.isArray(payload)) {
|
|
65
|
+
list = payload;
|
|
66
|
+
} else if (payload && Array.isArray(payload.listData)) {
|
|
67
|
+
list = payload.listData;
|
|
68
|
+
}
|
|
69
|
+
this.setState({ listData: list });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
render() {
|
|
73
|
+
const { listData } = this.state;
|
|
74
|
+
const {
|
|
75
|
+
className,
|
|
76
|
+
summaryTitle = '汇总信息',
|
|
77
|
+
quantityFieldDesc,
|
|
78
|
+
amountFieldDesc,
|
|
79
|
+
} = this.props;
|
|
80
|
+
console.log('listSummary__c:', this.props);
|
|
81
|
+
|
|
82
|
+
const qtyKey = getFirstFieldApiKey(quantityFieldDesc);
|
|
83
|
+
const amountKey = getFirstFieldApiKey(amountFieldDesc);
|
|
84
|
+
|
|
85
|
+
const hasRows = Array.isArray(listData) && listData.length > 0;
|
|
86
|
+
const totalQty = hasRows && qtyKey ? sumField(listData, qtyKey) : 0;
|
|
87
|
+
const totalAmount = hasRows && amountKey ? sumField(listData, amountKey) : 0;
|
|
88
|
+
|
|
89
|
+
const qtyDisplay =
|
|
90
|
+
!hasRows || !qtyKey
|
|
91
|
+
? '0'
|
|
92
|
+
: totalQty.toLocaleString('zh-CN');
|
|
93
|
+
|
|
94
|
+
const amountDisplay =
|
|
95
|
+
!hasRows || !amountKey
|
|
96
|
+
? '0'
|
|
97
|
+
: totalAmount.toLocaleString('zh-CN', {
|
|
98
|
+
minimumFractionDigits: 2,
|
|
99
|
+
maximumFractionDigits: 2,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<div className={`listSummary__c ${className || ''}`}>
|
|
104
|
+
<div className="list-summary-title">{summaryTitle}</div>
|
|
105
|
+
<div className="list-summary-body">
|
|
106
|
+
<div className="list-summary-item">
|
|
107
|
+
<span className="list-summary-label">商品总数</span>
|
|
108
|
+
<span className="list-summary-value">{qtyDisplay}</span>
|
|
109
|
+
</div>
|
|
110
|
+
<div className="list-summary-item">
|
|
111
|
+
<span className="list-summary-label">金额合计</span>
|
|
112
|
+
<span className="list-summary-value">{amountDisplay}</span>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export default StatusHoc(ListSummary);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 列表汇总组件对接编辑器的描述文件
|
|
3
|
+
* @description 根据外部传入的列表数据与配置的字段,展示数量合计与金额合计
|
|
4
|
+
*/
|
|
5
|
+
export class ListSummaryModel {
|
|
6
|
+
label: string = '列表汇总';
|
|
7
|
+
|
|
8
|
+
description: string =
|
|
9
|
+
'绑定实体与数量、金额字段,通过组件动作接收列表数据后展示商品总数与金额汇总';
|
|
10
|
+
|
|
11
|
+
iconUrl: string = 'https://custom-widgets.bj.bcebos.com/TargetNumber.svg';
|
|
12
|
+
|
|
13
|
+
targetPage: string[] = ['all'];
|
|
14
|
+
|
|
15
|
+
targetDevice: string = 'web';
|
|
16
|
+
|
|
17
|
+
enableDuplicate: boolean = true;
|
|
18
|
+
|
|
19
|
+
defaultComProps = {
|
|
20
|
+
summaryTitle: '汇总信息',
|
|
21
|
+
xObjectApiKey: 'opportunityProduct',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
functions = [
|
|
25
|
+
{
|
|
26
|
+
apiKey: 'setListData',
|
|
27
|
+
label: '接收列表数据',
|
|
28
|
+
helpTextKey: '将列表数据写入汇总组件中,用于汇总计算',
|
|
29
|
+
funcInParams: [
|
|
30
|
+
{
|
|
31
|
+
apiKey: 'listData',
|
|
32
|
+
label: '列表数据',
|
|
33
|
+
type: 'Array',
|
|
34
|
+
required: true,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
propsSchema = [
|
|
41
|
+
{
|
|
42
|
+
type: 'panelInput',
|
|
43
|
+
name: 'summaryTitle',
|
|
44
|
+
label: '汇总标题',
|
|
45
|
+
value: '汇总信息',
|
|
46
|
+
placeholder: '区块标题文案',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
type: 'xObjectEntityList',
|
|
50
|
+
name: 'xObjectApiKey',
|
|
51
|
+
label: '实体对象',
|
|
52
|
+
custom: false,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: 'selectFieldDescApi',
|
|
56
|
+
name: 'quantityFieldDesc',
|
|
57
|
+
xObjectApiKey: 'xObjectApiKey',
|
|
58
|
+
label: '计算字段(数量)',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: 'selectFieldDescApi',
|
|
62
|
+
name: 'amountFieldDesc',
|
|
63
|
+
xObjectApiKey: 'xObjectApiKey',
|
|
64
|
+
label: '金额字段',
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default ListSummaryModel;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
.listSummary__c {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
padding: 12px 16px;
|
|
4
|
+
background: #fafafa;
|
|
5
|
+
border: 1px solid #f0f0f0;
|
|
6
|
+
border-radius: 6px;
|
|
7
|
+
|
|
8
|
+
.list-summary-title {
|
|
9
|
+
font-size: 14px;
|
|
10
|
+
font-weight: 600;
|
|
11
|
+
color: #262626;
|
|
12
|
+
margin-bottom: 10px;
|
|
13
|
+
padding-bottom: 8px;
|
|
14
|
+
border-bottom: 1px solid #f0f0f0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.list-summary-body {
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-wrap: wrap;
|
|
20
|
+
gap: 16px 32px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.list-summary-item {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: column;
|
|
26
|
+
gap: 4px;
|
|
27
|
+
min-width: 120px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.list-summary-label {
|
|
31
|
+
font-size: 13px;
|
|
32
|
+
color: #8c8c8c;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.list-summary-value {
|
|
36
|
+
font-size: 18px;
|
|
37
|
+
font-weight: 600;
|
|
38
|
+
color: #262626;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import axios from 'axios'; // https://www.axios-http.cn/docs/intro
|
|
2
|
+
|
|
3
|
+
// 创建基于 axios 的 fetcher 函数
|
|
4
|
+
const axiosFetcher = async (options: any) => {
|
|
5
|
+
try {
|
|
6
|
+
const config = {
|
|
7
|
+
...options,
|
|
8
|
+
method: options?.method || 'GET',
|
|
9
|
+
data: options?.data || {},
|
|
10
|
+
headers: {
|
|
11
|
+
'Content-Type': 'application/json',
|
|
12
|
+
...options?.headers,
|
|
13
|
+
},
|
|
14
|
+
timeout: options?.timeout || 30000,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
if (config?.method === 'GET') {
|
|
18
|
+
config.params = options?.data || {};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const response = await axios(config);
|
|
22
|
+
return response?.data || {};
|
|
23
|
+
} catch (error) {
|
|
24
|
+
if (error.response) {
|
|
25
|
+
// 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
|
|
26
|
+
console.error('接口请求报错 / 接口服务异常:', error.message);
|
|
27
|
+
} else if (error.request) {
|
|
28
|
+
// 请求已经成功发起,但没有收到响应
|
|
29
|
+
console.error('接口请求报错 / 接口未正常响应:', error.message);
|
|
30
|
+
} else {
|
|
31
|
+
console.error('接口请求报错:', error, ',请求参数:', options);
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default axiosFetcher;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import axiosFetcher from '$utils/axiosFetcher';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 这里存放通用查询类 Open API
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** 将 where 规范为 SQL 片段:字符串直接使用;数组用 and 拼接各条件 */
|
|
8
|
+
function normalizeWhere(where: unknown): string {
|
|
9
|
+
if (where == null || where === '') {
|
|
10
|
+
return '';
|
|
11
|
+
}
|
|
12
|
+
if (typeof where === 'string') {
|
|
13
|
+
return where.trim();
|
|
14
|
+
}
|
|
15
|
+
if (Array.isArray(where)) {
|
|
16
|
+
return where
|
|
17
|
+
.map((part) => (part == null ? '' : String(part).trim()))
|
|
18
|
+
.filter(Boolean)
|
|
19
|
+
.join(' and ');
|
|
20
|
+
}
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 获取业务对象数据列表
|
|
25
|
+
export const queryXObjectData = async (options?: any) => {
|
|
26
|
+
const apiUrl = '/rest/data/v2/query';
|
|
27
|
+
const curOptions = options || {};
|
|
28
|
+
const xObjectApiKey = curOptions.xObjectApiKey || '';
|
|
29
|
+
const fields = curOptions.fields || [];
|
|
30
|
+
const page = curOptions.page || 1;
|
|
31
|
+
const pageSize = curOptions.pageSize || 10;
|
|
32
|
+
|
|
33
|
+
// 自动添加 objectId 字段
|
|
34
|
+
if (!fields.includes('id')) {
|
|
35
|
+
fields.push('id');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 计算分页偏移量
|
|
39
|
+
const offset = (page - 1) * pageSize;
|
|
40
|
+
|
|
41
|
+
// 构建 SQL 查询
|
|
42
|
+
let querySql = `select ${fields.join(',')} from ${xObjectApiKey}`;
|
|
43
|
+
|
|
44
|
+
// 添加排序条件(如果有的话)
|
|
45
|
+
if (curOptions.orderBy) {
|
|
46
|
+
querySql += ` order by ${curOptions.orderBy}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 添加过滤条件(如果有的话)
|
|
51
|
+
* 支持的操作符包括:=、!=、like、not like、not in、is not null、is null、>、<、<>、>=、<=、in、between ... and ...。
|
|
52
|
+
* 对于 =、like 和 in 有以下说明:
|
|
53
|
+
* “=” 作为字符串的条件时,表示精确匹配。例如,查询条件 city = '北京',将返回 city 字段值严格等于 "北京" 的所有记录。
|
|
54
|
+
* "like" 作为字符串的条件时,需要使用"%" 通配符进行模糊匹配。例如,city like‘北京%',将返回 city 字段值以 "北京" 开头的所有记录。
|
|
55
|
+
* 目前仅支持将通配符“%” 放到已知内容之后的查询方式,例如,不支持 city like ‘% 北京'的查询方式。
|
|
56
|
+
* 当 SQL 查询中包含“%”等特殊字符时,需要对 SQL 进行 URL 编码处理。
|
|
57
|
+
* 支持"in",但不包括子查询。
|
|
58
|
+
* 支持的逻辑运算符包括:and、or。
|
|
59
|
+
*
|
|
60
|
+
* `where` 可为字符串,或字符串数组(多项默认以 and 连接,等价于手写 `a and b`)。
|
|
61
|
+
*/
|
|
62
|
+
const whereClause = normalizeWhere(curOptions.where);
|
|
63
|
+
console.log('whereClause:', whereClause);
|
|
64
|
+
if (whereClause) {
|
|
65
|
+
querySql += ` where ${whereClause}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (curOptions.page || curOptions.pageSize) {
|
|
69
|
+
// 添加分页限制
|
|
70
|
+
querySql += ` limit ${pageSize} offset ${offset}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const config = {
|
|
75
|
+
url: apiUrl,
|
|
76
|
+
method: 'GET',
|
|
77
|
+
data: {
|
|
78
|
+
q: querySql,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const resultData = await axiosFetcher(config);
|
|
83
|
+
|
|
84
|
+
if (resultData.code === 200) {
|
|
85
|
+
const { records, totalSize } = resultData.result || {};
|
|
86
|
+
return {
|
|
87
|
+
status: true,
|
|
88
|
+
code: resultData.code,
|
|
89
|
+
msg: resultData.msg || '获取业务对象数据列表成功',
|
|
90
|
+
totalSize,
|
|
91
|
+
data: records || [],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
status: false,
|
|
97
|
+
code: resultData.code,
|
|
98
|
+
msg: resultData.msg || '获取业务对象数据列表失败',
|
|
99
|
+
data: [],
|
|
100
|
+
};
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error('获取业务对象数据列表失败:', error);
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
status: false,
|
|
106
|
+
msg: error.msg || error.message || '获取业务对象数据列表失败',
|
|
107
|
+
data: [],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export default queryXObjectData;
|