vue-2024-ui 0.0.25 → 0.0.26
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 +4 -12
- package/src/components/check-excel-item.vue +105 -0
- package/src/components/columns-setting.vue +168 -0
- package/src/components/db.js +39 -0
- package/src/components/g-ctrl.vue +231 -0
- package/src/components/g-form.vue +254 -0
- package/src/components/g-query-item.vue +30 -0
- package/src/components/g-query.vue +229 -0
- package/src/components/g-table.vue +586 -0
- package/src/components/index.d.ts +90 -0
- package/src/components/index.js +221 -0
- package/dist/favicon.ico +0 -0
- package/dist/index.css +0 -1
- package/dist/vue-2024-ui.min.js +0 -7877
package/package.json
CHANGED
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vue-2024-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.26",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./
|
|
7
|
-
"
|
|
8
|
-
"types": "./dist/types/index.d.ts",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"types": "./dist/types/index.d.ts",
|
|
12
|
-
"import": "./dist/vue-2024-ui.esm.js",
|
|
13
|
-
"require": "./dist/vue-2024-ui.cjs"
|
|
14
|
-
}
|
|
15
|
-
},
|
|
6
|
+
"main": "./src/components/index.js",
|
|
7
|
+
"types": "./dist/types/index.d.ts",
|
|
16
8
|
"author": {
|
|
17
9
|
"name": "guoyuanchao",
|
|
18
10
|
"email": "xg816620@163.com"
|
|
19
11
|
},
|
|
20
12
|
"files": [
|
|
21
|
-
"
|
|
13
|
+
"./src/components",
|
|
22
14
|
"README.md"
|
|
23
15
|
],
|
|
24
16
|
"scripts": {
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div style="padding:0;margin: 0;box-sizing: border-box;">
|
|
3
|
+
<div style="padding: 10px;box-sizing: border-box;">
|
|
4
|
+
<div style="margin: 10px">
|
|
5
|
+
<a @click="selectAll">全选</a>
|
|
6
|
+
<el-divider direction="vertical"></el-divider>
|
|
7
|
+
<a @click="clearAll">全不选</a>
|
|
8
|
+
</div>
|
|
9
|
+
<el-alert title="拖动列标题可以改变表格列的生成顺序 !" type="warning" show-icon :closable="false"
|
|
10
|
+
style="margin-bottom: 10px">
|
|
11
|
+
</el-alert>
|
|
12
|
+
<div style="margin: 1px 0;"></div>
|
|
13
|
+
<div style="display: flex;">
|
|
14
|
+
<el-checkbox-group id="excelSortEl" v-model="checkList" @change="handleCheckedCitiesChange" style="display: flex;flex-wrap: wrap;margin:0 !important;padding:0 !important;
|
|
15
|
+
">
|
|
16
|
+
<el-checkbox class="check-box-hover"
|
|
17
|
+
style=" width: 120px !important; height: 30px !important; border: 1px solid #dfe6ec; margin: 5px !important; border-radius: 3px !important; padding-left: 5px !important; display:flex !important; align-items: center !important;"
|
|
18
|
+
:data-id="index" v-for="(item, index) in excelItems" :value="item.value" :key="'el-i-' + index"
|
|
19
|
+
:title="item.label">
|
|
20
|
+
<span v-text="item.label"
|
|
21
|
+
style="display: block; text-overflow: ellipsis;width:95px;overflow: hidden;"></span>
|
|
22
|
+
</el-checkbox>
|
|
23
|
+
</el-checkbox-group>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<div
|
|
27
|
+
style="width:100%;display: flex;padding: 10px; box-sizing:border-box; justify-content: center;border-top: 1px solid #dcdfe6;">
|
|
28
|
+
<el-button type="primary" @click="createExcel" :disabled="checkList.length <= 0">
|
|
29
|
+
<a href="" :download="returnUrl" style="text-decoration: none;"> {{ props.commitText }}</a>
|
|
30
|
+
</el-button>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup>
|
|
36
|
+
import { ref, onMounted, onBeforeUnmount } from 'vue';
|
|
37
|
+
import Sortable from "sortablejs";
|
|
38
|
+
|
|
39
|
+
const props = defineProps({
|
|
40
|
+
items: Array,
|
|
41
|
+
commitText: String
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const emits = defineEmits(['save']);
|
|
45
|
+
// 定义响应式数据
|
|
46
|
+
const checkAll = ref(false);
|
|
47
|
+
const checkList = ref([]);
|
|
48
|
+
const excelItems = ref(props.items);
|
|
49
|
+
const isIndeterminate = ref(true);
|
|
50
|
+
const afterDragData = ref([]);
|
|
51
|
+
const returnUrl= ref('');
|
|
52
|
+
|
|
53
|
+
// 定义方法
|
|
54
|
+
const createExcel = () => {
|
|
55
|
+
let arr = [];
|
|
56
|
+
(afterDragData.value.length === 0 ? excelItems.value : afterDragData.value).forEach(element => {
|
|
57
|
+
if (checkList.value.includes(element)) {
|
|
58
|
+
arr.push(element);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
emits('save', arr);
|
|
62
|
+
console.log(arr);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const handleCheckAllChange = (val) => {
|
|
66
|
+
checkList.value = val ? props.items : [];
|
|
67
|
+
isIndeterminate.value = false;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const handleCheckedCitiesChange = (value) => {
|
|
71
|
+
let checkedCount = value.length;
|
|
72
|
+
checkAll.value = checkedCount === excelItems.value.length;
|
|
73
|
+
isIndeterminate.value = checkedCount > 0 && checkedCount < excelItems.value.length;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// 生命周期钩子
|
|
77
|
+
onMounted(() => {
|
|
78
|
+
checkAll.value = true;
|
|
79
|
+
isIndeterminate.value = false;
|
|
80
|
+
checkList.value = props.items || [];
|
|
81
|
+
const sortable = new Sortable(document.getElementById('excelSortEl'), {
|
|
82
|
+
animation: 150,
|
|
83
|
+
onEnd: () => {
|
|
84
|
+
afterDragData.value = [];
|
|
85
|
+
let indexArr = sortable.toArray();
|
|
86
|
+
console.log(indexArr);
|
|
87
|
+
indexArr.forEach(element => {
|
|
88
|
+
afterDragData.value.push(excelItems.value[parseInt(element)]);
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
// 保存 sortable 实例以便在组件销毁时销毁它
|
|
93
|
+
const sortableInstance = sortable;
|
|
94
|
+
onBeforeUnmount(() => {
|
|
95
|
+
if (sortableInstance) {
|
|
96
|
+
sortableInstance.destroy();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
</script>
|
|
101
|
+
<style scoped>
|
|
102
|
+
.check-box-hover:hover {
|
|
103
|
+
background: #f5f1f1;
|
|
104
|
+
}
|
|
105
|
+
</style>
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div style="margin: 10px" class="allcheck">
|
|
4
|
+
<a @click="selectAll">全选</a>
|
|
5
|
+
<el-divider direction="vertical"></el-divider>
|
|
6
|
+
<a @click="clearAll">全不选</a>
|
|
7
|
+
<el-divider direction="vertical"></el-divider>
|
|
8
|
+
<a @click="rowReset">复位</a>
|
|
9
|
+
</div>
|
|
10
|
+
<el-alert title="拖动表格列标题可以改变表格列显示顺序 !" type="warning" show-icon :closable="false" style="margin-bottom: 10px">
|
|
11
|
+
</el-alert>
|
|
12
|
+
<div>
|
|
13
|
+
<div id="cols" style="display: flex;flex-wrap: wrap;margin:0 !important;padding:0 !important; ">
|
|
14
|
+
<el-checkbox v-model="check.showCol" :data-id="check.value" class="check-box-hover"
|
|
15
|
+
:class="check.value == 'control' ? 'filtered' : ''" @change="(v) => change(v, check.value)" style=" width: 125px !important; height: 30px !important; border: 1px solid #dfe6ec; margin: 5px !important; border-radius: 2px !important;
|
|
16
|
+
padding-left: 5px !important; display: flex !important; align-items: center !important;" :value="check.value"
|
|
17
|
+
:title="check.label" :disabled="check.alwaysShow" v-for="(check) in cols" :key="check.value">
|
|
18
|
+
<span v-text="check.label"
|
|
19
|
+
style="display: block; text-overflow: ellipsis;width:95px;overflow: hidden;"></span>
|
|
20
|
+
</el-checkbox>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script setup>
|
|
28
|
+
import { ref, onMounted } from 'vue';
|
|
29
|
+
import Sortable from "sortablejs";
|
|
30
|
+
import { deleteTableInfo, saveTableInfo } from './db';
|
|
31
|
+
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
32
|
+
// 定义 props
|
|
33
|
+
const props = defineProps({
|
|
34
|
+
name: {
|
|
35
|
+
type: String,
|
|
36
|
+
required: true,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const cols = ref([]);
|
|
41
|
+
// 定义响应式数据
|
|
42
|
+
const arrKeys = defineModel({ required: true });
|
|
43
|
+
|
|
44
|
+
const change = async (val, key) => {
|
|
45
|
+
if (val) {
|
|
46
|
+
arrKeys.value[key].showCol = true;
|
|
47
|
+
} else {
|
|
48
|
+
arrKeys.value[key].showCol = false;
|
|
49
|
+
}
|
|
50
|
+
saveTableInfo(arrKeys.value.table.user, props.name, key, { showCol: val }).then((res) => {
|
|
51
|
+
console.log(res);
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 拖拽列
|
|
56
|
+
const rowDrop = () => {
|
|
57
|
+
const c = document.getElementById("cols");
|
|
58
|
+
if (c) {
|
|
59
|
+
let arr = Sortable.create(c, {
|
|
60
|
+
animation: 150,
|
|
61
|
+
filter: '.filtered', //
|
|
62
|
+
sort: true,
|
|
63
|
+
onEnd: () => {
|
|
64
|
+
let indexArr = arr.toArray();
|
|
65
|
+
indexArr.forEach((element, index) => {
|
|
66
|
+
arrKeys.value[element].sort = index;
|
|
67
|
+
let w = arrKeys.value[element].width || "auto";
|
|
68
|
+
saveTableInfo(arrKeys.value.table.user, props.name, element, { sort: index, width: w }).then((res) => {
|
|
69
|
+
console.log(res);
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
// 全选列
|
|
79
|
+
const selectAll = async () => {
|
|
80
|
+
try {
|
|
81
|
+
for (const element of cols.value) {
|
|
82
|
+
element.showCol = true;
|
|
83
|
+
arrKeys.value[element.value].showCol = true;
|
|
84
|
+
const res = await saveTableInfo(arrKeys.value.table.user, props.name, element.value, {
|
|
85
|
+
showCol: true, width: element.width, sort: element.sort
|
|
86
|
+
});
|
|
87
|
+
console.log(res);
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error('全选列保存信息时出错:', error);
|
|
91
|
+
ElMessage({
|
|
92
|
+
type: 'error',
|
|
93
|
+
message: '全选列保存信息失败!',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// 清除列
|
|
99
|
+
const clearAll = async () => {
|
|
100
|
+
try {
|
|
101
|
+
const filteredCols = cols.value.filter(a => !a.alwaysShow);
|
|
102
|
+
for (const element of filteredCols) {
|
|
103
|
+
element.showCol = false;
|
|
104
|
+
arrKeys.value[element.value].showCol = false;
|
|
105
|
+
const res = await saveTableInfo(arrKeys.value.table.user, props.name, element.value, {
|
|
106
|
+
showCol: false, width: element.width, sort: element.sort
|
|
107
|
+
});
|
|
108
|
+
console.log(res);
|
|
109
|
+
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error('清除列保存信息时出错:', error);
|
|
112
|
+
ElMessage({
|
|
113
|
+
type: 'error',
|
|
114
|
+
message: '清除列保存信息失败!',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
// 复位
|
|
119
|
+
const rowReset = () => {
|
|
120
|
+
ElMessageBox.confirm('确定要复位吗?', '提示', {
|
|
121
|
+
confirmButtonText: '确定',
|
|
122
|
+
cancelButtonText: '取消',
|
|
123
|
+
type: 'warning',
|
|
124
|
+
}).then(() => {
|
|
125
|
+
deleteTableInfo(arrKeys.value.table.user, props.name).then((res) => {
|
|
126
|
+
console.log(res);
|
|
127
|
+
window.location.reload();
|
|
128
|
+
}).catch(() => {
|
|
129
|
+
ElMessage({
|
|
130
|
+
type: 'info',
|
|
131
|
+
message: '复位失败!',
|
|
132
|
+
});
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
};
|
|
136
|
+
onMounted(async () => {
|
|
137
|
+
cols.value = Object.entries(arrKeys.value)
|
|
138
|
+
.filter(([key, value]) => value.visible !== false)
|
|
139
|
+
.filter(([key, value]) => value.type != "hidden").map(([key, value]) => {
|
|
140
|
+
return {
|
|
141
|
+
label: value.label,
|
|
142
|
+
value: key,
|
|
143
|
+
alwaysShow: value.alwaysShow,
|
|
144
|
+
showCol: value.showCol === false ? false : true,
|
|
145
|
+
sort: value.sort || 0,
|
|
146
|
+
width: value.width || "auto",
|
|
147
|
+
};
|
|
148
|
+
}).sort((a, b) => a.sort - b.sort);
|
|
149
|
+
rowDrop();
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
});
|
|
154
|
+
</script>
|
|
155
|
+
|
|
156
|
+
<style scoped>
|
|
157
|
+
.check-box-hover:hover {
|
|
158
|
+
background: #f5f1f1;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.allcheck a {
|
|
162
|
+
cursor: pointer;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.filtered {
|
|
166
|
+
pointer-events: none;
|
|
167
|
+
}
|
|
168
|
+
</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// db.js
|
|
2
|
+
import {Dexie} from 'dexie';
|
|
3
|
+
|
|
4
|
+
const db = new Dexie('gyc');
|
|
5
|
+
//删除数据库
|
|
6
|
+
//db.delete();
|
|
7
|
+
db.version(1).stores({
|
|
8
|
+
tableInfo: '++id,user,page,key,showCol,width,sort',
|
|
9
|
+
tableList: "++id,name"
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export async function saveTableInfo(user, page, key, options = {}) {
|
|
13
|
+
let count = await db.tableInfo.where({ user, page, key }).count();
|
|
14
|
+
if (count > 0) {
|
|
15
|
+
let m = await db.tableInfo.where({ user, page, key }).first();
|
|
16
|
+
await db.tableInfo.put({ ...m, ...options });
|
|
17
|
+
return 'update success'
|
|
18
|
+
} else {
|
|
19
|
+
let d = { showCol: true, width: 'auto', sort: 0, ...options }
|
|
20
|
+
await db.tableInfo.add({ user, page, key, ...d });
|
|
21
|
+
return 'add success'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function getTableInfo(user, page) {
|
|
26
|
+
return await db.tableInfo.where({ user, page }).toArray();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function deleteTableInfo(user, page) {
|
|
30
|
+
db.tableInfo.where({ user, page }).delete((deleteCount) => {
|
|
31
|
+
console.log("删除了" + deleteCount + "条数据");
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function existsTableName(page) {
|
|
36
|
+
let count = await db.tableInfo.where({ page }).count();
|
|
37
|
+
return count > 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div style="display: flex; width: 100%;" class="g-ctrl-container">
|
|
3
|
+
<!--radio-->
|
|
4
|
+
<el-radio-group v-model="ctrlValue" v-bind="itemInfo" v-if="ctrlType == 'radio'">
|
|
5
|
+
<slot :name="`${props.t}-${ctrlKey}`" :data="itemInfo">
|
|
6
|
+
<el-radio v-bind="option" v-for="option in model[ctrlKey].options">
|
|
7
|
+
<slot :name="`${props.t}-${ctrlKey}-options`" :option></slot>
|
|
8
|
+
</el-radio>
|
|
9
|
+
</slot>
|
|
10
|
+
</el-radio-group>
|
|
11
|
+
<!--radio-button-->
|
|
12
|
+
<el-radio-group v-model="ctrlValue" v-bind="itemInfo" v-else-if="ctrlType == 'radio-button'">
|
|
13
|
+
<slot :name="`${props.t}-${ctrlKey}`" :data="itemInfo">
|
|
14
|
+
<el-radio-button v-bind="option" v-for="option in model[ctrlKey].options">
|
|
15
|
+
<slot :name="`${props.t}-${ctrlKey}-options`" :option></slot>
|
|
16
|
+
</el-radio-button>
|
|
17
|
+
</slot>
|
|
18
|
+
</el-radio-group>
|
|
19
|
+
<!--checkbox-->
|
|
20
|
+
<el-checkbox v-model="ctrlValue" v-bind="itemInfo" v-else-if="ctrlType == 'checkbox'">
|
|
21
|
+
<slot :name="`${props.t}-${ctrlKey}`" :data="itemInfo">{{ " " }}</slot>
|
|
22
|
+
</el-checkbox>
|
|
23
|
+
<!--checkbox-group-->
|
|
24
|
+
<el-checkbox-group v-model="ctrlValue" v-bind="itemInfo" v-else-if="ctrlType == 'checkbox-group'">
|
|
25
|
+
<slot :name="`${props.t}-${ctrlKey}`" :data="itemInfo">
|
|
26
|
+
<el-checkbox v-bind="option" v-for="option in model[ctrlKey].options">
|
|
27
|
+
<slot :name="`${props.t}-${ctrlKey}-options`" :option>{{ option.label }}</slot>
|
|
28
|
+
</el-checkbox>
|
|
29
|
+
</slot>
|
|
30
|
+
</el-checkbox-group>
|
|
31
|
+
<!--checkbox-group-button-->
|
|
32
|
+
<el-checkbox-group v-model="ctrlValue" v-bind="itemInfo" v-else-if="ctrlType == 'checkbox-group-button'">
|
|
33
|
+
<slot :name="`${props.t}-${ctrlKey}`" :data="itemInfo">
|
|
34
|
+
<el-checkbox-button v-bind="option" v-for="option in model[ctrlKey].options">
|
|
35
|
+
<slot :name="`${props.t}-${ctrlKey}-options`" :option></slot>
|
|
36
|
+
</el-checkbox-button>
|
|
37
|
+
</slot>
|
|
38
|
+
</el-checkbox-group>
|
|
39
|
+
<!--select-->
|
|
40
|
+
<el-select v-model="ctrlValue" :placeholder="model[ctrlKey].label" v-bind="selectModel"
|
|
41
|
+
v-else-if="ctrlType === 'select'">
|
|
42
|
+
<template #default>
|
|
43
|
+
<slot :name="`${props.t}-${ctrlKey}`" :options="model[ctrlKey].options">
|
|
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"
|
|
56
|
+
@click.native="selectModel.change && selectModel.change(option)">
|
|
57
|
+
<slot :name="`${props.t}-${ctrlKey}-options`" :option></slot>
|
|
58
|
+
</el-option>
|
|
59
|
+
</template>
|
|
60
|
+
</slot>
|
|
61
|
+
</template>
|
|
62
|
+
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
63
|
+
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
64
|
+
</template>
|
|
65
|
+
</el-select>
|
|
66
|
+
<!--tree-select-->
|
|
67
|
+
<el-tree-select v-model="ctrlValue" :placeholder="model[ctrlKey].label" v-bind="itemInfo" :data="treeSelectData"
|
|
68
|
+
v-else-if="ctrlType == 'tree-select'">
|
|
69
|
+
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
70
|
+
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
71
|
+
</template>
|
|
72
|
+
</el-tree-select>
|
|
73
|
+
<!--time-->
|
|
74
|
+
<el-time-picker v-model="ctrlValue" arrow-control v-bind="itemInfo" :placeholder="model[ctrlKey].label"
|
|
75
|
+
v-else-if="ctrlType == 'time'" />
|
|
76
|
+
<!--time-select-->
|
|
77
|
+
<el-time-select v-model="ctrlValue" start="06:30" step="00:15" end="23:30" :placeholder="model[ctrlKey].label"
|
|
78
|
+
v-bind="itemInfo" v-else-if="ctrlType == 'time-select'" />
|
|
79
|
+
<!--date-->
|
|
80
|
+
<el-date-picker v-model="ctrlValue" type="date" :placeholder="model[ctrlKey].label" v-bind="itemInfo"
|
|
81
|
+
v-else-if="ctrlType == 'date'">
|
|
82
|
+
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
83
|
+
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
84
|
+
</template>
|
|
85
|
+
</el-date-picker>
|
|
86
|
+
<!--datetime-->
|
|
87
|
+
<el-date-picker v-model="ctrlValue" type="datetime" :placeholder="model[ctrlKey].label" v-bind="itemInfo"
|
|
88
|
+
v-else-if="ctrlType == 'datetime'">
|
|
89
|
+
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
90
|
+
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
91
|
+
</template>
|
|
92
|
+
</el-date-picker>
|
|
93
|
+
<!--color-->
|
|
94
|
+
<el-color-picker v-model="ctrlValue" v-bind="itemInfo" v-else-if="ctrlType == 'color'" />
|
|
95
|
+
<!--rate-->
|
|
96
|
+
<el-rate v-model="ctrlValue" v-bind="itemInfo" v-else-if="ctrlType == 'rate'" />
|
|
97
|
+
<!--slider-->
|
|
98
|
+
<el-slider v-model="ctrlValue" v-bind="itemInfo" v-else-if="ctrlType == 'slider'" />
|
|
99
|
+
<!--switch-->
|
|
100
|
+
<el-switch v-model="ctrlValue" v-bind="itemInfo" v-else-if="ctrlType == 'switch'">
|
|
101
|
+
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
102
|
+
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
103
|
+
</template>
|
|
104
|
+
</el-switch>
|
|
105
|
+
<!--transfer-->
|
|
106
|
+
<el-transfer v-model="ctrlValue" v-bind="itemInfo" v-else-if="ctrlType == 'transfer'">
|
|
107
|
+
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
108
|
+
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
109
|
+
</template>
|
|
110
|
+
</el-transfer>
|
|
111
|
+
<!--cascader-->
|
|
112
|
+
<el-cascader v-model="ctrlValue" v-bind="itemInfo" :options="model[ctrlKey].options"
|
|
113
|
+
v-else-if="ctrlType == 'cascader'">
|
|
114
|
+
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
115
|
+
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
116
|
+
</template>
|
|
117
|
+
</el-cascader>
|
|
118
|
+
<!--upload-->
|
|
119
|
+
<el-upload v-model="ctrlValue" v-bind="itemInfo" v-else-if="ctrlType == 'upload'">
|
|
120
|
+
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
121
|
+
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
122
|
+
</template>
|
|
123
|
+
</el-upload>
|
|
124
|
+
<!--autocomplete-->
|
|
125
|
+
<el-autocomplete v-model="ctrlValue" v-bind="itemInfo" :placeholder="model[ctrlKey].label"
|
|
126
|
+
v-else-if="ctrlType == 'autocomplete'">
|
|
127
|
+
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
128
|
+
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
129
|
+
</template>
|
|
130
|
+
</el-autocomplete>
|
|
131
|
+
<!--input-number-->
|
|
132
|
+
<el-input-number v-model="ctrlValue" :min="0" :max="100000000" :placeholder="model[ctrlKey].label"
|
|
133
|
+
v-bind="itemInfo" v-else-if="ctrlType == 'input-number'">
|
|
134
|
+
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
135
|
+
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
136
|
+
</template>
|
|
137
|
+
</el-input-number>
|
|
138
|
+
<!--input-->
|
|
139
|
+
<el-input v-model="ctrlValue" :placeholder="model[ctrlKey].label" :maxlength="itemInfo?.max || 25"
|
|
140
|
+
:clearable="true" v-bind="{ ...itemInfo, type: ctrlType }" v-else>
|
|
141
|
+
<template v-for="(slot, index) in slots()" :key="index" #[slot]="data">
|
|
142
|
+
<slot :name="`${props.t}-${ctrlKey}-${slot}`" :data> </slot>
|
|
143
|
+
</template>
|
|
144
|
+
</el-input>
|
|
145
|
+
</div>
|
|
146
|
+
</template>
|
|
147
|
+
|
|
148
|
+
<script setup>
|
|
149
|
+
defineOptions({ inheritAttrs: false });
|
|
150
|
+
import { onMounted, useSlots, ref } from "vue";
|
|
151
|
+
const ctrlValue = defineModel({ required: true });
|
|
152
|
+
const props = defineProps(["t", "ctrlKey", "item", "model", 'ctrlType'])
|
|
153
|
+
const itemInfo = props.item;
|
|
154
|
+
const ctrlKey = props.ctrlKey;
|
|
155
|
+
const ctrlType = props.ctrlType;
|
|
156
|
+
const model = props.model;
|
|
157
|
+
const treeSelectData = ref([]);
|
|
158
|
+
const slots = () => Object.keys(useSlots()).filter(a => a.startsWith(`${props.t}-${ctrlKey}-`)).map(a => a.replace(`${props.t}-${ctrlKey}-`, ''));
|
|
159
|
+
|
|
160
|
+
//select 默认属性
|
|
161
|
+
const selectModel = {
|
|
162
|
+
filterable: true,
|
|
163
|
+
remote: itemInfo && itemInfo["remote-method"] ? true : false,
|
|
164
|
+
...itemInfo
|
|
165
|
+
};
|
|
166
|
+
const selectRemoteMethod = (query) => {
|
|
167
|
+
itemInfo["remote-method"](query, (a) => {
|
|
168
|
+
model[ctrlKey].options = a;
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
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 () => {
|
|
188
|
+
if (itemInfo && itemInfo["remote-method"]) {
|
|
189
|
+
selectModel['remote-method'] = selectRemoteMethod;
|
|
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
|
+
|
|
230
|
+
})
|
|
231
|
+
</script>
|