Commit ea73ba1e authored by tyyin lan's avatar tyyin lan

Merge branch 'shirlyn'

parents ae77e323 473cbb27
import { request } from '@/utils/request'
export function fetchGetAgentApplicationList<T>(payload: object) {
return request.post<T>('/bizAgentApplicationMallRest/getList.json', payload)
}
export function fetchCollectOrCancelAgentApplication<T>(id: number | undefined) {
return request.post<T>(`/bizAgentApplicationMallRest/collectOrCancelAgentInMall.json?id=${id}`)
}
export function fetchGetMallCategoryList<T>() {
return request.post<T>('/bizAgentApplicationMallRest/getMallCategoryList.json')
}
import { request } from '@/utils/request'
export function fetchGetLongMemoryList<T>(agentId: string) {
return request.post<T>(`/agentApplicationInfoRest/getLongMemoryList.json?agentId=${agentId}`)
}
export function fetchDeleteLongMemoryByKey<T>(agentId: string, timestamp: string) {
return request.post<T>(
`/agentApplicationInfoRest/deleteLongMemoryByKey.json?agentId=${agentId}&timestamp=${timestamp}`,
)
}
export function fetchDeleteAllLongMemory<T>(agentId: string) {
return request.post<T>(`/agentApplicationInfoRest/deleteLongMemory.json?agentId=${agentId}`)
}
export function fetchGetMemoryVariableList<T>(agentId: string) {
return request.post<T>(`/agentApplicationInfoRest/getVariableList.json?agentId=${agentId}`)
}
......@@ -2,7 +2,7 @@
import { computed, h, ref, watchEffect } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { Plus } from '@icon-park/vue-next'
import { Plus, Commodity } from '@icon-park/vue-next'
import type { MenuOption } from 'naive-ui'
import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import { useUserStore } from '@/store/modules/user'
......@@ -31,6 +31,18 @@ const menuOptions = computed<MenuOption[]>(() => {
key: 'PersonalSpace',
icon: () => h('i', { class: 'iconfont icon-personal' }),
},
{
type: 'group',
label: () => h('div', {}, t('router_title_module.explore')),
key: 'Dialogue',
children: [
{
label: () => h('div', {}, t('router_title_module.application_square')),
key: 'ApplicationsSquare',
icon: () => h(Commodity, { theme: 'outline', size: '18', fill: '#333' }),
},
],
},
]
})
......
......@@ -67,8 +67,12 @@ common_module:
removal_failed: '下架失败'
collect_successfully: '收藏成功'
collect_unsubscribed: '已取消收藏'
cancel: '取消'
preservation: '保存'
open: '开'
close: '关'
delete_tip_title: '删除提示'
wipe_data: '清空数据'
delete_all_tip_title: '清空数据提示'
dialogue_module:
continue_question_message: '你可以继续提问'
......@@ -144,6 +148,8 @@ router_title_module:
knowledge_document_list: '知识库文档列表'
knowledge_document_detail: '知识库文档详情'
multi_model_dialogue: '多模型调试'
explore: '探索'
application_square: '应用广场'
personal_space_module:
title: '个人空间'
......@@ -161,7 +167,6 @@ personal_space_module:
channel_popover_text: '查看发布详情'
agent_copy: '的副本'
empty_agent_list: '暂无应用'
search_empty_agent_list: '没有搜索到相关内容'
delete_agent_dialog_title: '确定要删除选中的应用吗?'
delete_agent_dialog_content: '删除后,如需再次使用,请重新创建'
remove_applications_dialog_title: '确定要下架应用吗?'
......@@ -244,6 +249,12 @@ personal_space_module:
memory_variable_action_copy: '复制名称'
variable_name: '变量名称'
variable_value: '变量值'
memory_fragment: '记忆片段'
memory_fragment_message: '开启记忆片段功能,应用将根据对话内容存储用户提及的信息片段,并依据记忆片段答复。下面以「面试助手」为例:'
memory_fragment_content: '记录聊天对话中所有关于用户信息、用户偏好、用户计划的记忆片段。'
memory_variable_delete_tip_content: '删除后不可撤销。如应用已发布,更新发布后该应用的用户无法使用该记忆变量,是否继续?'
memory_fragment_delete_all_tip_content: '数据清空后不可撤销,确定要全部清空吗?'
memory_fragment_delete_row_tip_content: '数据删除后不可撤销,确定要删除吗?'
memory_variable_modal:
edit_memory_variable: '编辑记忆变量'
......@@ -259,6 +270,9 @@ personal_space_module:
default_value_placeholder: '请输入'
name_placeholder: '请输入名称'
add_variable: '新增变量'
memory_variable_add_now: '立即添加'
none_memory_variable: '暂无记忆变量'
add_variable_message: '添加记忆变量,更好地记录用户特征、用户信息'
memory_variable_rules:
name_not_null: '请输入名称'
......@@ -388,3 +402,8 @@ multi_model_dialogue_module:
please_select_model_first: '请先选择模型'
replace_configuration_tip: '是否将该模型的配置覆盖到原来的配置项上'
open_new_conversation: '已开启新会话'
applications_square_module:
create_application_btn_text: '创建应用'
all_application_btn_text: '所有应用'
immediate_use_btn_text: '立即使用'
......@@ -67,8 +67,12 @@ common_module:
removal_failed: '下架失敗'
collect_successfully: '收藏成功'
collect_unsubscribed: '已取消收藏'
cancel: '取消'
preservation: '保存'
open: '開'
close: '關'
delete_tip_title: '删除提示'
wipe_data: '清空數據'
delete_all_tip_title: '清空數據提示'
dialogue_module:
continue_question_message: '你可以繼續提問'
......@@ -144,6 +148,8 @@ router_title_module:
knowledge_document_list: '知識庫文檔列表'
knowledge_document_detail: '知識庫文檔詳情'
multi_model_dialogue: '多模型調試'
explore: '探索'
applications-square: '應用廣場'
personal_space_module:
title: '個人空間'
......@@ -161,7 +167,6 @@ personal_space_module:
channel_popover_text: '查看發佈詳情'
agent_copy: '的副本'
empty_agent_list: '暫無應用'
search_empty_agent_list: '沒有蒐索到相關內容'
delete_agent_dialog_title: '確定要刪除選中的應用嗎?'
delete_agent_dialog_content: '刪除後,如需再次使用,請重新創建'
remove_applications_dialog_title: '確定要下架應用嗎?'
......@@ -237,13 +242,19 @@ personal_space_module:
add_memory_variable: '添加記憶變數'
memory_variable: '記憶變量'
memory_message:
'开发者可根据应用设定记忆变量,应用用户在对话过程中可以录入变量内容,每个变量支持存储一维、单个数据
对话过程中,应用将依据存储的变量值进行答复。下面以「旅游助手」为例:'
memory_variable_message: '记录聊天对话中的一维、单个的应用信息或用户信息,能让智能体回答更加个性化。'
'開發者可根據應用設定記憶變數,應用用戶在對話過程中可以錄入變數內容,每個變數支持存儲一維、單個數據
對話過程中,應用將依據存儲的變數值進行答覆。 下面以「旅遊助手」為例:'
memory_variable_message: '記錄聊天對話中的一維、單個的應用資訊或用戶資訊,能讓智慧體回答更加個性化。'
memory_variable_action_edit: '編輯'
memory_variable_action_copy: '複製名稱'
variable_name: '变量名稱'
variable_value: '变量值'
memory_fragment: '記憶片段'
memory_fragment_message: '開啟記憶片段功能,應用將根據對話內容存儲用戶提及的資訊片段,並依據記憶片段答覆。 下面以「面試助手」為例'
memory_fragment_content: '記錄聊天對話中所有關於用戶資訊、用戶偏好、用戶計畫的記憶片段。'
memory_variable_delete_tip_content: '删除後不可撤銷。 如應用已發佈,更新發佈後該應用的用戶無法使用該記憶變數,是否繼續?'
memory_fragment_delete_all_tip_content: '數據清空後不可撤銷,確定要全部清空嗎?'
memory_fragment_delete_row_tip_content: '數據删除後不可撤銷,確定要删除嗎?'
memory_variable_modal:
edit_memory_variable: '編輯記憶變數'
......@@ -259,6 +270,9 @@ personal_space_module:
default_value_placeholder: '請輸入'
name_placeholder: '請輸入名稱'
add_variable: '新增變數'
memory_variable_add_now: '立即添加'
none_memory_variable: '暫無記憶變數'
add_variable_message: '添加記憶變數,更好地記錄用戶特徵、用戶資訊'
memory_variable_rules:
name_not_null: '請求輸入名稱'
......@@ -388,3 +402,9 @@ multi_model_dialogue_module:
please_select_model_first: '請先選擇模型'
replace_configuration_tip: '是否將該模型的配置覆蓋到原來的配置項上'
open_new_conversation: '已開啓新會話'
applications_square_module:
title: '應用廣場'
create_application_btn_text: '創建應用'
all_application_btn_text: '所有應用'
immediate_use_btn_text: '立即使用'
import { type RouteRecordRaw } from 'vue-router'
export default [
{
path: '/explore',
name: 'Explore',
meta: {
rank: 1001,
title: 'router_title_module.explore',
icon: 'mingcute:user-2-line',
belong: 'applications-square',
},
component: () => import('@/layout/index.vue'),
redirect: '/personalSpaceLayout',
children: [
{
path: '/applications-square',
name: 'ApplicationsSquare',
meta: {
rank: 1001,
title: 'router_title_module.applications-square',
belong: 'ApplicationsSquare',
},
component: () => import('@/views/applications-square/applications-square.vue'),
},
],
},
] as RouteRecordRaw[]
......@@ -18,6 +18,7 @@ export function defaultPersonalAppConfigState(): PersonalAppConfigState {
continuousQuestionSystem: '',
continuousQuestionTurn: 3,
variableStructure: [],
isLongMemory: 'N',
},
knowledgeConfig: {
knowledgeIds: [],
......
......@@ -4,6 +4,7 @@ export interface VariableStructureItem {
}
export interface PersonalAppConfigState {
agentType?: string
baseInfo: {
agentId: string //应用ID
agentTitle: string //应用标题
......@@ -11,14 +12,18 @@ export interface PersonalAppConfigState {
agentDesc: string //应用描述
agentSystem: string //角色指令
agentPublishStatus: 'draft' | 'publish' //发布状态 draft-草稿 publish-发布
memberId: number
}
clickNumber?: number
collectNumber?: number
commConfig: {
preamble: string //开场白
featuredQuestions: string[] //推荐问
continuousQuestionStatus: 'default' | 'close' //追问状态
continuousQuestionSystem: string // 追问提示词 customizable时必填
continuousQuestionTurn: number // 追问轮次 1-5 customizable时必填
variableStructure: VariableStructureItem[]
variableStructure: VariableStructureItem[] | null
isLongMemory: string
}
knowledgeConfig: {
knowledgeIds: string[] //知识库ID
......@@ -29,8 +34,11 @@ export interface PersonalAppConfigState {
communicationTurn: number //参考对话轮次 0-100
temperature: number //多样性 0-1.00
}
popularity?: number
modifiedTime: Date
id?: number
isCollect: string
isSale: string
isCopy?: string
agentPublishId: number
}
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import { Star, PreviewOpen } from '@icon-park/vue-next'
import { computed, ref, useTemplateRef, watch } from 'vue'
import {
fetchCollectOrCancelAgentApplication,
fetchGetAgentApplicationList,
fetchGetMallCategoryList,
} from '@/apis/application-square'
import type { PaginationInfo } from '@/components/custom-pagination/custom-pagination.vue'
import type { PersonalAppConfigState } from '@/store/types/personal-app-config'
import { useScroll } from '@vueuse/core'
import { router } from '@/router'
import searchEmptyImage from '@/assets/images/search-empty.png'
import applicationEmptyImage from '@/assets/images/application-empty.png'
const { t } = useI18n()
const searchQuery = ref('')
const checkedClassifyValue = ref(t('applications_square_module.all_application_btn_text'))
const agentApplicationList = ref<PersonalAppConfigState[]>([])
const pagingInfo = ref<PaginationInfo>({
pageNo: 1,
pageSize: 12,
totalPages: 0,
totalRows: 0,
})
const mallCategoryList = ref<string[]>([])
const cardContentWrapRef = useTemplateRef<HTMLDivElement>('cardContentWrapRef')
const isShowCarousel = ref(true)
const smooth = ref(false)
const agentApplicationBottomIsLoading = ref(false)
const agentApplicationClassifyIsLoading = ref(false)
const emptyTableText = ref(t('personal_space_module.agent_module.agent_list_module.empty_agent_list'))
const emptyTableImage = ref(applicationEmptyImage)
const behavior = computed(() => (smooth.value ? 'smooth' : 'auto'))
const { arrivedState } = useScroll(cardContentWrapRef, { behavior })
;(function () {
handleGetAgentApplicationList()
handleGetMallCategoryList()
})()
watch(checkedClassifyValue, () => {
agentApplicationClassifyIsLoading.value = true
if (searchQuery.value.length === 0) {
handleGetAgentApplicationList(true)
} else {
handleGetAgentApplicationList(true, true)
}
})
watch(
() => arrivedState.bottom,
() => {
if (arrivedState.bottom) {
if (pagingInfo.value.pageNo < pagingInfo.value.totalPages) {
agentApplicationBottomIsLoading.value = true
pagingInfo.value.pageNo += 1
if (searchQuery.value.length === 0) {
handleGetAgentApplicationList()
} else {
handleGetAgentApplicationList(false, true)
}
}
}
},
)
function handleGetAgentApplicationList(update = false, search = false) {
const agentType = ref('')
if (agentApplicationBottomIsLoading.value && agentApplicationClassifyIsLoading.value) return
if (search && searchQuery.value.length !== 0) {
isShowCarousel.value = false
} else {
isShowCarousel.value = true
}
if (update) pagingInfo.value.pageNo = 1
checkedClassifyValue.value === t('applications_square_module.all_application_btn_text')
? (agentType.value = '')
: (agentType.value = checkedClassifyValue.value)
const payload = {
search: searchQuery.value,
pagingInfo: pagingInfo.value,
agentType: agentType.value,
}
fetchGetAgentApplicationList<PersonalAppConfigState[]>(payload).then((res) => {
agentApplicationList.value = update ? res.data : [...agentApplicationList.value, ...res.data]
pagingInfo.value = res.pagingInfo as PaginationInfo
emptyTableText.value = searchQuery.value
? t('common_module.search_empty_data')
: t('personal_space_module.agent_module.agent_list_module.empty_agent_list')
emptyTableImage.value =
searchQuery.value && agentApplicationList.value.length === 0 ? searchEmptyImage : applicationEmptyImage
agentApplicationClassifyIsLoading.value = false
agentApplicationBottomIsLoading.value = false
})
}
function handleCollectOrCancelAgentApplication(id: number) {
fetchCollectOrCancelAgentApplication(id).then(() => {
handleGetAgentApplicationList(true)
})
}
function handleGetMallCategoryList() {
mallCategoryList.value[0] = t('applications_square_module.all_application_btn_text')
fetchGetMallCategoryList<string[]>().then((res) => {
if (res.code !== 0) return
mallCategoryList.value = [...mallCategoryList.value, ...res.data]
})
}
function handleToUseAgentApplication(agentId: string) {
router.replace({ name: 'ShareWebApplication', params: { agentId: agentId } })
}
function handleAddAgentApplications() {
router.push({ name: 'PersonalAppSetting' })
}
</script>
<template>
<div ref="cardContentWrapRef" class="flex h-full flex-col overflow-y-auto py-6" style="scrollbar-width: none">
<div class="mb-[19px] flex items-center justify-between">
<div class="flex flex-col">
<div class="flex items-center">
<img src="@/assets/images/applications-square-icon.png" />
<p class="ml-[5px] text-lg">{{ t('router_title_module.application_square') }}</p>
</div>
</div>
<div class="w-5/9">
<n-input
v-model:value="searchQuery"
type="text"
placeholder="搜索"
class="search-input rounded-[26px]! text-[16px]! leading-[32px]! border-[#9ea3ff]! border-[1px] py-[6px] shadow-[0_4px_10px_0px_rgba(103,103,103,.1)]"
clearable
@keyup.enter="handleGetAgentApplicationList(true, true)"
>
<template #prefix>
<div @click="handleGetAgentApplicationList(true)">
<img src="@/assets/images/search.png" width="14" height="14" class="mr-[5px] cursor-pointer" />
</div>
</template>
</n-input>
</div>
<div>
<n-button
type="primary"
:bordered="false"
:focusable="false"
class="w-[86px]!"
@click="handleAddAgentApplications"
>
<span class="text-sm text-[#fff]">{{ t('applications_square_module.create_application_btn_text') }}</span>
</n-button>
</div>
</div>
<div>
<n-collapse-transition :show="isShowCarousel">
<div>
<n-carousel autoplay class="h-[280px] w-full rounded-[10px] object-cover 2xl:object-fill">
<img
class="h-[280px] w-full cursor-pointer object-cover"
src="@/assets/images/application-square-carousel.png"
/>
<img
class="h-[280px] w-full cursor-pointer object-cover"
src="@/assets/images/application-square-carousel.png"
/>
</n-carousel>
</div>
<div class="h-[20px] bg-[#f3f6f9]"></div>
</n-collapse-transition>
<div class="sticky top-[-30px] z-10">
<div class="flex items-center rounded-[5px] bg-white py-[9px] pl-[9px]">
<button
v-for="classify in mallCategoryList"
:key="classify"
:focusable="false"
:class="['classify-radio-button', { active: checkedClassifyValue === classify }]"
class="mr-[4px] w-[86px] cursor-pointer rounded-[5px] border-[1px] border-[#fff] bg-transparent py-[5px] transition-colors duration-300 hover:bg-[#eeefff]"
@click="checkedClassifyValue = classify"
>
{{ classify }}
</button>
</div>
</div>
<n-scrollbar style="max-height: 920px">
<div>
<div class="mt-[14px] min-h-[800px]">
<div class="flex justify-center">
<n-spin v-show="agentApplicationClassifyIsLoading" size="large" />
</div>
<n-grid
v-show="!agentApplicationClassifyIsLoading && agentApplicationList.length !== 0"
cols="l:3 xl:4"
responsive="screen"
>
<n-grid-item
v-for="agentApplicationItem in agentApplicationList"
:key="agentApplicationItem.id"
class="mb-[20px] mr-[15px]"
>
<div
class="rounded-[10px]! max-w-[392px] bg-[#fff] px-[24px] pb-[20px] pt-[20px] shadow-[0_4px_10px_0px_rgba(103,103,103,.1)]"
>
<div class="flex cursor-pointer justify-between">
<div class="popover-trigger mr-[22px] text-[14px]">
<div class="agent-desc h-[23px] w-full max-w-[160px] font-semibold">
<n-ellipsis style="max-width: 180px" :line-clamp="1">
{{ agentApplicationItem.baseInfo.agentTitle }}
<template #tooltip>
<div style="max-width: 230px">
{{ agentApplicationItem.baseInfo.agentTitle }}
</div>
</template>
</n-ellipsis>
</div>
<div class="agent-desc mb-[15px] mt-[18px] h-[44px] w-full max-w-[228px] text-[#999999]">
<n-ellipsis style="max-width: 180px" :line-clamp="2">
{{ agentApplicationItem.baseInfo.agentDesc }}
<template #tooltip>
<div style="max-width: 230px">
{{ agentApplicationItem.baseInfo.agentDesc }}
</div>
</template>
</n-ellipsis>
</div>
</div>
<div class="h-[84px] w-[84px]">
<img :src="agentApplicationItem.baseInfo.agentAvatar" class="h-[84px] w-[84px] rounded-[10px]" />
</div>
</div>
<n-divider class="mt-0! mb-[14px]!" dashed />
<div>
<div class="flex justify-between">
<div class="flex">
<div class="flex">
<Star
theme="two-tone"
size="18"
:fill="agentApplicationItem.isCollect === 'Y' ? ['#ffc06d', '#ffc06d'] : ['#333', '#fff']"
:stroke-width="3"
class="cursor-pointer transition-all delay-150 duration-300 ease-in-out"
@click="handleCollectOrCancelAgentApplication(agentApplicationItem.id!)"
/>
<span class="ml-[6px] text-[12px] text-[#333]">{{ agentApplicationItem.collectNumber }}</span>
</div>
<div class="flex">
<PreviewOpen
theme="outline"
size="18"
fill="#333"
:stroke-width="3"
class="ml-[12px] cursor-pointer"
/>
<span class="ml-[6px] text-[12px] text-[#333]">{{ agentApplicationItem.clickNumber }}</span>
</div>
</div>
<button
class="hover:bg-theme-color text-theme-color border-[#eeefff]! rounded-[5px] border-[1px] bg-[#eeefff] bg-transparent px-[16px] py-[5px] text-[14px] transition-colors duration-300 hover:text-[#fff]"
@click="handleToUseAgentApplication(agentApplicationItem.baseInfo.agentId)"
>
{{ t('applications_square_module.immediate_use_btn_text') }}
</button>
</div>
</div>
</div>
</n-grid-item>
<n-grid-item v-for="item in 4" :key="item" class="mr-[15px]">
<div v-show="agentApplicationBottomIsLoading && pagingInfo.pageNo !== pagingInfo.totalPages">
<n-skeleton text :repeat="6" /> <n-skeleton text style="width: 60%" />
</div>
</n-grid-item>
</n-grid>
<div v-show="agentApplicationList.length === 0">
<div class="flex h-[500px] w-full items-center justify-center">
<div class="flex flex-col items-center justify-center">
<img :src="emptyTableImage" class="mb-[20px] h-[68px] w-[68px]" />
<p class="mb-[14px] text-[14px] text-[#999999]">{{ emptyTableText }}</p>
</div>
</div>
</div>
<div
v-show="agentApplicationList.length > 9 && pagingInfo.pageNo === pagingInfo.totalPages"
class="mb-[50px] mt-[30px] flex justify-center text-center text-[14px] text-[#a9b4cc]"
>
<div class="relative top-[10px] h-[1px] w-[14px] bg-[#a9b4cc]"></div>
<div class="mb-[8px] w-[80px]">
{{ t('personal_space_module.agent_module.agent_list_module.already_bottom') }}
</div>
<div class="relative top-[10px] h-[1px] w-[14px] bg-[#a9b4cc]"></div>
</div>
</div>
</div>
</n-scrollbar>
</div>
</div>
</template>
<style lang="scss" scoped>
.classify-radio-button.active {
color: #000dff;
background-color: #eeefff;
border: 1px #000dff solid;
}
@media (width >= 1536px) and (width <= 1670px) {
.popover-trigger,
.agent-desc {
width: 100%;
max-width: 120px;
}
}
@media (width >= 1371px) and (width <= 1535px) {
.popover-trigger,
.agent-desc {
width: 100%;
max-width: 160px;
}
}
@media (width <= 1370px) {
.popover-trigger,
.agent-desc {
width: 100%;
max-width: 120px;
}
}
.search-input:focus {
.carousel-content {
display: none;
}
}
</style>
......@@ -25,6 +25,7 @@ const continuousQuestionStatus = ref<'default' | 'close'>(personalAppConfigStore
const continuousQuestionList = ref<string[]>([])
const isShowMemoryPreviewModal = ref(false)
const selectedMemoryTabName = ref('memoryVariable')
function handleAddMessageItem(messageItem: ConversationMessageItem) {
messageList.value.push(messageItem)
......@@ -83,7 +84,8 @@ function handleTurnMultiModelDialogue() {
})
}
function handleMemoryVariable() {
function handleOpenMemoryPreviewModal(MemoryTabName: string) {
selectedMemoryTabName.value = MemoryTabName
isShowMemoryPreviewModal.value = true
}
</script>
......@@ -106,10 +108,16 @@ function handleMemoryVariable() {
<span>{{ t('common_module.multi_model_debug') }}</span>
</div>
<div v-show="personalAppConfigStore.commConfig.variableStructure !== null" class="cursor-pointer">
<div
v-show="
personalAppConfigStore.commConfig.variableStructure !== null ||
personalAppConfigStore.commConfig.isLongMemory === 'Y'
"
class="cursor-pointer"
>
<n-popover placement="bottom" trigger="hover" class="p-[4px]!" :show-arrow="false">
<template #trigger>
<div class="flex items-center justify-center px-5 text-[14px]">
<div class="flex items-center justify-center pl-5 text-[14px]">
<Brain theme="outline" size="16" fill="#333" />
<div class="mx-[4px]">
{{ t('personal_space_module.agent_module.agent_setting_module.agent_config_module.memory') }}
......@@ -121,10 +129,17 @@ function handleMemoryVariable() {
<div
v-show="personalAppConfigStore.commConfig.variableStructure !== null"
class="cursor-pointer px-[8px] py-[5px] hover:bg-[#f2f5f9]"
@click="handleMemoryVariable"
@click="handleOpenMemoryPreviewModal('memoryVariable')"
>
{{ t('personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_variable') }}
</div>
<div
v-show="personalAppConfigStore.commConfig.isLongMemory === 'Y'"
class="cursor-pointer px-[8px] py-[5px] hover:bg-[#f2f5f9]"
@click="handleOpenMemoryPreviewModal('memoryFragment')"
>
{{ t('personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_fragment') }}
</div>
</div>
</n-popover>
</div>
......@@ -160,7 +175,7 @@ function handleMemoryVariable() {
@update-continuous-question-status="handleUpdateContinueQuestionStatus"
/>
<MemoryPreviewModal v-model="isShowMemoryPreviewModal" />
<MemoryPreviewModal v-model="isShowMemoryPreviewModal" :data="selectedMemoryTabName" />
</div>
</template>
......
......@@ -80,6 +80,7 @@ const generateAgentAvatarLoading = ref(false) // 是否正在生成图片
const generatePreambleLoading = ref(false) // 是否正在生成开场白
const generateFeaturedQuestionsLoading = ref(false) // 是否正在生成推荐词
const isShowMemoryVariableModal = ref(false) //是否显示记忆变量弹窗
const isOpenLongMemory = ref(personalAppConfigStore.commConfig.isLongMemory === 'Y')
const personalAppFormRef = ref<FormInst | null>(null)
const agentSystemInputRef = ref<InputInst | null>(null)
......@@ -141,6 +142,13 @@ watch(
{ deep: true },
)
watch(
() => personalAppConfigStore.commConfig.isLongMemory,
(newValue) => {
isOpenLongMemory.value = newValue === 'Y'
},
)
onMounted(async () => {
if (router.currentRoute.value.params.agentId) {
isInitGetAgentAppDetail.value = true
......@@ -473,25 +481,27 @@ function handleShowMemoryVariableModal() {
}
function handleDeleteMemoryVariableItem(memoryVariable: object) {
window.$dialog.warning({
title: '删除提示',
content: '删除后不可撤销。如应用已发布,更新发布后该应用的用户无法使用该记忆变量,是否继续?',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
window.$message
.ctWarning(
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_variable_delete_tip_content',
),
t('common_module.delete_tip_title'),
)
.then(() => {
if (personalAppConfigStore.commConfig.variableStructure !== null) {
const updatedVariableStructure = personalAppConfigStore.commConfig.variableStructure.filter(
(variable) => variable !== memoryVariable,
)
personalAppConfigStore.updatePersonalAppConfigState({
commConfig: {
...personalAppConfigStore.commConfig,
variableStructure: personalAppConfigStore.commConfig.variableStructure.filter(
(variable) => variable !== memoryVariable,
),
variableStructure: updatedVariableStructure.length > 0 ? updatedVariableStructure : null,
},
})
window.$message.success('删除成功')
},
onNegativeClick: () => {
window.$message.success('已取消')
},
}
window.$message.success(t('common_module.delete_success_message'))
})
}
......@@ -505,7 +515,18 @@ function handleAddMemoryVariable() {
function handleCopyMemoryVariableName(memoryVariableItem: MemoryVariableForm) {
copyToClip(memoryVariableItem.key)
window.$message.success('成功复制名称')
window.$message.success(t('common_module.copy_success_message'))
}
function handleChangeMemoryFragmentState(value: boolean) {
const LongMemoryValue = value ? 'Y' : 'N'
personalAppConfigStore.updatePersonalAppConfigState({
commConfig: {
...personalAppConfigStore.commConfig,
isLongMemory: LongMemoryValue,
},
})
isOpenLongMemory.value = LongMemoryValue === 'Y'
}
</script>
......@@ -598,7 +619,7 @@ function handleCopyMemoryVariableName(memoryVariableItem: MemoryVariableForm) {
theme="outline"
size="15"
fill="#333"
:stroke-width="2"
:stroke-width="3"
class="ml-1 cursor-pointer text-base text-[#999] outline-none"
/>
</template>
......@@ -647,7 +668,7 @@ function handleCopyMemoryVariableName(memoryVariableItem: MemoryVariableForm) {
theme="outline"
size="15"
fill="#333"
:stroke-width="2"
:stroke-width="3"
class="ml-1 cursor-pointer text-base text-[#999] outline-none"
/>
</template>
......@@ -698,7 +719,7 @@ function handleCopyMemoryVariableName(memoryVariableItem: MemoryVariableForm) {
theme="outline"
size="15"
fill="#333"
:stroke-width="2"
:stroke-width="3"
class="ml-1 cursor-pointer text-base text-[#999] outline-none"
/>
</template>
......@@ -850,7 +871,7 @@ function handleCopyMemoryVariableName(memoryVariableItem: MemoryVariableForm) {
theme="outline"
size="15"
fill="#333"
:stroke-width="2"
:stroke-width="3"
class="ml-1 cursor-pointer text-base text-[#999] outline-none"
/>
</template>
......@@ -982,14 +1003,14 @@ function handleCopyMemoryVariableName(memoryVariableItem: MemoryVariableForm) {
<template #arrow>
<RightOne theme="multi-color" size="17" :fill="['#333', '#333', '#333', '#333']" />
</template>
<NCollapseItem name="preamble" class="my-[13px]!">
<NCollapseItem name="memoryVariable" class="my-[13px]!">
<template #header>
<span class="w-[60px]">{{
<span class="mr-[5px] w-[60px]">{{
t('personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_variable')
}}</span>
<n-popover trigger="hover" placement="top-start" class="p-[12px]! left-[-120px]!" :show-arrow="false">
<template #trigger>
<Help theme="outline" size="15" fill="#333" :stroke-width="2" class="mt-[2px]" />
<Help theme="outline" size="15" fill="#333" :stroke-width="3" class="mt-[2px]" />
</template>
<div class="w-[650px] text-[14px]">
<div class="m-w-[100%] mb-[16px] mt-[0px] leading-[22px]">
......@@ -1011,7 +1032,7 @@ function handleCopyMemoryVariableName(memoryVariableItem: MemoryVariableForm) {
<Plus
theme="outline"
size="22"
:stroke-width="2"
:stroke-width="3"
class="text-theme-color cursor-pointer"
@click="handleAddMemoryVariable"
/>
......@@ -1050,14 +1071,14 @@ function handleCopyMemoryVariableName(memoryVariableItem: MemoryVariableForm) {
<n-popover placement="bottom" trigger="hover" :show-arrow="false" class="p-[4px]!">
<template #trigger>
<MoreOne theme="outline" size="14" fill="#333" :stroke-width="2" class="mr-[4px] mt-[2px]" />
<MoreOne theme="outline" size="14" fill="#333" :stroke-width="3" class="mr-[4px] mt-[2px]" />
</template>
<div class="text-[12px]">
<div
class="flex h-[30px] w-[90px] cursor-pointer items-center justify-start px-[8px] py-[5px] hover:rounded-[4px] hover:bg-[#f2f5f9]"
@click="handleShowMemoryVariableModal"
>
<Edit theme="outline" size="16" fill="#333" :stroke-width="2" /><span class="ml-[4px]">
<Edit theme="outline" size="16" fill="#333" :stroke-width="3" /><span class="ml-[4px]">
{{
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_variable_action_edit',
......@@ -1069,7 +1090,7 @@ function handleCopyMemoryVariableName(memoryVariableItem: MemoryVariableForm) {
class="flex h-[30px] w-[90px] cursor-pointer items-center justify-start px-[8px] py-[5px] hover:rounded-[4px] hover:bg-[#f2f5f9]"
@click="handleCopyMemoryVariableName(memoryVariableItem)"
>
<Copy theme="outline" size="16" fill="#333" :stroke-width="2" />
<Copy theme="outline" size="16" fill="#333" :stroke-width="3" />
<span class="ml-[4px]">
{{
t(
......@@ -1083,7 +1104,7 @@ function handleCopyMemoryVariableName(memoryVariableItem: MemoryVariableForm) {
class="flex h-[30px] w-[90px] cursor-pointer items-center justify-start px-[8px] py-[5px] hover:rounded-[4px] hover:bg-[#f2f5f9]"
@click="handleDeleteMemoryVariableItem(memoryVariableItem)"
>
<ReduceOne theme="outline" size="16" fill="#333" :stroke-width="2" /><span class="ml-[4px]">
<ReduceOne theme="outline" size="16" fill="#333" :stroke-width="3" /><span class="ml-[4px]">
{{ t('common_module.delete') }}
</span>
</div>
......@@ -1094,6 +1115,55 @@ function handleCopyMemoryVariableName(memoryVariableItem: MemoryVariableForm) {
</div>
<div class="flex flex-1 flex-wrap items-center gap-[12px] overflow-hidden"></div>
</NCollapseItem>
<NCollapseItem name="memoryFragment" class="my-[13px]!">
<template #header>
<span class="mr-[5px] w-[60px]">
{{
t('personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_fragment')
}}
</span>
<n-popover trigger="hover" placement="top-start" class="p-[12px]! left-[-120px]!" :show-arrow="false">
<template #trigger>
<Help theme="outline" size="15" fill="#333" :stroke-width="3" class="mt-[2px]" />
</template>
<div class="w-[650px] text-[14px]">
<div class="m-w-[100%] mb-[16px] mt-[0px] leading-[22px]">
{{
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_fragment_message',
)
}}
</div>
<div>
<img src="@/assets/images/memory-fragment.png" width="650" height="206" />
</div>
</div>
</n-popover>
</template>
<template #header-extra>
<n-switch
v-model:value="isOpenLongMemory"
size="small"
@update:value="handleChangeMemoryFragmentState"
>
<template #checked> {{ t('common_module.open') }} </template>
<template #unchecked> {{ t('common_module.close') }} </template>
</n-switch>
</template>
<div>
<div class="mb-[16px] text-xs text-[#84868c]">
{{
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_fragment_content',
)
}}
</div>
<div class="flex flex-1 flex-wrap items-center gap-[12px] overflow-hidden"></div>
</div>
</NCollapseItem>
</NCollapse>
</div>
</section>
......
<script setup lang="ts">
import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
import { Close } from '@icon-park/vue-next'
import { Close, Delete } from '@icon-park/vue-next'
import { DataTableColumns } from 'naive-ui'
import { ref, watch } from 'vue'
import { MemoryVariableForm } from './memory-variable-modal.vue'
import { useI18n } from 'vue-i18n'
import {
fetchDeleteAllLongMemory,
fetchDeleteLongMemoryByKey,
fetchGetLongMemoryList,
fetchGetMemoryVariableList,
} from '@/apis/memory'
interface MemoryVariable {
key: string
value: string
}
interface LongMemory {
date: string
longMemoryContent: { content: string; time: string }[]
}
interface LongMemoryItem {
timestamp: string
content: string
}
const isShowMemoryPreviewModal = defineModel<boolean>()
const props = defineProps<{
data: string
}>()
const { t } = useI18n()
const memoryVariableColumns = createColumns()
const personalAppConfigStore = usePersonalAppConfigStore()
const memoryVariableData = ref([])
const memoryVariableData = ref<MemoryVariable[]>([])
const longMemoryList = ref<LongMemory[]>([])
const isShowMemoryPreviewModal = defineModel<boolean>()
const isMemoryLoading = ref(false)
const memoryTabsInfo = ref([
{
id: 1,
name: 'memoryVariable',
tabName: t('personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_variable'),
},
])
watch(
() => personalAppConfigStore.commConfig.variableStructure,
(newValue) => {
if (newValue !== null) {
if (!memoryTabsInfo.value.some((tab) => tab.id === 1)) {
memoryTabsInfo.value.unshift({
id: 1,
name: 'memoryVariable',
tabName: t('personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_variable'),
})
}
} else {
memoryTabsInfo.value = memoryTabsInfo.value.filter((tab) => tab.id !== 1)
}
},
{ immediate: true },
)
watch(
() => personalAppConfigStore.commConfig.isLongMemory,
(newValue) => {
if (newValue === 'Y') {
if (!memoryTabsInfo.value.some((tab) => tab.id === 2)) {
memoryTabsInfo.value.push({
id: 2,
name: 'memoryFragment',
tabName: t('personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_fragment'),
})
}
} else {
memoryTabsInfo.value = memoryTabsInfo.value.filter((tab) => tab.id !== 2)
}
},
{ immediate: true },
)
function createColumns(): DataTableColumns<MemoryVariableForm> {
return [
......@@ -24,42 +95,166 @@ function createColumns(): DataTableColumns<MemoryVariableForm> {
},
{
title: t('personal_space_module.agent_module.agent_setting_module.agent_config_module.variable_value'),
key: 'variableDefault',
key: 'value',
},
]
}
watch(
() => personalAppConfigStore.commConfig.variableStructure,
(newValue) => {
if (newValue !== null) {
memoryVariableData.value = JSON.parse(JSON.stringify(newValue))
function handlePreviewModalClose() {
isShowMemoryPreviewModal.value = false
}
function handleDeleteLongMemoryRow(time: string, date: string) {
const agentId = personalAppConfigStore.baseInfo.agentId
const timestamp = date + ' ' + time
window.$message
.ctWarning(
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_fragment_delete_row_tip_content',
),
t('common_module.delete_tip_title'),
)
.then(() => {
fetchDeleteLongMemoryByKey(agentId, timestamp).then(() => {
longMemoryList.value = longMemoryList.value
.map((LongMemoryItem) => {
LongMemoryItem.longMemoryContent = LongMemoryItem.longMemoryContent.filter((item) => {
return item.time !== time || LongMemoryItem.date !== date
})
return LongMemoryItem
})
.filter((memory) => memory.longMemoryContent.length > 0)
window.$message.success(t('common_module.delete_success_message'))
})
})
}
function handleDeleteAllLongMemory() {
const agentId = personalAppConfigStore.baseInfo.agentId
window.$message
.ctWarning(
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_fragment_delete_all_tip_content',
),
t('common_module.delete_tip_title'),
)
.then(() => {
fetchDeleteAllLongMemory(agentId).then(() => {
longMemoryList.value = []
window.$message.success(t('common_module.clear_success_message'))
})
})
}
function handleGetLongMemoryList() {
if (personalAppConfigStore.commConfig.isLongMemory === 'Y') {
fetchGetLongMemoryList(personalAppConfigStore.baseInfo.agentId).then((res) => {
const updateDate = res.data as LongMemoryItem[]
const groupedData: { [key: string]: LongMemory } = updateDate.reduce(
(acc, item: LongMemoryItem) => {
const [date, time] = item.timestamp.split(' ')
const content = item.content
if (!acc[date]) {
acc[date] = { date: date, longMemoryContent: [] }
}
acc[date].longMemoryContent.push({ content: content, time: time })
return acc
},
{ immediate: true },
)
{} as { [key: string]: LongMemory },
)
longMemoryList.value = Object.values(groupedData)
})
}
}
function handlePreviewModalClose() {
isShowMemoryPreviewModal.value = false
function handleGetMemoryVariableList() {
isMemoryLoading.value = true
fetchGetMemoryVariableList(personalAppConfigStore.baseInfo.agentId).then((res) => {
memoryVariableData.value = res.data as MemoryVariable[]
isMemoryLoading.value = false
})
}
function handleModalOpenAfter() {
if (personalAppConfigStore.commConfig.variableStructure !== null) handleGetMemoryVariableList()
if (personalAppConfigStore.commConfig.isLongMemory === 'Y') handleGetLongMemoryList()
}
</script>
<template>
<n-modal v-model:show="isShowMemoryPreviewModal" class="h-auto max-h-[720px]" :mask-closable="false">
<n-modal
v-model:show="isShowMemoryPreviewModal"
class="h-auto max-h-[720px]"
:on-after-enter="handleModalOpenAfter"
:mask-closable="false"
>
<div class="flex flex-col items-center justify-center">
<div class="max-h-[720px] w-[880px] rounded-lg bg-white p-[24px]">
<div class="max-h-[720px] min-h-[500px] w-[880px] rounded-lg bg-white p-[24px]">
<div class="flex items-center justify-end text-[20px]">
<Close theme="outline" size="18" fill="#00000073" class="cursor-pointer" @click="handlePreviewModalClose" />
</div>
<div class="">
<n-tabs type="line" animated>
<n-tab-pane
name="oasis"
:tab="t('personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_variable')"
>
<div class="flex max-h-[490px] justify-center overflow-y-hidden bg-[#f3f4fb]">
<div>
<n-tabs type="line" :default-value="props.data" animated>
<n-tab-pane v-for="tabs in memoryTabsInfo" :key="tabs.id" :name="tabs.name" :tab="tabs.tabName">
<div v-show="isMemoryLoading" class="flex h-[370px] items-center justify-center">
<n-spin size="large" />
</div>
<div v-show="!isMemoryLoading">
<div v-if="tabs.name === 'memoryVariable'" class="flex max-h-[490px] justify-center overflow-y-hidden">
<n-data-table :columns="memoryVariableColumns" :max-height="440" :data="memoryVariableData" />
</div>
<div v-else>
<div v-show="longMemoryList.length !== 0" class="flex w-full justify-end">
<n-button
strong
secondary
class="text-theme-color! bg-[#eef3fe]! px-[11px]! py-[5px]! border-[1px]!"
@click="handleDeleteAllLongMemory"
>{{ t('common_module.wipe_data') }}</n-button
>
</div>
<n-scrollbar style="max-height: 458px">
<div
v-for="(longMemory, longMemoryIndex) in longMemoryList"
:key="longMemoryIndex"
class="border-b-[1px] border-[#0505050f] py-[12px]"
>
<div class="mb-[24px] mt-[12px] text-[16px] font-semibold">
{{ longMemory.date }}
</div>
<div
v-for="(longMemoryContent, longMemoryContentIndex) in longMemory.longMemoryContent"
:key="longMemoryContentIndex"
class="long-memory-content mb-[16px] flex justify-between"
>
<div class="flex items-center">
<div class="w-[80px] text-[#84868c]">{{ longMemoryContent.time }}</div>
<div>{{ longMemoryContent.content }}</div>
</div>
<div class="delete-button mr-[20px] pt-[3px] opacity-0 transition-opacity duration-200">
<n-tooltip trigger="hover">
<template #trigger>
<Delete
theme="outline"
size="15"
fill="#333"
:stroke-width="3"
class="cursor-pointer"
@click="handleDeleteLongMemoryRow(longMemoryContent.time, longMemory.date)"
/>
</template>
{{ t('common_module.delete') }}
</n-tooltip>
</div>
</div>
</div>
<div v-show="longMemoryList.length === 0" class="mt-[60px] flex h-[250px] flex-col items-center">
<img src="@/assets/images/empty.png" width="144px" height="100px" />
<div class="text-[14px]">{{ t('common_module.empty_data') }}</div>
</div>
</n-scrollbar>
</div>
</div>
</n-tab-pane>
</n-tabs>
</div>
......@@ -88,4 +283,10 @@ function handlePreviewModalClose() {
}
}
}
.long-memory-content {
&:hover .delete-button {
opacity: 1;
}
}
</style>
......@@ -4,6 +4,7 @@ import { nextTick, ref, shallowReadonly, watch } from 'vue'
import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
import { FormInst, FormItemRule, FormRules } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { cloneDeep } from 'lodash-es'
export interface MemoryVariableForm {
key: string
......@@ -66,18 +67,28 @@ watch(
() => personalAppConfigStore.commConfig.variableStructure,
(newValue) => {
if (newValue !== null) {
memoryVariableTable.value = JSON.parse(JSON.stringify(newValue))
memoryVariableTable.value = cloneDeep(newValue)
} else {
memoryVariableTable.value = []
}
},
{ immediate: true },
)
function handlePreviewModalClose(refresh = false) {
function handleMemoryPreviewModalClose(refresh = false) {
isShowMemoryVariableModal.value = false
memoryVariableTable.value = refresh
? memoryVariableTable.value
: JSON.parse(JSON.stringify(personalAppConfigStore.commConfig.variableStructure))
: personalAppConfigStore.commConfig.variableStructure
? cloneDeep(personalAppConfigStore.commConfig.variableStructure)
: []
if (Array.isArray(memoryVariableTable.value)) {
memoryVariableTable.value = memoryVariableTable.value.filter((item) => item.key)
} else {
memoryVariableTable.value = []
}
}
function handleMemoryVariableFormSave() {
......@@ -99,7 +110,7 @@ function handleMemoryVariableFormSave() {
if (isAllValid) {
personalAppConfigStore.commConfig.variableStructure = memoryVariableTable.value
handlePreviewModalClose(true)
handleMemoryPreviewModalClose(true)
window.$message.success(t('common_module.save_success_message'))
} else {
window.$message.error(t('common_module.save_fail_message'))
......@@ -113,9 +124,9 @@ function handleAddMemoryVariableItem() {
nextTick(() => {
const newIndex = memoryVariableTable.value.length - 1
const input = memoryVariableInputRefs.value[newIndex]
if (input) {
input.focus()
const inputEl = memoryVariableInputRefs.value[newIndex]
if (inputEl) {
inputEl.focus()
}
})
}
......@@ -149,7 +160,13 @@ defineExpose({
)
}}</span
>
<Close theme="outline" size="18" fill="#00000073" class="cursor-pointer" @click="handlePreviewModalClose()" />
<Close
theme="outline"
size="18"
fill="#00000073"
class="cursor-pointer"
@click="handleMemoryPreviewModalClose()"
/>
</div>
<div
class="mb-[12px] mt-[16px] flex items-center justify-center rounded-[4px] bg-[#FFF4E6] px-[15px] pb-[3px] pt-[4px]"
......@@ -159,7 +176,7 @@ defineExpose({
theme="multi-color"
size="14"
:fill="['#ff9326', '#ff9326', '#FFF', '#43CCF8']"
:stroke-width="2"
:stroke-width="3"
/>
</div>
<div class="text-[14px] text-[#151B26]">
......@@ -199,7 +216,7 @@ defineExpose({
</div>
<n-popover trigger="hover" class="p-[12px]!">
<template #trigger>
<Help theme="outline" size="15" fill="#333" :stroke-width="2" class="mt-[2px]" />
<Help theme="outline" size="15" fill="#333" :stroke-width="3" class="mt-[2px]" />
</template>
<div class="mb-[8px] w-[226px]">
{{
......@@ -227,7 +244,7 @@ defineExpose({
</th>
</tr>
</thead>
<tbody>
<tbody v-if="memoryVariableTable.length !== 0">
<tr v-for="(item, index) in memoryVariableTable" :key="index">
<td class="pl-[12px]">
<n-form
......@@ -292,14 +309,14 @@ defineExpose({
/>
</n-form-item>
</td>
<td class="ml-[15px] mt-[10px] flex pl-[12px] pt-[10px]">
<td class="ml-[15px] mt-[5px] flex pl-[12px] pt-[10px]">
<n-tooltip trigger="hover">
<template #trigger>
<Delete
theme="outline"
size="15"
fill="#333"
:stroke-width="2"
:stroke-width="3"
class="mt-[2px] cursor-pointer"
@click="handleDeleteMemoryVariableRow(item)"
/>
......@@ -309,11 +326,49 @@ defineExpose({
</td>
</tr>
</tbody>
<tbody v-else>
<tr>
<td colspan="3">
<div class="flex h-[286px] flex-col items-center">
<img src="@/assets/images/empty.png" width="235px" height="160px" />
<div class="text-[18px]">
{{
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_variable_modal.none_memory_variable',
)
}}
</div>
<div class="mt-[12px] text-[14px] text-[#84868c]">
{{
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_variable_modal.add_variable_message',
)
}}
</div>
<div
class="text-theme-color mt-[6px] flex w-[78px] cursor-pointer"
@click="handleAddMemoryVariableItem"
>
<Plus theme="outline" size="22" :stroke-width="3" class="text-theme-color" />
<span>{{
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_variable_modal.memory_variable_add_now',
)
}}</span>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</n-scrollbar>
<div class="text-theme-color mt-[16px] flex w-[78px] cursor-pointer" @click="handleAddMemoryVariableItem">
<Plus theme="outline" size="22" :stroke-width="2" class="text-theme-color" />
<div
v-show="memoryVariableTable.length !== 0"
class="text-theme-color mt-[16px] flex w-[78px] cursor-pointer"
@click="handleAddMemoryVariableItem"
>
<Plus theme="outline" size="22" :stroke-width="3" class="text-theme-color" />
<span>{{
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.memory_variable_modal.add_variable',
......@@ -323,7 +378,7 @@ defineExpose({
<div class="mt-[24px] flex justify-end">
<button
class="hover:text-theme-color hover:border-theme-color !mr-[12px] box-content !h-[38px] !w-[74px] cursor-pointer rounded-[6px] border-[1px] border-solid border-[#dde3f0] px-[10px] outline-none transition-all duration-300 hover:border-[theme-color]"
@click="handlePreviewModalClose()"
@click="handleMemoryPreviewModalClose()"
>
{{ t('common_module.cancel_btn_text') }}
</button>
......
<script setup lang="ts">
import { computed, ref, useTemplateRef, watch } from 'vue'
import { ref, useTemplateRef, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { Search, More, Star } from '@icon-park/vue-next'
import { Search, MoreOne, Star } from '@icon-park/vue-next'
import { PaginationInfo } from '@/components/custom-pagination/custom-pagination.vue'
import { formatDateTime } from '@/utils/date-formatter'
......@@ -12,20 +12,16 @@ import {
fetchRemoveSalePublishApplication,
} from '@/apis/agent-application.ts'
import { PersonalAppConfigState } from '@/store/types/personal-app-config.ts'
import { useScroll } from '@vueuse/core'
import { router } from '@/router/index.ts'
import SaleApplicationsConfigurationModal from './sale-applications-configuration-modal.vue'
import { defaultPersonalAppConfigState } from '@/store/modules/personal-app-config'
import searchEmptyImage from '@/assets/images/search-empty.png'
import applicationEmptyImage from '@/assets/images/application-empty.png'
import { debounce } from 'lodash-es'
const { t } = useI18n()
const cardContentWrapRef = useTemplateRef<HTMLDivElement>('cardContentWrapRef')
const smooth = ref(false)
const behavior = computed(() => (smooth.value ? 'smooth' : 'auto'))
const { arrivedState } = useScroll(cardContentWrapRef, { behavior })
const selectedPublishStatusValue = ref('')
const isShowSaleApplicationsConfigurationModal = ref(false)
......@@ -65,12 +61,14 @@ const agentAppListBottomLoadingMore = ref(false)
const emptyTableText = ref(t('personal_space_module.agent_module.agent_list_module.application_empty'))
const emptyTableImage = ref()
const emptyTableImage = ref(applicationEmptyImage)
const isAgentAppListBottom = ref(false)
watch(
() => arrivedState.bottom,
() => isAgentAppListBottom.value,
() => {
if (arrivedState.bottom) {
if (isAgentAppListBottom.value) {
if (pagingInfo.value.pageNo < pagingInfo.value.totalPages) {
pagingInfo.value.pageNo += 1
agentAppListBottomLoadingMore.value = true
......@@ -108,7 +106,7 @@ function getApplicationList(isLoadMore = false) {
agentAppList.value = isLoadMore ? [...agentAppList.value, ...res.data] : res.data
pagingInfo.value = res.pagingInfo as PaginationInfo
emptyTableText.value = agentSearchInputValue.value
? t('personal_space_module.agent_module.agent_list_module.search_empty_agent_list')
? t('common_module.search_empty_data')
: t('personal_space_module.agent_module.agent_list_module.application_empty')
emptyTableImage.value =
agentSearchInputValue.value && agentAppList.value.length === 0 ? searchEmptyImage : applicationEmptyImage
......@@ -189,6 +187,17 @@ function handleSelectAddType() {
function handleAnalysisPersonalApp(personalApp: PersonalAppConfigState) {
console.log('分析', personalApp)
}
const handleCardContentScrollDebounce = debounce(
(event: { target: { scrollTop: number; clientHeight: number; scrollHeight: number } }) => {
if (!cardContentWrapRef.value) return
const scrollTop = event.target.scrollTop
const clientHeight = event.target.clientHeight
const scrollHeight = event.target.scrollHeight
isAgentAppListBottom.value = scrollTop + clientHeight >= scrollHeight
},
200,
)
</script>
<template>
......@@ -212,14 +221,15 @@ function handleAnalysisPersonalApp(personalApp: PersonalAppConfigState) {
theme="outline"
size="16"
fill="#999"
:stroke-width="2"
:stroke-width="3"
class="cursor-pointer text-base"
@click="getApplicationList()"
/>
</template>
</NInput>
</div>
<div ref="cardContentWrapRef" class="mb-[50px] h-full overflow-y-auto pb-[16px]" style="scrollbar-width: none">
<n-scrollbar style="max-height: 700px" @scroll="handleCardContentScrollDebounce">
<div ref="cardContentWrapRef" class="pb-[50px]">
<div class="flex justify-center">
<n-spin v-show="agentAppListLoading" size="large" />
</div>
......@@ -231,33 +241,29 @@ function handleAnalysisPersonalApp(personalApp: PersonalAppConfigState) {
class="mb-[20px] mr-[15px]"
>
<div
class="rounded-[10px]! ml-[5px] max-w-[380px] px-[24px] pb-[19px] pt-[13px] shadow-[0_4px_10px_0px_rgba(103,103,103,.3)]"
class="rounded-[10px]! ml-[5px] max-w-[380px] pb-[19px] pl-[24px] pr-[27px] pt-[20px] shadow-[0_4px_10px_0px_rgba(103,103,103,.1)]"
>
<div
class="mt-[6px] flex cursor-pointer justify-between"
class="flex cursor-pointer justify-between"
@click="handleEditPersonalApp(agentAppItem.baseInfo.agentId)"
>
<div class="mb-[19px] mr-[15px] text-[14px]">
<n-popover trigger="hover">
<template #trigger>
<div
class="popover-trigger h-[23px] w-full max-w-[160px] cursor-pointer truncate font-medium text-[#333333]"
>
{{ agentAppItem.baseInfo.agentTitle || '--' }}
<div class="popover-trigger mb-[19px] mr-[15px] text-[14px]">
<div class="agent-desc mb-[58px] h-[23px] w-full max-w-[160px] font-semibold">
<n-ellipsis style="max-width: 180px" :line-clamp="1">
{{ agentAppItem.baseInfo.agentTitle }}
<template #tooltip>
<div style="max-width: 230px">
{{ agentAppItem.baseInfo.agentTitle }}
</div>
</template>
<span>{{ agentAppItem.baseInfo.agentTitle || '--' }}</span>
</n-popover>
<div class="agent-desc my-[18px] h-[44px] w-full max-w-[160px] text-[#999999]">
<n-ellipsis :line-clamp="2">
{{ agentAppItem.baseInfo.agentDesc }}
</n-ellipsis>
</div>
<n-button
:color="agentAppItem.baseInfo.agentPublishStatus === 'draft' ? '#CCCCCC' : '#000DFF'"
class="h-[27px] w-[71px] rounded-[13px] border-[1px] text-[13px]"
ghost
class="h-[27px]! w-[71px]! pl-[17px]! pr-[16px]! pt-[7px]! pb-[8px]! text-[13px]! rounded-[13px] border-[1px]"
round
ghost
>
{{
agentAppItem.baseInfo.agentPublishStatus === 'draft'
......@@ -266,13 +272,13 @@ function handleAnalysisPersonalApp(personalApp: PersonalAppConfigState) {
}}</n-button
>
</div>
<div class="h-[99px] w-[101px]">
<img :src="agentAppItem.baseInfo.agentAvatar" class="h-[99px] min-w-[101px] rounded-[10px]" />
<div class="h-[68px] w-[68px]">
<img :src="agentAppItem.baseInfo.agentAvatar" class="h-[68px] rounded-[10px]" />
</div>
</div>
<div>
<div class="flex justify-between">
<div class="text-[12px] text-[#999999]">
<div class="text-[12px] leading-[12px] text-[#999999]">
{{ t('personal_space_module.agent_module.agent_list_module.modified_time') }}
{{ formatDateTime(agentAppItem.modifiedTime) }}
</div>
......@@ -282,7 +288,7 @@ function handleAnalysisPersonalApp(personalApp: PersonalAppConfigState) {
theme="two-tone"
size="18"
:fill="agentAppItem.isCollect === 'Y' ? ['#ffc06d', '#ffc06d'] : ['#333', '#fff']"
:stroke-width="2"
:stroke-width="3"
class="cursor-pointer transition-all delay-150 duration-300 ease-in-out"
@click="handleApplicationsCollect(agentAppItem)"
/>
......@@ -290,20 +296,14 @@ function handleAnalysisPersonalApp(personalApp: PersonalAppConfigState) {
placement="bottom-end"
trigger="hover"
:show-arrow="false"
class="rounded-[10px]! px-[12px]! cursor-pointer"
class="rounded-[10px]! py-[1px]! mb-[0px]! shadow-[0_4px_10px_0px_rgba(103,103,103,.15)]! px-[12px]! cursor-pointer"
>
<template #trigger>
<More
theme="outline"
size="18"
fill="#333"
:stroke-width="2"
class="ml-[12px] cursor-pointer"
/>
<MoreOne size="16" fill="#333" :stroke-width="3" class="ml-[13px] mt-[1px] cursor-pointer" />
</template>
<div
v-show="agentAppItem.baseInfo.agentPublishStatus !== 'draft'"
class="mb-[10px] w-full rounded-[5px] py-[4px] pl-[5px] text-[14px] text-[#333333] hover:bg-[#f1f1f1]"
class="mb-[10px] mt-[8px] h-[24px] w-full rounded-[4px] py-[5px] pl-[5px] text-[14px] leading-[14px] text-[#333333] hover:bg-[#f1f1f1c7]"
@click="handleAnalysisPersonalApp(agentAppItem)"
>
{{ t('common_module.data_table_module.analysis') }}
......@@ -319,19 +319,21 @@ function handleAnalysisPersonalApp(personalApp: PersonalAppConfigState) {
>
<template #trigger>
<div
class="mb-[10px] w-full rounded-[5px] py-[4px] pl-[5px] text-[14px] text-[#333333] hover:bg-[#f1f1f1]"
class="mb-[10px] h-[24px] w-full rounded-[4px] py-[5px] pl-[5px] text-[14px] leading-[14px] text-[#333333] hover:bg-[#f1f1f1c7]"
>
{{ t('common_module.data_table_module.remove_applications') }}
</div>
</template>
{{
t('personal_space_module.agent_module.agent_list_module.remove_applications_dialog_title')
t(
'personal_space_module.agent_module.agent_list_module.remove_applications_dialog_title',
)
}}
</n-popconfirm>
</div>
<div v-show="agentAppItem.isSale === 'N'">
<div
class="mb-[10px] w-full rounded-[5px] py-[4px] pl-[5px] text-[14px] text-[#333333] hover:bg-[#f1f1f1]"
class="mb-[10px] h-[24px] w-full rounded-[4px] py-[5px] pl-[5px] text-[14px] leading-[14px] text-[#333333] hover:bg-[#f1f1f1c7]"
@click="handleChangeApplicationsSaleStatus(agentAppItem)"
>
{{ t('common_module.data_table_module.listing_applications') }}
......@@ -340,7 +342,7 @@ function handleAnalysisPersonalApp(personalApp: PersonalAppConfigState) {
</div>
<div
class="w-[96px] rounded-[5px] py-[4px] pl-[8px] text-[14px] text-[#F25744] hover:bg-[#f1f1f1]"
class="mb-[8px] mt-[8px] h-[24px] w-[72px] rounded-[4px] py-[5px] pl-[8px] text-[14px] leading-[14px] text-[#F25744] hover:bg-[#f1f1f1c7]"
@click="handleDeletePersonalApp(agentAppItem.baseInfo.agentId)"
>
{{ t('common_module.delete') }}
......@@ -351,9 +353,11 @@ function handleAnalysisPersonalApp(personalApp: PersonalAppConfigState) {
</div>
</div>
</n-grid-item>
<div v-for="number in 4" v-show="agentAppListBottomLoadingMore" :key="number" class="w-[380px]">
<n-skeleton text :repeat="12" />
<n-grid-item v-for="item in 4" :key="item" class="mr-[15px]">
<div v-show="agentAppListBottomLoadingMore && pagingInfo.pageNo !== pagingInfo.totalPages">
<n-skeleton text :repeat="6" /> <n-skeleton text style="width: 60%" />
</div>
</n-grid-item>
</n-grid>
<div v-else>
<div class="flex h-[650px] w-full items-center justify-center">
......@@ -363,7 +367,9 @@ function handleAnalysisPersonalApp(personalApp: PersonalAppConfigState) {
{{ emptyTableText }}
</p>
<NButton
v-show="emptyTableText === t('personal_space_module.agent_module.agent_list_module.application_empty')"
v-show="
emptyTableText === t('personal_space_module.agent_module.agent_list_module.application_empty')
"
type="primary"
:bordered="false"
:focusable="false"
......@@ -375,8 +381,10 @@ function handleAnalysisPersonalApp(personalApp: PersonalAppConfigState) {
</div>
</div>
<div
v-show="pagingInfo.pageNo === pagingInfo.totalPages && agentAppList.length !== 0"
class="mb-[50px] mt-[30px] flex justify-center text-center text-[14px] text-[#a9b4cc]"
v-show="
pagingInfo.pageNo === pagingInfo.totalPages && agentAppList.length !== 0 && pagingInfo.totalRows > 12
"
class="mt-[30px] flex justify-center text-center text-[14px] text-[#a9b4cc]"
>
<div class="relative top-[10px] h-[1px] w-[14px] bg-[#a9b4cc]"></div>
<div class="mb-[8px] w-[80px]">
......@@ -386,6 +394,8 @@ function handleAnalysisPersonalApp(personalApp: PersonalAppConfigState) {
</div>
</div>
</div>
</n-scrollbar>
<SaleApplicationsConfigurationModal
v-model="isShowSaleApplicationsConfigurationModal"
:data="saleApplicationsInfo"
......
<script setup lang="ts">
import { fetchSalePublishApplication } from '@/apis/agent-application'
import { fetchGetMallCategoryList } from '@/apis/application-square'
import { PersonalAppConfigState } from '@/store/types/personal-app-config'
import { Close, Help, Notes, CheckSmall } from '@icon-park/vue-next'
import { ref, watch } from 'vue'
......@@ -23,64 +24,11 @@ const saleApplicationsId = ref(props.data.agentPublishId)
const isClassifyError = ref(false)
const applicationsClassify = [
{
value: 'mediaEntertainment',
label: t(
'personal_space_module.agent_module.agent_setting_module.agent_sale_module.application_classify.media_entertainment',
),
},
{
value: 'educationTraining',
label: t(
'personal_space_module.agent_module.agent_setting_module.agent_sale_module.application_classify.education_training',
),
},
{
value: 'businessServices',
label: t(
'personal_space_module.agent_module.agent_setting_module.agent_sale_module.application_classify.business_services',
),
},
{
value: 'medicalHealth',
label: t(
'personal_space_module.agent_module.agent_setting_module.agent_sale_module.application_classify.medical_health',
),
},
{
value: 'efficiencyTools',
label: t(
'personal_space_module.agent_module.agent_setting_module.agent_sale_module.application_classify.efficiency_tools',
),
},
{
value: 'officePersonnel',
label: t(
'personal_space_module.agent_module.agent_setting_module.agent_sale_module.application_classify.office_personnel',
),
},
{
value: 'marketingCommerce',
label: t(
'personal_space_module.agent_module.agent_setting_module.agent_sale_module.application_classify.marketing_commerce',
),
},
{
value: 'finance',
label: t('personal_space_module.agent_module.agent_setting_module.agent_sale_module.application_classify.finance'),
},
{
value: 'law',
label: t('personal_space_module.agent_module.agent_setting_module.agent_sale_module.application_classify.law'),
},
{
value: 'cultureTourism',
label: t(
'personal_space_module.agent_module.agent_setting_module.agent_sale_module.application_classify.culture_tourism',
),
},
]
const applicationsClassify = ref<string[]>([])
;(function () {
handleGetMallCategoryList()
})()
watch(
() => checkedClassifyValue.value,
......@@ -127,6 +75,13 @@ function handleApplicationReleaseBtn() {
function handleIsCopySwitchUpdateValue(value: string) {
isCopy.value = value
}
function handleGetMallCategoryList() {
fetchGetMallCategoryList().then((res) => {
if (res.code !== 0) return
applicationsClassify.value = res.data as string[]
})
}
</script>
<template>
......@@ -163,22 +118,22 @@ function handleIsCopySwitchUpdateValue(value: string) {
</div>
<div class="text-[#f33e3e]">*</div>
</div>
<div class="flex flex-wrap justify-between">
<div class="flex flex-wrap">
<button
v-for="classify in applicationsClassify"
:key="classify.value"
:class="['classify-radio-button', { active: checkedClassifyValue === classify.value }]"
class="relative mb-[8px] mr-[4px] h-[26px] cursor-pointer rounded-[6px] border-[1px] border-[#edeef7] bg-[#edeef7] px-[8px] text-[12px]"
@click="checkedClassifyValue = classify.value"
:key="classify"
:class="['classify-radio-button', { active: checkedClassifyValue === classify }]"
class="relative mb-[8px] mr-[8px] h-[26px] cursor-pointer rounded-[6px] border-[1px] border-[#edeef7] bg-[#edeef7] px-[8px] text-[12px]"
@click="checkedClassifyValue = classify"
>
<div
v-show="checkedClassifyValue === classify.value"
v-show="checkedClassifyValue === classify"
class="bg-theme-color absolute left-0 top-[-1px] h-[14px] w-[14px] rounded-[3px]"
style="clip-path: polygon(0 0, 100% 0, 0 100%)"
>
<CheckSmall theme="outline" size="10" fill="#fff" />
</div>
{{ classify.label }}
{{ classify }}
</button>
</div>
<div class="mb-[10px] h-[16px] text-red-500">
......@@ -219,7 +174,7 @@ function handleIsCopySwitchUpdateValue(value: string) {
class="hover:text-theme-color hover:border-theme-color !mr-[12px] box-content !h-[38px] !w-[74px] cursor-pointer rounded-[6px] border-[1px] border-solid border-[#dde3f0] px-[10px] outline-none transition-all duration-300 hover:border-[theme-color]"
@click="handleApplicationsSaleSettingModalClose"
>
{{ t('common_module.cancel') }}
{{ t('common_module.cancel_btn_text') }}
</button>
<button
class="bg-theme-color !box-content !h-[38px] !w-[74px] cursor-pointer rounded-[6px] border-[1px] border-solid border-[#dde3f0] bg-[te] px-[10px] text-[#ffffff] transition-all duration-300 hover:bg-[#528EFF]"
......
......@@ -68,8 +68,12 @@ declare namespace I18n {
removal_failed: string
collect_successfully: string
collect_unsubscribed: string
cancel: string
preservation: string
open: string
close: string
delete_tip_title: string
wipe_data: string
delete_all_tip_title: string
dialogue_module: {
continue_question_message: string
......@@ -153,6 +157,8 @@ declare namespace I18n {
knowledge_document_list: string
knowledge_document_detail: string
multi_model_dialogue: string
explore: string
applications_square: string
}
personal_space_module: {
......@@ -173,7 +179,6 @@ declare namespace I18n {
channel_popover_text: string
agent_copy: string
empty_agent_list: string
search_empty_agent_list: string
delete_agent_dialog_title: string
delete_agent_dialog_content: string
}
......@@ -244,6 +249,12 @@ declare namespace I18n {
memory_variable_action_copy: string
variable_name: string
variable_value: string
memory_fragment: string
memory_fragment_message: string
memory_fragment_content: string
memory_variable_delete_tip_content: string
memory_fragment_delete_all_tip_content: string
memory_fragment_delete_row_tip_content: string
memory_variable_modal: {
edit_memory_variable: string
......@@ -259,6 +270,9 @@ declare namespace I18n {
default_value_placeholder: string
name_placeholder: string
add_variable: string
memory_variable_add_now: string
none_memory_variable: string
add_variable_message: string
memory_variable_rules: {
name_not_null: string
......@@ -403,5 +417,12 @@ declare namespace I18n {
replace_configuration_tip: string
open_new_conversation: string
}
applications_square_module: {
title: string
create_application_btn_text: string
all_application_btn_text: string
immediate_use_btn_text: string
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment