vue-2024-ui 0.0.13 → 0.0.15
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 +1 -1
- package/src/components/g-ctrl.vue +76 -19
- package/src/components/g-query-item.vue +12 -14
- package/src/components/g-query.vue +36 -42
- package/src/components/g-table.vue +60 -22
- package/src/components/index.js +24 -1
package/package.json
CHANGED
|
@@ -38,23 +38,25 @@
|
|
|
38
38
|
</el-checkbox-group>
|
|
39
39
|
<!--select-->
|
|
40
40
|
<el-select v-model="ctrlValue" :placeholder="model[ctrlKey].label" v-bind="selectModel"
|
|
41
|
-
v-else-if="ctrlType
|
|
42
|
-
<template #default
|
|
41
|
+
v-else-if="ctrlType === 'select'">
|
|
42
|
+
<template #default>
|
|
43
43
|
<slot :name="`${props.t}-${ctrlKey}`" :options="model[ctrlKey].options">
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
<!-- 根据是否存在子选项渲染不同结构 -->
|
|
45
|
+
<template v-if="model[ctrlKey]?.options?.some(a => a.options)">
|
|
46
|
+
<el-option-group v-for="group in model[ctrlKey].options" :key="group.label"
|
|
47
|
+
:label="group.label">
|
|
48
|
+
<el-option v-bind="option" v-for="option in group.options" :key="option.value"
|
|
49
|
+
@click.native="selectModel.change && selectModel.change(option)">
|
|
50
|
+
<slot :name="`${props.t}-${ctrlKey}-options`" :option></slot>
|
|
51
|
+
</el-option>
|
|
52
|
+
</el-option-group>
|
|
53
|
+
</template>
|
|
54
|
+
<template v-else>
|
|
55
|
+
<el-option v-bind="option" v-for="option in model[ctrlKey].options" :key="option.value"
|
|
46
56
|
@click.native="selectModel.change && selectModel.change(option)">
|
|
47
57
|
<slot :name="`${props.t}-${ctrlKey}-options`" :option></slot>
|
|
48
58
|
</el-option>
|
|
49
|
-
</
|
|
50
|
-
</slot>
|
|
51
|
-
</template>
|
|
52
|
-
<template #default v-else>
|
|
53
|
-
<slot :name="`${props.t}-${ctrlKey}`" :options="model[ctrlKey].options">
|
|
54
|
-
<el-option v-bind="option" v-for="option in model[ctrlKey].options"
|
|
55
|
-
@click.native="selectModel.change && selectModel.change(option)">
|
|
56
|
-
<slot :name="`${props.t}-${ctrlKey}-options`" :option></slot>
|
|
57
|
-
</el-option>
|
|
59
|
+
</template>
|
|
58
60
|
</slot>
|
|
59
61
|
</template>
|
|
60
62
|
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
@@ -62,7 +64,7 @@
|
|
|
62
64
|
</template>
|
|
63
65
|
</el-select>
|
|
64
66
|
<!--tree-select-->
|
|
65
|
-
<el-tree-select v-model="ctrlValue" :placeholder="model[ctrlKey].label" v-bind="itemInfo"
|
|
67
|
+
<el-tree-select v-model="ctrlValue" :placeholder="model[ctrlKey].label" v-bind="itemInfo" :data="treeSelectData"
|
|
66
68
|
v-else-if="ctrlType == 'tree-select'">
|
|
67
69
|
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
68
70
|
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
@@ -107,7 +109,8 @@
|
|
|
107
109
|
</template>
|
|
108
110
|
</el-transfer>
|
|
109
111
|
<!--cascader-->
|
|
110
|
-
<el-cascader v-model="ctrlValue" v-bind="itemInfo"
|
|
112
|
+
<el-cascader v-model="ctrlValue" v-bind="itemInfo" :options="model[ctrlKey].options"
|
|
113
|
+
v-else-if="ctrlType == 'cascader'">
|
|
111
114
|
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
112
115
|
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
113
116
|
</template>
|
|
@@ -134,7 +137,7 @@
|
|
|
134
137
|
</el-input-number>
|
|
135
138
|
<!--input-->
|
|
136
139
|
<el-input v-model="ctrlValue" :placeholder="model[ctrlKey].label" :maxlength="itemInfo?.max || 25"
|
|
137
|
-
:clearable="true" v-bind="itemInfo" v-else>
|
|
140
|
+
:clearable="true" v-bind="{ ...itemInfo, type: ctrlType }" v-else>
|
|
138
141
|
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
139
142
|
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
140
143
|
</template>
|
|
@@ -144,14 +147,14 @@
|
|
|
144
147
|
|
|
145
148
|
<script setup>
|
|
146
149
|
defineOptions({ inheritAttrs: false });
|
|
147
|
-
import { onMounted, useSlots } from "vue";
|
|
148
|
-
import { filterObject } from ".";
|
|
150
|
+
import { onMounted, useSlots, ref } from "vue";
|
|
149
151
|
const ctrlValue = defineModel({ required: true });
|
|
150
152
|
const props = defineProps(["t", "ctrlKey", "item", "model", 'ctrlType'])
|
|
151
153
|
const itemInfo = props.item;
|
|
152
154
|
const ctrlKey = props.ctrlKey;
|
|
153
155
|
const ctrlType = props.ctrlType;
|
|
154
156
|
const model = props.model;
|
|
157
|
+
const treeSelectData = ref([]);
|
|
155
158
|
const slots = () => Object.keys(useSlots()).filter(a => a.startsWith(`${props.t}-${ctrlKey}-`)).map(a => a.replace(`${props.t}-${ctrlKey}-`, ''));
|
|
156
159
|
|
|
157
160
|
//select 默认属性
|
|
@@ -166,9 +169,63 @@ const selectRemoteMethod = (query) => {
|
|
|
166
169
|
})
|
|
167
170
|
}
|
|
168
171
|
|
|
169
|
-
|
|
172
|
+
// 新增:标记数据是否加载完成
|
|
173
|
+
const isOptionsLoaded = ref(false);
|
|
174
|
+
|
|
175
|
+
// 模拟异步获取数据的函数
|
|
176
|
+
const options = async (keyValue = 'options') => {
|
|
177
|
+
try {
|
|
178
|
+
// 这里替换为实际的异步请求
|
|
179
|
+
const response = await itemInfo?.options(model);
|
|
180
|
+
model[ctrlKey][keyValue] = response;
|
|
181
|
+
isOptionsLoaded.value = true;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error('Failed to fetch options:', error);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
onMounted(async () => {
|
|
170
188
|
if (itemInfo && itemInfo["remote-method"]) {
|
|
171
189
|
selectModel['remote-method'] = selectRemoteMethod;
|
|
172
190
|
}
|
|
191
|
+
// 新增:在组件挂载时调用异步获取数据的函数
|
|
192
|
+
// 提取公共逻辑到一个函数中
|
|
193
|
+
const loadOptions = (key, keyValue = 'options', targetRef = model[ctrlKey]) => {
|
|
194
|
+
if (typeof itemInfo.options === 'function') {
|
|
195
|
+
options(keyValue).catch(error => {
|
|
196
|
+
console.error(`Failed to load ${keyValue} for ${key}:`, error);
|
|
197
|
+
});
|
|
198
|
+
} else if (Array.isArray(itemInfo.options)) {
|
|
199
|
+
targetRef[keyValue] = itemInfo.options;
|
|
200
|
+
// 更新数据加载状态
|
|
201
|
+
isOptionsLoaded.value = true;
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// 处理不同的 ctrlType
|
|
206
|
+
const typesWithOptions = ['radio', 'radio-button', 'checkbox-group', 'checkbox-group-button', 'select', 'cascader'];
|
|
207
|
+
if (typesWithOptions.includes(ctrlType)) {
|
|
208
|
+
loadOptions(ctrlType);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (ctrlType === 'tree-select') {
|
|
212
|
+
const loadTreeSelectOptions = async () => {
|
|
213
|
+
try {
|
|
214
|
+
if (typeof itemInfo.options === 'function') {
|
|
215
|
+
treeSelectData.value = await itemInfo.options(model);
|
|
216
|
+
} else if (Array.isArray(itemInfo?.data)) {
|
|
217
|
+
treeSelectData.value = itemInfo.data;
|
|
218
|
+
} else if (itemInfo?.options && Array.isArray(itemInfo?.options)) {
|
|
219
|
+
treeSelectData.value = itemInfo.options;
|
|
220
|
+
}
|
|
221
|
+
// 更新数据加载状态
|
|
222
|
+
isOptionsLoaded.value = true;
|
|
223
|
+
} catch (error) {
|
|
224
|
+
console.error(`Failed to load data for tree-select:`, error);
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
await loadTreeSelectOptions();
|
|
228
|
+
}
|
|
229
|
+
|
|
173
230
|
})
|
|
174
231
|
</script>
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<template v-for="(item, key) of getQueryModel(props.more)" :key="key">
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<
|
|
9
|
-
<slot :name="slotKey" :data :item :model></slot>
|
|
10
|
-
</template>
|
|
11
|
-
</g-ctrl>
|
|
12
|
-
<template #label>
|
|
13
|
-
<slot :name="`q-${key}-label`" :item :model></slot>
|
|
3
|
+
<slot :name="`q-${key}`" :item :model>
|
|
4
|
+
<el-form-item :label="item.label" v-bind="{ ...model.queryItems, ...item?.search }">
|
|
5
|
+
<g-ctrl v-model="queryModel[key]" :item="{ ...item?.editor, ...item.search }" :ctrlKey="key"
|
|
6
|
+
:ctrlType="item.type" :model t="q">
|
|
7
|
+
<template v-for="(slot, slotKey, index) in $slots" :key="index" #[slotKey]="data">
|
|
8
|
+
<slot :name="slotKey" :data :item :model></slot>
|
|
14
9
|
</template>
|
|
15
|
-
</
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
</g-ctrl>
|
|
11
|
+
<template #label>
|
|
12
|
+
<slot :name="`q-${key}-label`" :item :model></slot>
|
|
13
|
+
</template>
|
|
14
|
+
</el-form-item>
|
|
15
|
+
</slot>
|
|
18
16
|
</template>
|
|
19
17
|
</template>
|
|
20
18
|
|
|
@@ -6,42 +6,41 @@
|
|
|
6
6
|
<slot :name="slotKey" :model></slot>
|
|
7
7
|
</template>
|
|
8
8
|
</g-query-item>
|
|
9
|
-
<el-col v-bind="model.query.btns.col" style="width:100%;">
|
|
10
|
-
<el-form-item style="width: 100%;">
|
|
11
|
-
<div :style="model.query.btns.style">
|
|
12
|
-
<el-button v-bind="model.query.query" @click="model.query.query.click()">
|
|
13
|
-
{{ model.query.query.label }}
|
|
14
|
-
</el-button>
|
|
15
|
-
<el-button v-bind="model.query.reset" @click="model.query.reset.click()">
|
|
16
|
-
{{ model.query.reset.label }}
|
|
17
|
-
</el-button>
|
|
18
|
-
<el-button v-bind="model.query.more" @click="model.query.more.click()"
|
|
19
|
-
v-if="model.query.more.mode !== 3">
|
|
20
|
-
{{ model.query.more.label }}
|
|
21
|
-
</el-button>
|
|
22
|
-
<el-popover v-bind="model.query.more.dialog" v-if="model.query.more.mode == 3">
|
|
23
|
-
<template #reference>
|
|
24
|
-
<el-button v-bind="model.query.more">
|
|
25
|
-
{{ model.query.more.label }}
|
|
26
|
-
</el-button>
|
|
27
|
-
</template>
|
|
28
|
-
<template #default>
|
|
29
|
-
<el-form
|
|
30
|
-
v-bind="filterObject(model.query, k => !['query', 'more', 'reset'].includes(k))">
|
|
31
|
-
<g-query-item v-model="model" v-model:info="queryModel" :more="true">
|
|
32
|
-
<template v-for="(slot, slotKey, index) in $slots" :key="index"
|
|
33
|
-
#[slotKey]="data">
|
|
34
|
-
<slot :name="slotKey" :model></slot>
|
|
35
|
-
</template>
|
|
36
|
-
</g-query-item>
|
|
37
|
-
</el-form>
|
|
38
|
-
</template>
|
|
39
|
-
</el-popover>
|
|
40
|
-
<slot name="q-btns"></slot>
|
|
41
|
-
</div>
|
|
42
|
-
</el-form-item>
|
|
43
|
-
</el-col>
|
|
44
9
|
</el-form>
|
|
10
|
+
<el-form style="display: flex;">
|
|
11
|
+
<el-form-item style="width: 100%;">
|
|
12
|
+
<div :style="model.query.btns.style">
|
|
13
|
+
<el-button v-bind="model.query.query" @click="model.query.query.click()">
|
|
14
|
+
{{ model.query.query.label }}
|
|
15
|
+
</el-button>
|
|
16
|
+
<el-button v-bind="model.query.reset" @click="model.query.reset.click()">
|
|
17
|
+
{{ model.query.reset.label }}
|
|
18
|
+
</el-button>
|
|
19
|
+
<el-button v-bind="model.query.more" @click="model.query.more.click()"
|
|
20
|
+
v-if="model.query.more.mode !== 3">
|
|
21
|
+
{{ model.query.more.label }}
|
|
22
|
+
</el-button>
|
|
23
|
+
<el-popover v-bind="model.query.more.dialog" v-if="model.query.more.mode == 3">
|
|
24
|
+
<template #reference>
|
|
25
|
+
<el-button v-bind="model.query.more">
|
|
26
|
+
{{ model.query.more.label }}
|
|
27
|
+
</el-button>
|
|
28
|
+
</template>
|
|
29
|
+
<template #default>
|
|
30
|
+
<el-form v-bind="filterObject(model.query, k => !['query', 'more', 'reset'].includes(k))">
|
|
31
|
+
<g-query-item v-model="model" v-model:info="queryModel" :more="true">
|
|
32
|
+
<template v-for="(slot, slotKey, index) in $slots" :key="index" #[slotKey]="data">
|
|
33
|
+
<slot :name="slotKey" :model></slot>
|
|
34
|
+
</template>
|
|
35
|
+
</g-query-item>
|
|
36
|
+
</el-form>
|
|
37
|
+
</template>
|
|
38
|
+
</el-popover>
|
|
39
|
+
<slot name="q-btns"></slot>
|
|
40
|
+
</div>
|
|
41
|
+
</el-form-item>
|
|
42
|
+
</el-form>
|
|
43
|
+
|
|
45
44
|
<Transition :duration="300" name="nested">
|
|
46
45
|
<div v-if="isShowMore && !model.query.more.hidden && model.query.more.mode == 1" class="outer">
|
|
47
46
|
<div class="inner">
|
|
@@ -124,13 +123,9 @@ const defaultQueryAttrs = {
|
|
|
124
123
|
isShowMore.value = false;
|
|
125
124
|
}
|
|
126
125
|
},
|
|
127
|
-
cols: {
|
|
128
|
-
span: 6, offset: 0, xs: 24, sm: 12, md: 8, lg: 6, xl: 4,
|
|
129
|
-
},
|
|
130
126
|
btns: {
|
|
131
|
-
col: { span: 8, offset: 0, xs: 24, sm: 12, md: 8, lg: 6, xl: 4, },
|
|
132
127
|
style: {
|
|
133
|
-
width: "100%", display: "flex", justifyContent: "flex-
|
|
128
|
+
width: "100%", display: "flex", flexWrap: "wrap", justifyContent: "flex-start",
|
|
134
129
|
}
|
|
135
130
|
}
|
|
136
131
|
}
|
|
@@ -153,9 +148,8 @@ model.value.query.more.dialog = model.value.query.more.mode == 2 ? mergeObjects(
|
|
|
153
148
|
const defaultQueryItemsAttrs = {
|
|
154
149
|
type: "hidden",
|
|
155
150
|
labelPosition: 'right',
|
|
156
|
-
span: 8,
|
|
157
151
|
style: {
|
|
158
|
-
width: "
|
|
152
|
+
width: "280px"
|
|
159
153
|
}
|
|
160
154
|
};
|
|
161
155
|
model.value.queryItems = mergeObjects(defaultQueryItemsAttrs, options?.queryItems, model.value.queryItems);
|
|
@@ -7,17 +7,23 @@
|
|
|
7
7
|
</template>
|
|
8
8
|
<template #q-btns>
|
|
9
9
|
<slot name="q-btns">
|
|
10
|
-
<div class="btns"
|
|
10
|
+
<div class="btns">
|
|
11
11
|
<slot name="control-add-left"></slot>
|
|
12
|
-
<slot name="control-add">
|
|
12
|
+
<slot name="control-add" v-if="model.control.add.auth()">
|
|
13
13
|
<el-button v-bind="model.control.add" @click="addRow(model)">{{
|
|
14
14
|
model.control.add.label
|
|
15
15
|
}}</el-button>
|
|
16
16
|
</slot>
|
|
17
17
|
<slot name="control-add-right"></slot>
|
|
18
18
|
</div>
|
|
19
|
+
<div class="btns" v-if="model.control.download.auth()">
|
|
20
|
+
<slot name="control-download">
|
|
21
|
+
<el-button v-bind="model.control.download" @click="download(model)">{{
|
|
22
|
+
model.control.download.label
|
|
23
|
+
}}</el-button>
|
|
24
|
+
</slot>
|
|
25
|
+
</div>
|
|
19
26
|
</slot>
|
|
20
|
-
|
|
21
27
|
</template>
|
|
22
28
|
</g-query>
|
|
23
29
|
</slot>
|
|
@@ -94,6 +100,7 @@
|
|
|
94
100
|
<div>{{ model.dialog.title }}</div>
|
|
95
101
|
</slot>
|
|
96
102
|
</div>
|
|
103
|
+
<!-- :icon="isFullscreen ? 'radix-icons:exit-full-screen' : 'radix-icons:enter-full-screen'" -->
|
|
97
104
|
<!--最大化-->
|
|
98
105
|
<div v-if="model?.dialog?.fullScreen === false" @click="model.dialog.fullScreen = true;"
|
|
99
106
|
class="max">
|
|
@@ -148,7 +155,7 @@ import { computed, watchEffect, inject, ref } from 'vue';
|
|
|
148
155
|
import GForm from './g-form.vue';
|
|
149
156
|
import gQuery from './g-query.vue';
|
|
150
157
|
import { mergeObjects, filterObject, convertToPx } from './index';
|
|
151
|
-
import { FullScreen, Remove } from '@element-plus/icons-vue';
|
|
158
|
+
import { FullScreen, Remove, } from '@element-plus/icons-vue';
|
|
152
159
|
|
|
153
160
|
defineOptions({
|
|
154
161
|
name: "g-table",
|
|
@@ -236,6 +243,13 @@ const defaultControl = {
|
|
|
236
243
|
message: '此操作将永久删除该文件, 是否继续?', title: '提示', options: { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }
|
|
237
244
|
},
|
|
238
245
|
},
|
|
246
|
+
download: {
|
|
247
|
+
label: '下载', text: false, type: 'primary',
|
|
248
|
+
style: {
|
|
249
|
+
marginLeft: "10px",
|
|
250
|
+
},
|
|
251
|
+
auth: () => false,
|
|
252
|
+
},
|
|
239
253
|
};
|
|
240
254
|
model.value.control = mergeObjects(
|
|
241
255
|
defaultControl,
|
|
@@ -290,44 +304,59 @@ const initFormData = Object.fromEntries(Object.entries(filterObject(model.value,
|
|
|
290
304
|
return (val.type != 'control' && val.editor !== false && val.type != 'hidden');
|
|
291
305
|
})).map(([key, val]) => [key, val.value]));
|
|
292
306
|
|
|
293
|
-
//扩展formatter方法
|
|
294
307
|
const formatterExtends = (item, str) => {
|
|
308
|
+
// 初始化最终值为输入的字符串
|
|
295
309
|
let trueValue = str;
|
|
296
|
-
|
|
297
|
-
|
|
310
|
+
// 处理小数位数
|
|
311
|
+
if (item.decimals &&!isNaN(str)) {
|
|
312
|
+
if (typeof item.decimals === 'number') {
|
|
313
|
+
// 确保输入是有效的数字,然后保留指定小数位数
|
|
298
314
|
trueValue = parseFloat(trueValue).toFixed(item.decimals);
|
|
299
|
-
}
|
|
300
|
-
else if (typeof item.decimals == 'object') {
|
|
315
|
+
} else if (typeof item.decimals === 'object') {
|
|
301
316
|
if (item.decimals.num) {
|
|
302
317
|
if (item.decimals.pad) {
|
|
318
|
+
// 保留指定小数位数并补零
|
|
303
319
|
trueValue = parseFloat(trueValue).toFixed(item.decimals.num);
|
|
304
320
|
} else {
|
|
321
|
+
// 保留指定小数位数但不补零
|
|
305
322
|
trueValue = parseFloat(parseFloat(trueValue).toFixed(item.decimals.num));
|
|
306
323
|
}
|
|
307
324
|
}
|
|
308
325
|
}
|
|
309
326
|
}
|
|
327
|
+
|
|
328
|
+
// 处理日期格式化
|
|
310
329
|
if (item.dateFormat && dayjs(str).isValid()) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
330
|
+
switch (item.dateFormat) {
|
|
331
|
+
case 'date':
|
|
332
|
+
trueValue = dayjs(trueValue).format('YYYY-MM-DD');
|
|
333
|
+
break;
|
|
334
|
+
case 'time':
|
|
335
|
+
trueValue = dayjs(trueValue).format('HH:mm:ss');
|
|
336
|
+
break;
|
|
337
|
+
case 'datetime':
|
|
338
|
+
trueValue = dayjs(trueValue).format('YYYY-MM-DD HH:mm:ss');
|
|
339
|
+
break;
|
|
340
|
+
default:
|
|
341
|
+
trueValue = dayjs(trueValue).format(item.dateFormat);
|
|
321
342
|
}
|
|
322
343
|
}
|
|
344
|
+
|
|
345
|
+
// 处理前缀
|
|
323
346
|
if (item.prefix && trueValue) {
|
|
347
|
+
// 使用模板字符串添加前缀
|
|
324
348
|
trueValue = `<span>${item.prefix}${trueValue}</span>`;
|
|
325
349
|
}
|
|
350
|
+
|
|
351
|
+
// 处理后缀
|
|
326
352
|
if (item.suffix && trueValue) {
|
|
327
|
-
|
|
353
|
+
// 使用模板字符串添加后缀
|
|
354
|
+
trueValue = `${trueValue}<span>${item.suffix}</span>`;
|
|
328
355
|
}
|
|
329
|
-
|
|
330
|
-
|
|
356
|
+
|
|
357
|
+
return trueValue;
|
|
358
|
+
};
|
|
359
|
+
|
|
331
360
|
|
|
332
361
|
|
|
333
362
|
//重置查询初始值
|
|
@@ -339,6 +368,7 @@ const queryReset = (q) => {
|
|
|
339
368
|
//查询方法
|
|
340
369
|
const query = (q) => {
|
|
341
370
|
queryInfo.value = q;
|
|
371
|
+
model.value.table.load();
|
|
342
372
|
}
|
|
343
373
|
|
|
344
374
|
//新增方法
|
|
@@ -429,6 +459,14 @@ const formReset = (callback) => {
|
|
|
429
459
|
emits("reset", callback)
|
|
430
460
|
}
|
|
431
461
|
|
|
462
|
+
const download = (model) => {
|
|
463
|
+
if (model.control.download?.click) {
|
|
464
|
+
model.control.download.click(model);
|
|
465
|
+
} else {
|
|
466
|
+
alert("download");
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
432
470
|
//表格列
|
|
433
471
|
const tableColumns = computed(() => Object.fromEntries(
|
|
434
472
|
Object.entries(model.value)
|
package/src/components/index.js
CHANGED
|
@@ -178,4 +178,27 @@ function filterObject(obj, filter = (key, value) => filter(key, value)) {
|
|
|
178
178
|
return result;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
/**
|
|
182
|
+
* 在树形结构中通过一个 value 值查找对应的 label,使用递归方式。
|
|
183
|
+
* @param {Array} treeData - 树形结构的数据数组。
|
|
184
|
+
* @param {*} value - 需要查找的 value 值。
|
|
185
|
+
* @param {string} [valueKey="value"] - 数据节点中表示 value 的键名。
|
|
186
|
+
* @param {string} [labelKey="label"] - 数据节点中表示 label 的键名。
|
|
187
|
+
* @param {string} [childrenKey="children"] - 数据节点中表示子节点的键名。
|
|
188
|
+
* @returns {string|null} - 如果找到对应的 label 则返回该 label,否则返回 null。
|
|
189
|
+
*/
|
|
190
|
+
function findTreeLabelByValue(treeData, value, valueKey = "value", labelKey = "label", childrenKey = "children") {
|
|
191
|
+
for (const node of treeData) {
|
|
192
|
+
if (node[valueKey] === value) {
|
|
193
|
+
return node[labelKey];
|
|
194
|
+
}
|
|
195
|
+
if (node[childrenKey] && node[childrenKey].length > 0) {
|
|
196
|
+
const result = findTreeLabelByValue(node[childrenKey], value, valueKey, labelKey, childrenKey);
|
|
197
|
+
if (result) {
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
export { openModal, convertToPx, mergeObjects, filterObject, findTreeLabelByValue };
|