@leevan/jtui 2.0.52 → 2.0.54

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leevan/jtui",
3
- "version": "2.0.52",
3
+ "version": "2.0.54",
4
4
  "scripts": {
5
5
  "serve": "vue-cli-service serve",
6
6
  "build": "vue-cli-service build",
@@ -0,0 +1,196 @@
1
+ <template>
2
+ <div class="edit-input-wrapper">
3
+ <el-input
4
+ v-if="inputType === 'text'"
5
+ v-model="currentValue"
6
+ type="text"
7
+ size="mini"
8
+ ref="inputRef"
9
+ @blur="handleBlur"
10
+ @change="handleChange"
11
+ @keyup.enter="handleBlur"
12
+ />
13
+ <el-input
14
+ v-else-if="inputType === 'password'"
15
+ v-model="currentValue"
16
+ type="password"
17
+ show-password
18
+ size="mini"
19
+ ref="inputRef"
20
+ @blur="handleBlur"
21
+ @change="handleChange"
22
+ @keyup.enter="handleBlur"
23
+ />
24
+ <el-input-number
25
+ v-else-if="inputType === 'number'"
26
+ v-model="currentValue"
27
+ :controls="true"
28
+ size="mini"
29
+ ref="inputRef"
30
+ @blur="handleBlur"
31
+ @change="handleChange"
32
+ />
33
+ <el-input-number
34
+ v-else-if="inputType === 'integer'"
35
+ v-model="currentValue"
36
+ :precision="0"
37
+ :step="1"
38
+ size="mini"
39
+ ref="inputRef"
40
+ @blur="handleBlur"
41
+ @change="handleChange"
42
+ />
43
+ <el-input-number
44
+ v-else-if="inputType === 'float'"
45
+ v-model="currentValue"
46
+ :precision="2"
47
+ :step="0.1"
48
+ size="mini"
49
+ ref="inputRef"
50
+ @blur="handleBlur"
51
+ @change="handleChange"
52
+ />
53
+ <el-date-picker
54
+ v-else-if="inputType === 'date'"
55
+ v-model="currentValue"
56
+ type="date"
57
+ value-format="yyyy-MM-dd"
58
+ size="mini"
59
+ ref="inputRef"
60
+ @change="handleChange"
61
+ />
62
+ <el-date-picker
63
+ v-else-if="inputType === 'datetime'"
64
+ v-model="currentValue"
65
+ type="datetime"
66
+ value-format="yyyy-MM-dd HH:mm:ss"
67
+ size="mini"
68
+ ref="inputRef"
69
+ @change="handleChange"
70
+ />
71
+ <el-date-picker
72
+ v-else-if="inputType === 'week'"
73
+ v-model="currentValue"
74
+ type="week"
75
+ format="yyyy 第 WW 周"
76
+ value-format="yyyy-Www"
77
+ size="mini"
78
+ ref="inputRef"
79
+ @change="handleChange"
80
+ />
81
+ <el-date-picker
82
+ v-else-if="inputType === 'month'"
83
+ v-model="currentValue"
84
+ type="month"
85
+ value-format="yyyy-MM"
86
+ size="mini"
87
+ ref="inputRef"
88
+ @change="handleChange"
89
+ />
90
+ <el-date-picker
91
+ v-else-if="inputType === 'year'"
92
+ v-model="currentValue"
93
+ type="year"
94
+ value-format="yyyy"
95
+ size="mini"
96
+ ref="inputRef"
97
+ @change="handleChange"
98
+ />
99
+ <el-input
100
+ v-else
101
+ v-model="currentValue"
102
+ type="text"
103
+ size="mini"
104
+ ref="inputRef"
105
+ @blur="handleBlur"
106
+ @change="handleChange"
107
+ @keyup.enter="handleBlur"
108
+ />
109
+ </div>
110
+ </template>
111
+
112
+ <script>
113
+ export default {
114
+ name: 'EditInput',
115
+ props: {
116
+ value: [String, Number],
117
+ type: {
118
+ type: String,
119
+ default: 'text'
120
+ }
121
+ },
122
+ data() {
123
+ return {
124
+ currentValue: this.value
125
+ };
126
+ },
127
+ computed: {
128
+ inputType() {
129
+ return this.type || 'text';
130
+ }
131
+ },
132
+ watch: {
133
+ value(newVal) {
134
+ this.currentValue = newVal;
135
+ }
136
+ },
137
+ mounted() {
138
+ this.$nextTick(() => {
139
+ if (this.$refs.inputRef) {
140
+ const input = this.$refs.inputRef.$el ? this.$refs.inputRef.$el.querySelector('input') : this.$refs.inputRef;
141
+ if (input && input.focus) {
142
+ input.focus();
143
+ }
144
+ }
145
+ });
146
+ },
147
+ methods: {
148
+ handleBlur(e) {
149
+ this.doComplete();
150
+ },
151
+ handleChange(val) {
152
+ this.doComplete();
153
+ },
154
+ doComplete() {
155
+ this.$emit('input', this.currentValue);
156
+ this.closeEdit();
157
+ },
158
+ closeEdit() {
159
+ try {
160
+ let vm = this.$parent;
161
+ let count = 0;
162
+ while (vm && count < 30) {
163
+ const componentName = vm.$options && vm.$options.name;
164
+ if (componentName === 'VxeTable' || componentName === 'VxeTable') {
165
+ if (vm.$xegrid) {
166
+ if (typeof vm.$xegrid._clearActived === 'function') {
167
+ vm.$xegrid._clearActived();
168
+ return;
169
+ }
170
+ }
171
+ if (typeof vm._clearActived === 'function') {
172
+ vm._clearActived();
173
+ return;
174
+ }
175
+ }
176
+ vm = vm.$parent;
177
+ count++;
178
+ }
179
+ } catch (e) {
180
+ console.error('closeEdit error', e);
181
+ }
182
+ }
183
+ }
184
+ };
185
+ </script>
186
+
187
+ <style lang="scss">
188
+ .edit-input-wrapper {
189
+ width: 100%;
190
+ ::v-deep .el-input,
191
+ ::v-deep .el-input-number,
192
+ ::v-deep .el-date-editor {
193
+ width: 100%;
194
+ }
195
+ }
196
+ </style>
@@ -0,0 +1,178 @@
1
+ <template>
2
+ <div class="custom-select-wrapper" ref="selectWrapper">
3
+ <div
4
+ class="custom-select-input"
5
+ @click="toggleDropdown"
6
+ ref="inputRef"
7
+ >
8
+ <span class="custom-select-value">
9
+ {{ displayLabel }}
10
+ </span>
11
+ <i class="custom-select-arrow" :class="{'is-open': isOpen}"></i>
12
+ </div>
13
+ <div class="custom-select-dropdown" v-show="isOpen" ref="dropdownRef">
14
+ <ul>
15
+ <li
16
+ v-for="op in options"
17
+ :key="op.value"
18
+ :class="{'is-selected': value === op.value}"
19
+ @mousedown.prevent="selectOption(op)"
20
+ >
21
+ {{ op.label }}
22
+ </li>
23
+ </ul>
24
+ </div>
25
+ </div>
26
+ </template>
27
+
28
+ <script>
29
+ export default {
30
+ name: 'EditSelect',
31
+ props: {
32
+ value: [String, Number],
33
+ options: {
34
+ type: Array,
35
+ default: () => []
36
+ }
37
+ },
38
+ data() {
39
+ return {
40
+ isOpen: true
41
+ };
42
+ },
43
+ computed: {
44
+ displayLabel() {
45
+ const findItem = this.options.find(op => op.value === this.value);
46
+ return findItem ? findItem.label : (this.value || '请选择');
47
+ }
48
+ },
49
+ mounted() {
50
+ document.addEventListener('click', this.handleClickOutside);
51
+ },
52
+ beforeDestroy() {
53
+ document.removeEventListener('click', this.handleClickOutside);
54
+ },
55
+ methods: {
56
+ toggleDropdown() {
57
+ this.isOpen = !this.isOpen;
58
+ },
59
+ selectOption(op) {
60
+ this.$emit('input', op.value);
61
+ this.isOpen = false;
62
+ this.closeEdit();
63
+ },
64
+ handleClickOutside(e) {
65
+ if (this.$refs.selectWrapper && !this.$refs.selectWrapper.contains(e.target)) {
66
+ this.isOpen = false;
67
+ this.closeEdit();
68
+ }
69
+ },
70
+ closeEdit() {
71
+ // 向上查找vxe-table实例
72
+ let parent = this.$parent;
73
+ while (parent) {
74
+ if (parent.$vxe && parent.$vxe.table) {
75
+ parent.$vxe.table.clearEdit();
76
+ break;
77
+ }
78
+ parent = parent.$parent;
79
+ }
80
+ }
81
+ }
82
+ };
83
+ </script>
84
+
85
+ <style lang="scss">
86
+ .custom-select-wrapper {
87
+ position: relative;
88
+ width: 100%;
89
+ }
90
+
91
+ .custom-select-input {
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: space-between;
95
+ box-sizing: border-box;
96
+ width: 100%;
97
+ height: 30px;
98
+ padding: 0 5px;
99
+ font-size: 14px;
100
+ color: #606266;
101
+ background-color: #fff;
102
+ border: 1px solid #dcdfe6;
103
+ border-radius: 4px;
104
+ cursor: pointer;
105
+ transition: border-color 0.2s;
106
+
107
+ &:hover {
108
+ border-color: #c0c4cc;
109
+ }
110
+ }
111
+
112
+ .custom-select-value {
113
+ flex: 1;
114
+ overflow: hidden;
115
+ text-overflow: ellipsis;
116
+ white-space: nowrap;
117
+ }
118
+
119
+ .custom-select-arrow {
120
+ position: relative;
121
+ width: 0;
122
+ height: 0;
123
+ margin-left: 3px;
124
+ border-left: 5px solid transparent;
125
+ border-right: 5px solid transparent;
126
+ border-top: 6px solid #c0c4cc;
127
+ transition: transform 0.3s;
128
+
129
+ &.is-open {
130
+ transform: rotate(180deg);
131
+ }
132
+ }
133
+
134
+ .custom-select-dropdown {
135
+ position: absolute;
136
+ top: 100%;
137
+ left: 0;
138
+ z-index: 9999;
139
+ min-width: fit-content;
140
+ width: auto;
141
+ margin-top: 4px;
142
+ padding: 6px 0;
143
+ background-color: #fff;
144
+ border: 1px solid #e4e7ed;
145
+ border-radius: 4px;
146
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
147
+ max-height: 274px;
148
+ overflow-y: auto;
149
+
150
+ ul {
151
+ margin: 0;
152
+ padding: 0;
153
+ list-style: none;
154
+ }
155
+
156
+ li {
157
+ padding: 0 20px;
158
+ height: 34px;
159
+ line-height: 34px;
160
+ font-size: 14px;
161
+ color: #606266;
162
+ cursor: pointer;
163
+ white-space: nowrap;
164
+ overflow: hidden;
165
+ text-overflow: ellipsis;
166
+
167
+ &:hover {
168
+ background-color: #f5f7fa;
169
+ }
170
+
171
+ &.is-selected {
172
+ color: #409eff;
173
+ font-weight: 700;
174
+ background-color: #f5f7fa;
175
+ }
176
+ }
177
+ }
178
+ </style>
@@ -32,8 +32,8 @@
32
32
  :formatter="formatEnum"
33
33
  :cell-render="cellRenderData(subSubItem.cellRender)"
34
34
  >
35
- <template v-slot:edit="{ row }" v-if="item && item.edit && item.edit.name == '$select'">
36
- <div class="custom-select-wrapper" ref="selectWrapper">
35
+ <template v-slot:edit="{ row }">
36
+ <div v-if="item && item.edit && item.edit.name == '$select'" class="custom-select-wrapper" ref="selectWrapper">
37
37
  <div
38
38
  class="custom-select-input"
39
39
  @click="toggleDropdown"
@@ -57,6 +57,12 @@
57
57
  </ul>
58
58
  </div>
59
59
  </div>
60
+ <EditInput
61
+ v-else-if="item && item.edit && item.edit.name == '$input'"
62
+ :value="row[subSubItem.prop]"
63
+ @input="(val) => handleInputChange(val, row, subSubItem.prop)"
64
+ :type="(item.edit.props && item.edit.props.type) || 'text'"
65
+ />
60
66
  </template>
61
67
  </vxe-table-column>
62
68
  </vxe-colgroup>
@@ -78,8 +84,8 @@
78
84
  :formatter="formatEnum"
79
85
  :cell-render="cellRenderData(subItem.cellRender)"
80
86
  >
81
- <template v-slot:edit="{ row }" v-if="item && item.edit && item.edit.name == '$select'">
82
- <div class="custom-select-wrapper" ref="selectWrapper">
87
+ <template v-slot:edit="{ row }">
88
+ <div v-if="item && item.edit && item.edit.name == '$select'" class="custom-select-wrapper" ref="selectWrapper">
83
89
  <div
84
90
  class="custom-select-input"
85
91
  @click="toggleDropdown"
@@ -103,6 +109,12 @@
103
109
  </ul>
104
110
  </div>
105
111
  </div>
112
+ <EditInput
113
+ v-else-if="item && item.edit && item.edit.name == '$input'"
114
+ :value="row[subItem.prop]"
115
+ @input="(val) => handleInputChange(val, row, subItem.prop)"
116
+ :type="(item.edit.props && item.edit.props.type) || 'text'"
117
+ />
106
118
  </template>
107
119
  </vxe-table-column>
108
120
  </template>
@@ -125,8 +137,8 @@
125
137
  :formatter="formatEnum"
126
138
  :cell-render="cellRenderData(item.cellRender)"
127
139
  >
128
- <template v-slot:edit="{ row }" v-if="item && item.edit && item.edit.name == '$select'">
129
- <div class="custom-select-wrapper" ref="selectWrapper">
140
+ <template v-slot:edit="{ row }">
141
+ <div v-if="item && item.edit && item.edit.name == '$select'" class="custom-select-wrapper" ref="selectWrapper">
130
142
  <div
131
143
  class="custom-select-input"
132
144
  @click="toggleDropdown"
@@ -150,18 +162,30 @@
150
162
  </ul>
151
163
  </div>
152
164
  </div>
165
+ <EditInput
166
+ v-else-if="item && item.edit && item.edit.name == '$input'"
167
+ :value="row[item.prop]"
168
+ @input="(val) => handleInputChange(val, row, item.prop)"
169
+ :type="(item.edit.props && item.edit.props.type) || 'text'"
170
+ />
153
171
  </template>
154
172
  </vxe-table-column>
155
173
  </template>
156
174
 
157
175
 
158
176
  <script>
177
+ import EditInput from './edit-components/EditInput.vue';
178
+
159
179
  export default {
160
180
  name: "tableColumn",
181
+ components: {
182
+ EditInput
183
+ },
161
184
 
162
185
  data() {
163
186
  return {
164
- isOpen: false
187
+ isOpen: false,
188
+ vxeTableInstance: null
165
189
  };
166
190
  },
167
191
  mounted() {
@@ -171,6 +195,8 @@ export default {
171
195
  this.$nextTick(() => {
172
196
  this.isOpen = true;
173
197
  });
198
+ // 查找并保存vxe-table实例
199
+ this.findVxeTable();
174
200
  },
175
201
  beforeDestroy() {
176
202
  document.removeEventListener('click', this.handleClickOutside);
@@ -202,17 +228,83 @@ export default {
202
228
  },
203
229
 
204
230
  methods: {
231
+ findVxeTable() {
232
+ // 向上查找vxe-table实例
233
+ let parent = this.$parent;
234
+ let count = 0;
235
+ while (parent && count < 30) {
236
+ const componentName = parent.$options && parent.$options.name;
237
+ if (componentName === 'VxeTable' || componentName === 'VxeTable') {
238
+ if (parent.clearEdit && typeof parent.clearEdit === 'function') {
239
+ this.vxeTableInstance = parent;
240
+ return;
241
+ }
242
+ if (parent.$vxe && parent.$vxe.table) {
243
+ this.vxeTableInstance = parent.$vxe.table;
244
+ return;
245
+ }
246
+ if (parent.xetable) {
247
+ this.vxeTableInstance = parent.xetable;
248
+ return;
249
+ }
250
+ }
251
+ if (parent.clearEdit && typeof parent.clearEdit === 'function') {
252
+ this.vxeTableInstance = parent;
253
+ return;
254
+ }
255
+ parent = parent.$parent;
256
+ count++;
257
+ }
258
+ },
205
259
  getLabel(value) {
206
260
  if (!this.item || !this.item.edit || !this.item.edit.options) return value;
207
261
  const findItem = this.item.edit.options.find(op => op.value === value);
208
262
  return findItem ? findItem.label : (value || '请选择');
209
263
  },
264
+ handleInputChange(val, row, prop) {
265
+ if (!(prop in row)) {
266
+ this.$set(row, prop, val);
267
+ } else {
268
+ row[prop] = val;
269
+ }
270
+ },
210
271
  toggleDropdown() {
211
272
  this.isOpen = !this.isOpen;
212
273
  },
213
274
  selectOption(op, row) {
214
275
  row[this.item.prop] = op.value;
215
276
  this.isOpen = false;
277
+ this.closeEdit();
278
+ },
279
+ closeEdit() {
280
+ try {
281
+ let vm = this.$parent;
282
+ let count = 0;
283
+ while (vm && count < 30) {
284
+ const componentName = vm.$options && vm.$options.name;
285
+
286
+ if (componentName === 'VxeTable' || componentName === 'VxeTable') {
287
+ if (vm.$xegrid) {
288
+ if (typeof vm.$xegrid._clearActived === 'function') {
289
+ vm.$xegrid._clearActived();
290
+ return;
291
+ }
292
+ if (typeof vm.$xegrid.clearEdit === 'function') {
293
+ vm.$xegrid.clearEdit();
294
+ return;
295
+ }
296
+ }
297
+ if (typeof vm._clearActived === 'function') {
298
+ vm._clearActived();
299
+ return;
300
+ }
301
+ }
302
+ vm = vm.$parent;
303
+ count++;
304
+ }
305
+ } catch (e) {
306
+ console.error('closeEdit error', e);
307
+ }
216
308
  },
217
309
  handleClickOutside(e) {
218
310
  if (this.$refs.selectWrapper && !this.$refs.selectWrapper.contains(e.target)) {
@@ -316,4 +408,13 @@ export default {
316
408
  }
317
409
  }
318
410
  }
411
+
412
+ .edit-input-wrapper {
413
+ width: 100%;
414
+ ::v-deep .el-input,
415
+ ::v-deep .el-input-number,
416
+ ::v-deep .el-date-editor {
417
+ width: 100%;
418
+ }
419
+ }
319
420
  </style>