jobdone-shared-files 1.1.11 → 1.1.12
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/tagEditor.vue +156 -116
package/package.json
CHANGED
package/tagEditor.vue
CHANGED
|
@@ -13,135 +13,156 @@
|
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
15
15
|
</template>
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
<template v-if="!disabled && !isMaxTagCountReached">
|
|
17
|
+
<input class="new-tag-input" list="datalistOptions" type="text" :placeholder="placeholder"
|
|
18
|
+
:maxlength="singleTagMaxLength || 50" v-model.trim="newTag" @keydown.enter="addTag($event)"
|
|
19
|
+
@keyup="keyupFunction">
|
|
20
|
+
<datalist id="datalistOptions" v-if="autoCompleteShow">
|
|
21
|
+
<option :value="opt" v-for="(opt, idx) in autoCompleteOption" :key="idx">{{ opt }}</option>
|
|
22
|
+
</datalist>
|
|
23
|
+
</template>
|
|
21
24
|
</div>
|
|
22
25
|
</div>
|
|
23
26
|
<div class="helper-text-box" v-if="!disabled">
|
|
24
|
-
<small class="helper-text"
|
|
27
|
+
<small class="helper-text">在輸入框中輸入文字後,按下鍵盤的「Enter鍵」即可增加標籤。標籤僅接受中文、英文、數字、下底線、<span class="text-danger">長度限制
|
|
28
|
+
{{ singleTagMaxLength }} 個字元</span>。
|
|
29
|
+
<template v-if="maxTagCount > 0">
|
|
30
|
+
<span class="text-danger">最多新增 {{ maxTagCount }} 個標籤</span>,
|
|
31
|
+
</template>標籤不可重複。</small>
|
|
25
32
|
</div>
|
|
26
33
|
</div>
|
|
27
34
|
</template>
|
|
28
|
-
<script>
|
|
35
|
+
<script setup>
|
|
29
36
|
import { ref, reactive, onMounted, computed } from 'vue'
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
type: Array,
|
|
35
|
-
default: () => []
|
|
36
|
-
},
|
|
37
|
-
placeholder: {
|
|
38
|
-
type: String,
|
|
39
|
-
default: '請在此處輸入標籤文字'
|
|
40
|
-
},
|
|
41
|
-
autoComplete: {
|
|
42
|
-
type: Boolean,
|
|
43
|
-
default: true
|
|
44
|
-
},
|
|
45
|
-
autoCompleteOption: {
|
|
46
|
-
type: Array,
|
|
47
|
-
default: () => []
|
|
48
|
-
},
|
|
49
|
-
disabled: {
|
|
50
|
-
type: Boolean,
|
|
51
|
-
default: false
|
|
52
|
-
}
|
|
37
|
+
const props = defineProps({
|
|
38
|
+
defaultTagList: {
|
|
39
|
+
type: Array,
|
|
40
|
+
default: () => []
|
|
53
41
|
},
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
42
|
+
placeholder: {
|
|
43
|
+
type: String,
|
|
44
|
+
default: '請輸入標籤文字'
|
|
45
|
+
},
|
|
46
|
+
autoComplete: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: true
|
|
49
|
+
},
|
|
50
|
+
autoCompleteOption: {
|
|
51
|
+
type: Array,
|
|
52
|
+
default: () => []
|
|
53
|
+
},
|
|
54
|
+
disabled: {
|
|
55
|
+
type: Boolean,
|
|
56
|
+
default: false
|
|
57
|
+
},
|
|
58
|
+
singleTagMaxLength: {
|
|
59
|
+
type: Number,
|
|
60
|
+
default: 50
|
|
61
|
+
},
|
|
62
|
+
maxTagCount: {
|
|
63
|
+
type: Number,
|
|
64
|
+
default: 0
|
|
65
|
+
}
|
|
66
|
+
})
|
|
76
67
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
function keyupFunction() {
|
|
82
|
-
if (props.autoCompleteOption) {
|
|
83
|
-
updateAutoCompleteOption()
|
|
84
|
-
}
|
|
85
|
-
newTag.value = newTag.value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g, '_')
|
|
86
|
-
}
|
|
68
|
+
// 基本資料
|
|
69
|
+
const tagAry = reactive([])
|
|
70
|
+
const newTag = ref('')
|
|
87
71
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
72
|
+
const autoCompleteShow = computed(() => {
|
|
73
|
+
let show = props.autoComplete
|
|
74
|
+
if (!newTag.value || props.autoCompleteOption.length < 1) {
|
|
75
|
+
show = false
|
|
76
|
+
}
|
|
77
|
+
return show
|
|
78
|
+
})
|
|
92
79
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
// 移除Tag
|
|
105
|
-
function removeTag(index) {
|
|
106
|
-
tagAry.splice(index, 1)
|
|
107
|
-
}
|
|
108
|
-
function reset() {
|
|
109
|
-
tagAry.splice(0, tagAry.length)
|
|
110
|
-
newTag.value = ''
|
|
111
|
-
}
|
|
80
|
+
// 輸入時 AutoComplete
|
|
81
|
+
var autoCompleteTimer
|
|
82
|
+
function updateAutoCompleteOption() {
|
|
83
|
+
clearTimeout(autoCompleteTimer);
|
|
84
|
+
if (newTag.value) {
|
|
85
|
+
autoCompleteTimer = setTimeout(() => {
|
|
86
|
+
emit('update-auto-complete-option', newTag.value);
|
|
87
|
+
}, 500);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
112
90
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
91
|
+
// 刷新預設選中內容
|
|
92
|
+
function getDefaultTag(updateData = []) {
|
|
93
|
+
tagAry.splice(0, tagAry.length, ...updateData)
|
|
94
|
+
}
|
|
95
|
+
function keyupFunction() {
|
|
96
|
+
if (props.autoCompleteOption) {
|
|
97
|
+
updateAutoCompleteOption()
|
|
98
|
+
}
|
|
99
|
+
newTag.value = newTag.value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g, '_')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 重複標籤禁止新增
|
|
103
|
+
var isDuplicate = computed(() => {
|
|
104
|
+
return newTag.value ? !!tagAry.find(tag => tag == newTag.value) : false
|
|
105
|
+
})
|
|
106
|
+
const isMaxTagCountReached = computed(() => {
|
|
107
|
+
return props.maxTagCount > 0 ? tagAry.length >= props.maxTagCount : false
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
// 增加Tag
|
|
111
|
+
function addTag(event) {
|
|
112
|
+
// 檢查是否為中文輸入法組合狀態
|
|
113
|
+
if (event.isComposing || event.keyCode === 229) {
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
if (newTag.value && !isDuplicate.value && !isMaxTagCountReached.value) {
|
|
117
|
+
tagAry.push(newTag.value)
|
|
129
118
|
}
|
|
119
|
+
newTag.value = ''
|
|
130
120
|
}
|
|
121
|
+
// 移除Tag
|
|
122
|
+
function removeTag(index) {
|
|
123
|
+
tagAry.splice(index, 1)
|
|
124
|
+
}
|
|
125
|
+
function reset() {
|
|
126
|
+
tagAry.splice(0, tagAry.length)
|
|
127
|
+
newTag.value = ''
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
onMounted(() => {
|
|
131
|
+
getDefaultTag(props.defaultTagList)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
defineExpose({
|
|
135
|
+
tagAry,
|
|
136
|
+
newTag,
|
|
137
|
+
addTag,
|
|
138
|
+
removeTag,
|
|
139
|
+
updateAutoCompleteOption,
|
|
140
|
+
autoCompleteTimer,
|
|
141
|
+
autoCompleteShow,
|
|
142
|
+
reset,
|
|
143
|
+
keyupFunction,
|
|
144
|
+
isDuplicate,
|
|
145
|
+
getDefaultTag,
|
|
146
|
+
isMaxTagCountReached
|
|
147
|
+
})
|
|
148
|
+
const emit = defineEmits(['update-auto-complete-option'])
|
|
149
|
+
|
|
131
150
|
</script>
|
|
132
151
|
|
|
133
152
|
<style lang="scss" scoped>
|
|
134
153
|
.tag-editor {
|
|
135
|
-
background: var(--bs-gray-100);
|
|
136
|
-
border-radius: var(--bs-border-radius);
|
|
137
|
-
padding: .
|
|
154
|
+
background: var(--bs-gray-100, #f9f9fd);
|
|
155
|
+
border-radius: var(--bs-border-radius-lg, 0.5rem);
|
|
156
|
+
padding: .75rem;
|
|
138
157
|
|
|
139
158
|
.helper-text-box {
|
|
159
|
+
margin-top: .25rem;
|
|
140
160
|
text-align: start;
|
|
141
161
|
|
|
142
162
|
.helper-text {
|
|
143
|
-
|
|
144
|
-
|
|
163
|
+
line-height: 125%;
|
|
164
|
+
font-size: 0.875rem;
|
|
165
|
+
color: var(--bs-gray-500, #A9B3BD);
|
|
145
166
|
}
|
|
146
167
|
}
|
|
147
168
|
|
|
@@ -162,9 +183,9 @@ export default {
|
|
|
162
183
|
position: absolute;
|
|
163
184
|
top: calc(100% + 0.25rem);
|
|
164
185
|
background: #fff;
|
|
165
|
-
border: 1px solid var(--bs-gray-300);
|
|
166
|
-
border-radius: var(--bs-border-radius);
|
|
167
|
-
box-shadow: var(--bs-box-shadow);
|
|
186
|
+
border: 1px solid var(--bs-gray-300, #DBE2E7);
|
|
187
|
+
border-radius: var(--bs-border-radius, 0.375rem);
|
|
188
|
+
box-shadow: var(--bs-box-shadow, 0 0.5rem 1rem rgba(73, 85, 98, 0.15));
|
|
168
189
|
}
|
|
169
190
|
|
|
170
191
|
.opt-item {
|
|
@@ -184,7 +205,8 @@ export default {
|
|
|
184
205
|
display: flex;
|
|
185
206
|
align-items: center;
|
|
186
207
|
flex-wrap: wrap;
|
|
187
|
-
|
|
208
|
+
gap: .25rem;
|
|
209
|
+
padding: .5rem;
|
|
188
210
|
|
|
189
211
|
&.is-disabled:hover {
|
|
190
212
|
cursor: not-allowed;
|
|
@@ -192,22 +214,41 @@ export default {
|
|
|
192
214
|
}
|
|
193
215
|
|
|
194
216
|
.new-tag-input {
|
|
217
|
+
height: 32px;
|
|
195
218
|
all: unset;
|
|
196
219
|
flex-grow: 1;
|
|
197
|
-
|
|
198
|
-
background: var(--bs-gray-100);
|
|
220
|
+
background: var(--bs-gray-100, #f9f9fd);
|
|
199
221
|
padding: .25rem .75rem;
|
|
200
222
|
border-radius: 99px;
|
|
201
223
|
border: 1px solid rgba(#000, 0);
|
|
224
|
+
transition: .2s ease-out;
|
|
225
|
+
border: 1px solid var(--bs-gray-200, #e8edf4);
|
|
226
|
+
outline-width: 3px;
|
|
227
|
+
outline-color: rgba(var(--purple-500-rgb, 100, 122, 241), 0);
|
|
228
|
+
outline-style: solid;
|
|
229
|
+
|
|
230
|
+
&::placeholder {
|
|
231
|
+
color: var(--bs-secondary-color, rgba(103, 120, 137, 0.5));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
&:focus {
|
|
235
|
+
outline-width: 3px;
|
|
236
|
+
outline-color: rgba(var(--purple-500-rgb, 100, 122, 241), .25);
|
|
237
|
+
outline-style: solid;
|
|
238
|
+
}
|
|
202
239
|
}
|
|
203
240
|
|
|
204
241
|
.badge.rounded-pill {
|
|
205
|
-
margin: 0 .25rem .25rem 0;
|
|
206
242
|
display: inline-flex;
|
|
207
243
|
align-items: stretch;
|
|
208
244
|
overflow: hidden;
|
|
245
|
+
height: 32px;
|
|
246
|
+
padding: .5rem .75rem;
|
|
247
|
+
margin: 0;
|
|
209
248
|
|
|
210
249
|
.tag-text {
|
|
250
|
+
font-size: .75rem;
|
|
251
|
+
font-weight: 500;
|
|
211
252
|
margin: auto;
|
|
212
253
|
overflow: hidden;
|
|
213
254
|
text-overflow: ellipsis;
|
|
@@ -221,7 +262,7 @@ export default {
|
|
|
221
262
|
display: block;
|
|
222
263
|
content: ' ';
|
|
223
264
|
height: 100%;
|
|
224
|
-
border-left: 1px solid var(--bs-gray-300);
|
|
265
|
+
border-left: 1px solid var(--bs-gray-300, #DBE2E7);
|
|
225
266
|
margin: 0 0.25rem;
|
|
226
267
|
}
|
|
227
268
|
}
|
|
@@ -235,7 +276,7 @@ export default {
|
|
|
235
276
|
.material-icons {
|
|
236
277
|
font-size: 16px;
|
|
237
278
|
line-height: 16px;
|
|
238
|
-
color: var(--bs-purple);
|
|
279
|
+
color: var(--bs-purple, #647AF1);
|
|
239
280
|
opacity: .5;
|
|
240
281
|
transition: .3s;
|
|
241
282
|
}
|
|
@@ -249,6 +290,5 @@ export default {
|
|
|
249
290
|
}
|
|
250
291
|
}
|
|
251
292
|
}
|
|
252
|
-
|
|
253
293
|
}
|
|
254
294
|
</style>
|