fix: bug fix

This commit is contained in:
dataeaseShu
2025-07-24 11:42:41 +08:00
parent 73784388f4
commit ec2ad683ce
3 changed files with 425 additions and 83 deletions
+86 -83
View File
@@ -1,8 +1,10 @@
<script setup lang="ts">
<script lang="ts" setup>
import { onMounted, ref, computed, shallowRef } from 'vue'
import icon_close_outlined from '@/assets/svg/operate/ope-close.svg'
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
import { chatApi, ChatInfo } from '@/api/chat.ts'
import { onMounted, ref } from 'vue'
import { datasourceApi } from '@/api/datasource.ts'
import DatasourceItemCard from '../ds/DatasourceItemCard.vue'
import Card from '@/views/ds/ChatCard.vue'
const props = withDefaults(
defineProps<{
@@ -13,32 +15,40 @@ const props = withDefaults(
}
)
const dsList = ref<Array<any>>([])
const datasourceConfigvVisible = ref(false)
const keywords = ref('')
const datasourceList = shallowRef([] as any[])
const datasourceListWithSearch = computed(() => {
if (!keywords.value) return datasourceList.value
return datasourceList.value.filter((ele) =>
ele.name.toLowerCase().includes(keywords.value.toLowerCase())
)
})
const beforeClose = () => {
datasourceConfigvVisible.value = false
keywords.value = ''
}
const emits = defineEmits(['onChatCreated'])
function listDs() {
datasourceApi.list().then((res) => {
dsList.value = res
datasourceList.value = res
})
}
const dialogVisible = ref(false)
const DatasourceListRef = ref()
const innerDs = ref()
const loading = ref(false)
function showDs() {
listDs()
dialogVisible.value = true
datasourceConfigvVisible.value = true
}
function hideDs() {
innerDs.value = undefined
dialogVisible.value = false
datasourceConfigvVisible.value = false
}
function selectDsInDialog(ds: any) {
@@ -77,7 +87,6 @@ onMounted(() => {
if (props.hidden) {
return
}
listDs()
})
defineExpose({
@@ -88,79 +97,73 @@ defineExpose({
</script>
<template>
<div v-if="!hidden">
<el-drawer
ref="DatasourceListRef"
v-model="dialogVisible"
direction="btt"
:close-on-press-escape="false"
:close-on-click-modal="false"
destroy-on-close
:show-close="false"
size="100%"
>
<template #header>
<div>
<div>Choose Datasource</div>
</div>
</template>
<el-scrollbar v-loading="loading">
<div class="ds-row-container">
<template v-for="(item, _index) in dsList" :key="_index">
<DatasourceItemCard
:ds="item"
class="ds-card"
:class="[item?.id === innerDs ? 'ds-card-selected' : '']"
@click="selectDsInDialog(item)"
/>
<el-drawer
v-model="datasourceConfigvVisible"
:close-on-click-modal="false"
size="calc(100% - 100px)"
modal-class="datasource-drawer-chat"
direction="btt"
:before-close="beforeClose"
:show-close="false"
>
<template #header="{ close }">
<span style="white-space: nowrap">{{ $t('qa.select_datasource') }}</span>
<div class="flex-center" style="width: 100%">
<el-input
v-model="keywords"
clearable
style="width: 320px"
:placeholder="$t('datasource.search')"
>
<template #prefix>
<el-icon>
<icon_searchOutline_outlined />
</el-icon>
</template>
</div>
</el-scrollbar>
<template #footer>
<div class="dialog-footer">
<el-button :disabled="loading" @click="hideDs">Cancel</el-button>
<el-button
type="primary"
:disabled="loading || innerDs === undefined"
@click="confirmSelectDs"
>
Confirm
</el-button>
</div>
</template>
</el-drawer>
</div>
</el-input>
</div>
<el-icon style="cursor: pointer" @click="close">
<icon_close_outlined></icon_close_outlined>
</el-icon>
</template>
<div class="card-content">
<Card
v-for="ele in datasourceListWithSearch"
:id="ele.id"
:key="ele.id"
:name="ele.name"
:type="ele.type"
:type-name="ele.type_name"
:num="ele.num"
:is-selected="ele.id === innerDs"
:description="ele.description"
@select-ds="selectDsInDialog(ele)"
></Card>
</div>
<template #footer>
<div class="dialog-footer">
<el-button secondary :disabled="loading" @click="hideDs">{{
$t('common.cancel')
}}</el-button>
<el-button
:type="loading || innerDs === undefined ? 'info' : 'primary'"
:disabled="loading || innerDs === undefined"
@click="confirmSelectDs"
>
{{ $t('datasource.confirm') }}
</el-button>
</div>
</template>
</el-drawer>
</template>
<style scoped lang="less">
.welcome-content {
padding: 12px;
}
.sub {
color: grey;
font-size: 0.8em;
}
.ds-select-row {
display: flex;
align-items: center;
flex-direction: row;
justify-content: space-between;
}
.ds-row-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 24px;
}
.ds-card {
cursor: pointer;
}
.ds-card-selected {
box-shadow: 0 1px 3px var(--ed-color-primary-light-5);
border: 1px solid var(--ed-color-primary-light-5);
<style lang="less">
.datasource-drawer-chat {
.card-content {
display: flex;
flex-wrap: wrap;
max-height: 100%;
overflow-y: auto;
}
}
</style>
+170
View File
@@ -0,0 +1,170 @@
<script lang="ts" setup>
import { onMounted, ref, computed, shallowRef } from 'vue'
import icon_close_outlined from '@/assets/svg/operate/ope-close.svg'
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
import { chatApi, ChatInfo } from '@/api/chat.ts'
import { datasourceApi } from '@/api/datasource.ts'
import Card from '@/views/ds/ChatCard.vue'
const props = withDefaults(
defineProps<{
hidden?: boolean
}>(),
{
hidden: false,
}
)
const datasourceConfigvVisible = ref(false)
const keywords = ref('')
const datasourceList = shallowRef([] as any[])
const datasourceListWithSearch = computed(() => {
if (!keywords.value) return datasourceList.value
return datasourceList.value.filter((ele) =>
ele.name.toLowerCase().includes(keywords.value.toLowerCase())
)
})
const beforeClose = () => {
datasourceConfigvVisible.value = false
keywords.value = ''
}
const emits = defineEmits(['onChatCreated'])
function listDs() {
datasourceApi.list().then((res) => {
datasourceList.value = res
})
}
const dialogVisible = ref(false)
const innerDs = ref()
const loading = ref(false)
function showDs() {
listDs()
dialogVisible.value = true
}
function hideDs() {
innerDs.value = undefined
dialogVisible.value = false
}
function selectDsInDialog(ds: any) {
innerDs.value = ds.id
}
function confirmSelectDs() {
if (innerDs.value) {
createChat(innerDs.value)
}
}
function createChat(datasource: number) {
loading.value = true
chatApi
.startChat({
datasource: datasource,
})
.then((res) => {
const chat: ChatInfo | undefined = chatApi.toChatInfo(res)
if (chat == undefined) {
throw Error('chat is undefined')
}
emits('onChatCreated', chat)
hideDs()
})
.catch((e) => {
console.error(e)
})
.finally(() => {
loading.value = false
})
}
onMounted(() => {
if (props.hidden) {
return
}
})
defineExpose({
showDs,
hideDs,
createChat,
})
</script>
<template>
<el-drawer
v-model="datasourceConfigvVisible"
:close-on-click-modal="false"
size="calc(100% - 100px)"
modal-class="datasource-drawer-chat"
direction="btt"
:before-close="beforeClose"
:show-close="false"
>
<template #header="{ close }">
<span style="white-space: nowrap">{{ $t('qa.select_datasource') }}</span>
<div class="flex-center" style="width: 100%">
<el-input
v-model="keywords"
clearable
style="width: 320px"
:placeholder="$t('datasource.search')"
>
<template #prefix>
<el-icon>
<icon_searchOutline_outlined />
</el-icon>
</template>
</el-input>
</div>
<el-icon style="cursor: pointer" @click="close">
<icon_close_outlined></icon_close_outlined>
</el-icon>
</template>
<div class="card-content">
<Card
v-for="ele in datasourceListWithSearch"
:id="ele.id"
:key="ele.id"
:name="ele.name"
:type="ele.type"
:type-name="ele.type_name"
:num="ele.num"
:description="ele.description"
@select-ds="selectDsInDialog(ele)"
></Card>
</div>
<template #footer>
<div class="dialog-footer">
<el-button secondary :disabled="loading" @click="hideDs">{{
$t('common.cancel')
}}</el-button>
<el-button
type="primary"
:disabled="loading || innerDs === undefined"
@click="confirmSelectDs"
>
{{ $t('datasource.confirm') }}
</el-button>
</div>
</template>
</el-drawer>
</template>
<style lang="less">
.datasource-drawer-chat {
.card-content {
display: flex;
flex-wrap: wrap;
max-height: calc(100% - 40px);
overflow-y: auto;
}
}
</style>
+169
View File
@@ -0,0 +1,169 @@
<script lang="ts" setup>
import icon_form_outlined from '@/assets/svg/icon_form_outlined.svg'
import { computed } from 'vue'
import { dsTypeWithImg } from './js/ds-type'
const props = withDefaults(
defineProps<{
name: string
type: string
typeName: string
num: string
isSelected: boolean
description?: string
id?: string
}>(),
{
name: '-',
type: '-',
description: '-',
id: '-',
typeName: '-',
isSelected: false,
}
)
const emits = defineEmits(['selectDs'])
const icon = computed(() => {
return (dsTypeWithImg.find((ele) => props.type === ele.type) || {}).img
})
const SelectDs = () => {
emits('selectDs')
}
</script>
<template>
<div class="card" @click="SelectDs" :class="isSelected && 'is-selected'">
<div class="name-icon">
<img :src="icon" width="32px" height="32px" />
<div class="info">
<div :title="name" class="name ellipsis">{{ name }}</div>
<div class="type">{{ typeName }}</div>
</div>
</div>
<div :title="description" class="type-value">
{{ description }}
</div>
<div class="bottom-info">
<div class="form-rate">
<el-icon class="form-icon" size="16">
<icon_form_outlined></icon_form_outlined>
</el-icon>
{{ num }}
</div>
<div click.stop class="methods"></div>
</div>
</div>
</template>
<style lang="less" scoped>
.card {
width: 370px;
border: 1px solid #dee0e3;
padding: 16px;
border-radius: 12px;
cursor: pointer;
margin: 0 16px 16px 0;
&:hover {
box-shadow: 0px 6px 24px 0px #1f232914;
}
.name-icon {
display: flex;
align-items: center;
margin-bottom: 12px;
.info {
margin-left: 12px;
.name {
font-weight: 500;
font-size: 16px;
line-height: 24px;
max-width: 250px;
}
.type {
font-weight: 400;
font-size: 12px;
line-height: 20px;
color: #646a73;
}
}
}
.type-value {
font-weight: 400;
font-size: 14px;
line-height: 22px;
color: #646a73;
height: 44px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
width: 100%;
}
.bottom-info {
margin-top: 16px;
display: flex;
align-items: center;
justify-content: space-between;
height: 28px;
.ed-button {
height: 28px;
min-width: 78px;
}
.form-rate {
display: flex;
align-items: center;
color: #646a73;
font-weight: 400;
font-size: 14px;
line-height: 22px;
.form-icon {
margin-right: 8px;
}
}
.methods {
align-items: center;
display: none;
.more {
position: relative;
cursor: pointer;
&::after {
content: '';
background-color: #1f23291a;
position: absolute;
border-radius: 6px;
width: 24px;
height: 24px;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
display: none;
}
&:hover {
&::after {
display: block;
}
}
}
}
}
&.is-selected {
border: 1px solid #1cba90;
background: #1cba901a;
}
}
</style>