Add File
This commit is contained in:
243
frontend/src/components/layout/Workspace.vue
Normal file
243
frontend/src/components/layout/Workspace.vue
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
import icon_expand_down_filled from '@/assets/svg/icon_expand-down_filled.svg'
|
||||||
|
import icon_moments_categories_outlined from '@/assets/svg/icon_moments-categories_outlined.svg'
|
||||||
|
import icon_done_outlined from '@/assets/svg/icon_done_outlined.svg'
|
||||||
|
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
|
||||||
|
import { userApi } from '@/api/auth'
|
||||||
|
import { ElMessage } from 'element-plus-secondary'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const { t } = useI18n()
|
||||||
|
defineProps({
|
||||||
|
collapse: { type: [Boolean], required: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const currentWorkspace = ref({
|
||||||
|
id: '',
|
||||||
|
name: '',
|
||||||
|
})
|
||||||
|
const defaultDatasourceList = ref([] as any[])
|
||||||
|
const workspaceKeywords = ref('')
|
||||||
|
const defaultWorkspaceListWithSearch = computed(() => {
|
||||||
|
if (!workspaceKeywords.value) return defaultDatasourceList.value
|
||||||
|
return defaultDatasourceList.value.filter((ele) =>
|
||||||
|
ele.name.toLowerCase().includes(workspaceKeywords.value.toLowerCase())
|
||||||
|
)
|
||||||
|
})
|
||||||
|
const formatKeywords = (item: string) => {
|
||||||
|
if (!workspaceKeywords.value) return item
|
||||||
|
return item.replaceAll(
|
||||||
|
workspaceKeywords.value,
|
||||||
|
`<span class="isSearch">${workspaceKeywords.value}</span>`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits(['selectWorkspace'])
|
||||||
|
|
||||||
|
const handleDefaultWorkspaceChange = (item: any) => {
|
||||||
|
if (item.id.toString() === currentWorkspace.value.id.toString()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
currentWorkspace.value = { id: item.id, name: item.name }
|
||||||
|
userApi.ws_change(item.id).then(() => {
|
||||||
|
ElMessage.success(t('common.switch_success'))
|
||||||
|
router.push('/chat/index')
|
||||||
|
setTimeout(() => {
|
||||||
|
location.reload()
|
||||||
|
}, 300)
|
||||||
|
})
|
||||||
|
emit('selectWorkspace', item)
|
||||||
|
}
|
||||||
|
|
||||||
|
const init_ws_data = async () => {
|
||||||
|
defaultDatasourceList.value = await userApi.ws_options()
|
||||||
|
}
|
||||||
|
|
||||||
|
const init_current_ws = () => {
|
||||||
|
const oid = userStore.getOid
|
||||||
|
currentWorkspace.value = defaultDatasourceList.value.find(
|
||||||
|
(item) => item.id.toString() === oid.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onMounted(async () => {
|
||||||
|
await init_ws_data()
|
||||||
|
init_current_ws()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-popover
|
||||||
|
trigger="click"
|
||||||
|
popper-class="system-workspace"
|
||||||
|
:placement="collapse ? 'right' : 'bottom'"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<button class="workspace" :class="collapse && 'collapse'">
|
||||||
|
<el-icon size="18">
|
||||||
|
<icon_moments_categories_outlined></icon_moments_categories_outlined>
|
||||||
|
</el-icon>
|
||||||
|
<span v-if="!collapse" :title="currentWorkspace.name" class="name ellipsis">{{
|
||||||
|
currentWorkspace.name
|
||||||
|
}}</span>
|
||||||
|
<el-icon v-if="!collapse" style="transform: scale(0.5)" class="expand" size="24">
|
||||||
|
<icon_expand_down_filled></icon_expand_down_filled>
|
||||||
|
</el-icon></button
|
||||||
|
></template>
|
||||||
|
<div class="popover">
|
||||||
|
<el-input
|
||||||
|
v-model="workspaceKeywords"
|
||||||
|
clearable
|
||||||
|
style="width: 100%; margin-right: 12px"
|
||||||
|
:placeholder="$t('datasource.search_by_name')"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<el-icon>
|
||||||
|
<icon_searchOutline_outlined class="svg-icon" />
|
||||||
|
</el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<div class="popover-content">
|
||||||
|
<el-scrollbar max-height="400px">
|
||||||
|
<div
|
||||||
|
v-for="ele in defaultWorkspaceListWithSearch"
|
||||||
|
:key="ele.name"
|
||||||
|
class="popover-item"
|
||||||
|
:class="currentWorkspace.id === ele.id && 'isActive'"
|
||||||
|
@click="handleDefaultWorkspaceChange(ele)"
|
||||||
|
>
|
||||||
|
<el-icon size="16">
|
||||||
|
<icon_moments_categories_outlined></icon_moments_categories_outlined>
|
||||||
|
</el-icon>
|
||||||
|
<div
|
||||||
|
:title="ele.name"
|
||||||
|
class="datasource-name ellipsis"
|
||||||
|
v-html="formatKeywords(ele.name)"
|
||||||
|
></div>
|
||||||
|
<el-icon size="16" class="done">
|
||||||
|
<icon_done_outlined></icon_done_outlined>
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
|
||||||
|
<div v-if="!defaultWorkspaceListWithSearch.length" class="popover-item empty">
|
||||||
|
{{ $t('model.relevant_results_found') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.workspace {
|
||||||
|
background: #1f23290a;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid #1f23291a;
|
||||||
|
padding: 0 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 208px;
|
||||||
|
height: 40px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
&.collapse {
|
||||||
|
width: 40px;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
margin-left: 8px;
|
||||||
|
max-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #1f23291a;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: #1f232926;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.system-workspace.system-workspace {
|
||||||
|
padding: 4px 0;
|
||||||
|
width: 280px !important;
|
||||||
|
box-shadow: 0 4px 8px 0 #1f23291a;
|
||||||
|
border: 1px solid #dee0e3;
|
||||||
|
.ed-input {
|
||||||
|
.ed-input__wrapper {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
border-bottom: 1px solid #1f232926;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover {
|
||||||
|
.popover-content {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
.popover-item {
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 12px;
|
||||||
|
padding-right: 8px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
&:not(.empty):hover {
|
||||||
|
background: #1f23291a;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.empty {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
color: #8f959e;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.datasource-name {
|
||||||
|
margin-left: 8px;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
max-width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.done {
|
||||||
|
margin-left: auto;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.isSearch {
|
||||||
|
color: var(--ed-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.isActive {
|
||||||
|
color: var(--ed-color-primary);
|
||||||
|
|
||||||
|
.done {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user