feat: 对话日志
This commit is contained in:
parent
717cf97758
commit
eb0b630fbb
@ -25,7 +25,7 @@ const listSplitPattern: (
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文档列表
|
* 文档分页列表
|
||||||
* @param 参数 dataset_id,
|
* @param 参数 dataset_id,
|
||||||
* page {
|
* page {
|
||||||
"current_page": "string",
|
"current_page": "string",
|
||||||
@ -49,6 +49,13 @@ const getDocument: (
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getAllDocument: (dataset_id: string, loading?: Ref<boolean>) => Promise<Result<any>> = (
|
||||||
|
dataset_id,
|
||||||
|
loading
|
||||||
|
) => {
|
||||||
|
return get(`${prefix}/${dataset_id}/document`, undefined, loading)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建批量文档
|
* 创建批量文档
|
||||||
* @param 参数
|
* @param 参数
|
||||||
@ -117,6 +124,7 @@ const getDocumentDetail: (dataset_id: string, document_id: string) => Promise<Re
|
|||||||
export default {
|
export default {
|
||||||
postSplitDocument,
|
postSplitDocument,
|
||||||
getDocument,
|
getDocument,
|
||||||
|
getAllDocument,
|
||||||
postDocument,
|
postDocument,
|
||||||
putDocument,
|
putDocument,
|
||||||
delDocument,
|
delDocument,
|
||||||
|
|||||||
@ -64,8 +64,43 @@ const getChatRecordLog: (
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改日志内容
|
||||||
|
* @param 参数
|
||||||
|
* application_id, chart_id, chart_record_id, dataset_id, document_id
|
||||||
|
* data {
|
||||||
|
"title": "string",
|
||||||
|
"content": "string",
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const putChatRecordLog: (
|
||||||
|
applicaiton_id: String,
|
||||||
|
chart_id: String,
|
||||||
|
chart_record_id: String,
|
||||||
|
dataset_id: String,
|
||||||
|
document_id: String,
|
||||||
|
data: any,
|
||||||
|
loading?: Ref<boolean>
|
||||||
|
) => Promise<Result<any>> = (
|
||||||
|
applicaiton_id,
|
||||||
|
chart_id,
|
||||||
|
chart_record_id,
|
||||||
|
dataset_id,
|
||||||
|
document_id,
|
||||||
|
data,
|
||||||
|
loading
|
||||||
|
) => {
|
||||||
|
return put(
|
||||||
|
`${prefix}/${applicaiton_id}/chat/${chart_id}/chat_record/${chart_record_id}/dataset/${dataset_id}/document_id/${document_id}/improve`,
|
||||||
|
data,
|
||||||
|
undefined,
|
||||||
|
loading
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getChatLog,
|
getChatLog,
|
||||||
delChatLog,
|
delChatLog,
|
||||||
getChatRecordLog
|
getChatRecordLog,
|
||||||
|
putChatRecordLog
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@ interface chatType {
|
|||||||
*/
|
*/
|
||||||
is_stop?: boolean
|
is_stop?: boolean
|
||||||
record_id: string
|
record_id: string
|
||||||
vote_status: string
|
vote_status: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ChatRecordManage {
|
export class ChatRecordManage {
|
||||||
|
|||||||
@ -1 +1,19 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.5 2.5H12.5V6.25H13.75V8.75H6.875C5.49429 8.75 4.375 9.86929 4.375 11.25V25C4.375 26.3807 5.49429 27.5 6.875 27.5H23.125C24.5057 27.5 25.625 26.3807 25.625 25V11.25C25.625 9.86929 24.5057 8.75 23.125 8.75H16.25V6.25H17.5V2.5ZM8.75 16.25H12.5V20H8.75V16.25ZM21.25 16.25V20H17.5V16.25H21.25Z" fill="url(#paint0_linear_1514_13484)"/>
|
||||||
|
<path d="M2.5 15H0V21.25H2.5V15Z" fill="url(#paint1_linear_1514_13484)"/>
|
||||||
|
<path d="M27.5 15H30V21.25H27.5V15Z" fill="url(#paint2_linear_1514_13484)"/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="paint0_linear_1514_13484" x1="15" y1="2.5" x2="15" y2="27.5" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#3370FF"/>
|
||||||
|
<stop offset="1" stop-color="#7F3BF5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_1514_13484" x1="15" y1="2.5" x2="15" y2="27.5" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#3370FF"/>
|
||||||
|
<stop offset="1" stop-color="#7F3BF5"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_1514_13484" x1="15" y1="2.5" x2="15" y2="27.5" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#3370FF"/>
|
||||||
|
<stop offset="1" stop-color="#7F3BF5"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 276 B After Width: | Height: | Size: 1.2 KiB |
65
ui/src/components/ai-chat/LogOperationButton.vue
Normal file
65
ui/src/components/ai-chat/LogOperationButton.vue
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-tooltip effect="dark" content="修改内容" placement="top">
|
||||||
|
<el-button text @click="editContent(data)">
|
||||||
|
<el-icon><EditPen /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
<el-tooltip effect="dark" content="复制" placement="top">
|
||||||
|
<el-button text @click="copyClick(data?.answer_text)">
|
||||||
|
<AppIcon iconName="app-copy"></AppIcon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-divider direction="vertical" v-if="buttonData?.vote_status !== '-1'" />
|
||||||
|
<el-button text disabled v-if="buttonData?.vote_status === '0'">
|
||||||
|
<AppIcon iconName="app-like-color"></AppIcon>
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
<el-button text disabled v-if="buttonData?.vote_status === '1'">
|
||||||
|
<AppIcon iconName="app-oppose-color"></AppIcon>
|
||||||
|
</el-button>
|
||||||
|
<EditContentDialog
|
||||||
|
ref="EditContentDialogRef"
|
||||||
|
:chartId="chartId"
|
||||||
|
@updateContent="updateContent"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref, watch, onMounted } from 'vue'
|
||||||
|
import { copyClick } from '@/utils/clipboard'
|
||||||
|
import EditContentDialog from '@/views/log/component/EditContentDialog.vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
|
applicationId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
chartId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
log: Boolean
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:data'])
|
||||||
|
|
||||||
|
const EditContentDialogRef = ref()
|
||||||
|
|
||||||
|
const buttonData = ref(props.data)
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
function editContent(data: any) {
|
||||||
|
EditContentDialogRef.value.open(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateContent(data: any) {
|
||||||
|
emit('update:data', data)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@ -71,7 +71,8 @@ const props = defineProps({
|
|||||||
chartId: {
|
chartId: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
}
|
},
|
||||||
|
log: Boolean
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['update:data', 'regeneration'])
|
const emit = defineEmits(['update:data', 'regeneration'])
|
||||||
|
|||||||
@ -22,7 +22,8 @@
|
|||||||
<template v-for="(item, index) in data?.example" :key="index">
|
<template v-for="(item, index) in data?.example" :key="index">
|
||||||
<div
|
<div
|
||||||
@click="quickProblemHandel(item)"
|
@click="quickProblemHandel(item)"
|
||||||
class="problem-button cursor ellipsis-2"
|
class="problem-button ellipsis-2"
|
||||||
|
:class="log ? 'disabled' : 'cursor'"
|
||||||
v-if="item"
|
v-if="item"
|
||||||
>
|
>
|
||||||
<el-icon><EditPen /></el-icon>
|
<el-icon><EditPen /></el-icon>
|
||||||
@ -66,7 +67,14 @@
|
|||||||
:inner_suffix="false"
|
:inner_suffix="false"
|
||||||
></MarkdownRenderer>
|
></MarkdownRenderer>
|
||||||
</el-card>
|
</el-card>
|
||||||
<div class="flex-between mt-8">
|
<div class="flex-between mt-8" v-if="log">
|
||||||
|
<el-text type="info">
|
||||||
|
消耗 {{ item?.message_tokens + item?.answer_tokens }} tokens
|
||||||
|
</el-text>
|
||||||
|
<LogOperationButton :data="item" :applicationId="appId" :chartId="item.id" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-between mt-8" v-else>
|
||||||
<div>
|
<div>
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@ -94,7 +102,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
<div class="ai-chat__operate p-24" v-if="!record">
|
<div class="ai-chat__operate p-24" v-if="!log">
|
||||||
<div class="operate-textarea flex">
|
<div class="operate-textarea flex">
|
||||||
<el-input
|
<el-input
|
||||||
ref="quickInputRef"
|
ref="quickInputRef"
|
||||||
@ -124,8 +132,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, nextTick, onUpdated, computed } from 'vue'
|
import { ref, nextTick, onUpdated, computed, watch } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
import LogOperationButton from './LogOperationButton.vue'
|
||||||
import OperationButton from './OperationButton.vue'
|
import OperationButton from './OperationButton.vue'
|
||||||
import applicationApi from '@/api/application'
|
import applicationApi from '@/api/application'
|
||||||
import { ChatManagement, type chatType } from '@/api/type/application'
|
import { ChatManagement, type chatType } from '@/api/type/application'
|
||||||
@ -142,7 +151,11 @@ const props = defineProps({
|
|||||||
default: () => {}
|
default: () => {}
|
||||||
},
|
},
|
||||||
appId: String,
|
appId: String,
|
||||||
record: Boolean
|
log: Boolean,
|
||||||
|
record: {
|
||||||
|
type: Array<chatType[]>,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
})
|
})
|
||||||
const { application } = useStore()
|
const { application } = useStore()
|
||||||
|
|
||||||
@ -152,18 +165,32 @@ const dialogScrollbar = ref()
|
|||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const inputValue = ref('')
|
const inputValue = ref('')
|
||||||
const chartOpenId = ref('')
|
const chartOpenId = ref('')
|
||||||
const chatList = ref<chatType[]>([])
|
const chatList = ref<any[]>([])
|
||||||
|
|
||||||
const isDisabledChart = computed(
|
const isDisabledChart = computed(
|
||||||
() => !(inputValue.value && (props.appId || (props.data?.name && props.data?.model_id)))
|
() => !(inputValue.value && (props.appId || (props.data?.name && props.data?.model_id)))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.record,
|
||||||
|
(value) => {
|
||||||
|
if (props.log) {
|
||||||
|
chatList.value = value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
function quickProblemHandel(val: string) {
|
function quickProblemHandel(val: string) {
|
||||||
|
if (!props.log) {
|
||||||
inputValue.value = val
|
inputValue.value = val
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
quickInputRef.value?.focus()
|
quickInputRef.value?.focus()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function sendChatHandle(event: any) {
|
function sendChatHandle(event: any) {
|
||||||
if (!event.ctrlKey) {
|
if (!event.ctrlKey) {
|
||||||
@ -286,7 +313,9 @@ function handleScrollBottom() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onUpdated(() => {
|
onUpdated(() => {
|
||||||
|
if (!props.log) {
|
||||||
handleScrollBottom()
|
handleScrollBottom()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -330,6 +359,11 @@ onUpdated(() => {
|
|||||||
&:hover {
|
&:hover {
|
||||||
background: var(--el-color-primary-light-9);
|
background: var(--el-color-primary-light-9);
|
||||||
}
|
}
|
||||||
|
&.disabled {
|
||||||
|
&:hover {
|
||||||
|
background: var(--app-layout-bg-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
:deep(.el-icon) {
|
:deep(.el-icon) {
|
||||||
color: var(--el-color-primary);
|
color: var(--el-color-primary);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,9 @@
|
|||||||
<div class="flex-center h-full">
|
<div class="flex-center h-full">
|
||||||
<div class="app-title-container flex-center">
|
<div class="app-title-container flex-center">
|
||||||
<div class="app-title-icon"></div>
|
<div class="app-title-icon"></div>
|
||||||
<div class="app-title-text app-logo-font">{{ defaultTitle }}</div>
|
<div class="app-title-text app-logo-font ml-4">
|
||||||
|
{{ defaultTitle }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<TopMenu></TopMenu>
|
<TopMenu></TopMenu>
|
||||||
</div>
|
</div>
|
||||||
@ -26,10 +28,11 @@ const defaultTitle = import.meta.env.VITE_APP_TITLE
|
|||||||
.app-title-container {
|
.app-title-container {
|
||||||
margin-right: 45px;
|
margin-right: 45px;
|
||||||
.app-title-icon {
|
.app-title-icon {
|
||||||
background-image: url('@/assets/logo.png');
|
background-image: url('@/assets/logo.svg');
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
width: 34px;
|
width: 30px;
|
||||||
height: 34px;
|
height: 30px;
|
||||||
|
background-position: center -1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-title-text {
|
.app-title-text {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import useDatasetStore from './modules/dataset'
|
|||||||
import useParagraphStore from './modules/paragraph'
|
import useParagraphStore from './modules/paragraph'
|
||||||
import useModelStore from './modules/model'
|
import useModelStore from './modules/model'
|
||||||
import useApplicationStore from './modules/application'
|
import useApplicationStore from './modules/application'
|
||||||
|
import useDocumentStore from './modules/document'
|
||||||
|
|
||||||
const useStore = () => ({
|
const useStore = () => ({
|
||||||
common: useCommonStore(),
|
common: useCommonStore(),
|
||||||
@ -14,7 +15,8 @@ const useStore = () => ({
|
|||||||
dataset: useDatasetStore(),
|
dataset: useDatasetStore(),
|
||||||
paragraph: useParagraphStore(),
|
paragraph: useParagraphStore(),
|
||||||
model: useModelStore(),
|
model: useModelStore(),
|
||||||
application: useApplicationStore()
|
application: useApplicationStore(),
|
||||||
|
document: useDocumentStore()
|
||||||
})
|
})
|
||||||
|
|
||||||
export default useStore
|
export default useStore
|
||||||
|
|||||||
@ -34,6 +34,19 @@ const useApplicationStore = defineStore({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async asyncGetApplicationDataset(id: string, loading?: Ref<boolean>) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
applicationApi
|
||||||
|
.getApplicationDataset(id, loading)
|
||||||
|
.then((data) => {
|
||||||
|
resolve(data)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
async asyncGetAccessToken(id: string, loading?: Ref<boolean>) {
|
async asyncGetAccessToken(id: string, loading?: Ref<boolean>) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
applicationApi
|
applicationApi
|
||||||
|
|||||||
24
ui/src/stores/modules/document.ts
Normal file
24
ui/src/stores/modules/document.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import documentApi from '@/api/document'
|
||||||
|
import { type Ref } from 'vue'
|
||||||
|
|
||||||
|
const useDocumentStore = defineStore({
|
||||||
|
id: 'documents',
|
||||||
|
state: () => ({}),
|
||||||
|
actions: {
|
||||||
|
async asyncGetAllDocument(id: string, loading?: Ref<boolean>) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
documentApi
|
||||||
|
.getAllDocument(id, loading)
|
||||||
|
.then((res) => {
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default useDocumentStore
|
||||||
@ -195,3 +195,11 @@
|
|||||||
padding: 16px 24px;
|
padding: 16px 24px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-cascader-node {
|
||||||
|
padding-left: 2px;
|
||||||
|
}
|
||||||
|
.el-cascader-node__prefix {
|
||||||
|
right: 10px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
|||||||
@ -191,7 +191,7 @@ import type { Provider } from '@/api/type/model'
|
|||||||
import { realatedObject } from '@/utils/utils'
|
import { realatedObject } from '@/utils/utils'
|
||||||
import { MsgSuccess } from '@/utils/message'
|
import { MsgSuccess } from '@/utils/message'
|
||||||
import useStore from '@/stores'
|
import useStore from '@/stores'
|
||||||
import type Result from '@/request/Result'
|
|
||||||
const { model, dataset, application, user } = useStore()
|
const { model, dataset, application, user } = useStore()
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -293,7 +293,7 @@ function getDetail() {
|
|||||||
|
|
||||||
function getDataset() {
|
function getDataset() {
|
||||||
if (id) {
|
if (id) {
|
||||||
applicationApi.getApplicationDataset(id, datasetLoading).then((res) => {
|
application.asyncGetApplicationDataset(id, datasetLoading).then((res: any) => {
|
||||||
datasetList.value = res.data
|
datasetList.value = res.data
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -7,29 +7,51 @@
|
|||||||
class="chat-record-drawer"
|
class="chat-record-drawer"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<h4>应用标题</h4>
|
<h4>{{ data?.name }}</h4>
|
||||||
</template>
|
</template>
|
||||||
<AiChat record></AiChat>
|
<div v-loading="paginationConfig.current_page === 1 && loading">
|
||||||
|
<div v-infinite-scroll="loadDataset" :infinite-scroll-disabled="disabledScroll">
|
||||||
|
<AiChat :data="data" :record="recordList" log></AiChat>
|
||||||
|
</div>
|
||||||
|
<div style="padding: 16px 10px">
|
||||||
|
<el-divider class="custom-divider" v-if="recordList.length > 0 && loading">
|
||||||
|
<el-text type="info"> 加载中...</el-text>
|
||||||
|
</el-divider>
|
||||||
|
<el-divider class="custom-divider" v-if="noMore">
|
||||||
|
<el-text type="info"> 到底啦!</el-text>
|
||||||
|
</el-divider>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div>
|
<div>
|
||||||
<el-button>上一条</el-button>
|
<el-button :disabled="loading">上一条</el-button>
|
||||||
<el-button>下一条</el-button>
|
<el-button :disabled="loading">下一条</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive, computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import logApi from '@/api/log'
|
import logApi from '@/api/log'
|
||||||
|
import { type chatType } from '@/api/type/application'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const {
|
const {
|
||||||
params: { id }
|
params: { id }
|
||||||
} = route
|
} = route
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
|
const recordList = ref<chatType[]>([])
|
||||||
|
const currentChatId = ref('')
|
||||||
|
|
||||||
const paginationConfig = reactive({
|
const paginationConfig = reactive({
|
||||||
current_page: 1,
|
current_page: 1,
|
||||||
@ -37,17 +59,43 @@ const paginationConfig = reactive({
|
|||||||
total: 0
|
total: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
function closeHandel() {}
|
const noMore = computed(
|
||||||
|
() =>
|
||||||
|
recordList.value.length > 0 &&
|
||||||
|
recordList.value.length === paginationConfig.total &&
|
||||||
|
paginationConfig.total > 20 &&
|
||||||
|
!loading.value
|
||||||
|
)
|
||||||
|
const disabledScroll = computed(
|
||||||
|
() => recordList.value.length > 0 && (loading.value || noMore.value)
|
||||||
|
)
|
||||||
|
|
||||||
function getChatRecord(chatId:string) {
|
function closeHandel() {
|
||||||
logApi.getChatRecordLog(id as string, chatId, paginationConfig, loading).then((res) => {
|
recordList.value = []
|
||||||
// tableData.value = res.data.records
|
currentChatId.value = ''
|
||||||
|
paginationConfig.total = 0
|
||||||
|
paginationConfig.current_page = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadDataset() {
|
||||||
|
if (paginationConfig.total > paginationConfig.page_size) {
|
||||||
|
paginationConfig.current_page += 1
|
||||||
|
getChatRecord()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getChatRecord() {
|
||||||
|
logApi
|
||||||
|
.getChatRecordLog(id as string, currentChatId.value, paginationConfig, loading)
|
||||||
|
.then((res) => {
|
||||||
paginationConfig.total = res.data.total
|
paginationConfig.total = res.data.total
|
||||||
|
recordList.value = [...recordList.value, ...res.data.records]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const open = (id: string) => {
|
const open = (id: string) => {
|
||||||
getChatRecord(id)
|
currentChatId.value = id
|
||||||
|
getChatRecord()
|
||||||
visible.value = true
|
visible.value = true
|
||||||
}
|
}
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
|||||||
172
ui/src/views/log/component/EditContentDialog.vue
Normal file
172
ui/src/views/log/component/EditContentDialog.vue
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog title="修改内容" v-model="dialogVisible" width="600">
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
label-position="top"
|
||||||
|
require-asterisk-position="right"
|
||||||
|
:rules="rules"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<el-form-item label="关联问题">
|
||||||
|
<span>{{ form.problem_text }}</span>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="内容" prop="content">
|
||||||
|
<el-input
|
||||||
|
v-model="form.content"
|
||||||
|
placeholder="请输入内容"
|
||||||
|
maxlength="1024"
|
||||||
|
show-word-limit
|
||||||
|
:rows="8"
|
||||||
|
type="textarea"
|
||||||
|
>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="标题">
|
||||||
|
<el-input v-model="form.title" placeholder="请给当前内容设置一个标题,以便管理查看">
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="保存至文档" prop="document">
|
||||||
|
<el-cascader v-model="form.document" :props="LoadDocument" placeholder="请选择文档">
|
||||||
|
<template #default="{ node, data }">
|
||||||
|
<span class="flex align-center">
|
||||||
|
<AppAvatar v-if="!node.isLeaf" class="mr-12" shape="square" :size="24">
|
||||||
|
<img src="@/assets/icon_document.svg" style="width: 58%" alt="" />
|
||||||
|
</AppAvatar>
|
||||||
|
{{ data.name }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-cascader>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click.prevent="dialogVisible = false"> 取消 </el-button>
|
||||||
|
<el-button type="primary" @click="submitForm(formRef)"> 保存 </el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch, reactive } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import logApi from '@/api/log'
|
||||||
|
import type { CascaderProps } from 'element-plus'
|
||||||
|
|
||||||
|
import useStore from '@/stores'
|
||||||
|
|
||||||
|
const { application, document } = useStore()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
chartId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const {
|
||||||
|
params: { id }
|
||||||
|
} = route as any
|
||||||
|
|
||||||
|
const emit = defineEmits(['updateContent'])
|
||||||
|
|
||||||
|
const formRef = ref()
|
||||||
|
|
||||||
|
const dialogVisible = ref<boolean>(false)
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
const form = ref<any>({
|
||||||
|
record_id: '',
|
||||||
|
problem_text: '',
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
document: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
content: [{ required: true, message: '请输入内容', trigger: 'blur' }],
|
||||||
|
document: [{ type: 'array', required: true, message: '请选择文档', trigger: 'change' }]
|
||||||
|
})
|
||||||
|
|
||||||
|
const datasetList = ref([])
|
||||||
|
|
||||||
|
watch(dialogVisible, (bool) => {
|
||||||
|
if (!bool) {
|
||||||
|
form.value = {
|
||||||
|
record_id: '',
|
||||||
|
problem_text: '',
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
document: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const LoadDocument: CascaderProps = {
|
||||||
|
lazy: true,
|
||||||
|
value: 'id',
|
||||||
|
label: 'name',
|
||||||
|
leaf: 'dataset_id',
|
||||||
|
lazyLoad(node, resolve: any) {
|
||||||
|
const { level, data } = node
|
||||||
|
if (data?.id) {
|
||||||
|
getDocument(data?.id as string, resolve)
|
||||||
|
} else {
|
||||||
|
getDataset(resolve)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDocument(id: string, resolve: any) {
|
||||||
|
document.asyncGetAllDocument(id, loading).then((res: any) => {
|
||||||
|
datasetList.value = res.data
|
||||||
|
resolve(datasetList.value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDataset(resolve: any) {
|
||||||
|
application.asyncGetApplicationDataset(id, loading).then((res: any) => {
|
||||||
|
datasetList.value = res.data
|
||||||
|
resolve(datasetList.value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const open = (data: any) => {
|
||||||
|
form.value.record_id = data.id
|
||||||
|
form.value.problem_text = data.problem_text
|
||||||
|
form.value.content = data.answer_text
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
await formEl.validate((valid, fields) => {
|
||||||
|
if (valid) {
|
||||||
|
const obj = {
|
||||||
|
title: form.value.title,
|
||||||
|
content: form.value.content
|
||||||
|
}
|
||||||
|
logApi
|
||||||
|
.putChatRecordLog(
|
||||||
|
id,
|
||||||
|
props.chartId,
|
||||||
|
form.value.record_id,
|
||||||
|
form.value.document[0],
|
||||||
|
form.value.document[1],
|
||||||
|
obj,
|
||||||
|
loading
|
||||||
|
)
|
||||||
|
.then((res: any) => {
|
||||||
|
emit('updateContent', res.data)
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log('error submit!', fields)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scope></style>
|
||||||
@ -62,7 +62,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</app-table>
|
</app-table>
|
||||||
</div>
|
</div>
|
||||||
<ChatRecordDrawer ref="ChatRecordRef" />
|
<ChatRecordDrawer ref="ChatRecordRef" :data="detail" />
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -72,6 +72,8 @@ import ChatRecordDrawer from './component/ChatRecordDrawer.vue'
|
|||||||
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||||
import logApi from '@/api/log'
|
import logApi from '@/api/log'
|
||||||
import { datetimeFormat } from '@/utils/time'
|
import { datetimeFormat } from '@/utils/time'
|
||||||
|
import useStore from '@/stores'
|
||||||
|
const { application } = useStore()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const {
|
const {
|
||||||
params: { id }
|
params: { id }
|
||||||
@ -107,6 +109,7 @@ const tableData = ref([])
|
|||||||
|
|
||||||
const history_day = ref(7)
|
const history_day = ref(7)
|
||||||
const search = ref('')
|
const search = ref('')
|
||||||
|
const detail = ref<any>(null)
|
||||||
|
|
||||||
function rowClickHandle(row: any) {
|
function rowClickHandle(row: any) {
|
||||||
// router.push({ path: `/dataset/${id}/${row.id}` })
|
// router.push({ path: `/dataset/${id}/${row.id}` })
|
||||||
@ -152,8 +155,15 @@ function getList() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDetail() {
|
||||||
|
application.asyncGetApplicationDetail(id as string, loading).then((res: any) => {
|
||||||
|
detail.value = res.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList()
|
getList()
|
||||||
|
getDetail()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user