el-crud-page 1.0.0

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.
@@ -0,0 +1,339 @@
1
+ <template>
2
+ <!--
3
+
4
+ queryItems: [
5
+ // input string
6
+ {
7
+ label: "项目名称",
8
+ prop: "name",
9
+ type: "input",
10
+ placeholder: "请输入项目名称",
11
+ },
12
+ // select
13
+ {
14
+ label: "申办单位",
15
+ prop: "sponsorId",
16
+ type: "select",
17
+ placeholder: "请选择申办单位",
18
+ options: [],
19
+ },
20
+ // date日期
21
+ {
22
+ label: "创建日期",
23
+ prop: ["createDateStart", "createDateEnd"],
24
+ type: "date",
25
+ range: true,
26
+ placeholder: "请选择创建日期",
27
+ },
28
+ // datetime 时间
29
+ {
30
+ label: "更新时间",
31
+ prop: "updateTime",
32
+ type: "datetime",
33
+ placeholder: "请选择更新时间",
34
+ },
35
+ ],
36
+
37
+ -->
38
+ <div class="container-main el-crud-query" v-if="queryItems.length">
39
+ <el-form :model="queryParams" :size="size" :style="{ maxHeight: expand ? '' : (formMaxHeight + 'px') }"
40
+ ref="queryForm" :inline="inline" :label-width="labelWidthStr" class="el-crud-query-form" @submit.native.prevent>
41
+ <el-form-item v-for="item in queryFormItems" v-show="expand || !item.hidden" :label="item.label"
42
+ :prop="item.prop" :key="item.prop">
43
+ <el-input v-if="item.type === 'input'" v-model="queryParams[item.prop]" :placeholder="item.placeholder"
44
+ clearable @keyup.enter.native="handleQuery" :style="inputStyle"></el-input>
45
+ <el-select v-else-if="item.type === 'select'" v-model="queryParams[item.prop]"
46
+ :placeholder="item.placeholder" clearable filterable
47
+ @visible-change="($event) => item.visibleChange && item.visibleChange($event, queryParams)"
48
+ :style="inputStyle">
49
+
50
+ <template v-if="typeof item.options === 'function'">
51
+ <el-option v-for="option in item.options()" :key="option.value" :label="option.label" :value="option.value"></el-option>
52
+ </template>
53
+ <template v-else>
54
+ <el-option v-for="option in item.options" :key="option.value" :label="option.label" :value="option.value"></el-option>
55
+ </template>
56
+
57
+ </el-select>
58
+
59
+ <el-date-picker v-else-if="item.type === 'date'" :type="item.range ? 'daterange' : 'date'"
60
+ v-model="queryParams[item.prop]" :placeholder="item.placeholder" clearable
61
+ :start-placeholder="item['startPlaceholder'] || '开始日期'"
62
+ :end-placeholder="item['endPlaceholder'] || '结束日期'" :range-separator="item['rangeSeparator']"
63
+ :value-format="item['valueFormat'] || 'yyyy-MM-dd'"
64
+ :style="item.range ? dateRangeStyle : inputStyle"></el-date-picker>
65
+ <el-date-picker v-else-if="item.type === 'datetime'" :type="item.range ? 'datetimerange' : 'datetime'"
66
+ v-model="queryParams[item.prop]" :placeholder="item.placeholder" clearable
67
+ :start-placeholder="item['startPlaceholder'] || '开始时间'"
68
+ :end-placeholder="item['endPlaceholder'] || '结束时间'" :range-separator="item['rangeSeparator']"
69
+ :value-format="item['valueFormat'] || 'yyyy-MM-dd HH:mm:ss'"
70
+ :style="item.range ? dateRangeStyle : inputStyle"></el-date-picker>
71
+ </el-form-item>
72
+ <el-form-item label=" " ref="queryFormBtn">
73
+ <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
74
+ <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
75
+ <el-button type="text" @click="handelExpand" v-if="needExpand">
76
+ <span>更多</span>
77
+ <i :class="expand ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i>
78
+ </el-button>
79
+ </el-form-item>
80
+ </el-form>
81
+ </div>
82
+
83
+ </template>
84
+
85
+ <script>
86
+
87
+ import { debounce } from './utils'
88
+ export default {
89
+ props: {
90
+
91
+ // queryParams: {
92
+ // type: Object,
93
+ // required: true
94
+ // },
95
+ queryItems: {
96
+ type: Array,
97
+ required: true
98
+ },
99
+ size: {
100
+ type: String,
101
+ default: 'mini'
102
+ },
103
+ labelWidth: {
104
+ type: Number,
105
+ default: 80
106
+ },
107
+ inputWidth: {
108
+ type: Number,
109
+ default: 200
110
+ },
111
+ lineClamp: {
112
+ type: Number,
113
+ default: 1
114
+ },
115
+ inline: {
116
+ type: Boolean,
117
+ default: true
118
+ }
119
+
120
+ },
121
+ watch: {
122
+ queryItems: {
123
+ handler(val) {
124
+ this.reset()
125
+ },
126
+ deep: true,
127
+ immediate: true
128
+ }
129
+ },
130
+ created() {
131
+
132
+ },
133
+ data() {
134
+ return {
135
+ queryParams: {},
136
+ queryFormItems: [],
137
+ formMaxHeight: 0,
138
+ expand: false,
139
+ needExpand: false,
140
+ // 用于展示窗口大小变化绑定
141
+ $_sidebarElm: null,
142
+ $_resizeHandler: null
143
+ }
144
+ },
145
+ computed: {
146
+ labelWidthStr() {
147
+ if (typeof this.labelWidth === 'number') {
148
+ return this.labelWidth + 'px';
149
+ }
150
+ return this.labelWidth + 'px';
151
+ },
152
+ inputStyle() {
153
+ return {
154
+ width: this.inputWidth + 'px'
155
+ };
156
+ },
157
+ dateRangeStyle() {
158
+ return {
159
+ width: (this.inputWidth * 2 + this.labelWidth + 10) + 'px'
160
+ };
161
+ }
162
+ },
163
+ mounted() {
164
+ this.$nextTick(() => {
165
+ this.formMaxHeight = this.measureHeight() * this.lineClamp;
166
+ // this.handleNeedExpand()
167
+ this.redraw();
168
+ this.bindResize();
169
+ setTimeout(() => {
170
+ this.$_resizeHandler && this.$_resizeHandler();
171
+ }, 100);
172
+
173
+ });
174
+
175
+ },
176
+ activated() {
177
+ if (!this.$_resizeHandler) {
178
+ this.bindResize();
179
+ }
180
+ },
181
+ beforeDestroy() {
182
+ this.unbindResize();
183
+ },
184
+ deactivated() {
185
+ this.unbindResize();
186
+ },
187
+ methods: {
188
+ $_sidebarResizeHandler(e) {
189
+ if (e.propertyName === 'width') {
190
+ this.$_resizeHandler()
191
+ }
192
+ },
193
+ // 展示窗口大小变化绑定
194
+ bindResize() {
195
+ this.$_resizeHandler = debounce(() => {
196
+ this.drawTime = 0;
197
+ this.queryFormItems.forEach(item => {
198
+ item.hidden = false;
199
+ });
200
+ this.$nextTick(() => {
201
+ this.handleNeedExpand()
202
+ this.redraw();
203
+ })
204
+
205
+ }, 100)
206
+
207
+ window.addEventListener('resize', this.$_resizeHandler);
208
+ this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
209
+ this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
210
+
211
+
212
+ },
213
+ // unbindResize
214
+ unbindResize() {
215
+ window.removeEventListener('resize', this.$_resizeHandler)
216
+ this.$_resizeHandler = null
217
+ this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
218
+ },
219
+ handelExpand() {
220
+ this.drawTime = 0;
221
+ this.expand = !this.expand;
222
+ this.$_resizeHandler();
223
+
224
+ },
225
+ handleNeedExpand() {
226
+ const $queryForm = this.$refs?.queryForm?.$el;
227
+ let scrollHeight = $queryForm.scrollHeight;
228
+ if ( this.formMaxHeight < scrollHeight) {
229
+ this.needExpand = true;
230
+ } else {
231
+ this.needExpand = false;
232
+ }
233
+
234
+ },
235
+ //
236
+ redraw() {
237
+ if (typeof this.drawTime == 'undefined') {
238
+ this.drawTime = 0;
239
+ }
240
+ if (this.drawTime > 60) {
241
+ return;
242
+ }
243
+ // 确保DOM完全渲染后再执行某些操作
244
+ const $queryForm = this.$refs?.queryForm?.$el;
245
+ if ($queryForm) {
246
+ $queryForm.style.overflow = "hidden";
247
+ }
248
+ this.$nextTick(() => {
249
+ let scrollHeight = $queryForm.scrollHeight;
250
+ let clientHeight = $queryForm.clientHeight;
251
+ if (scrollHeight > clientHeight) {
252
+ this.drawTime++;
253
+ let noHiddenItems = this.queryFormItems.filter(item => !item.hidden);
254
+ let lastItem = noHiddenItems.find((item, index) => (noHiddenItems.length - 1 == index))
255
+ if (lastItem) {
256
+ this.$set(lastItem, 'hidden', true);
257
+ this.redraw();
258
+ }
259
+
260
+ }
261
+ // 判断是否有滚动条
262
+
263
+ });
264
+
265
+
266
+ },
267
+
268
+ //测量单行高度 + margin-top + margin-bottom
269
+ measureHeight() {
270
+ let queryFormBtn = this.$refs.queryFormBtn;
271
+ if(queryFormBtn){
272
+ let queryFormBtnHeight = queryFormBtn.$el.clientHeight || 29;
273
+ let queryFormItemsMarginTop = parseInt(window.getComputedStyle(queryFormBtn.$el).marginTop);
274
+ let queryFormItemsMarginBottom = parseInt(window.getComputedStyle(queryFormBtn.$el).marginBottom);
275
+ return queryFormBtnHeight + queryFormItemsMarginTop + queryFormItemsMarginBottom
276
+ }
277
+
278
+ },
279
+
280
+ reset() {
281
+ this.queryItems.forEach(item => {
282
+ this.$set(this.queryParams, item.prop, null);
283
+ });
284
+ this.queryFormItems = this.queryItems.map(item => {
285
+ let placeholder = item.placeholder;
286
+ if( !placeholder){
287
+
288
+ switch (item.type) {
289
+ case 'input':
290
+ placeholder = '请输入' + item.label;
291
+ break;
292
+ default:
293
+ placeholder = '请选择' + item.label;
294
+ }
295
+
296
+ }
297
+
298
+
299
+ return {
300
+ ...item,
301
+ placeholder,
302
+ hidden: false
303
+ }
304
+ });
305
+ },
306
+ resetQuery() {
307
+
308
+ this.$refs.queryForm?.resetFields();
309
+ this.handleQuery();
310
+ },
311
+ handleQuery() {
312
+ this.$emit('queryTable', this.queryParams);
313
+ }
314
+
315
+ }
316
+ }
317
+
318
+ </script>
319
+
320
+ <style scoped lang="scss">
321
+ .container-main{
322
+ background-color: #fff;
323
+ }
324
+ .el-crud-query{
325
+ overflow: hidden;
326
+ padding: 10px;
327
+ .el-crud-query-form {
328
+ margin-bottom: -10px;
329
+
330
+ &::v-deep {
331
+ .el-form-item--mini.el-form-item, .el-form-item--small.el-form-item{
332
+ margin-bottom: 10px;
333
+ }
334
+ }
335
+ }
336
+ }
337
+
338
+
339
+ </style>
@@ -0,0 +1,172 @@
1
+ <template>
2
+ <div class="top-right-btn" :style="style">
3
+ <div class="flex flex-row items-center">
4
+ <el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top" v-if="search">
5
+ <el-button size="mini" circle icon="el-icon-search" @click="toggleSearch()" />
6
+ </el-tooltip>
7
+ <el-tooltip class="item" effect="dark" content="刷新" placement="top">
8
+ <el-button size="mini" circle icon="el-icon-refresh" @click="refresh()" />
9
+ </el-tooltip>
10
+ <el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="columns">
11
+ <el-button size="mini" circle icon="el-icon-menu" @click="showColumn()" v-if="showColumnsType == 'transfer'"/>
12
+ <el-dropdown trigger="click" :hide-on-click="false" style="padding-left: 12px" v-if="showColumnsType == 'checkbox'">
13
+ <el-button size="mini" circle icon="el-icon-menu" />
14
+ <el-dropdown-menu slot="dropdown">
15
+ <template >
16
+ <el-dropdown-item v-for="item in columns" :key="item.key" v-if="item.type!=`index` && item.type!=`selection` && (typeof item.visible) !== `undefined` ">
17
+ <el-checkbox :checked="item.visible" @change="checkboxChange($event, item)" :label="item.label" />
18
+ </el-dropdown-item>
19
+ </template>
20
+ </el-dropdown-menu>
21
+ </el-dropdown>
22
+ </el-tooltip>
23
+ </div>
24
+ <el-dialog :title="title" :visible.sync="open" append-to-body>
25
+ <el-transfer
26
+ :titles="['显示', '隐藏']"
27
+ v-model="value"
28
+ :data="columns"
29
+ @change="dataChange"
30
+ ></el-transfer>
31
+ </el-dialog>
32
+ </div>
33
+ </template>
34
+ <script>
35
+ export default {
36
+ name: "RightToolbar",
37
+ inject: ["crud"],
38
+ data() {
39
+ return {
40
+ // 显隐数据
41
+ value: [],
42
+ // 弹出层标题
43
+ title: "显示/隐藏",
44
+ // 是否显示弹出层
45
+ open: false,
46
+ // 本地列数据副本(用于拖拽)
47
+ localColumns: [],
48
+ };
49
+ },
50
+ props: {
51
+ /* 是否显示检索条件 */
52
+ showSearch: {
53
+ type: Boolean,
54
+ default: true,
55
+ },
56
+ /* 显隐列信息 */
57
+ columns: {
58
+ type: Array,
59
+ },
60
+ /* 是否显示检索图标 */
61
+ search: {
62
+ type: Boolean,
63
+ default: true,
64
+ },
65
+ /* 显隐列类型(transfer穿梭框、checkbox复选框) */
66
+ showColumnsType: {
67
+ type: String,
68
+ default: "checkbox",
69
+ },
70
+ /* 右外边距 */
71
+ gutter: {
72
+ type: Number,
73
+ default: 10,
74
+ },
75
+ },
76
+ computed: {
77
+ style() {
78
+ const ret = {};
79
+ if (this.gutter) {
80
+ ret.marginRight = `${this.gutter / 2}px`;
81
+ }
82
+ return ret;
83
+ }
84
+ },
85
+ watch: {
86
+ columns: {
87
+ handler(newVal) {
88
+ // 当 columns prop 变化时,更新本地副本
89
+ this.localColumns = newVal ? [...newVal] : [];
90
+ },
91
+ immediate: true,
92
+ deep: true
93
+ }
94
+ },
95
+ created() {
96
+ if (this.showColumnsType == 'transfer') {
97
+ // 显隐列初始默认隐藏列
98
+ for (let item in this.columns) {
99
+ if (this.columns[item].visible === false) {
100
+ this.value.push(parseInt(item));
101
+ }
102
+ }
103
+ }
104
+ },
105
+ methods: {
106
+ // 搜索
107
+ toggleSearch() {
108
+ this.$emit("update:showSearch", !this.showSearch);
109
+ },
110
+ // 刷新
111
+ refresh() {
112
+ this.$emit("queryTable");
113
+ },
114
+ // 右侧列表元素变化
115
+ dataChange(data) {
116
+ for (let item in this.columns) {
117
+ const key = this.columns[item].key;
118
+ this.columns[item].visible = !data.includes(key);
119
+ }
120
+ },
121
+ // 打开显隐列dialog
122
+ showColumn() {
123
+ this.open = true;
124
+ },
125
+ // 勾选
126
+ checkboxChange(event, item) {
127
+ item.visible = event;
128
+ // 通知父组件更新
129
+ this.$emit('update:columns', this.localColumns);
130
+ },
131
+ // 拖拽结束
132
+ onDragEnd(event) {
133
+ // 拖拽结束后,通知父组件列顺序已改变
134
+ this.$emit('update:columns', this.localColumns);
135
+ this.$emit('columns-order-changed', this.localColumns);
136
+ }
137
+ },
138
+ };
139
+ </script>
140
+ <style lang="scss" scoped>
141
+ ::v-deep .el-transfer__button {
142
+ border-radius: 50%;
143
+ padding: 12px;
144
+ display: block;
145
+ margin-left: 0px;
146
+ }
147
+ ::v-deep .el-transfer__button:first-child {
148
+ margin-bottom: 10px;
149
+ }
150
+
151
+ .drag-item {
152
+ padding: 8px;
153
+ cursor: move;
154
+ border-bottom: 1px solid #ebeef5;
155
+ display: flex;
156
+ align-items: center;
157
+
158
+ &:hover {
159
+ background-color: #f5f7fa;
160
+ }
161
+ }
162
+
163
+ .drag-handle {
164
+ color: #909399;
165
+
166
+ &:hover {
167
+ color: #409eff;
168
+ }
169
+ }
170
+
171
+ </style>
172
+
package/src/style.scss ADDED
@@ -0,0 +1,115 @@
1
+ .el-crud {
2
+ // Flex utilities
3
+ .flex { display: flex; }
4
+ .inline-flex { display: inline-flex; }
5
+ .hidden { display: none; }
6
+ .block { display: block; }
7
+ .inline-block { display: inline-block; }
8
+
9
+ // Flex direction
10
+ .flex-row { flex-direction: row; }
11
+ .flex-row-reverse { flex-direction: row-reverse; }
12
+ .flex-col { flex-direction: column; }
13
+ .flex-col-reverse { flex-direction: column-reverse; }
14
+
15
+ // Flex wrap
16
+ .flex-wrap { flex-wrap: wrap; }
17
+ .flex-nowrap { flex-wrap: nowrap; }
18
+ .flex-wrap-reverse { flex-wrap: wrap-reverse; }
19
+
20
+ // Justify content
21
+ .justify-start { justify-content: flex-start; }
22
+ .justify-end { justify-content: flex-end; }
23
+ .justify-center { justify-content: center; }
24
+ .justify-between { justify-content: space-between; }
25
+ .justify-around { justify-content: space-around; }
26
+ .justify-evenly { justify-content: space-evenly; }
27
+
28
+ // Align items
29
+ .items-start { align-items: flex-start; }
30
+ .items-end { align-items: flex-end; }
31
+ .items-center { align-items: center; }
32
+ .items-baseline { align-items: baseline; }
33
+ .items-stretch { align-items: stretch; }
34
+
35
+ // Align content
36
+ .content-start { align-content: flex-start; }
37
+ .content-end { align-content: flex-end; }
38
+ .content-center { align-content: center; }
39
+ .content-between { align-content: space-between; }
40
+ .content-around { align-content: space-around; }
41
+ .content-evenly { align-content: space-evenly; }
42
+
43
+ // Align self
44
+ .self-auto { align-self: auto; }
45
+ .self-start { align-self: flex-start; }
46
+ .self-end { align-self: flex-end; }
47
+ .self-center { align-self: center; }
48
+ .self-stretch { align-self: stretch; }
49
+
50
+ // Flex grow & shrink
51
+ .flex-1 { flex: 1 1 0%; }
52
+ .flex-auto { flex: 1 1 auto; }
53
+ .flex-initial { flex: 0 1 auto; }
54
+ .flex-none { flex: none; }
55
+ .grow { flex-grow: 1; }
56
+ .grow-0 { flex-grow: 0; }
57
+ .shrink { flex-shrink: 1; }
58
+ .shrink-0 { flex-shrink: 0; }
59
+
60
+
61
+ // Width
62
+ .w-full { width: 100%; }
63
+ .w-auto { width: auto; }
64
+
65
+ // Height
66
+ .h-full { height: 100%; }
67
+ .h-auto { height: auto; }
68
+ .h-screen { height: 100vh; }
69
+
70
+ // Margin
71
+ .m-0 { margin: 0; }
72
+ .m-auto { margin: auto; }
73
+ .mx-auto { margin-left: auto; margin-right: auto; }
74
+ .my-auto { margin-top: auto; margin-bottom: auto; }
75
+
76
+
77
+ // Text align
78
+ .text-left { text-align: left; }
79
+ .text-center { text-align: center; }
80
+ .text-right { text-align: right; }
81
+ .text-justify { text-align: justify; }
82
+
83
+ // Font weight
84
+ .font-normal { font-weight: 400; }
85
+ .font-medium { font-weight: 500; }
86
+ .font-semibold { font-weight: 600; }
87
+ .font-bold { font-weight: 700; }
88
+
89
+ // Overflow
90
+ .overflow-hidden { overflow: hidden; }
91
+ .overflow-auto { overflow: auto; }
92
+ .overflow-scroll { overflow: scroll; }
93
+ .overflow-x-auto { overflow-x: auto; }
94
+ .overflow-y-auto { overflow-y: auto; }
95
+
96
+ // Position
97
+ .relative { position: relative; }
98
+ .absolute { position: absolute; }
99
+ .fixed { position: fixed; }
100
+ .sticky { position: sticky; }
101
+
102
+ // Cursor
103
+ .cursor-pointer { cursor: pointer; }
104
+ .cursor-not-allowed { cursor: not-allowed; }
105
+
106
+
107
+
108
+
109
+ &-toolbar{
110
+ margin-top: 10px;
111
+ }
112
+ .crud-table{
113
+ margin-top: 10px;
114
+ }
115
+ }