cd-vue-filter 2.2.5 → 2.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cd-vue-filter.js +7811 -0
- package/dist/cd-vue-filter.umd.cjs +3 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/style.css +1 -0
- package/dist/types/index.d.ts +60 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/province.d.ts +3 -0
- package/dist/utils/province.d.ts.map +1 -0
- package/package.json +23 -12
- package/src/components/FilterComponent.vue +0 -359
- package/src/components/SavePlanDialog.vue +0 -239
- package/src/components/cd-filter-bar.vue +0 -412
- package/src/components/cd-filter.vue +0 -1002
- package/src/components/filterDialog.vue +0 -345
- package/src/index.ts +0 -43
- package/src/types/index.ts +0 -65
- package/src/utils/province.ts +0 -5502
- /package/{src → dist}/vue-shim.d.ts +0 -0
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<t-dialog
|
|
3
|
-
:header="isEditing ? '编辑筛选方案' : '保存筛选方案'"
|
|
4
|
-
:visible="visible"
|
|
5
|
-
@update:visible="$emit('update:visible', $event)"
|
|
6
|
-
width="600px"
|
|
7
|
-
:footer="true"
|
|
8
|
-
@confirm="handleConfirm"
|
|
9
|
-
@close="handleClose"
|
|
10
|
-
>
|
|
11
|
-
<template #body>
|
|
12
|
-
<div class="save-plan-content">
|
|
13
|
-
<t-form :data="formData" label-align="left" label-width="100px">
|
|
14
|
-
<t-form-item label="方案名称" required>
|
|
15
|
-
<t-input v-model="formData.planName" placeholder="请输入方案名称" />
|
|
16
|
-
</t-form-item>
|
|
17
|
-
<t-form-item label="共享设置">
|
|
18
|
-
<t-radio-group v-model="formData.shareMode" :disabled="isShareModeDisabled">
|
|
19
|
-
<t-radio value="none">不共享</t-radio>
|
|
20
|
-
<t-radio value="share">共享给其他人</t-radio>
|
|
21
|
-
<t-tooltip content="复制方案只支持复制一次,建议共享方案" placement="top">
|
|
22
|
-
<t-radio value="copy">复制给其他人</t-radio>
|
|
23
|
-
</t-tooltip>
|
|
24
|
-
</t-radio-group>
|
|
25
|
-
</t-form-item>
|
|
26
|
-
<t-form-item v-if="formData.shareMode === 'share'" label="共享范围">
|
|
27
|
-
<t-radio-group v-model="formData.shareType">
|
|
28
|
-
<t-radio value="specific">指定用户</t-radio>
|
|
29
|
-
<t-radio value="all">所有用户</t-radio>
|
|
30
|
-
</t-radio-group>
|
|
31
|
-
</t-form-item>
|
|
32
|
-
<t-form-item v-if="(formData.shareMode === 'share' && formData.shareType === 'specific') || formData.shareMode === 'copy'" label="共享人员">
|
|
33
|
-
<CdUsersList
|
|
34
|
-
:users="sharedUsersList"
|
|
35
|
-
:avatar-size="32"
|
|
36
|
-
:max-display="10"
|
|
37
|
-
:edit="true"
|
|
38
|
-
:person-tabs="tabs"
|
|
39
|
-
:person-organizations="organizations"
|
|
40
|
-
:dept-members-data="deptMembersData"
|
|
41
|
-
@person-select="handlePersonSelect"
|
|
42
|
-
@load-users="handleLoadUsers"
|
|
43
|
-
@search="handlePersonSearch"
|
|
44
|
-
@dept-click="handleDeptClick"
|
|
45
|
-
/>
|
|
46
|
-
</t-form-item>
|
|
47
|
-
</t-form>
|
|
48
|
-
</div>
|
|
49
|
-
</template>
|
|
50
|
-
<template #footer>
|
|
51
|
-
<t-button theme="default" @click="handleClose">取消</t-button>
|
|
52
|
-
<t-button theme="primary" @click="handleConfirm">确定</t-button>
|
|
53
|
-
</template>
|
|
54
|
-
</t-dialog>
|
|
55
|
-
</template>
|
|
56
|
-
<script setup>
|
|
57
|
-
import { ref, watch, computed } from 'vue'
|
|
58
|
-
import { MessagePlugin } from 'tdesign-vue-next'
|
|
59
|
-
import { CdUsersList } from 'cd-usercard'
|
|
60
|
-
|
|
61
|
-
const props = defineProps({
|
|
62
|
-
visible: {
|
|
63
|
-
type: Boolean,
|
|
64
|
-
default: false
|
|
65
|
-
},
|
|
66
|
-
isEditing: {
|
|
67
|
-
type: Boolean,
|
|
68
|
-
default: false
|
|
69
|
-
},
|
|
70
|
-
planName: {
|
|
71
|
-
type: String,
|
|
72
|
-
default: ''
|
|
73
|
-
},
|
|
74
|
-
userOptions: {
|
|
75
|
-
type: Array,
|
|
76
|
-
default: () => []
|
|
77
|
-
},
|
|
78
|
-
tabs: {
|
|
79
|
-
type: Array,
|
|
80
|
-
default: () => []
|
|
81
|
-
},
|
|
82
|
-
organizations: {
|
|
83
|
-
type: Array,
|
|
84
|
-
default: () => []
|
|
85
|
-
},
|
|
86
|
-
deptMembersDataProp: {
|
|
87
|
-
type: Array,
|
|
88
|
-
default: () => []
|
|
89
|
-
},
|
|
90
|
-
// 原始方案的共享配置
|
|
91
|
-
originalShareMode: {
|
|
92
|
-
type: String,
|
|
93
|
-
default: 'none'
|
|
94
|
-
},
|
|
95
|
-
originalShareType: {
|
|
96
|
-
type: String,
|
|
97
|
-
default: 'specific'
|
|
98
|
-
},
|
|
99
|
-
originalSelectedUsers: {
|
|
100
|
-
type: Array,
|
|
101
|
-
default: () => []
|
|
102
|
-
}
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
const emit = defineEmits(['update:visible', 'confirm', 'close', 'load-users', 'search', 'dept-click'])
|
|
106
|
-
|
|
107
|
-
const formData = ref({
|
|
108
|
-
planName: '',
|
|
109
|
-
shareMode: 'none',
|
|
110
|
-
shareType: 'specific',
|
|
111
|
-
selectedUsers: []
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
const sharedUsersList = ref([])
|
|
115
|
-
const deptMembersData = ref([])
|
|
116
|
-
|
|
117
|
-
// 判断是否禁用共享设置radio - 编辑模式下如果原方案是复制模式则禁用
|
|
118
|
-
const isShareModeDisabled = computed(() => {
|
|
119
|
-
return props.isEditing && props.originalShareMode === 'copy'
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
watch(() => props.visible, (newVal) => {
|
|
123
|
-
if (newVal) {
|
|
124
|
-
// 打开对话框时,如果是编辑模式,预填充方案名称和共享配置
|
|
125
|
-
if (props.isEditing && props.planName) {
|
|
126
|
-
formData.value.planName = props.planName
|
|
127
|
-
formData.value.shareMode = props.originalShareMode || 'none'
|
|
128
|
-
formData.value.shareType = props.originalShareType || 'specific'
|
|
129
|
-
|
|
130
|
-
// 恢复原始共享用户列表
|
|
131
|
-
if (props.originalSelectedUsers && props.originalSelectedUsers.length > 0) {
|
|
132
|
-
formData.value.selectedUsers = [...props.originalSelectedUsers]
|
|
133
|
-
// 这里需要从父组件传入完整的用户信息
|
|
134
|
-
// 暂时只保存ID,实际使用时需要完整的用户信息
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
} else {
|
|
138
|
-
resetForm()
|
|
139
|
-
}
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
watch(() => props.deptMembersDataProp, (newVal) => {
|
|
143
|
-
if (newVal) {
|
|
144
|
-
deptMembersData.value = newVal
|
|
145
|
-
}
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
const resetForm = () => {
|
|
149
|
-
formData.value = {
|
|
150
|
-
planName: '',
|
|
151
|
-
shareMode: 'none',
|
|
152
|
-
shareType: 'specific',
|
|
153
|
-
selectedUsers: []
|
|
154
|
-
}
|
|
155
|
-
sharedUsersList.value = []
|
|
156
|
-
deptMembersData.value = []
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const handlePersonSelect = (persons) => {
|
|
160
|
-
console.log('选中人员:', persons)
|
|
161
|
-
// 将选中的人员/部门转换为用户列表格式并添加到列表中
|
|
162
|
-
const newItems = persons.map(p => ({
|
|
163
|
-
id: p.id,
|
|
164
|
-
name: p.displayName || p.name,
|
|
165
|
-
avatar: '',
|
|
166
|
-
department: p.department,
|
|
167
|
-
role: p.position,
|
|
168
|
-
email: '',
|
|
169
|
-
mobile: p.phone || '',
|
|
170
|
-
employeeId: '',
|
|
171
|
-
signature: '',
|
|
172
|
-
tags: [],
|
|
173
|
-
isUser: p.isUser === true,
|
|
174
|
-
}))
|
|
175
|
-
// 去重并添加
|
|
176
|
-
newItems.forEach(newItem => {
|
|
177
|
-
const exists = sharedUsersList.value.find(u => u.id === newItem.id)
|
|
178
|
-
if (!exists) {
|
|
179
|
-
sharedUsersList.value.push(newItem)
|
|
180
|
-
}
|
|
181
|
-
})
|
|
182
|
-
// 更新 selectedUsers 用于提交
|
|
183
|
-
formData.value.selectedUsers = sharedUsersList.value.map(u => u.id)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const handleLoadUsers = (payload) => {
|
|
187
|
-
emit('load-users', payload)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const handlePersonSearch = (payload) => {
|
|
191
|
-
emit('search', payload)
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const handleDeptClick = (dept) => {
|
|
195
|
-
emit('dept-click', dept)
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const handleConfirm = () => {
|
|
199
|
-
if (!formData.value.planName.trim()) {
|
|
200
|
-
MessagePlugin.warning('请输入方案名称')
|
|
201
|
-
return
|
|
202
|
-
}
|
|
203
|
-
if ((formData.value.shareMode === 'share' || formData.value.shareMode === 'copy') &&
|
|
204
|
-
formData.value.shareType === 'specific' &&
|
|
205
|
-
formData.value.selectedUsers.length === 0) {
|
|
206
|
-
MessagePlugin.warning('请选择要共享的用户')
|
|
207
|
-
return
|
|
208
|
-
}
|
|
209
|
-
emit('confirm', {
|
|
210
|
-
planName: formData.value.planName,
|
|
211
|
-
shareMode: formData.value.shareMode,
|
|
212
|
-
shareType: formData.value.shareType,
|
|
213
|
-
selectedUsers: formData.value.selectedUsers
|
|
214
|
-
})
|
|
215
|
-
emit('update:visible', false)
|
|
216
|
-
}
|
|
217
|
-
const handleClose = () => {
|
|
218
|
-
emit('close')
|
|
219
|
-
emit('update:visible', false)
|
|
220
|
-
}
|
|
221
|
-
</script>
|
|
222
|
-
<style scoped>
|
|
223
|
-
.save-plan-content {
|
|
224
|
-
padding: 20px 0;
|
|
225
|
-
font-size: 9pt;
|
|
226
|
-
}
|
|
227
|
-
.save-plan-content :deep(.t-form-item__label) {
|
|
228
|
-
font-size: 9pt;
|
|
229
|
-
}
|
|
230
|
-
.save-plan-content :deep(.t-input),
|
|
231
|
-
.save-plan-content :deep(.t-checkbox),
|
|
232
|
-
.save-plan-content :deep(.t-radio),
|
|
233
|
-
.save-plan-content :deep(.t-select) {
|
|
234
|
-
font-size: 9pt;
|
|
235
|
-
}
|
|
236
|
-
.save-plan-content :deep(.t-input__inner) {
|
|
237
|
-
font-size: 9pt;
|
|
238
|
-
}
|
|
239
|
-
</style>
|
|
@@ -1,412 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="cd-filter-bar">
|
|
3
|
-
<!-- 内联筛选组件区域 -->
|
|
4
|
-
<div class="inline-filter-toolbar" v-if="filterCount > 0">
|
|
5
|
-
<FilterComponent
|
|
6
|
-
v-for="(cond, idx) in inlineHeaderConditions"
|
|
7
|
-
:key="idx"
|
|
8
|
-
:field-options="fieldOptions"
|
|
9
|
-
:size="size"
|
|
10
|
-
:filter-condition="inlineHeaderConditions[idx]"
|
|
11
|
-
:select-options="selectOptions"
|
|
12
|
-
/>
|
|
13
|
-
</div>
|
|
14
|
-
<!-- 我的方案 - Radio Group 模式(当筛选长度为0时) -->
|
|
15
|
-
<div class="plan-radio-group" v-if="filterCount === 0 && planFilterOptions.length > 0">
|
|
16
|
-
<span class="plan-label">我的方案:</span>
|
|
17
|
-
<t-radio-group v-model="selectedPlanValue" :size="size" @change="handlePlanRadioChange">
|
|
18
|
-
<t-radio-button
|
|
19
|
-
v-for="plan in planFilterOptions"
|
|
20
|
-
:key="plan.value"
|
|
21
|
-
:value="plan.value"
|
|
22
|
-
:disabled="plan.disabled"
|
|
23
|
-
>
|
|
24
|
-
{{ plan.content }}
|
|
25
|
-
</t-radio-button>
|
|
26
|
-
</t-radio-group>
|
|
27
|
-
<!-- 高级筛选图标按钮 -->
|
|
28
|
-
<t-button theme="default" variant="outline" :size="size" @click="openAdvancedFilter" title="高级筛选">
|
|
29
|
-
<template #icon>
|
|
30
|
-
<t-icon name="filter" />
|
|
31
|
-
</template>
|
|
32
|
-
</t-button>
|
|
33
|
-
</div>
|
|
34
|
-
<!-- 操作按钮区域 -->
|
|
35
|
-
<div class="filter-action-buttons">
|
|
36
|
-
<!-- 搜索按钮 -->
|
|
37
|
-
<t-button theme="primary" :size="size" @click="emitSearch" title="搜索">
|
|
38
|
-
<template #icon>
|
|
39
|
-
<t-icon name="search" />
|
|
40
|
-
</template>
|
|
41
|
-
</t-button>
|
|
42
|
-
<!-- 重置按钮 -->
|
|
43
|
-
<t-button theme="primary" :size="size" @click="handleReset" title="重置">
|
|
44
|
-
<template #icon>
|
|
45
|
-
<t-icon name="refresh" />
|
|
46
|
-
</template>
|
|
47
|
-
</t-button>
|
|
48
|
-
<!-- 高级筛选按钮(当筛选长度大于0时) -->
|
|
49
|
-
<t-button v-if="filterCount > 0" theme="primary" :size="size" @click="openAdvancedFilter">
|
|
50
|
-
<template #icon>
|
|
51
|
-
<t-icon name="filter" />
|
|
52
|
-
</template>
|
|
53
|
-
</t-button>
|
|
54
|
-
<!-- 我的方案下拉菜单(当筛选长度大于0时) -->
|
|
55
|
-
<t-dropdown v-if="filterCount > 0" :options="dropdownOptions" @click="handlePlanSelect">
|
|
56
|
-
<t-button theme="primary" :size="size" class="margin-reset">
|
|
57
|
-
我的方案
|
|
58
|
-
<template #suffix><t-icon name="chevron-down" /></template>
|
|
59
|
-
</t-button>
|
|
60
|
-
</t-dropdown>
|
|
61
|
-
</div>
|
|
62
|
-
<!-- 高级筛选对话框 -->
|
|
63
|
-
<cd-filter
|
|
64
|
-
v-model:visible="showFilterDialog"
|
|
65
|
-
:field-options="fieldOptions"
|
|
66
|
-
:select-options="selectOptions"
|
|
67
|
-
:plan-filter-options="planFilterOptions"
|
|
68
|
-
:filter-cards="innerFilterCards"
|
|
69
|
-
:top-op="innerTopOp"
|
|
70
|
-
:size="size"
|
|
71
|
-
:person-tabs="personTabs"
|
|
72
|
-
:person-organizations="personOrganizations"
|
|
73
|
-
:visible-columns="visibleColumns"
|
|
74
|
-
width="1000"
|
|
75
|
-
@confirm="handleConfirm"
|
|
76
|
-
@reset="handleReset"
|
|
77
|
-
@delete-plan="(plan) => emit('delete-plan', plan)"
|
|
78
|
-
@copy-plan="(plan) => emit('copy-plan', plan)"
|
|
79
|
-
@set-default-plan="(plan) => emit('set-default-plan', plan)"
|
|
80
|
-
@update-plan="(payload) => emit('update-plan', payload)"
|
|
81
|
-
@load-users="(payload) => emit('load-users', payload)"
|
|
82
|
-
@search="(payload) => emit('search-persons', payload)"
|
|
83
|
-
@dept-click="(payload) => emit('dept-click', payload)"
|
|
84
|
-
@column-change="(columns) => emit('column-change', columns)"
|
|
85
|
-
/>
|
|
86
|
-
<!-- 保存筛选方案弹窗 -->
|
|
87
|
-
<t-dialog
|
|
88
|
-
:header="planTitle"
|
|
89
|
-
:visible="savePlanDialogVisible"
|
|
90
|
-
width="600px"
|
|
91
|
-
@close="closeSavePlanDialog"
|
|
92
|
-
>
|
|
93
|
-
<template #body>
|
|
94
|
-
<div class="save-plan-content">
|
|
95
|
-
<t-form :data="newPlanData" label-width="100px">
|
|
96
|
-
<t-form-item label="方案名称" required>
|
|
97
|
-
<t-input v-model="newPlanData.name" placeholder="请输入筛选方案名称" />
|
|
98
|
-
</t-form-item>
|
|
99
|
-
</t-form>
|
|
100
|
-
</div>
|
|
101
|
-
</template>
|
|
102
|
-
<template #footer>
|
|
103
|
-
<t-button theme="default" @click="closeSavePlanDialog">取消</t-button>
|
|
104
|
-
<t-button theme="primary" @click="emitSavePlan">确定</t-button>
|
|
105
|
-
</template>
|
|
106
|
-
</t-dialog>
|
|
107
|
-
</div>
|
|
108
|
-
</template>
|
|
109
|
-
<script setup>
|
|
110
|
-
import { ref, computed, watch } from 'vue'
|
|
111
|
-
import FilterComponent from './FilterComponent.vue'
|
|
112
|
-
import CdFilter from './cd-filter.vue'
|
|
113
|
-
// Props
|
|
114
|
-
const props = defineProps({
|
|
115
|
-
fieldOptions: { type: Array, required: true },
|
|
116
|
-
filterCount: { type: Number, default: 2 },
|
|
117
|
-
selectOptions: { type: Array, default: () => [] },
|
|
118
|
-
filterCards: {
|
|
119
|
-
type: Array,
|
|
120
|
-
default: () => [
|
|
121
|
-
{
|
|
122
|
-
id: 1,
|
|
123
|
-
connector: 'and',
|
|
124
|
-
conditions: [
|
|
125
|
-
{ field: '', operator: 'eq', value: '' },
|
|
126
|
-
{ field: '', operator: 'eq', value: '' }
|
|
127
|
-
]
|
|
128
|
-
}
|
|
129
|
-
]
|
|
130
|
-
},
|
|
131
|
-
topOp: { type: String, default: 'and' },
|
|
132
|
-
planFilterOptions: { type: Array, default: () => [] },
|
|
133
|
-
size: { type: String, default: 'small' },
|
|
134
|
-
width: { type: String, default: '1000px' },
|
|
135
|
-
personTabs: { type: Array, default: () => [] },
|
|
136
|
-
personOrganizations: { type: Array, default: () => [] },
|
|
137
|
-
visibleColumns: { type: Array, default: () => [] }
|
|
138
|
-
})
|
|
139
|
-
const emit = defineEmits([
|
|
140
|
-
'search',
|
|
141
|
-
'reset',
|
|
142
|
-
'save-plan',
|
|
143
|
-
'delete-plan',
|
|
144
|
-
'copy-plan',
|
|
145
|
-
'set-default-plan',
|
|
146
|
-
'update-plan',
|
|
147
|
-
'confirm',
|
|
148
|
-
'load-users',
|
|
149
|
-
'search-persons',
|
|
150
|
-
'dept-click',
|
|
151
|
-
'column-change'
|
|
152
|
-
])
|
|
153
|
-
// 内联条件根据 filterComCount 派生
|
|
154
|
-
const inlineHeaderConditions = ref([])
|
|
155
|
-
const makeBlankCondition = () => ({ field: '', operator: 'eq', value: '' })
|
|
156
|
-
const initInlineHeaderConditions = () => {
|
|
157
|
-
// 如果 filterCount 为 0,不初始化内联条件
|
|
158
|
-
if (props.filterCount === 0) {
|
|
159
|
-
inlineHeaderConditions.value = []
|
|
160
|
-
return
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const base = props.filterCards?.[0]?.conditions || []
|
|
164
|
-
inlineHeaderConditions.value = Array.from({ length: props.filterCount }, (_, i) => {
|
|
165
|
-
return base[i] ? JSON.parse(JSON.stringify(base[i])) : makeBlankCondition()
|
|
166
|
-
})
|
|
167
|
-
}
|
|
168
|
-
initInlineHeaderConditions()
|
|
169
|
-
const clearInlineHeaderConditions = () => {
|
|
170
|
-
// 如果 filterCount 为 0,清空即可
|
|
171
|
-
if (props.filterCount === 0) {
|
|
172
|
-
inlineHeaderConditions.value = []
|
|
173
|
-
return
|
|
174
|
-
}
|
|
175
|
-
inlineHeaderConditions.value = Array.from({ length: props.filterCount }, () => makeBlankCondition())
|
|
176
|
-
}
|
|
177
|
-
const planTitle = ref('保存筛选方案')
|
|
178
|
-
// 高级筛选内部状态
|
|
179
|
-
const showFilterDialog = ref(false)
|
|
180
|
-
const innerTopOp = ref(props.topOp)
|
|
181
|
-
const innerFilterCards = ref(JSON.parse(JSON.stringify(props.filterCards)))
|
|
182
|
-
watch(() => props.topOp, (v) => (innerTopOp.value = v))
|
|
183
|
-
watch(() => props.filterCards, (v) => (innerFilterCards.value = JSON.parse(JSON.stringify(v))))
|
|
184
|
-
// 方案相关
|
|
185
|
-
const selectedPlanFilter = ref(null)
|
|
186
|
-
const selectedPlanValue = ref('') // Radio Group 选中的值
|
|
187
|
-
|
|
188
|
-
const dropdownOptions = computed(() => {
|
|
189
|
-
return props.planFilterOptions && props.planFilterOptions.length > 0
|
|
190
|
-
? props.planFilterOptions
|
|
191
|
-
: [{ content: '暂无方案', value: 'empty', disabled: true }]
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
// Radio Group 方案选择处理
|
|
195
|
-
const handlePlanRadioChange = (value) => {
|
|
196
|
-
const selectedPlan = props.planFilterOptions.find(p => p.value === value)
|
|
197
|
-
if (selectedPlan) {
|
|
198
|
-
handlePlanSelect(selectedPlan)
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// 通用方案选择处理(适用于 dropdown 和 radio)
|
|
203
|
-
const handlePlanSelect = (option) => {
|
|
204
|
-
if (!option.precepts || option.precepts.length === 0) return
|
|
205
|
-
// 更新选中的方案
|
|
206
|
-
selectedPlanFilter.value = option
|
|
207
|
-
selectedPlanValue.value = option.value // 同步更新 radio 选中值
|
|
208
|
-
|
|
209
|
-
// 更新内部筛选卡片和顶层操作符
|
|
210
|
-
innerFilterCards.value = JSON.parse(JSON.stringify(option.precepts))
|
|
211
|
-
innerTopOp.value = option.sqlConnectType
|
|
212
|
-
|
|
213
|
-
// 同步更新内联条件显示(仅当 filterCount > 0 时)
|
|
214
|
-
if (props.filterCount > 0) {
|
|
215
|
-
const firstCard = option.precepts[0]
|
|
216
|
-
if (firstCard && firstCard.conditions) {
|
|
217
|
-
inlineHeaderConditions.value = Array.from({ length: props.filterCount }, (_, i) => {
|
|
218
|
-
return firstCard.conditions[i]
|
|
219
|
-
? JSON.parse(JSON.stringify(firstCard.conditions[i]))
|
|
220
|
-
: makeBlankCondition()
|
|
221
|
-
})
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const cleaned = cleanFilterCards(option.precepts)
|
|
226
|
-
const transformed = transformConditions(cleaned, option.sqlConnectType)
|
|
227
|
-
emit('confirm', transformed)
|
|
228
|
-
|
|
229
|
-
// 如果方案包含列配置,通知父组件(只传递显示的列)
|
|
230
|
-
if (option.columns && option.columns.length > 0) {
|
|
231
|
-
const visibleColumns = option.columns.filter(col => col.show !== false)
|
|
232
|
-
emit('column-change', visibleColumns)
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
const emitSearch = () => {
|
|
236
|
-
// 当 filterCount 为 0 时,不处理内联条件,直接发送空筛选
|
|
237
|
-
if (props.filterCount === 0) {
|
|
238
|
-
emit('search', { conditions: { and: [] } })
|
|
239
|
-
return
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const cleaned = cleanFilterCards([
|
|
243
|
-
{ id: 1, connector: innerTopOp.value, conditions: inlineHeaderConditions.value }
|
|
244
|
-
])
|
|
245
|
-
const transformed = transformConditions(cleaned, 'and')
|
|
246
|
-
emit('search', transformed)
|
|
247
|
-
}
|
|
248
|
-
// 高级筛选弹窗开关
|
|
249
|
-
const openAdvancedFilter = () => {
|
|
250
|
-
showFilterDialog.value = true
|
|
251
|
-
}
|
|
252
|
-
const closeAdvancedFilter = () => {
|
|
253
|
-
showFilterDialog.value = false
|
|
254
|
-
}
|
|
255
|
-
// 清理筛选卡片,保证字段有效
|
|
256
|
-
const cleanFilterCards = (cards) => {
|
|
257
|
-
return cards
|
|
258
|
-
.map((card) => {
|
|
259
|
-
const validConditions = card.conditions
|
|
260
|
-
.filter((condition) => condition.field && condition.field.trim() !== '')
|
|
261
|
-
.map((condition) => {
|
|
262
|
-
let cleanValue = ''
|
|
263
|
-
if (condition.value !== null && condition.value !== undefined) {
|
|
264
|
-
if (Array.isArray(condition.value)) {
|
|
265
|
-
cleanValue = condition.value.join('/')
|
|
266
|
-
} else {
|
|
267
|
-
cleanValue = String(condition.value)
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return {
|
|
271
|
-
field: condition.field.trim(),
|
|
272
|
-
operator: condition.operator || 'eq',
|
|
273
|
-
value: cleanValue
|
|
274
|
-
}
|
|
275
|
-
})
|
|
276
|
-
return {
|
|
277
|
-
...card,
|
|
278
|
-
connector: card.connector || 'and',
|
|
279
|
-
conditions: validConditions.length > 0 ? validConditions : [{ field: '', operator: 'eq', value: '' }]
|
|
280
|
-
}
|
|
281
|
-
})
|
|
282
|
-
.filter((card) => card.conditions.length > 0 && card.conditions[0].field !== '')
|
|
283
|
-
}
|
|
284
|
-
// 构建新的查询条件格式
|
|
285
|
-
function transformConditions(conditions, type) {
|
|
286
|
-
if (type !== 'and' && type !== 'or') {
|
|
287
|
-
throw new Error('type参数必须是"and"或"or"')
|
|
288
|
-
}
|
|
289
|
-
function transformSingleCondition(condition) {
|
|
290
|
-
return {
|
|
291
|
-
[condition.field]: {
|
|
292
|
-
[condition.operator]: condition.value
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
function transformConditionGroup(group) {
|
|
297
|
-
if (group.conditions.length === 1) {
|
|
298
|
-
return transformSingleCondition(group.conditions[0])
|
|
299
|
-
}
|
|
300
|
-
return {
|
|
301
|
-
[group.connector]: group.conditions.map(transformSingleCondition)
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
const result = {
|
|
305
|
-
conditions: {
|
|
306
|
-
[type]: conditions.map(transformConditionGroup)
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
return result
|
|
310
|
-
}
|
|
311
|
-
// 保存方案对话框
|
|
312
|
-
const openSavePlanDialog = (plan) => {
|
|
313
|
-
if (selectedPlanFilter.value) {
|
|
314
|
-
planTitle.value = '更新筛选方案'
|
|
315
|
-
newPlanData.value.name = selectedPlanFilter.value.content || ''
|
|
316
|
-
} else {
|
|
317
|
-
planTitle.value = '保存筛选方案'
|
|
318
|
-
newPlanData.value.name = ''
|
|
319
|
-
selectedPlanFilter.value = null
|
|
320
|
-
}
|
|
321
|
-
savePlanDialogVisible.value = true
|
|
322
|
-
}
|
|
323
|
-
const closeSavePlanDialog = () => {
|
|
324
|
-
savePlanDialogVisible.value = false
|
|
325
|
-
}
|
|
326
|
-
// 重置、保存
|
|
327
|
-
const handleReset = () => {
|
|
328
|
-
clearInlineHeaderConditions()
|
|
329
|
-
selectedPlanFilter.value = null
|
|
330
|
-
selectedPlanValue.value = '' // 清空 radio 选中值
|
|
331
|
-
innerFilterCards.value = [
|
|
332
|
-
{
|
|
333
|
-
id: 1,
|
|
334
|
-
connector: 'and',
|
|
335
|
-
conditions: [
|
|
336
|
-
{ field: '', operator: 'eq', value: '' },
|
|
337
|
-
{ field: '', operator: 'eq', value: '' }
|
|
338
|
-
]
|
|
339
|
-
}
|
|
340
|
-
]
|
|
341
|
-
innerTopOp.value = 'and'
|
|
342
|
-
emit('reset')
|
|
343
|
-
emitSearch()
|
|
344
|
-
}
|
|
345
|
-
const emitSavePlan = () => {
|
|
346
|
-
if (selectedPlanFilter.value) {
|
|
347
|
-
const cleaned = cleanFilterCards(innerFilterCards.value)
|
|
348
|
-
emit('update-plan', {
|
|
349
|
-
name: newPlanData.value.name,
|
|
350
|
-
precepts: cleaned,
|
|
351
|
-
topOp: innerTopOp.value,
|
|
352
|
-
plan: selectedPlanFilter.value,
|
|
353
|
-
columns: props.visibleColumns || [] // 包含当前列配置
|
|
354
|
-
})
|
|
355
|
-
} else {
|
|
356
|
-
const cleaned = cleanFilterCards(innerFilterCards.value)
|
|
357
|
-
emit('save-plan', {
|
|
358
|
-
name: newPlanData.value.name,
|
|
359
|
-
precepts: cleaned,
|
|
360
|
-
topOp: innerTopOp.value,
|
|
361
|
-
plan: selectedPlanFilter.value,
|
|
362
|
-
columns: props.visibleColumns || [] // 包含当前列配置
|
|
363
|
-
})
|
|
364
|
-
}
|
|
365
|
-
closeSavePlanDialog()
|
|
366
|
-
}
|
|
367
|
-
const handleConfirm = (condition) => {
|
|
368
|
-
const transformed = transformConditions(condition.filterCards, condition.type1)
|
|
369
|
-
emit('confirm', transformed)
|
|
370
|
-
// 仅在 filterCount > 0 时清空内联条件
|
|
371
|
-
if (props.filterCount > 0) {
|
|
372
|
-
clearInlineHeaderConditions()
|
|
373
|
-
}
|
|
374
|
-
closeAdvancedFilter()
|
|
375
|
-
}
|
|
376
|
-
// 保存方案弹窗数据
|
|
377
|
-
const savePlanDialogVisible = ref(false)
|
|
378
|
-
const newPlanData = ref({ name: '' })
|
|
379
|
-
</script>
|
|
380
|
-
<style scoped lang="scss">
|
|
381
|
-
.cd-filter-bar {
|
|
382
|
-
display: flex;
|
|
383
|
-
align-items: center;
|
|
384
|
-
gap: 8px;
|
|
385
|
-
}
|
|
386
|
-
.inline-filter-toolbar {
|
|
387
|
-
display: inline-flex;
|
|
388
|
-
align-items: center;
|
|
389
|
-
gap: 8px;
|
|
390
|
-
}
|
|
391
|
-
.plan-radio-group {
|
|
392
|
-
display: flex;
|
|
393
|
-
align-items: center;
|
|
394
|
-
gap: 12px;
|
|
395
|
-
flex: 1;
|
|
396
|
-
|
|
397
|
-
.plan-label {
|
|
398
|
-
font-size: 14px;
|
|
399
|
-
font-weight: 500;
|
|
400
|
-
color: #333;
|
|
401
|
-
white-space: nowrap;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
.filter-action-buttons {
|
|
405
|
-
display: flex;
|
|
406
|
-
gap: 8px;
|
|
407
|
-
align-items: center;
|
|
408
|
-
}
|
|
409
|
-
.margin-reset {
|
|
410
|
-
margin: 0;
|
|
411
|
-
}
|
|
412
|
-
</style>
|