n20-common-lib 3.0.97 → 3.0.99
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
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
:key="getOnlyKey(item)"
|
|
8
8
|
:class="[prefixCls + '-item', activeClass(item)]"
|
|
9
9
|
:label="item.label"
|
|
10
|
-
:required="item.required
|
|
10
|
+
:required="!!item.required"
|
|
11
11
|
:disabled="item.props && item.props.disabled"
|
|
12
12
|
>
|
|
13
13
|
<div :class="prefixCls + '-content'">
|
|
@@ -313,38 +313,24 @@ export default {
|
|
|
313
313
|
return this.model
|
|
314
314
|
},
|
|
315
315
|
activeClass(item) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
return this.model[item.value] !== null &&
|
|
321
|
-
this.model[item.value] !== undefined &&
|
|
322
|
-
this.model[item.value] !== ''
|
|
323
|
-
? this.prefixCls + '-active'
|
|
324
|
-
: ''
|
|
325
|
-
}
|
|
316
|
+
// 判断值是否有效(非空)
|
|
317
|
+
const hasValue = (val) => {
|
|
318
|
+
if (Array.isArray(val)) return val.length > 0
|
|
319
|
+
return val !== null && val !== undefined && val !== ''
|
|
326
320
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
case 'daterange':
|
|
339
|
-
case 'datetimerange':
|
|
340
|
-
case ' monthrange':
|
|
341
|
-
flag = this.model[item.startDate] && this.model[item.endDate] ? this.prefixCls + '-active' : ''
|
|
342
|
-
break
|
|
343
|
-
default:
|
|
344
|
-
flag = getFlag()
|
|
345
|
-
break
|
|
321
|
+
|
|
322
|
+
// 判断范围类型是否有效(起止值都存在)
|
|
323
|
+
const hasRange = (start, end) => hasValue(this.model[start]) && hasValue(this.model[end])
|
|
324
|
+
|
|
325
|
+
const rangeTypes = ['daterange', 'datetimerange', 'monthrange']
|
|
326
|
+
|
|
327
|
+
if (item.type === 'numberrange') {
|
|
328
|
+
return hasRange(item.startValue, item.endValue) ? this.prefixCls + '-active' : ''
|
|
329
|
+
}
|
|
330
|
+
if (rangeTypes.includes(item.type)) {
|
|
331
|
+
return hasRange(item.startDate, item.endDate) ? this.prefixCls + '-active' : ''
|
|
346
332
|
}
|
|
347
|
-
return
|
|
333
|
+
return hasValue(this.model[item.value]) ? this.prefixCls + '-active' : ''
|
|
348
334
|
},
|
|
349
335
|
handleClose(item) {
|
|
350
336
|
switch (item.type) {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
@mouseenter="hoveredReportId = report.id"
|
|
21
21
|
@mouseleave="hoveredReportId = null"
|
|
22
22
|
>
|
|
23
|
-
<i class="
|
|
23
|
+
<i :class="getChartTypeIcon(report.chartType)" class="report-icon"></i>
|
|
24
24
|
<span v-if="editingReportId !== report.id" class="report-name">{{ report.name }}</span>
|
|
25
25
|
<input
|
|
26
26
|
v-else
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
<!-- 内容头部工具栏 -->
|
|
71
71
|
<div class="main-toolbar">
|
|
72
72
|
<div class="toolbar-left">
|
|
73
|
-
<div
|
|
73
|
+
<div>
|
|
74
74
|
<h2 class="report-title">{{ currentReport.name }}</h2>
|
|
75
75
|
<div class="add-to-home-btn" @click="handleAddToHome">
|
|
76
76
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
|
|
@@ -195,13 +195,16 @@
|
|
|
195
195
|
<!-- 右侧维度配置 -->
|
|
196
196
|
<div class="pivot-sidebar-right" :class="{ collapsed: isRightSidebarCollapsed }">
|
|
197
197
|
<div class="sidebar-header">
|
|
198
|
-
<
|
|
198
|
+
<template v-if="!isRightSidebarCollapsed">
|
|
199
|
+
<i class="v3-icon-move-right sidebar-header-collapse" @click="handleToggleRightSidebar"></i>
|
|
200
|
+
<span class="sidebar-title">维度配置</span>
|
|
201
|
+
</template>
|
|
199
202
|
</div>
|
|
200
203
|
|
|
201
204
|
<div class="config-form">
|
|
202
205
|
<!-- 报表名称 -->
|
|
203
206
|
<div class="form-item">
|
|
204
|
-
<label class="form-label"
|
|
207
|
+
<label class="form-label">报表标题</label>
|
|
205
208
|
|
|
206
209
|
<div class="input-wrapper">
|
|
207
210
|
<input class="form-input" type="text" v-model="currentReport.name" placeholder="请输入报表名称" />
|
|
@@ -226,10 +229,7 @@
|
|
|
226
229
|
<label class="form-label">展示形式</label>
|
|
227
230
|
<div class="select-wrapper" @click="showChartTypeDropdown = !showChartTypeDropdown">
|
|
228
231
|
<div class="select-value">
|
|
229
|
-
<
|
|
230
|
-
<rect x="1" y="3" width="12" height="8" rx="1" stroke="currentColor" stroke-width="1.5" />
|
|
231
|
-
<path d="M3 8V11M7 6V11M11 9V11" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
|
|
232
|
-
</svg>
|
|
232
|
+
<i :class="getChartTypeIcon(currentReport.chartType)" class="report-icon"></i>
|
|
233
233
|
<span>{{ getChartTypeLabel(currentReport.chartType) }}</span>
|
|
234
234
|
</div>
|
|
235
235
|
<svg class="select-arrow" width="10" height="10" viewBox="0 0 10 10" fill="none">
|
|
@@ -255,6 +255,8 @@
|
|
|
255
255
|
</div>
|
|
256
256
|
</div>
|
|
257
257
|
|
|
258
|
+
<div class="form-divider"></div>
|
|
259
|
+
|
|
258
260
|
<!-- 分组维度 -->
|
|
259
261
|
<div class="form-item">
|
|
260
262
|
<label class="form-label">
|
|
@@ -309,6 +311,8 @@
|
|
|
309
311
|
</div>
|
|
310
312
|
</div>
|
|
311
313
|
|
|
314
|
+
<div class="form-divider"></div>
|
|
315
|
+
|
|
312
316
|
<!-- 计算指标 -->
|
|
313
317
|
<div class="form-item">
|
|
314
318
|
<div class="form-label-row">
|
|
@@ -897,6 +901,17 @@ export default {
|
|
|
897
901
|
return chart ? chart.label : '柱状图'
|
|
898
902
|
},
|
|
899
903
|
|
|
904
|
+
// 获取图表类型图标
|
|
905
|
+
getChartTypeIcon(type) {
|
|
906
|
+
const iconMap = {
|
|
907
|
+
bar: 'v3-icon-chart-histogram',
|
|
908
|
+
line: 'v3-icon-chart-line',
|
|
909
|
+
pie: 'v3-icon-chart-pie',
|
|
910
|
+
horizontalBar: 'v3-icon-histogram'
|
|
911
|
+
}
|
|
912
|
+
return iconMap[type] || 'v3-icon-chart-histogram'
|
|
913
|
+
},
|
|
914
|
+
|
|
900
915
|
// 获取聚合类型标签
|
|
901
916
|
getAggregateLabel(type) {
|
|
902
917
|
const agg = this.aggregateTypes.find((t) => t.value === type)
|
|
@@ -1113,11 +1128,14 @@ export default {
|
|
|
1113
1128
|
.el-dialog {
|
|
1114
1129
|
box-sizing: border-box;
|
|
1115
1130
|
margin-top: 3vh !important;
|
|
1116
|
-
max-height:
|
|
1131
|
+
max-height: 94vh;
|
|
1117
1132
|
display: flex;
|
|
1118
1133
|
flex-direction: column;
|
|
1119
1134
|
.el-dialog__body {
|
|
1120
1135
|
padding: 0;
|
|
1136
|
+
flex: 1;
|
|
1137
|
+
min-height: 0;
|
|
1138
|
+
overflow: hidden;
|
|
1121
1139
|
}
|
|
1122
1140
|
}
|
|
1123
1141
|
}
|
|
@@ -1125,7 +1143,6 @@ export default {
|
|
|
1125
1143
|
display: flex;
|
|
1126
1144
|
background: #fff;
|
|
1127
1145
|
height: 100%;
|
|
1128
|
-
min-height: 800px;
|
|
1129
1146
|
border-radius: 8px;
|
|
1130
1147
|
overflow: hidden;
|
|
1131
1148
|
font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
@@ -1447,6 +1464,8 @@ export default {
|
|
|
1447
1464
|
flex: 1;
|
|
1448
1465
|
padding: 16px;
|
|
1449
1466
|
overflow: hidden;
|
|
1467
|
+
border: 1px solid #e5e6eb;
|
|
1468
|
+
border-radius: 4px;
|
|
1450
1469
|
}
|
|
1451
1470
|
|
|
1452
1471
|
.chart-view,
|
|
@@ -1459,7 +1478,6 @@ export default {
|
|
|
1459
1478
|
.chart-container {
|
|
1460
1479
|
width: 100%;
|
|
1461
1480
|
height: 100%;
|
|
1462
|
-
min-height: 500px;
|
|
1463
1481
|
}
|
|
1464
1482
|
|
|
1465
1483
|
.table-container {
|
|
@@ -1577,14 +1595,34 @@ export default {
|
|
|
1577
1595
|
line-height: 22px; /* 157.143% */
|
|
1578
1596
|
}
|
|
1579
1597
|
|
|
1598
|
+
.pivot-sidebar-right .sidebar-header-collapse {
|
|
1599
|
+
font-size: 14px;
|
|
1600
|
+
color: #86909c;
|
|
1601
|
+
cursor: pointer;
|
|
1602
|
+
transition: color 0.2s;
|
|
1603
|
+
&:hover {
|
|
1604
|
+
color: #1d2129;
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1580
1608
|
.config-form {
|
|
1581
1609
|
flex: 1;
|
|
1582
|
-
padding: 16px;
|
|
1610
|
+
padding: 0 16px;
|
|
1583
1611
|
overflow-y: auto;
|
|
1612
|
+
|
|
1613
|
+
.form-item:first-child {
|
|
1614
|
+
margin-top: 16px;
|
|
1615
|
+
}
|
|
1584
1616
|
}
|
|
1585
1617
|
|
|
1586
1618
|
.form-item {
|
|
1587
|
-
margin-bottom:
|
|
1619
|
+
margin-bottom: 16px;
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
.form-divider {
|
|
1623
|
+
height: 1px;
|
|
1624
|
+
background-color: #e5e6eb;
|
|
1625
|
+
margin: 16px 0;
|
|
1588
1626
|
}
|
|
1589
1627
|
|
|
1590
1628
|
.form-label {
|
|
@@ -1669,8 +1707,8 @@ export default {
|
|
|
1669
1707
|
position: relative;
|
|
1670
1708
|
display: flex;
|
|
1671
1709
|
align-items: center;
|
|
1672
|
-
|
|
1673
|
-
padding:
|
|
1710
|
+
gap: 4px;
|
|
1711
|
+
padding: 4px 12px;
|
|
1674
1712
|
background: #fff;
|
|
1675
1713
|
border: 1px solid #e5e6eb;
|
|
1676
1714
|
border-radius: 4px;
|
|
@@ -1689,6 +1727,17 @@ export default {
|
|
|
1689
1727
|
gap: 8px;
|
|
1690
1728
|
font-size: 14px;
|
|
1691
1729
|
color: #1d2129;
|
|
1730
|
+
.report-icon {
|
|
1731
|
+
width: 16px;
|
|
1732
|
+
height: 16px;
|
|
1733
|
+
font-size: 16px;
|
|
1734
|
+
line-height: 16px;
|
|
1735
|
+
display: inline-flex;
|
|
1736
|
+
align-items: center;
|
|
1737
|
+
justify-content: center;
|
|
1738
|
+
margin-right: 0;
|
|
1739
|
+
color: #007aff;
|
|
1740
|
+
}
|
|
1692
1741
|
}
|
|
1693
1742
|
|
|
1694
1743
|
.select-value .placeholder {
|
|
@@ -1696,7 +1745,7 @@ export default {
|
|
|
1696
1745
|
}
|
|
1697
1746
|
|
|
1698
1747
|
.select-arrow {
|
|
1699
|
-
color: #
|
|
1748
|
+
color: #4e5969;
|
|
1700
1749
|
transition: transform 0.2s;
|
|
1701
1750
|
}
|
|
1702
1751
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<div class="flex-box flex-v">
|
|
6
6
|
<el-popover
|
|
7
7
|
v-if="bussId"
|
|
8
|
-
v-model="
|
|
8
|
+
v-model="viewPopoverVisible"
|
|
9
9
|
popper-class="pro-filter-view-popover"
|
|
10
10
|
placement="bottom-start"
|
|
11
11
|
trigger="click"
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
</div>
|
|
20
20
|
</el-button>
|
|
21
21
|
<div class="p-s">
|
|
22
|
-
<cl-input-search v-model="
|
|
22
|
+
<cl-input-search v-model="searchKeyword" class="w-100p" placeholder="请输入关键字" />
|
|
23
23
|
<div style="color: var(--color-text-secondary); margin: 12px 0 8px 0">{{ $lc('自定义视图') }}</div>
|
|
24
24
|
<div class="filter-view-wrapper">
|
|
25
|
-
<cl-drag-list class="flex-item" :list="filteredList" :hide-delete="true" @change="
|
|
25
|
+
<cl-drag-list class="flex-item" :list="filteredList" :hide-delete="true" @change="handleDragSort">
|
|
26
26
|
<template v-slot="{ item }">
|
|
27
27
|
<div class="proFilterView-list-item" :class="{ 'is-selected': selectedItem === item.viewName }">
|
|
28
28
|
<span class="proFilterView-list-item__name" :title="item.viewName" @click="handleSelect(item)">{{
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
</div>
|
|
68
68
|
</el-button>
|
|
69
69
|
<div class="flex-box flex-v">
|
|
70
|
-
<el-button icon="v3-icon-filter" class="m-r-s botton" @click="
|
|
70
|
+
<el-button icon="v3-icon-filter" class="m-r-s botton" @click="filterExpanded = !filterExpanded">{{
|
|
71
71
|
'筛选' | $lc
|
|
72
72
|
}}</el-button>
|
|
73
73
|
<slot name="rightContent"></slot>
|
|
@@ -77,8 +77,8 @@
|
|
|
77
77
|
<cl-advanced-filter
|
|
78
78
|
ref="filter"
|
|
79
79
|
class="filter"
|
|
80
|
-
:class="{ 'is-hidden': !
|
|
81
|
-
:visible.sync="
|
|
80
|
+
:class="{ 'is-hidden': !filterExpanded }"
|
|
81
|
+
:visible.sync="filterExpanded"
|
|
82
82
|
:filter-id="filterId"
|
|
83
83
|
:buss-id="bussId"
|
|
84
84
|
:model="searchValue"
|
|
@@ -95,11 +95,7 @@
|
|
|
95
95
|
<div slot="prefix">
|
|
96
96
|
<slot name="prefix"></slot>
|
|
97
97
|
</div>
|
|
98
|
-
|
|
99
|
-
<template
|
|
100
|
-
v-for="filter in filterList.filter((item) => item.type === 'slot' && $scopedSlots[item.slotName])"
|
|
101
|
-
#[filter.slotName]="{ model }"
|
|
102
|
-
>
|
|
98
|
+
<template v-for="filter in slotFiltersWithValue" #[filter.slotName]="{ model }">
|
|
103
99
|
<slot
|
|
104
100
|
:name="filter.slotName"
|
|
105
101
|
:model="model"
|
|
@@ -107,6 +103,15 @@
|
|
|
107
103
|
:input="(val) => handleSlotInput(filter.value, val)"
|
|
108
104
|
></slot>
|
|
109
105
|
</template>
|
|
106
|
+
<!-- 无 value 的 slot(如 startDate/endDate 多值绑定),传递 searchValue 让父组件自行管理 -->
|
|
107
|
+
<template v-for="filter in slotFiltersWithoutValue" #[filter.slotName]="{ model }">
|
|
108
|
+
<slot
|
|
109
|
+
:name="filter.slotName"
|
|
110
|
+
:model="model"
|
|
111
|
+
:search-value="searchValue"
|
|
112
|
+
:update-search-value="updateSearchValue"
|
|
113
|
+
></slot>
|
|
114
|
+
</template>
|
|
110
115
|
<div slot="suffix">
|
|
111
116
|
<slot name="suffix"></slot>
|
|
112
117
|
</div>
|
|
@@ -131,27 +136,23 @@
|
|
|
131
136
|
<div>{{ $lc('数据范围') }}</div>
|
|
132
137
|
<div style="color: var(--color-primary); cursor: pointer" @click="typeChange">
|
|
133
138
|
<i class="v3-icon-switch"></i>
|
|
134
|
-
<span v-if="form.viewType ===
|
|
139
|
+
<span v-if="form.viewType === VIEW_TYPE.ADVANCED"> {{ $lc('高级查询') }}</span>
|
|
135
140
|
<span v-else> {{ $lc('基础查询') }}</span>
|
|
136
141
|
</div>
|
|
137
142
|
</div>
|
|
138
143
|
<cl-advanced-filter
|
|
139
|
-
v-if="form.viewType ===
|
|
144
|
+
v-if="form.viewType === VIEW_TYPE.ADVANCED"
|
|
140
145
|
ref="filter"
|
|
141
|
-
:key="
|
|
146
|
+
:key="dialogFilterKey"
|
|
142
147
|
class="filter"
|
|
143
|
-
:visible
|
|
148
|
+
:visible="visible"
|
|
144
149
|
:model="searchForm"
|
|
145
150
|
only-key="id"
|
|
146
151
|
:filter-list="filterList"
|
|
147
152
|
:check-ids="form.keyIds"
|
|
148
153
|
@saveCheckData="saveCheckData"
|
|
149
154
|
>
|
|
150
|
-
|
|
151
|
-
<template
|
|
152
|
-
v-for="filter in filterList.filter((item) => item.type === 'slot' && $scopedSlots[item.slotName])"
|
|
153
|
-
#[filter.slotName]="{ model }"
|
|
154
|
-
>
|
|
155
|
+
<template v-for="filter in slotFiltersWithValue" #[filter.slotName]="{ model }">
|
|
155
156
|
<slot
|
|
156
157
|
:name="filter.slotName"
|
|
157
158
|
:model="model"
|
|
@@ -159,6 +160,15 @@
|
|
|
159
160
|
:input="(val) => (searchForm[filter.value] = val)"
|
|
160
161
|
></slot>
|
|
161
162
|
</template>
|
|
163
|
+
<!-- 无 value 的 slot(如 startDate/endDate 多值绑定),传递 searchForm 让父组件自行管理 -->
|
|
164
|
+
<template v-for="filter in slotFiltersWithoutValue" #[filter.slotName]="{ model }">
|
|
165
|
+
<slot
|
|
166
|
+
:name="filter.slotName"
|
|
167
|
+
:model="model"
|
|
168
|
+
:search-value="searchForm"
|
|
169
|
+
:update-search-value="(updates) => Object.assign(searchForm, updates)"
|
|
170
|
+
></slot>
|
|
171
|
+
</template>
|
|
162
172
|
</cl-advanced-filter>
|
|
163
173
|
<advancedQuery
|
|
164
174
|
v-else
|
|
@@ -168,11 +178,7 @@
|
|
|
168
178
|
:filter-id="filterId"
|
|
169
179
|
:buss-id="bussId"
|
|
170
180
|
>
|
|
171
|
-
|
|
172
|
-
<template
|
|
173
|
-
v-for="filter in filterList.filter((item) => item.type === 'slot' && $scopedSlots[item.slotName])"
|
|
174
|
-
#[filter.slotName]="{ model, value, input, disabled }"
|
|
175
|
-
>
|
|
181
|
+
<template v-for="filter in slotFiltersWithValue" #[filter.slotName]="{ model, value, input, disabled }">
|
|
176
182
|
<slot
|
|
177
183
|
:name="filter.slotName"
|
|
178
184
|
:model="model"
|
|
@@ -181,6 +187,16 @@
|
|
|
181
187
|
:disabled="disabled"
|
|
182
188
|
></slot>
|
|
183
189
|
</template>
|
|
190
|
+
<!-- 无 value 的 slot(如 startDate/endDate 多值绑定),传递 searchForm 让父组件自行管理 -->
|
|
191
|
+
<template v-for="filter in slotFiltersWithoutValue" #[filter.slotName]="{ model, value, input, disabled }">
|
|
192
|
+
<slot
|
|
193
|
+
:name="filter.slotName"
|
|
194
|
+
:model="model"
|
|
195
|
+
:search-value="searchForm"
|
|
196
|
+
:update-search-value="(updates) => Object.assign(searchForm, updates)"
|
|
197
|
+
:disabled="disabled"
|
|
198
|
+
></slot>
|
|
199
|
+
</template>
|
|
184
200
|
</advancedQuery>
|
|
185
201
|
</el-form>
|
|
186
202
|
<div slot="footer" class="flex-box flex-c flex-v page-button-shadow">
|
|
@@ -199,6 +215,8 @@ import ClDragList from '../DragList/index.vue'
|
|
|
199
215
|
import ClDialog from '../Dialog/index.vue'
|
|
200
216
|
import axios from '../../utils/axios.js'
|
|
201
217
|
|
|
218
|
+
const VIEW_TYPE = { ADVANCED: '0', BASIC: '1' }
|
|
219
|
+
|
|
202
220
|
export default {
|
|
203
221
|
name: 'ProFilterView',
|
|
204
222
|
components: {
|
|
@@ -234,19 +252,17 @@ export default {
|
|
|
234
252
|
},
|
|
235
253
|
data() {
|
|
236
254
|
return {
|
|
237
|
-
|
|
255
|
+
VIEW_TYPE,
|
|
256
|
+
searchKeyword: '',
|
|
238
257
|
list: ['无视图'],
|
|
239
258
|
selectedItem: '无视图', // 默认选中第一项
|
|
240
|
-
|
|
259
|
+
viewPopoverVisible: false,
|
|
241
260
|
visible: false,
|
|
242
261
|
isAdd: false,
|
|
243
262
|
form: { userNo: sessionStorage.getItem('userNo'), pageNo: this.filterId },
|
|
244
263
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
checkData: [],
|
|
248
|
-
key: 0,
|
|
249
|
-
keyIds: [],
|
|
264
|
+
filterExpanded: this.defaultExpanded,
|
|
265
|
+
dialogFilterKey: 0,
|
|
250
266
|
selectItem: '',
|
|
251
267
|
// 高级视图筛选
|
|
252
268
|
conditionGroups: [],
|
|
@@ -255,26 +271,41 @@ export default {
|
|
|
255
271
|
// 普通筛选值
|
|
256
272
|
searchValue: {},
|
|
257
273
|
viewId: undefined,
|
|
258
|
-
isRefresh: false
|
|
274
|
+
isRefresh: false,
|
|
275
|
+
// 视图类型切换时缓存对方数据
|
|
276
|
+
savedViewConfigs: {}
|
|
259
277
|
}
|
|
260
278
|
},
|
|
261
279
|
computed: {
|
|
262
280
|
/**
|
|
263
281
|
* 本地搜索过滤视图列表
|
|
264
|
-
* @returns {Array} 根据
|
|
282
|
+
* @returns {Array} 根据 searchKeyword 过滤后的视图列表;searchKeyword 为空时返回完整列表
|
|
265
283
|
*/
|
|
266
284
|
filteredList() {
|
|
267
|
-
if (!this.
|
|
285
|
+
if (!this.searchKeyword) {
|
|
268
286
|
return this.list
|
|
269
287
|
}
|
|
270
|
-
const keyword = this.
|
|
288
|
+
const keyword = this.searchKeyword.toLowerCase()
|
|
271
289
|
return this.list.filter((item) => item.viewName && item.viewName.toLowerCase().includes(keyword))
|
|
272
290
|
},
|
|
291
|
+
// 筛选出类型为 slot 且在父组件提供了对应作用域插槽的筛选项
|
|
292
|
+
slotFilters() {
|
|
293
|
+
return this.filterList.filter((item) => item.type === 'slot' && this.$scopedSlots[item.slotName])
|
|
294
|
+
},
|
|
295
|
+
// 筛选出有 value 字段的 slot 类型筛选项(用于 searchValue 初始化和值传递)
|
|
296
|
+
slotFiltersWithValue() {
|
|
297
|
+
return this.slotFilters.filter((item) => item.value)
|
|
298
|
+
},
|
|
299
|
+
// 筛选出无 value 字段的 slot 类型筛选项(如 startDate/endDate 多值绑定)
|
|
300
|
+
slotFiltersWithoutValue() {
|
|
301
|
+
return this.slotFilters.filter((item) => !item.value)
|
|
302
|
+
},
|
|
273
303
|
getInitialSearchValue() {
|
|
274
304
|
const obj = {}
|
|
275
|
-
// 遍历 filterList,为每个 type 为 slot
|
|
305
|
+
// 遍历 filterList,为每个 type 为 slot 且有 value 字段的项初始化值
|
|
306
|
+
// 注意:跳过无 value 的 slot(如 startDate/endDate 多值绑定),这些由父组件在 slot 内部管理
|
|
276
307
|
this.filterList.forEach((item) => {
|
|
277
|
-
if (item.type === 'slot') {
|
|
308
|
+
if (item.type === 'slot' && item.value) {
|
|
278
309
|
obj[item.value] = undefined
|
|
279
310
|
}
|
|
280
311
|
})
|
|
@@ -335,8 +366,14 @@ export default {
|
|
|
335
366
|
this.searchValue = { ...this.getInitialSearchValue, ...this.initialValue }
|
|
336
367
|
},
|
|
337
368
|
methods: {
|
|
369
|
+
updateSearchValue(updates) {
|
|
370
|
+
console.log(updates, 'updates')
|
|
371
|
+
Object.assign(searchValue, updates)
|
|
372
|
+
},
|
|
338
373
|
// 处理 slot 类型字段的输入事件,同时更新 searchValue 和 initialValue
|
|
339
374
|
handleSlotInput(fieldName, val) {
|
|
375
|
+
// 防御性检查:如果 fieldName 无效,不执行任何操作
|
|
376
|
+
if (!fieldName) return
|
|
340
377
|
// 更新 searchValue
|
|
341
378
|
this.searchValue[fieldName] = val
|
|
342
379
|
// 同步更新 initialValue,确保双向绑定生效
|
|
@@ -381,8 +418,40 @@ export default {
|
|
|
381
418
|
this.$emit('filter', this.filterObj, 'clean')
|
|
382
419
|
},
|
|
383
420
|
handleClear() {
|
|
384
|
-
|
|
385
|
-
|
|
421
|
+
// 收集 required 项的当前值,清空时保留
|
|
422
|
+
const preserved = {}
|
|
423
|
+
this.filterList.forEach((item) => {
|
|
424
|
+
if (!item.required) return
|
|
425
|
+
if (item.type === 'daterange' || item.type === 'datetimerange' || item.type === 'monthrange') {
|
|
426
|
+
if (item.startDate && this.searchValue[item.startDate] !== undefined) {
|
|
427
|
+
preserved[item.startDate] = this.searchValue[item.startDate]
|
|
428
|
+
}
|
|
429
|
+
if (item.endDate && this.searchValue[item.endDate] !== undefined) {
|
|
430
|
+
preserved[item.endDate] = this.searchValue[item.endDate]
|
|
431
|
+
}
|
|
432
|
+
} else if (item.type === 'numberrange') {
|
|
433
|
+
if (item.startValue && this.searchValue[item.startValue] !== undefined) {
|
|
434
|
+
preserved[item.startValue] = this.searchValue[item.startValue]
|
|
435
|
+
}
|
|
436
|
+
if (item.endValue && this.searchValue[item.endValue] !== undefined) {
|
|
437
|
+
preserved[item.endValue] = this.searchValue[item.endValue]
|
|
438
|
+
}
|
|
439
|
+
} else if (item.value && this.searchValue[item.value] !== undefined) {
|
|
440
|
+
preserved[item.value] = this.searchValue[item.value]
|
|
441
|
+
}
|
|
442
|
+
})
|
|
443
|
+
this.searchValue = { ...this.getInitialSearchValue, ...preserved }
|
|
444
|
+
// 直接构建 payload,绕过 filterObj 避免 initialValue 重新注入
|
|
445
|
+
this.$emit(
|
|
446
|
+
'filter',
|
|
447
|
+
{
|
|
448
|
+
conditionGroups: this.conditionGroups,
|
|
449
|
+
searchValue: { ...this.searchValue },
|
|
450
|
+
viewId: this.selectItem ? this.selectItem.viewId : null,
|
|
451
|
+
viewType: this.selectItem ? this.selectItem.viewType : null
|
|
452
|
+
},
|
|
453
|
+
'clear'
|
|
454
|
+
)
|
|
386
455
|
},
|
|
387
456
|
isEnter() {
|
|
388
457
|
this.$rulesValidateForm('ruleValidate', (valid) => {
|
|
@@ -406,7 +475,7 @@ export default {
|
|
|
406
475
|
.get(`/bems/query/viewColumn/getViewInfo`, { bussId: this.bussId })
|
|
407
476
|
.then((res) => {
|
|
408
477
|
list = res.data.map((item) => {
|
|
409
|
-
item.keyIds =
|
|
478
|
+
item.keyIds = this.safeParse(item.keyIds, [])
|
|
410
479
|
return item
|
|
411
480
|
})
|
|
412
481
|
this.list = [
|
|
@@ -434,13 +503,13 @@ export default {
|
|
|
434
503
|
// 新增
|
|
435
504
|
add() {
|
|
436
505
|
this.isRefresh = false
|
|
437
|
-
this.
|
|
506
|
+
this.viewPopoverVisible = false
|
|
438
507
|
this.visible = true
|
|
439
508
|
this.isAdd = true
|
|
440
509
|
this.form = {
|
|
441
510
|
userNo: sessionStorage.getItem('userNo'),
|
|
442
511
|
pageNo: this.filterId,
|
|
443
|
-
viewType:
|
|
512
|
+
viewType: VIEW_TYPE.ADVANCED
|
|
444
513
|
}
|
|
445
514
|
this.viewId = undefined
|
|
446
515
|
this.form.keyIds = []
|
|
@@ -449,30 +518,37 @@ export default {
|
|
|
449
518
|
...this.getInitialSearchValue
|
|
450
519
|
}
|
|
451
520
|
// 新建时重置切换缓存
|
|
452
|
-
this.
|
|
521
|
+
this.savedViewConfigs = {}
|
|
453
522
|
},
|
|
454
523
|
// 修改
|
|
455
524
|
edit(item, isRefresh = false) {
|
|
456
525
|
this.isRefresh = isRefresh
|
|
457
526
|
console.log(item)
|
|
458
|
-
this.
|
|
527
|
+
this.viewPopoverVisible = false
|
|
459
528
|
this.visible = true
|
|
460
529
|
this.isAdd = false
|
|
461
|
-
this.
|
|
530
|
+
this.dialogFilterKey++
|
|
462
531
|
// 赋值操作
|
|
463
532
|
this.form = item
|
|
464
533
|
this.viewId = item.viewId
|
|
465
534
|
// 初始化两种类型的已保存数据缓存,供 typeChange 切换时恢复使用
|
|
466
|
-
this.
|
|
467
|
-
if (item.viewType ===
|
|
468
|
-
const parsed =
|
|
535
|
+
this.savedViewConfigs = {}
|
|
536
|
+
if (item.viewType === VIEW_TYPE.ADVANCED) {
|
|
537
|
+
const parsed = this.safeParse(item.viewConfig)
|
|
469
538
|
this.searchForm = { ...this.getInitialSearchValue, ...parsed }
|
|
470
|
-
this.
|
|
539
|
+
this.savedViewConfigs[VIEW_TYPE.ADVANCED] = { ...parsed }
|
|
471
540
|
} else {
|
|
472
|
-
const parsed =
|
|
541
|
+
const parsed = this.safeParse(item.viewConfig)
|
|
473
542
|
this.conditionGroups = parsed.conditionGroups || []
|
|
474
543
|
|
|
475
|
-
this.
|
|
544
|
+
this.savedViewConfigs[VIEW_TYPE.BASIC] = { conditionGroups: this.conditionGroups }
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
safeParse(str, fallback = {}) {
|
|
548
|
+
try {
|
|
549
|
+
return JSON.parse(str || '{}')
|
|
550
|
+
} catch {
|
|
551
|
+
return fallback
|
|
476
552
|
}
|
|
477
553
|
},
|
|
478
554
|
// 保存筛选条件
|
|
@@ -481,29 +557,31 @@ export default {
|
|
|
481
557
|
return item.id
|
|
482
558
|
})
|
|
483
559
|
},
|
|
484
|
-
//
|
|
485
|
-
|
|
486
|
-
// 如果没有 bussId,不保存视图
|
|
487
|
-
if (!this.bussId) {
|
|
488
|
-
this.$message.warning('缺少业务ID,无法保存视图')
|
|
489
|
-
return
|
|
490
|
-
}
|
|
491
|
-
|
|
560
|
+
// 构建视图保存请求体
|
|
561
|
+
buildViewPayload() {
|
|
492
562
|
let viewConfig
|
|
493
563
|
let keyIds
|
|
494
|
-
if (this.form.viewType ===
|
|
564
|
+
if (this.form.viewType === VIEW_TYPE.ADVANCED) {
|
|
495
565
|
viewConfig = JSON.stringify(this.searchForm)
|
|
496
566
|
keyIds = this.form.keyIds
|
|
497
567
|
} else {
|
|
498
568
|
viewConfig = JSON.stringify({ conditionGroups: this.conditionGroups })
|
|
499
569
|
keyIds = []
|
|
500
570
|
}
|
|
501
|
-
console.log(this.conditionGroups)
|
|
502
571
|
this.form.viewConfig = viewConfig
|
|
503
|
-
|
|
504
|
-
|
|
572
|
+
return {
|
|
573
|
+
viewName: this.form.viewName,
|
|
574
|
+
viewType: this.form.viewType,
|
|
575
|
+
bussId: this.bussId,
|
|
576
|
+
viewConfig,
|
|
577
|
+
keyIds: JSON.stringify(keyIds),
|
|
578
|
+
viewId: this.viewId
|
|
579
|
+
}
|
|
580
|
+
},
|
|
581
|
+
// 检查基础查询条件是否有空值
|
|
582
|
+
hasEmptyCondition() {
|
|
583
|
+
return this.conditionGroups.some((group) =>
|
|
505
584
|
group.conditions.some((condition) => {
|
|
506
|
-
// operator 5(为空) 和 6(不为空) 不需要填写 value
|
|
507
585
|
if (condition.operator === 5 || condition.operator === 6) {
|
|
508
586
|
return false
|
|
509
587
|
}
|
|
@@ -511,35 +589,34 @@ export default {
|
|
|
511
589
|
return val === null || val === undefined || val === '' || (Array.isArray(val) && val.length === 0)
|
|
512
590
|
})
|
|
513
591
|
)
|
|
592
|
+
},
|
|
593
|
+
// 保存视图
|
|
594
|
+
saveSt() {
|
|
595
|
+
if (!this.bussId) {
|
|
596
|
+
this.$message.warning('缺少业务ID,无法保存视图')
|
|
597
|
+
return
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const payload = this.buildViewPayload()
|
|
601
|
+
const hasEmptyValue = this.hasEmptyCondition()
|
|
514
602
|
|
|
515
603
|
this.$refs.form.validate(async (valid) => {
|
|
516
604
|
if (!valid) {
|
|
517
605
|
this.$message.error('请输入视图名称')
|
|
518
606
|
return
|
|
519
607
|
}
|
|
520
|
-
|
|
521
|
-
if (this.form.viewType === '0' && !keyIds.length) {
|
|
608
|
+
if (this.form.viewType === VIEW_TYPE.ADVANCED && !this.form.keyIds.length) {
|
|
522
609
|
this.$message.warning('至少添加一个条件')
|
|
523
610
|
return
|
|
524
611
|
}
|
|
525
|
-
if (this.form.viewType ===
|
|
612
|
+
if (this.form.viewType === VIEW_TYPE.BASIC) {
|
|
526
613
|
if (!this.conditionGroups.length || hasEmptyValue) {
|
|
527
614
|
this.$message.warning('至少添加一个条件')
|
|
528
615
|
return
|
|
529
616
|
}
|
|
530
617
|
}
|
|
531
618
|
|
|
532
|
-
|
|
533
|
-
const obj = {
|
|
534
|
-
viewName: this.form.viewName,
|
|
535
|
-
viewType: this.form.viewType,
|
|
536
|
-
bussId: this.bussId,
|
|
537
|
-
viewConfig: this.form.viewConfig,
|
|
538
|
-
keyIds: JSON.stringify(keyIds),
|
|
539
|
-
viewId: this.viewId
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
axios.post('/bems/query/viewColumn/saveOrUpdateViewInfo', obj).then((res) => {
|
|
619
|
+
axios.post('/bems/query/viewColumn/saveOrUpdateViewInfo', payload).then((res) => {
|
|
543
620
|
if (res.code !== 200) {
|
|
544
621
|
return false
|
|
545
622
|
}
|
|
@@ -567,7 +644,7 @@ export default {
|
|
|
567
644
|
// 选中视图
|
|
568
645
|
handleSelect(item) {
|
|
569
646
|
console.log(item)
|
|
570
|
-
this.
|
|
647
|
+
this.viewPopoverVisible = false
|
|
571
648
|
this.selectItem = item
|
|
572
649
|
this.selectedItem = item.viewName
|
|
573
650
|
if (item.viewName === '无视图') {
|
|
@@ -575,17 +652,18 @@ export default {
|
|
|
575
652
|
this.searchValue = {}
|
|
576
653
|
this.conditionGroups = []
|
|
577
654
|
}
|
|
578
|
-
if (item.viewType ===
|
|
579
|
-
|
|
580
|
-
this.
|
|
581
|
-
|
|
582
|
-
|
|
655
|
+
if (item.viewType === VIEW_TYPE.ADVANCED) {
|
|
656
|
+
const config = this.safeParse(item.viewConfig)
|
|
657
|
+
this.searchForm = config
|
|
658
|
+
this.searchValue = config
|
|
659
|
+
} else if (item.viewType === VIEW_TYPE.BASIC) {
|
|
660
|
+
this.conditionGroups = this.safeParse(item.viewConfig).conditionGroups || []
|
|
583
661
|
this.searchValue = { ...this.getInitialSearchValue }
|
|
584
662
|
}
|
|
585
663
|
this.$emit('filter', this.filterObj, 'filter')
|
|
586
664
|
},
|
|
587
665
|
// 拖动保存视图列表
|
|
588
|
-
|
|
666
|
+
handleDragSort(list) {
|
|
589
667
|
console.log('当前list:', list)
|
|
590
668
|
},
|
|
591
669
|
/**
|
|
@@ -594,23 +672,22 @@ export default {
|
|
|
594
672
|
* 若无已保存数据则重置为初始值
|
|
595
673
|
*/
|
|
596
674
|
typeChange() {
|
|
597
|
-
this.form.viewType = this.form.viewType ===
|
|
598
|
-
//
|
|
599
|
-
if (this.form.viewType ===
|
|
675
|
+
this.form.viewType = this.form.viewType === VIEW_TYPE.ADVANCED ? VIEW_TYPE.BASIC : VIEW_TYPE.ADVANCED
|
|
676
|
+
// 切换到高级查询
|
|
677
|
+
if (this.form.viewType === VIEW_TYPE.ADVANCED) {
|
|
600
678
|
this.conditionGroups = []
|
|
601
679
|
// 若已有保存的 viewConfig 且原始类型也是基础查询,则恢复已保存的搜索条件
|
|
602
|
-
const savedConfig = this.
|
|
680
|
+
const savedConfig = this.savedViewConfigs[VIEW_TYPE.ADVANCED]
|
|
603
681
|
if (savedConfig) {
|
|
604
682
|
this.searchForm = { ...this.getInitialSearchValue, ...savedConfig }
|
|
605
683
|
} else {
|
|
606
684
|
this.searchForm = { ...this.getInitialSearchValue }
|
|
607
685
|
}
|
|
608
686
|
} else {
|
|
609
|
-
//
|
|
610
|
-
|
|
611
|
-
this._savedViewConfigs['0'] = { ...this.searchForm }
|
|
687
|
+
// 切换到基础查询,保存当前高级查询数据
|
|
688
|
+
this.savedViewConfigs[VIEW_TYPE.ADVANCED] = { ...this.searchForm }
|
|
612
689
|
// 恢复已保存的高级查询数据,若无则重置
|
|
613
|
-
const savedConfig = this.
|
|
690
|
+
const savedConfig = this.savedViewConfigs[VIEW_TYPE.BASIC]
|
|
614
691
|
if (savedConfig) {
|
|
615
692
|
this.conditionGroups = savedConfig.conditionGroups || []
|
|
616
693
|
} else {
|
|
@@ -624,17 +701,15 @@ export default {
|
|
|
624
701
|
* 供下游调用以恢复组件初始状态
|
|
625
702
|
*/
|
|
626
703
|
resetState() {
|
|
627
|
-
this.
|
|
704
|
+
this.searchKeyword = ''
|
|
628
705
|
this.selectedItem = '无视图'
|
|
629
706
|
this.selectItem = ''
|
|
630
707
|
this.searchValue = { ...this.getInitialSearchValue, ...this.initialValue }
|
|
631
708
|
this.searchForm = { ...this.getInitialSearchValue }
|
|
632
709
|
this.conditionGroups = []
|
|
633
|
-
this.
|
|
634
|
-
this.checkData = []
|
|
635
|
-
this.keyIds = []
|
|
710
|
+
this.filterExpanded = this.defaultExpanded
|
|
636
711
|
this.viewId = undefined
|
|
637
|
-
this.
|
|
712
|
+
this.savedViewConfigs = {}
|
|
638
713
|
}
|
|
639
714
|
}
|
|
640
715
|
}
|