| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- <template>
- <div class="ep-topbar" @click="visible = false">
- <div class="ep-topbar-content">
- <div class="time-btns">
- <div :class="currentTime === 'week' ? 'primary' : 'default'" @click="selectTime('week')">近一周</div>
- <div :class="currentTime === 'month' ? 'primary' : 'default'" @click="selectTime('month')">近一月</div>
- <div :class="currentTime === 'quarter' ? 'primary' : 'default'" @click="selectTime('quarter')">近三月</div>
- <div :class="currentTime === 'year' ? 'primary' : 'default'" @click="selectTime('year')">近一年</div>
- <div :class="currentTime === 'custom' ? 'primary' : 'default'" @click="selectTime('custom')">自定义时间范围</div>
- <div class="custom-style-date-picker-wrap" v-if="currentTime === 'custom'">
- <el-date-picker class="custom-style-date-picker" v-model="dateRange" type="daterange" range-separator="至"
- start-placeholder="开始" end-placeholder="结束" style="width:320px" @change="() => searchHandler()" />
- </div>
- </div>
- <el-popover class="popover" title="" :visible="visible" placement="bottom-start" trigger="click" width="45vw">
- <template #reference>
- <div class="primary" style="border-radius: 6px;" @click.stop="visible = !visible">{{ props.deptType === 'user' ?
- '组织架构/模糊搜索' : '部门选择' }}</div>
- </template>
- <div class="custom-el-style">
- <div>
- <el-autocomplete v-model="personName" :fetch-suggestions="props.deptType === 'user' ? queryUsers : queryDept"
- :placeholder="props.deptType === 'user' ? '搜索员工/团队画像' : '搜索部门'" style="width:320px;" clearable>
- <template #suffix><el-icon>
- <Search />
- </el-icon></template>
- <template #default="{ item }">
- <span>{{ item.nickName || item.deptName }}</span>
- <span v-if="item.deptName && item.nickName" style="font-size:12px;color:#999;margin-left:8px">{{
- item.deptName }}</span>
- </template>
- </el-autocomplete>
- <div class="primary" style="border-radius: 6px;" @click="() => searchHandler()">模糊搜索</div>
- </div>
- <div style="margin-top: 20px;">
- <el-tree :data="departments" :default-expanded-keys="[100]" :props="{ value: 'id', showPrefix: false }"
- accordion @node-click="handleNodeClick" />
- </div>
- </div>
- </el-popover>
- </div>
- </div>
- </template>
- <script setup>
- import { onMounted, onUnmounted } from 'vue'
- import { searchPortraitUsers } from '@/api/score/index'
- import { getDeptList,getDeptUserTree } from '@/api/item/items'
- import { listDept } from '@/api/system/dept'
- const props = defineProps({
- deptType: {
- type: String,
- default: 'user'
- }
- })
- const visible = defineModel('visible', false)
- const emit = defineEmits(['search'])
- const currentTime = ref('year')
- const personName = ref('')
- const departments = ref([])
- const dateRange = ref([])
- const queryUsers = async (query, cb) => {
- if (!query?.trim()) { cb([]); return }
- try {
- const res = await searchPortraitUsers(query.trim())
- cb((res.data || []).map(u => ({ ...u, value: u.nickName })))
- } catch (_) { cb([]) }
- }
- const queryDept = async (query, cb) => {
- if (!query?.trim()) { cb([]); return }
- try {
- const res = await listDept({ deptName: query.trim(), deptType: props.deptType })
- cb((res.data || []).map(d => ({ ...d, value: d.deptName })))
- } catch (_) { cb([]) }
- }
- const filterDeptTree = (data, targetType) => {
- const filterNode = (node) => {
- if (node.deptType === targetType) {
- return { ...node, children: undefined }
- }
- if (node.children && node.children.length > 0) {
- const filteredChildren = node.children.map(child => filterNode(child)).filter(Boolean)
- if (filteredChildren.length > 0) {
- return { ...node, children: filteredChildren }
- }
- }
- return null
- }
- return data.map(node => filterNode(node)).filter(Boolean)
- }
- const getTimeRange = () => {
- if (currentTime.value === 'custom') {
- if (dateRange.value?.length === 2) {
- if(props.deptType === 'user'){
- return { beginTime: formatDate(dateRange.value[0]), endTime: formatDate(dateRange.value[1]) }
- }else{
- return { startDate: formatDate(dateRange.value[0]), endDate: formatDate(dateRange.value[1]) }
- }
-
- }
- return {}
- }
- const end = new Date(), begin = new Date()
- if (currentTime.value === 'week') begin.setDate(end.getDate() - 7)
- else if (currentTime.value === 'month') begin.setMonth(end.getMonth() - 1)
- else if (currentTime.value === 'quarter') begin.setMonth(end.getMonth() - 3)
- else begin.setFullYear(end.getFullYear() - 1)
- if(props.deptType === 'user'){
- return { beginTime: formatDate(begin), endTime: formatDate(end) }
- }else{
- return { startDate: formatDate(begin), endDate: formatDate(end) }
- }
- }
- const formatDate = (d) => {
- const dt = new Date(d)
- return `${dt.getFullYear()}-${String(dt.getMonth() + 1).padStart(2, '0')}-${String(dt.getDate()).padStart(2, '0')}`
- }
- const selectTime = (t) => {
- currentTime.value = t
- if (t !== 'custom') searchHandler()
- }
- const searchHandler = (query = {}) => {
- const queryParams = { ...getTimeRange(), ...query }
- if (props.deptType === 'user') {
- if (queryParams.personName) {
- emit('search', queryParams)
- }
- } else {
- emit('search', queryParams)
- visible.value = false
- }
- }
- const handleNodeClick = (node) => {
- if (props.deptType === 'user') {
- if (node.nodeType === 'user') {
- personName.value = node.label
- searchHandler({ personName: node.label })
- }
- } else {
- if (node.deptType === props.deptType) {
- personName.value = node.deptName || node.name || node.label;
- let obj = {}
-
- if (props.deptType === 'BRIGADE'||props.deptType === 'STATION') {
- obj = { deptId: node.deptId || node.id }
- }
- if (props.deptType === 'MANAGER') {
- obj = { teamId: node.deptId || node.id, deptId: node.deptId || node.id }
- }
- if (props.deptType === 'TEAMS') {
- obj = { groupId: node.deptId || node.id, deptId: node.deptId || node.id }
- }
- searchHandler(obj)
- }
- }
- }
- const setStyle = () => {
- const root = document.querySelector(':root')
- root.style.setProperty('--el-bg-color-overlay', '#1c1936')
- root.style.setProperty('--el-border-color-extra-light', '#5c676d')
- root.style.setProperty('--el-border-color-light', 'transparent')
- root.style.setProperty('--el-popover-padding', '0px')
- root.style.setProperty('--el-text-color-regular', '#fff')
- root.style.setProperty('--el-fill-color-light', '#5c676d')
- }
- const resetStyle = () => {
- const root = document.querySelector(':root')
- root.style.setProperty('--el-bg-color-overlay', '#ffffff')
- root.style.setProperty('--el-border-color-extra-light', '#f2f6fc')
- root.style.setProperty('--el-border-color-light', '#e4e7ed')
- root.style.setProperty('--el-popover-padding', '12px')
- root.style.setProperty('--el-text-color-regular', '#606266')
- root.style.setProperty('--el-fill-color-light', '#f5f7fa')
- }
- onMounted(async () => {
- setStyle()
- if (props.deptType === 'user') {
- const res = await getDeptUserTree()
- departments.value = res.data
- } else {
- const res = await getDeptList({ deptType: props.deptType })
- departments.value = filterDeptTree(res.data, props.deptType)
- }
- })
- onUnmounted(() => {
- resetStyle()
- })
- defineExpose({
- getDefQuery() {
- return {
- ...getTimeRange(),
- }
- }
- })
- </script>
- <style lang="scss" scoped>
- .ep-topbar {
- height: 60px;
- position: relative;
- .ep-topbar-content {
- position: absolute;
- padding: 0 15px;
- inset: 0;
- display: flex;
- align-items: center;
- justify-content: flex-start;
- box-sizing: border-box;
- gap: 12px;
- flex-wrap: wrap;
- z-index: 1000;
- }
- .time-btns {
- display: flex;
- align-items: center;
- gap: 10px;
- flex-wrap: wrap;
- margin-right: 40px;
- &>div {
- padding: 8px 24px;
- border-radius: 28px;
- font-weight: 500;
- }
- }
- .primary {
- background: linear-gradient(125deg, #2AB3E6, #9605FC);
- color: #fff;
- padding: 8px 24px;
- }
- .default {
- background: #1C1936;
- color: #4C4C93;
- position: relative;
- &::before {
- content: '';
- position: absolute;
- inset: -1px;
- border-radius: 29px;
- background: linear-gradient(150deg, #0f46fa 0%, #bd03fb 100%);
- filter: brightness(2) contrast(150%);
- z-index: -1;
- opacity: 0.5;
- }
- }
- .custom-style-date-picker-wrap {
- position: relative;
- border-radius: 19px;
- height: 38px;
- padding: 0 !important;
- --el-text-color-primary: #fff;
- &::before {
- content: '';
- position: absolute;
- inset: -1px;
- border-radius: 19px;
- background: linear-gradient(150deg, #0f46fa 0%, #bd03fb 100%);
- filter: brightness(2) contrast(150%);
- z-index: -1;
- opacity: 0.5;
- }
- }
- }
- </style>
- <style lang="scss">
- .custom-el-style {
- width: 100%;
- padding: 10px;
- position: relative;
- background: #1c1936;
- border-radius: 8px;
- --el-text-color-regular: #fff;
- --el-fill-color-blank: #17122A;
- --el-border-color: linear-gradient(150deg, #0f46fa 0%, #bd03fb 100%);
- --el-border-color-hover: linear-gradient(150deg, #0f46fa 0%, #bd03fb 100%);
- .primary {
- background: linear-gradient(125deg, #2AB3E6, #9605FC);
- color: #fff;
- padding: 6px 20px;
- display: inline-block;
- margin-left: 15px;
- }
- &::before {
- content: '';
- position: absolute;
- inset: -2px;
- border-radius: 10px;
- background: linear-gradient(150deg, #0f46fa 0%, #0f46fa 10%, #020E15, #020E15, #020E15, #bd03fb 90%, #bd03fb 100%);
- filter: brightness(2) contrast(150%);
- z-index: -2;
- opacity: 0.5;
- }
- .el-input__wrapper {}
- .el-tree {
- background-color: #1c1936;
- color: #fff;
- .el-tree-node__content {
- --el-tree-node-hover-bg-color: #5c676d;
- }
- }
- }
- .el-autocomplete-suggestion {
- background: #17122A;
- }
- .custom-style-date-picker {
- background: #1C1936 !important;
- box-shadow: none !important;
- height: 38px !important;
- border-radius: 19px;
- }
- .el-popper {
- --el-popover-padding: 0px;
- }
- </style>
|