|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+<template>
|
|
|
2
|
+ <div class="ep-topbar" @click="visible = false">
|
|
|
3
|
+ <div class="time-btns">
|
|
|
4
|
+ <el-button size="small" :type="currentTime==='week'?'primary':'default'" @click="selectTime('week')">近一周</el-button>
|
|
|
5
|
+ <el-button size="small" :type="currentTime==='month'?'primary':'default'" @click="selectTime('month')">近一月</el-button>
|
|
|
6
|
+ <el-button size="small" :type="currentTime==='quarter'?'primary':'default'" @click="selectTime('quarter')">近三月</el-button>
|
|
|
7
|
+ <el-button size="small" :type="currentTime==='year'?'primary':'default'" @click="selectTime('year')">近一年</el-button>
|
|
|
8
|
+ <el-button size="small" :type="currentTime==='custom'?'primary':'default'" @click="selectTime('custom')">自定义时间范围</el-button>
|
|
|
9
|
+ <el-date-picker
|
|
|
10
|
+ v-if="currentTime==='custom'"
|
|
|
11
|
+ v-model="dateRange"
|
|
|
12
|
+ type="daterange"
|
|
|
13
|
+ range-separator="至"
|
|
|
14
|
+ start-placeholder="开始"
|
|
|
15
|
+ end-placeholder="结束"
|
|
|
16
|
+ size="small"
|
|
|
17
|
+ style="margin-left:8px;width:240px"
|
|
|
18
|
+ @change="() => searchHandler()" />
|
|
|
19
|
+ </div>
|
|
|
20
|
+ <el-popover title="" :visible="visible" placement="bottom-end" trigger="click" width="60vw">
|
|
|
21
|
+ <template #reference>
|
|
|
22
|
+ <el-button type="primary" @click.stop="visible = !visible">组织架构/模糊搜索</el-button>
|
|
|
23
|
+ </template>
|
|
|
24
|
+ <div style="width:100%; padding: 15px;">
|
|
|
25
|
+ <div>
|
|
|
26
|
+ <el-autocomplete
|
|
|
27
|
+ v-model="personName"
|
|
|
28
|
+ :fetch-suggestions="queryUsers"
|
|
|
29
|
+ placeholder="搜索员工/团队画像"
|
|
|
30
|
+ style="width:320px"
|
|
|
31
|
+ clearable>
|
|
|
32
|
+ <template #suffix
|
|
|
33
|
+ ><el-icon><Search /></el-icon
|
|
|
34
|
+ ></template>
|
|
|
35
|
+ <template #default="{ item }">
|
|
|
36
|
+ <span>{{ item.nickName }}</span>
|
|
|
37
|
+ <span v-if="item.deptName" style="font-size:12px;color:#999;margin-left:8px">{{ item.deptName }}</span>
|
|
|
38
|
+ </template>
|
|
|
39
|
+ </el-autocomplete>
|
|
|
40
|
+ <el-button type="primary" style="margin-left: 30px;" @click="() => searchHandler()">模糊搜索</el-button>
|
|
|
41
|
+ </div>
|
|
|
42
|
+ <div style="margin-top: 20px;">
|
|
|
43
|
+ <el-tree :data="departments" :props="{ value: 'id', showPrefix: false }" accordion @node-click="handleNodeClick" />
|
|
|
44
|
+ </div>
|
|
|
45
|
+ </div>
|
|
|
46
|
+ </el-popover>
|
|
|
47
|
+ </div>
|
|
|
48
|
+</template>
|
|
|
49
|
+
|
|
|
50
|
+<script setup>
|
|
|
51
|
+const visible = defineModel('visible', false)
|
|
|
52
|
+const emit = defineEmits(['search'])
|
|
|
53
|
+const currentTime = ref('year')
|
|
|
54
|
+const personName = ref('')
|
|
|
55
|
+
|
|
|
56
|
+const queryUsers = async (query, cb) => {
|
|
|
57
|
+ if (!query?.trim()) { cb([]); return }
|
|
|
58
|
+ try {
|
|
|
59
|
+ const res = await searchPortraitUsers(query.trim())
|
|
|
60
|
+ cb((res.data || []).map(u => ({ ...u, value: u.nickName })))
|
|
|
61
|
+ } catch (_) { cb([]) }
|
|
|
62
|
+}
|
|
|
63
|
+
|
|
|
64
|
+const getTimeRange = () => {
|
|
|
65
|
+ if (currentTime.value === 'custom') {
|
|
|
66
|
+ if (dateRange.value?.length === 2) {
|
|
|
67
|
+ return { beginTime: formatDate(dateRange.value[0]), endTime: formatDate(dateRange.value[1]) }
|
|
|
68
|
+ }
|
|
|
69
|
+ return {}
|
|
|
70
|
+ }
|
|
|
71
|
+ const end = new Date(), begin = new Date()
|
|
|
72
|
+ if (currentTime.value === 'week') begin.setDate(end.getDate()-7)
|
|
|
73
|
+ else if (currentTime.value === 'month') begin.setMonth(end.getMonth()-1)
|
|
|
74
|
+ else if (currentTime.value === 'quarter') begin.setMonth(end.getMonth()-3)
|
|
|
75
|
+ else begin.setFullYear(end.getFullYear()-1)
|
|
|
76
|
+ return { beginTime: formatDate(begin), endTime: formatDate(end) }
|
|
|
77
|
+}
|
|
|
78
|
+
|
|
|
79
|
+const selectTime = (t) => {
|
|
|
80
|
+ currentTime.value = t
|
|
|
81
|
+ if (t !== 'custom') searchHandler()
|
|
|
82
|
+}
|
|
|
83
|
+
|
|
|
84
|
+const searchHandler = (query = {}) => {
|
|
|
85
|
+ emit('search', { ...getTimeRange(), personName: personName.value }, ...query)
|
|
|
86
|
+}
|
|
|
87
|
+
|
|
|
88
|
+const handleNodeClick = (node) => {
|
|
|
89
|
+ if (node.nodeType === 'user') {
|
|
|
90
|
+ searchHandler({ personName: node.label })
|
|
|
91
|
+ }
|
|
|
92
|
+}
|
|
|
93
|
+</script>
|
|
|
94
|
+
|
|
|
95
|
+<style lang="scss" scoped>
|
|
|
96
|
+.ep-topbar {
|
|
|
97
|
+ display: flex;
|
|
|
98
|
+ align-items: center;
|
|
|
99
|
+ justify-content: flex-start;
|
|
|
100
|
+ height: 90px;
|
|
|
101
|
+ padding: 15px;
|
|
|
102
|
+ box-sizing: border-box;
|
|
|
103
|
+ gap: 12px;
|
|
|
104
|
+ flex-wrap: wrap;
|
|
|
105
|
+
|
|
|
106
|
+ .time-btns {
|
|
|
107
|
+ display: flex;
|
|
|
108
|
+ align-items: center;
|
|
|
109
|
+ gap: 6px;
|
|
|
110
|
+ flex-wrap: wrap;
|
|
|
111
|
+ margin-right: 40px;
|
|
|
112
|
+ }
|
|
|
113
|
+}
|
|
|
114
|
+</style>
|