| | |
| | | <template> |
| | | <div class="container" :class="isHome ? 'top-[100%] mt-[8px]' : 'bottom-[100%] mb-[8px]'"> |
| | | <div ref="commonPhrasesRef" class="container" :class="isHome ? 'top-[100%] mt-[8px]' : 'bottom-[100%] mb-[8px]'"> |
| | | <div class="container_header"> |
| | | <div class="title">常用语</div> |
| | | <div class="question">常用语</div> |
| | | <span class="ywifont ywicon-guanbi text-[15px] cursor-pointer text-[#767a97]" @click="closeCommonPhrases"></span> |
| | | </div> |
| | | <div class="container_content"> |
| | |
| | | <div class="w-full h-full absolute top-0"> |
| | | <div class="py-0 mt-0 box-border h-full"> |
| | | <div style="overflow-anchor: none" v-for="(item, index) in commonPhrases" :key="index"> |
| | | <div class="phase_item"> |
| | | <div class="phase_item" @click="titleClick(item)"> |
| | | <div class="flex flex-col"> |
| | | <div class="title" @click="titleClick(item)"> |
| | | {{ item.title }} |
| | | <div class="question"> |
| | | {{ item.question }} |
| | | </div> |
| | | <!-- <div class="content"> |
| | | {{ item.content }} |
| | |
| | | <div class="py-2"> |
| | | <span |
| | | class="ywifont ywicon-bianji cursor-pointer text-[#767a97] pt-[4px] pr-[6px] pb-[2px] pl-0 rounded-lg !text-[13px]" |
| | | @click="editCommonPhrases(item)" |
| | | @click.stop="editCommonPhrases(item)" |
| | | ></span> |
| | | <span |
| | | class="ywifont ywicon-shanchu3 cursor-pointer text-[red] pt-[4px] pr-[6px] pb-[2px] pl-0 rounded-lg" |
| | | @click="deleteCommonPhrases(item)" |
| | | @click.stop="deleteCommonPhrases(item)" |
| | | ></span> |
| | | </div> |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { ElMessageBox } from 'element-plus'; |
| | | import { computed, reactive, ref } from 'vue'; |
| | | import { addUserSample } from '/@/api/ai/chat'; |
| | | import { activeGroupType } from '/@/stores/chatRoom'; |
| | | import { ElMessage, ElMessageBox } from 'element-plus'; |
| | | import { computed, onMounted, reactive, ref } from 'vue'; |
| | | import { addUserSample, deleteUserSample, listUserSample, updateUserSample } from '/@/api/ai/chat'; |
| | | import { activeGroupType, activeRoomId, activeSampleId, setRoomConfig } from '/@/stores/chatRoom'; |
| | | import { onClickOutside } from '@vueuse/core'; |
| | | const state = reactive({ |
| | | useCommonPhrasesDialog: false, |
| | | show_sample_title: false, |
| | | inputCommonPhrases: '', |
| | | sample_title: null, |
| | | sample_id: null, |
| | | }); |
| | | const commonPhrases = ref([]); |
| | | const props = defineProps(['isHome']); |
| | | const props = defineProps({ |
| | | isHome: Boolean, |
| | | }); |
| | | const isShow = defineModel('isShow', { |
| | | type: Boolean, |
| | | }); |
| | |
| | | isShow.value = false; |
| | | }; |
| | | //#endregion |
| | | |
| | | //#region ====================== 获取常用语 ====================== |
| | | const updatePhrase = async () => { |
| | | const res = await listUserSample({ |
| | | group_type: activeGroupType.value, |
| | | }); |
| | | if (res.json_ok) { |
| | | commonPhrases.value = res.values; |
| | | } |
| | | }; |
| | | //#endregion |
| | | //#region ====================== 添加常用语 ====================== |
| | | //关闭常用语弹窗 |
| | | const handleClose = () => { |
| | |
| | | }; |
| | | const editCommonPhrases = (item) => { |
| | | state.useCommonPhrasesDialog = true; |
| | | state.inputCommonPhrases = item.content; |
| | | state.show_sample_title = true; |
| | | state.inputCommonPhrases = item.question; |
| | | state.sample_id = item.id; |
| | | }; |
| | | const deleteCommonPhrases = (item) => { |
| | | ElMessageBox.confirm(`你确定要删除常用语吗?<div style="white-space: pre-line;">[${item.title}]</div>`, '提示', { |
| | | const deleteCommonPhrases = (row) => { |
| | | ElMessageBox.confirm(`你确定要删除常用语吗?`, '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning', |
| | | dangerouslyUseHTMLString: true, |
| | | closeOnClickModal: false, |
| | | type: 'warning', |
| | | }).then(async () => { |
| | | commonPhrases.value = commonPhrases.value.filter((i) => i.id !== item.id); |
| | | const res = await deleteUserSample({ |
| | | sample_id: row.id, |
| | | }); |
| | | const foundIndex = commonPhrases.value.findIndex((item) => item === row); |
| | | foundIndex > -1 && commonPhrases.value.splice(foundIndex, 1); |
| | | }); |
| | | }; |
| | | //提交常用语 |
| | | const submitCommonPhrases = async () => { |
| | | if (state.show_sample_title) { |
| | | const res = await updateUserSample({ |
| | | sample_id: state.sample_id, |
| | | question: state.inputCommonPhrases, |
| | | }); |
| | | if (res.json_ok) { |
| | | const foundIndex = commonPhrases.value.findIndex((item) => item.id === state.sample_id); |
| | | foundIndex > -1 && (commonPhrases.value[foundIndex].question = state.inputCommonPhrases); |
| | | handleClose(); |
| | | } |
| | | } else { |
| | | addCommonPhrasesData(); |
| | | } |
| | | }; |
| | | //添加一条数据源 |
| | | const addCommonPhrasesData = async () => { |
| | | const res = await addUserSample({ |
| | | question: state.inputCommonPhrases, |
| | | group_type: activeGroupType.value, |
| | |
| | | if (res.json_ok) { |
| | | commonPhrases.value.push({ |
| | | id: res.sample_id, |
| | | title: state.inputCommonPhrases, |
| | | question: state.inputCommonPhrases, |
| | | }); |
| | | state.useCommonPhrasesDialog = false; |
| | | handleClose(); |
| | | } |
| | | }; |
| | | //#endregion |
| | | //#region ====================== 常用语到对话框 ====================== |
| | | const titleClick = (item) => {}; |
| | | const emits = defineEmits<{ |
| | | (event: 'updateInput', val): void; |
| | | }>(); |
| | | const titleClick = (item) => { |
| | | emits('updateInput', item.question); |
| | | isShow.value = false; |
| | | setRoomConfig(activeRoomId.value, 'isAnswerByLLM', false); |
| | | activeSampleId.value = item.id; |
| | | }; |
| | | const commonChatByUser = (data) => { |
| | | const question = data.question; |
| | | const isCommon = commonPhrases.value.findIndex((item) => item.question === question) > -1; |
| | | if (isCommon) { |
| | | return ElMessage.warning('该问题已存在常用语中'); |
| | | } else { |
| | | state.inputCommonPhrases = question; |
| | | addCommonPhrasesData(); |
| | | } |
| | | }; |
| | | //#endregion |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | .container { |
| | | position: absolute; |
| | | width: 100%; |
| | | max-height: 40vh; |
| | | padding: 0 8px 8px; |
| | | left: 0px; |
| | | border-radius: 12px; |
| | | background-color: #ffffff; |
| | | border: 1px solid #e5e5e5; |
| | | box-shadow: 0px 8px 25px 0px #0000000d; |
| | | display: flex; |
| | | flex-direction: column; |
| | | z-index: 990; |
| | | &_header { |
| | | width: 100%; |
| | | display: flex; |
| | | flex-direction: row; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 10px 6px; |
| | | color: #060607; |
| | | .title { |
| | | font-size: 14px; |
| | | color: #060607; |
| | | font-weight: 600; |
| | | line-height: 20px; |
| | | letter-spacing: 0.25px; |
| | | flex-grow: 1; |
| | | display: flex; |
| | | } |
| | | |
| | | const commonPhrasesRef = ref<HTMLDivElement>(null); |
| | | onClickOutside( |
| | | commonPhrasesRef, |
| | | () => { |
| | | isShow.value = false; |
| | | }, |
| | | { |
| | | ignore: ['.el-message-box'], |
| | | } |
| | | &_content { |
| | | width: 100%; |
| | | max-height: 35vh; |
| | | height: fit-content; |
| | | overflow-y: auto; |
| | | .set_phrases { |
| | | outline: none; |
| | | overflow-y: auto; |
| | | position: relative; |
| | | transition: height 0.1s linear; |
| | | .phase_item { |
| | | display: flex; |
| | | flex-direction: row; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | cursor: pointer; |
| | | padding: 6px 8px; |
| | | flex-shrink: 0; |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | width: 100%; |
| | | &:hover { |
| | | background: #e5e7ed; |
| | | } |
| | | .title { |
| | | font-size: 14px; |
| | | color: #060607; |
| | | font-family: PingFang HK; |
| | | font-weight: 600; |
| | | font-style: normal; |
| | | white-space: nowrap; |
| | | text-overflow: ellipsis; |
| | | overflow: hidden; |
| | | } |
| | | .content { |
| | | font-size: 12px; |
| | | color: #5e6772; |
| | | font-family: PingFang SC; |
| | | white-space: nowrap; |
| | | text-overflow: ellipsis; |
| | | overflow: hidden; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | &_add { |
| | | display: flex; |
| | | flex-direction: row; |
| | | align-items: center; |
| | | cursor: pointer; |
| | | padding: 6px 8px; |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | &:hover { |
| | | background: #e5e7ed; |
| | | } |
| | | ); |
| | | |
| | | const addPhrase = (val) =>{ |
| | | if (!props.isHome) { |
| | | let obj = { |
| | | id: val?.historyId, |
| | | question: val?.content.values, |
| | | }; |
| | | commonChatByUser(obj); |
| | | isShow.value = true; |
| | | } |
| | | } |
| | | onMounted(() => { |
| | | updatePhrase(); |
| | | }); |
| | | defineExpose({ addPhrase, updatePhrase }); |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | @use './index.scss'; |
| | | </style> |