cd-personselector 1.3.4 → 1.3.6
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/dist/index.js +1 -1
- package/dist/index.mjs +442 -392
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/InputSelect.vue +98 -26
- package/src/PersonSelector.vue +1 -0
package/package.json
CHANGED
package/src/InputSelect.vue
CHANGED
|
@@ -26,34 +26,49 @@
|
|
|
26
26
|
>
|
|
27
27
|
<template #panel>
|
|
28
28
|
<div v-if="currentSearchResults.length > 0" class="cd-input-select__panel">
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
<div
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
<div class="cd-input-select__option-info">
|
|
49
|
-
<div class="cd-input-select__option-name">{{ result.name }}</div>
|
|
50
|
-
<div v-if="result.department || result.position" class="cd-input-select__option-desc">
|
|
51
|
-
{{ result.department }}{{ result.department && result.position ? ' · ' : '' }}{{ result.position }}
|
|
29
|
+
<div class="cd-input-select__grid">
|
|
30
|
+
<t-checkbox
|
|
31
|
+
v-for="result in paginatedSearchResults"
|
|
32
|
+
:key="result.id"
|
|
33
|
+
:value="result.id"
|
|
34
|
+
:checked="isSelected(result.id)"
|
|
35
|
+
class="cd-input-select__option"
|
|
36
|
+
@change="(checked: boolean) => handleCheckboxChange(checked, result)"
|
|
37
|
+
>
|
|
38
|
+
<div class="cd-input-select__option-content">
|
|
39
|
+
<div v-if="result.avatar" class="cd-input-select__option-avatar">
|
|
40
|
+
<img :src="result.avatar" :alt="result.name" />
|
|
41
|
+
</div>
|
|
42
|
+
<div v-else class="cd-input-select__option-avatar cd-input-select__option-avatar--placeholder"
|
|
43
|
+
:style="{
|
|
44
|
+
backgroundColor: getNodeTypeColor(result.nodeType),
|
|
45
|
+
color: '#fff'
|
|
46
|
+
}">
|
|
47
|
+
{{ getNodeTypeIcon(result.nodeType) }}
|
|
52
48
|
</div>
|
|
49
|
+
<div class="cd-input-select__option-info">
|
|
50
|
+
<div class="cd-input-select__option-name">{{ result.name }}</div>
|
|
51
|
+
<div v-if="result.isUser && (result.department || result.post)" class="cd-input-select__option-desc">
|
|
52
|
+
{{ result.department }}{{ result.department && result.post ? ' · ' : '' }}{{ result.post }}
|
|
53
|
+
</div>
|
|
54
|
+
<div v-else-if="result.fnumber" class="cd-input-select__option-desc">
|
|
55
|
+
{{ result.fnumber }}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
<span class="cd-input-select__option-tag" :style="{ backgroundColor: getNodeTypeColor(result.nodeType) + '18', color: getNodeTypeColor(result.nodeType) }">
|
|
59
|
+
{{ getNodeTypeLabel(result.nodeType) }}
|
|
60
|
+
</span>
|
|
53
61
|
</div>
|
|
54
|
-
|
|
62
|
+
</t-checkbox>
|
|
63
|
+
</div>
|
|
64
|
+
<div v-if="searchTotalPages > 1" class="cd-input-select__pager">
|
|
65
|
+
<span class="cd-input-select__pager-info">{{ currentSearchResults.length }} 条结果</span>
|
|
66
|
+
<div class="cd-input-select__pager-btns">
|
|
67
|
+
<t-button size="small" variant="text" :disabled="searchPage <= 1" @click="searchPage--">上一页</t-button>
|
|
68
|
+
<span class="cd-input-select__pager-num">{{ searchPage }}/{{ searchTotalPages }}</span>
|
|
69
|
+
<t-button size="small" variant="text" :disabled="searchPage >= searchTotalPages" @click="searchPage++">下一页</t-button>
|
|
55
70
|
</div>
|
|
56
|
-
</
|
|
71
|
+
</div>
|
|
57
72
|
</div>
|
|
58
73
|
<div v-else-if="searchLoading" class="cd-input-select__loading">
|
|
59
74
|
搜索中...
|
|
@@ -108,6 +123,13 @@ const emit = defineEmits<{
|
|
|
108
123
|
}>();
|
|
109
124
|
const searchLoading = ref(false);
|
|
110
125
|
const currentSearchResults = ref<UserItem[]>([]);
|
|
126
|
+
const searchPage = ref(1);
|
|
127
|
+
const searchPageSize = 10;
|
|
128
|
+
const paginatedSearchResults = computed(() => {
|
|
129
|
+
const start = (searchPage.value - 1) * searchPageSize;
|
|
130
|
+
return currentSearchResults.value.slice(start, start + searchPageSize);
|
|
131
|
+
});
|
|
132
|
+
const searchTotalPages = computed(() => Math.ceil(currentSearchResults.value.length / searchPageSize));
|
|
111
133
|
const showPersonSelector = ref(false);
|
|
112
134
|
const selectedIds = ref<(string | number)[]>([]);
|
|
113
135
|
const selectedOptions = ref<UserItem[]>([]);
|
|
@@ -137,6 +159,19 @@ const isDepartment = (id: string | number): boolean => {
|
|
|
137
159
|
return String(id).startsWith('dept-');
|
|
138
160
|
};
|
|
139
161
|
|
|
162
|
+
// nodeType 辅助函数
|
|
163
|
+
const nodeTypeMap: Record<string, { label: string; color: string; icon: string }> = {
|
|
164
|
+
department: { label: '部门', color: '#0052d9', icon: '部' },
|
|
165
|
+
user: { label: '人员', color: '#1890ff', icon: '人' },
|
|
166
|
+
post: { label: '岗位', color: '#52c41a', icon: '岗' },
|
|
167
|
+
position: { label: '职务', color: '#722ed1', icon: '职' },
|
|
168
|
+
business: { label: '商业', color: '#fa8c16', icon: '商' },
|
|
169
|
+
external: { label: '外部', color: '#eb2f96', icon: '外' },
|
|
170
|
+
};
|
|
171
|
+
const getNodeTypeLabel = (t?: string) => nodeTypeMap[t || '']?.label || '其他';
|
|
172
|
+
const getNodeTypeColor = (t?: string) => nodeTypeMap[t || '']?.color || '#999';
|
|
173
|
+
const getNodeTypeIcon = (t?: string) => nodeTypeMap[t || '']?.icon || '?';
|
|
174
|
+
|
|
140
175
|
// 根据 value (ID) 获取标签主题颜色
|
|
141
176
|
const getTagThemeByValue = (value: string | number): 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info' => {
|
|
142
177
|
const idStr = String(value);
|
|
@@ -277,6 +312,7 @@ watch(inputValue, (keyword) => {
|
|
|
277
312
|
keyword,
|
|
278
313
|
callback: (results: UserItem[]) => {
|
|
279
314
|
currentSearchResults.value = results;
|
|
315
|
+
searchPage.value = 1;
|
|
280
316
|
searchLoading.value = false;
|
|
281
317
|
if (results.length > 0) {
|
|
282
318
|
popupVisible.value = true;
|
|
@@ -313,8 +349,37 @@ watch(inputValue, (keyword) => {
|
|
|
313
349
|
margin: 0 !important;
|
|
314
350
|
}
|
|
315
351
|
&__panel {
|
|
316
|
-
max-height:
|
|
352
|
+
max-height: 400px;
|
|
317
353
|
overflow-y: auto;
|
|
354
|
+
width: 100%;
|
|
355
|
+
box-sizing: border-box;
|
|
356
|
+
padding: 4px;
|
|
357
|
+
}
|
|
358
|
+
&__grid {
|
|
359
|
+
display: grid;
|
|
360
|
+
grid-template-columns: 1fr 1fr;
|
|
361
|
+
gap: 4px;
|
|
362
|
+
}
|
|
363
|
+
&__pager {
|
|
364
|
+
display: flex;
|
|
365
|
+
align-items: center;
|
|
366
|
+
justify-content: space-between;
|
|
367
|
+
padding: 6px 8px;
|
|
368
|
+
border-top: 1px solid #e5e7eb;
|
|
369
|
+
margin-top: 4px;
|
|
370
|
+
&-info {
|
|
371
|
+
font-size: 12px;
|
|
372
|
+
color: #999;
|
|
373
|
+
}
|
|
374
|
+
&-btns {
|
|
375
|
+
display: flex;
|
|
376
|
+
align-items: center;
|
|
377
|
+
gap: 4px;
|
|
378
|
+
}
|
|
379
|
+
&-num {
|
|
380
|
+
font-size: 12px;
|
|
381
|
+
color: #666;
|
|
382
|
+
}
|
|
318
383
|
}
|
|
319
384
|
&__loading,
|
|
320
385
|
&__empty {
|
|
@@ -383,5 +448,12 @@ watch(inputValue, (keyword) => {
|
|
|
383
448
|
color: var(--td-brand-color, #0052d9);
|
|
384
449
|
flex-shrink: 0;
|
|
385
450
|
}
|
|
451
|
+
&-tag {
|
|
452
|
+
font-size: 11px;
|
|
453
|
+
padding: 1px 6px;
|
|
454
|
+
border-radius: 3px;
|
|
455
|
+
flex-shrink: 0;
|
|
456
|
+
white-space: nowrap;
|
|
457
|
+
}
|
|
386
458
|
}
|
|
387
459
|
</style>
|