Commit ca9e4b38 authored by nick zheng's avatar nick zheng

feat: 支持多语言

parent e3bd38c7
VITE_APP_ENV = 'DEV'
VITE_APP_NAME = 'POC'
VITE_APP_NAME = 'SuperLink'
VITE_APP_THEME_COLOR = '#000DFF'
VITE_PORT = 8848
......
VITE_APP_ENV = 'PROD'
VITE_APP_NAME = 'POC'
VITE_APP_NAME = 'SuperLink'
VITE_APP_THEME_COLOR = '#000DFF'
VITE_PUBLIC_PATH = /fe
......
<script setup lang="ts">
import { computed, useSlots } from 'vue'
import { useI18n } from 'vue-i18n'
import { modalHeaderStyle, modalContentStyle, modalFooterStyle } from './modal-style'
interface Props {
......@@ -22,14 +23,16 @@ interface Emits {
(e: 'confirm'): void
}
const { t } = useI18n()
const props = withDefaults(defineProps<Props>(), {
height: 240,
width: 500,
borderRadius: 6,
btnLoading: false,
btnDisabled: false,
cancelBtnText: '取 消',
confirmBtnText: '确 认',
cancelBtnText: 'common_module.cancel_btn_text',
confirmBtnText: 'common_module.confirm_btn_text',
labelWidth: 80,
labelPlacement: 'left',
})
......@@ -90,7 +93,7 @@ function handleConfirm() {
<slot v-if="slots.footer" name="footer" />
<div v-else class="flex w-full items-center justify-end">
<NButton class="h-[32px]! rounded-md! px-6!" @click="handleCloseModal"> {{ cancelBtnText }} </NButton>
<NButton class="h-[32px]! rounded-md! px-6!" @click="handleCloseModal"> {{ t(confirmBtnText) }} </NButton>
<NButton
:loading="btnLoading"
type="primary"
......@@ -99,7 +102,7 @@ function handleConfirm() {
class="h-[32px]! px-6! rounded-md! ml-4!"
@click="handleConfirm"
>
{{ confirmBtnText }}
{{ t(confirmBtnText) }}
</NButton>
</div>
</template>
......
<script setup lang="ts">
import { h } from 'vue'
import { useI18n } from 'vue-i18n'
export interface PaginationInfo {
pageNo: number
pageSize: number
......@@ -10,21 +13,23 @@ interface Props {
pagingInfo: PaginationInfo
}
const { t } = useI18n()
const pageSizes = [
{
label: '10 / 每页',
label: () => h('span', {}, '10 / ' + t('common_module.pagination_module.page_unit')),
value: 10,
},
{
label: '20 / 每页',
label: () => h('span', {}, '20 / ' + t('common_module.pagination_module.page_unit')),
value: 20,
},
{
label: '30 / 每页',
label: () => h('span', {}, '30 / ' + t('common_module.pagination_module.page_unit')),
value: 30,
},
{
label: '40 / 每页',
label: () => h('span', {}, '40 / ' + t('common_module.pagination_module.page_unit')),
value: 40,
},
]
......@@ -49,7 +54,10 @@ async function handleUpdatePageSize(pageSize: number) {
<template>
<div class="flex items-center">
<span class="text-[#999]">{{ pagingInfo.totalRows }}</span>
<span class="text-[#999]">
{{ t('common_module.pagination_module.total') }} {{ pagingInfo.totalRows }}
{{ t('common_module.pagination_module.page_no') }}
</span>
<NPagination
class="custom-pagination"
......@@ -59,10 +67,11 @@ async function handleUpdatePageSize(pageSize: number) {
size="medium"
show-quick-jumper
show-size-picker
:goto="() => h('span', {}, t('common_module.pagination_module.goto'))"
@update:page="handleUpdatePageNo"
@update:page-size="handleUpdatePageSize"
/>
<span class="ml-[10px] text-[#999]"></span>
<span class="ml-[10px] text-[#999]">{{ t('common_module.pagination_module.page_size') }}</span>
</div>
</template>
......
<script setup lang="ts">
import { h, readonly, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { Plus } from '@icon-park/vue-next'
import { sidebarMenus } from '@/router/index'
import { type MenuOption } from '@/router/utils'
import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import { useUserStore } from '@/store/modules/user'
const { t } = useI18n()
const currentRoute = useRoute()
const router = useRouter()
......@@ -23,7 +26,7 @@ const avatarOptions = readonly([
// icon: () => h(CustomIcon, { icon: 'bx:user' }),
// },
{
label: '退出登录',
label: () => h('div', {}, t('sidebar_module.dropdown_module.logout')),
key: 'logout',
icon: () => h(CustomIcon, { icon: 'teenyicons:logout-solid' }),
},
......@@ -76,7 +79,7 @@ function handleToLogin() {
@click="handleToPersonAppSettingPage"
>
<Plus theme="outline" size="16" fill="#fff" :stroke-width="4" />
<span class="ml-[5px]">创建应用</span>
<span class="ml-[5px]">{{ t('sidebar_module.create_application_btn_text') }}</span>
</button>
</div>
......@@ -89,7 +92,7 @@ function handleToLogin() {
@click="handleUpdateValue(sidebarMenuItem.routeName, sidebarMenuItem)"
>
<CustomIcon :icon="sidebarMenuItem.icon" class="mr-2 text-base" />
<span class="line-clamp-1 max-w-[150px]">{{ sidebarMenuItem.label }}</span>
<span class="line-clamp-1 max-w-[150px]">{{ t(sidebarMenuItem.label) }}</span>
</li>
</ul>
</div>
......@@ -106,13 +109,15 @@ function handleToLogin() {
<NAvatar round :size="40" object-fit="cover" :src="userStore.userInfo.avatarUrl || defaultAvatar" />
<div class="ml-3 line-clamp-1 max-w-[140px] select-none break-all text-base">
{{ userStore.userInfo.nickName || '未登录' }}
{{ userStore.userInfo.nickName || t('sidebar_module.not_login_text') }}
</div>
</div>
</NDropdown>
<div v-else>
<NButton type="primary" class="w-full! rounded-md!" @click="handleToLogin">立即登录</NButton>
<NButton type="primary" class="w-full! rounded-md!" @click="handleToLogin">
{{ t('sidebar_module.login_btn_text') }}
</NButton>
</div>
</div>
</div>
......
......@@ -21,7 +21,7 @@ watchEffect(() => {
<template>
<NLayout has-sider class="h-full min-w-[1280px]">
<NLayoutSider
class="border-r border-[#e8e9eb] px-2"
class="px-2 shadow-[0_2px_20px_0px_rgba(0,4,65,0.07)]"
collapse-mode="width"
:collapsed-width="64"
:width="layoutSideWidth"
......
......@@ -12,3 +12,5 @@ const i18n = createI18n({
export function setupI18n(app: App) {
app.use(i18n)
}
export default i18n
home_module:
agent_welcome_message: 'Hi, 歡迎使用SuperLink'
agent_description: '在这里,你可以体验多个平台的模型和专属的智能体'
common_module:
cancel_btn_text: ' 消'
confirm_btn_text: ' 认'
copy_success_message: '复制成功'
delete_success_message: '删除成功'
save_success_message: '保存成功'
edit_success_message: '编辑成功'
publish_success_message: '发布成功'
clear_success_message: '清空成功'
dialogue_module:
continue_question_message: '你可以继续提问'
empty_message_content: '[空内容]'
question_input_placeholder: '请输入你的问题进行提问'
generate_warning_message: '以上内容均由AI生成,仅供参考'
clear_message_popover_message: '清空历史会话'
clear_message_dialog_title: '确认要清空对话吗?'
clear_message_dialog_content: '清空对话将清空调试区域所有历史对话内容,确定清空对话吗?'
data_table_module:
action: '操作'
edit: '编辑'
copy: '复制'
delete: '删除'
pagination_module:
page_no: '条'
page_size: '页'
page_unit: '每页'
total: '共'
goto: '跳至'
router_title_module:
login: '登录'
server_error: '服务器错误'
universal: '未找到该页面'
home: '首页'
personal: '个人空间'
app_setting: '应用设置'
agent_application: 'Agent应用'
share_application: '我的Agent应用'
sidebar_module:
create_application_btn_text: '创建应用'
login_btn_text: '立即登录'
not_login_text: '未登录'
dropdown_module:
logout: '退出登录'
personal_space_module:
title: '个人空间'
create_btn_text: '新建'
dropdown_module:
create_agent: '应用'
tab_module:
agent: '应用'
agent_module:
agent_list_module:
search_agent_placeholder: '请输入应用名称或描述'
agent_title: '应用标题'
large_model: '模型名称'
agent_id: '应用ID'
agent_publish_status: '发布状态'
draft_status: '未发布'
publish_status: '已发布'
modified_time: '最近编辑时间'
channel: '渠道'
channel_popover_text: '查看发布详情'
agent_copy: '的副本'
empty_agent_list: '暂无应用'
search_empty_agent_list: '暂⽆搜索结果,请换⼀个关键词进⾏搜索'
delete_agent_dialog_title: '确定要删除选中的应用吗?'
delete_agent_dialog_content: '删除后,如需再次使用,请重新创建'
agent_setting_module:
modified: '已变更'
auto_save_in: '自动保存于'
update_publish_btn_text: '更新发布'
publish_btn_text: ' 布'
please_finish_publish: '请先完成发布'
missing_agent_title_message: '应用名称不能为空'
missing_agent_desc_message: '暂无描述'
agent_options_module:
config: '配置'
publish: '发布'
agent_config_module:
stop_generate: '停止生成'
generating_config_message: '配置信息生成中...'
title: '应用配置'
ai_auto_config: 'AI自动配置'
question_answer_model: '问答模型'
question_answer_model_desc: '用于总结生成回复结果'
topP: '多样性:'
topP_popover_message: '用于控制模型输出的多样性。推荐值为 0,数值越大,模型每次输出内容的差异性越大'
communication_turn: '参考对话轮数:'
communication_turn_popover_message: '传入大模型上下文的最大对话轮数。推荐值为2,数值越大,多轮对话中上下文相关性越强,但Tokens消耗越多'
agent_setting: '应用设定'
base_info: '基本信息'
agent_title_input_placeholder: '请输入应用名称'
agent_title_input_rule_message: '请输入应用名称'
agent_desc_input_placeholder: '请描述你的应用,该描述将在应用发布后固定展示'
update_avatar: '修改头像'
ai_generate: 'AI生成'
agent_system_prompt: '角色指令'
agent_system_popover_message: '通过角色指令(Instruction)功能,你能够精确设定Agent应用的作用范围。包括指定应用将扮演的角色、能够使用的组件以及输出结果的格式与风格。此外,你还可以规定应用不得执行哪些操作等。'
optimize_agent_system_prompt: '优化'
optimize_agent_system_popover_message: 'AI优化'
agent_system_template: '模板'
agent_system_template_message: '
#角色设定
作为一个____,你的任务是____。
#组件能力
你具备____能力。
#要求与限制
1.输出内容的风格要求____
2.输出结果的格式为____
3.输出内容的字数限制不超过____
......'
agent_system_input_placeholder: '请输入希望角色完成的任务目标、具备的组件能力以及对输出答案的要求与限制等'
ability_expand: '能力扩展'
knowledge: '知识'
knowledge_base: '知识库'
knowledge_base_desc: '引用文本数据、表格型知识数据(含FAQ问答,多列索引问答)以及网页数据,实现知识库问答,应用最多可关联5个知识库,请详细填写知识库描述信息以提高问答准确率'
dialogue: '对话'
preamble: '开场白'
preamble_input_placeholder: '请输入开场白'
featured_questions: '推荐问'
featured_questions_input_placeholder: '请输入推荐问'
continuous_question: '追问'
continuous_question_popover_message: '大模型根据对话内容自动生成的追加问题'
continuous_question_default: '默认'
continuous_question_default_desc: '根据用户最近一轮对话,在回复后自动提供3个提问建议。'
continuous_question_close: '关闭'
continuous_question_close_desc: '在每轮回复后,不会提供用户任何提问建议'
preview: '预览与调试'
avatar_oversize_message: '图片不能超过3MB'
generate_format_error_message: '生成内容格式出错啦'
auto_config_modal_module:
modal_title: 'AI生成配置信息'
generate_tip_message: '生成结果将覆盖当前的配置内容,请确认是否继续生成'
auto_config_input_placeholder: '请告诉我你想创建一个什么样的应用,大模型将为你自动生成'
cancel_btn_text: ' 消'
random_generate_btn_text: '随机生成'
ai_generate_btn_text: 'AI生成'
optimize_system_modal_module:
modal_title: '角色指令优化'
confirm_btn_text: '使 用'
regenerate_btn_text: '重新生成'
agent_publish_module:
channel: '发布渠道'
web_channel_name: '网页端'
web_channel_desc: '可通过PC或移动设备立即开始对话'
publish_status: '状态'
published: '已发布'
publish_time_label: '发布'
access_page: '立即访问'
share_link: '分享链接'
copy_share_url_success_message: '链接复制成功,快分享给你的好友吧!'
share_agent_module:
not_login_text: '请先登录'
please: '请先'
login: '登录'
after_action: '后开始提问'
create_agent_btn_text: '创建应用'
login_btn_text: '立即登录'
publish_time_in: '发布于'
create_agent_dialogue_title: '温馨提示'
create_agent_dialogue_content: '为保证您的体验,请通过pc端访问'
create_agent_dialogue_positive_text: '我知道啦'
home_module:
agent_welcome_message: 'Hi, 歡迎使用SuperLink'
agent_description: '在這裏,你可以體驗多個平臺的模型和專屬的智'
common_module:
cancel_btn_text: ' 消'
confirm_btn_text: ' 認'
copy_success_message: '複製成功'
delete_success_message: '刪除成功'
save_success_message: '保存成功'
edit_success_message: '編輯成功'
publish_success_message: '發佈成功'
clear_success_message: '清空成功'
dialogue_module:
continue_question_message: '你可以繼續提問'
empty_message_content: '[空內容]'
question_input_placeholder: '請輸入你的問題進行提問'
generate_warning_message: '以上內容均由AI生成,僅供參考'
clear_message_popover_message: '清空歷史會話'
clear_message_dialog_title: '確認要清空對話嗎?'
clear_message_dialog_content: '清空對話將清空調試區域所有歷史對話內容,確定清空對話嗎?'
data_table_module:
action: '操作'
edit: '編輯'
copy: '複製'
delete: '刪除'
pagination_module:
page_no: '條'
page_size: '頁'
page_unit: '每頁'
total: '共'
goto: '跳至'
router_title_module:
login: '登錄'
server_error: '服務器錯誤'
universal: '未找到該頁面'
home: '首頁'
personal: '個人空間'
app_setting: '應用設置'
agent_application: 'Agent應用'
share_application: '我的Agent應用'
sidebar_module:
create_application_btn_text: '創建應用'
login_btn_text: '立即登錄'
not_login_text: '未登錄'
dropdown_module:
logout: '退出登錄'
personal_space_module:
title: '個人空間'
create_btn_text: '新建'
dropdown_module:
create_agent: '應用'
tab_module:
agent: '應用'
agent_module:
agent_list_module:
search_agent_placeholder: '請輸入應用名稱或描述'
agent_title: '應用標題'
large_model: '模型名稱'
agent_id: '應用ID'
agent_publish_status: '發佈狀態'
draft_status: '未發佈'
publish_status: '已發佈'
modified_time: '最近編輯時間'
channel: '渠道'
channel_popover_text: '查看發佈詳情'
agent_copy: '的副本'
empty_agent_list: '暫無應用'
search_empty_agent_list: '暫⽆搜索結果,請換⼀個關鍵詞進⾏搜索'
delete_agent_dialog_title: '確定要刪除選中的應用嗎?'
delete_agent_dialog_content: '刪除後,如需再次使用,請重新創建'
agent_setting_module:
modified: '已變更'
auto_save_in: '自動保存於'
update_publish_btn_text: '更新發布'
publish_btn_text: ' 布'
please_finish_publish: '請先完成發佈'
missing_agent_title_message: '應用名稱不能爲空'
missing_agent_desc_message: '暫無描述'
agent_options_module:
config: '配置'
publish: '發佈'
agent_config_module:
stop_generate: '停止生成'
generating_config_message: '配置信息生成中...'
title: '應用配置'
ai_auto_config: 'AI自動配置'
question_answer_model: '問答模型'
question_answer_model_desc: '用於總結生成回覆結果'
topP: '多樣性:'
topP_popover_message: '用於控制模型輸出的多樣性。推薦值爲 0,數值越大,模型每次輸出內容的差異性越大'
communication_turn: '參考對話輪數:'
communication_turn_popover_message: '傳入大模型上下文的最大對話輪數。推薦值爲2,數值越大,多輪對話中上下文相關性越強,但Tokens消耗越多'
agent_setting: '應用設定'
base_info: '基本信息'
agent_title_input_placeholder: '請輸入應用名稱'
agent_title_input_rule_message: '請輸入應用名稱'
agent_desc_input_placeholder: '請描述你的應用,該描述將在應用發佈後固定展示'
update_avatar: '修改頭像'
ai_generate: 'AI生成'
agent_system_prompt: '角色指令'
agent_system_popover_message: '通過角色指令(Instruction)功能,你能夠精確設定Agent應用的作用範圍。包括指定應用將扮演的角色、能夠使用的組件以及輸出結果的格式與風格。此外,你還可以規定應用不得執行哪些操作等。'
optimize_agent_system_prompt: '優化'
optimize_agent_system_popover_message: 'AI優化'
agent_system_template: '模板'
agent_system_template_message: "
#角色设定\n
作为一个____,你的任务是____。\n\n
#组件能力\n
你具备____能力。\n\n
#要求与限制\n
1.输出内容的风格要求____\n
2.输出结果的格式为____\n
3.输出内容的字数限制不超过____\n
......"
agent_system_input_placeholder: '請輸入希望角色完成的任務目標、具備的組件能力以及對輸出答案的要求與限制等'
ability_expand: '能力擴展'
knowledge: '知識'
knowledge_base: '知識庫'
knowledge_base_desc: '引用文本數據、表格型知識數據(含FAQ問答,多列索引問答)以及網頁數據,實現知識庫問答,應用最多可關聯5個知識庫,請詳細填寫知識庫描述信息以提高問答準確率'
dialogue: '對話'
preamble: '開場白'
preamble_input_placeholder: '請輸入開場白'
featured_questions: '推薦問'
featured_questions_input_placeholder: '請輸入推薦問'
continuous_question: '追問'
continuous_question_popover_message: '大模型根據對話內容自動生成的追加問題'
continuous_question_default: '默認'
continuous_question_default_desc: '根據用戶最近一輪對話,在回覆後自動提供3個提問建議。'
continuous_question_close: '關閉'
continuous_question_close_desc: '在每輪迴復後,不會提供用戶任何提問建議'
preview: '預覽與調試'
avatar_oversize_message: '圖片不能超過3MB'
generate_format_error_message: '生成內容格式出錯啦'
auto_config_modal_module:
modal_title: 'AI生成配置信息'
generate_tip_message: '生成結果將覆蓋當前的配置內容,請確認是否繼續生成'
auto_config_input_placeholder: '請告訴我你想創建一個什麼樣的應用,大模型將爲你自動生成'
cancel_btn_text: ' 消'
random_generate_btn_text: '隨機生成'
ai_generate_btn_text: 'AI生成'
optimize_system_modal_module:
modal_title: '角色指令優化'
confirm_btn_text: '使 用'
regenerate_btn_text: '重新生成'
agent_publish_module:
channel: '發佈渠道'
web_channel_name: '網頁端'
web_channel_desc: '可通過PC或移動設備立即開始對話'
publish_status: '狀態'
published: '已發佈'
publish_time_label: '發佈'
access_page: '立即訪問'
share_link: '分享鏈接'
copy_share_url_success_message: '鏈接複製成功,快分享給你的好友吧!'
share_agent_module:
not_login_text: '請先登錄'
please: '請先'
login: '登錄'
after_action: '後開始提問'
create_agent_btn_text: '創建應用'
login_btn_text: '立即登錄'
publish_time_in: '發佈於'
create_agent_dialogue_title: '溫馨提示'
create_agent_dialogue_content: '爲保證您的體驗,請通過pc端訪問'
create_agent_dialogue_positive_text: '我知道啦'
import type { Router } from 'vue-router'
import { useUserStore } from '@/store/modules/user'
import i18n from '@/locales'
/** 路由白名单 */
const whitePathList = ['/login']
......@@ -33,7 +34,7 @@ export function createRouterGuards(router: Router) {
if (to.meta.hiddenTitle) {
document.title = ''
} else if (to.meta.title) {
document.title = `${import.meta.env.VITE_APP_NAME}-${to.meta.title}`
document.title = `${import.meta.env.VITE_APP_NAME}-${i18n.global.t(to.meta.title as string)}`
} else {
document.title = import.meta.env.VITE_APP_NAME
}
......
......@@ -6,7 +6,7 @@ export default [
name: 'Login',
meta: {
rank: 1001,
title: '登录',
title: 'router_title_module.login',
},
component: () => import('@/views/login/login.vue'),
},
......@@ -23,7 +23,7 @@ export default [
name: 'ServerError',
meta: {
rank: 1001,
title: '服务器错误',
title: 'router_title_module.server_error',
},
component: () => import('@/views/exception/500.vue'),
},
......@@ -32,7 +32,7 @@ export default [
name: 'Universal',
meta: {
rank: 1001,
title: '未找到该页面',
title: 'router_title_module.universal',
},
component: () => import('@/views/exception/404.vue'),
},
......
......@@ -18,7 +18,7 @@ export default [
name: 'Home',
meta: {
rank: 1001,
title: '首页',
title: 'router_title_module.home',
icon: 'material-symbols:home-outline',
belong: 'Home',
},
......
......@@ -6,7 +6,7 @@ export default [
name: 'PersonalSpace',
meta: {
rank: 1001,
title: '个人空间',
title: 'router_title_module.personal',
icon: 'mingcute:user-2-line',
belong: 'personal-space',
},
......@@ -18,7 +18,7 @@ export default [
name: 'PersonalSpaceLayout',
meta: {
rank: 1001,
title: '个人空间',
title: 'router_title_module.personal',
belong: 'PersonalSpace',
},
component: () => import('@/views/personal-space/personal-space.vue'),
......@@ -29,7 +29,7 @@ export default [
name: 'PersonalSpaceApp',
meta: {
rank: 1001,
title: 'Agent应用',
title: 'router_title_module.agent_application',
belong: 'PersonalSpace',
},
component: () => import('@/views/personal-space/personal-app/personal-app.vue'),
......@@ -43,7 +43,7 @@ export default [
name: 'PersonalAppSetting',
meta: {
rank: 1001,
title: '应用设置',
title: 'router_title_module.app_setting',
icon: 'mingcute:user-2-line',
belong: 'PersonalAppSetting',
hideSideMenItem: true,
......
......@@ -6,7 +6,7 @@ export default [
name: 'ShareWebApplication',
meta: {
rank: 1001,
title: '我的Agent应用',
title: 'router_title_module.share_application',
hideSideMenItem: true,
ignoreAuth: true,
},
......@@ -17,7 +17,7 @@ export default [
name: 'ShareMobileApplication',
meta: {
rank: 1001,
title: '我的Agent应用',
title: 'router_title_module.share_application',
hideSideMenItem: true,
ignoreAuth: true,
},
......
import { h } from 'vue'
import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import { formatDateTime } from '@/utils/date-formatter'
import i18n from '@/locales'
const t = i18n.global.t
export function createChannelPublishColumn(handleChannelPublishTableAction: (actionType: string) => void) {
return [
{
title: '发布渠道',
title: () =>
h('span', {}, t('personal_space_module.agent_module.agent_setting_module.agent_publish_module.channel')),
key: 'channel',
align: 'left',
width: 540,
......@@ -43,9 +47,9 @@ export function createChannelPublishColumn(handleChannelPublishTableAction: (act
h(
'span',
{},
{
default: () => '网页端',
},
t(
'personal_space_module.agent_module.agent_setting_module.agent_publish_module.web_channel_name',
),
),
h(
'span',
......@@ -54,9 +58,9 @@ export function createChannelPublishColumn(handleChannelPublishTableAction: (act
color: '#84868c',
},
},
{
default: () => '可通过PC或移动设备立即开始对话',
},
t(
'personal_space_module.agent_module.agent_setting_module.agent_publish_module.web_channel_desc',
),
),
],
},
......@@ -67,7 +71,8 @@ export function createChannelPublishColumn(handleChannelPublishTableAction: (act
},
},
{
title: '状态',
title: () =>
h('span', {}, t('personal_space_module.agent_module.agent_setting_module.agent_publish_module.publish_status')),
key: 'agentPublishStatus',
align: 'left',
width: 220,
......@@ -95,9 +100,7 @@ export function createChannelPublishColumn(handleChannelPublishTableAction: (act
marginBottom: '4px',
},
},
{
default: () => '已发布',
},
t('personal_space_module.agent_module.agent_setting_module.agent_publish_module.published'),
),
h(
'span',
......@@ -107,7 +110,11 @@ export function createChannelPublishColumn(handleChannelPublishTableAction: (act
},
},
{
default: () => formatDateTime(new Date()) + '发布',
default: () =>
formatDateTime(new Date()) +
t(
'personal_space_module.agent_module.agent_setting_module.agent_publish_module.publish_time_label',
),
},
),
],
......@@ -116,7 +123,7 @@ export function createChannelPublishColumn(handleChannelPublishTableAction: (act
},
},
{
title: '操作',
title: () => h('span', {}, t('common_module.data_table_module.action')),
key: 'action',
align: 'left',
width: '460',
......@@ -154,9 +161,7 @@ export function createChannelPublishColumn(handleChannelPublishTableAction: (act
h(
'span',
{},
{
default: () => '立即访问',
},
t('personal_space_module.agent_module.agent_setting_module.agent_publish_module.access_page'),
),
],
},
......@@ -182,9 +187,7 @@ export function createChannelPublishColumn(handleChannelPublishTableAction: (act
h(
'span',
{},
{
default: () => '分享链接',
},
t('personal_space_module.agent_module.agent_setting_module.agent_publish_module.share_link'),
),
],
},
......
<script setup lang="ts">
import { ref } from 'vue'
import Preamble from './preamble.vue'
import { useI18n } from 'vue-i18n'
import MessageList from './message-list.vue'
import FooterInput from './footer-input.vue'
import { fetchCreateContinueQuestions } from '@/apis/agent-application'
import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
const { t } = useI18n()
const personalAppConfigStore = usePersonalAppConfigStore()
const messageListRef = ref<InstanceType<typeof MessageList> | null>(null)
......@@ -39,14 +42,14 @@ function handleUpdatePageScroll() {
function handleClearAllMessage() {
window.$dialog.warning({
title: '确认要清空对话吗?',
content: '清空对话将清空调试区域所有历史对话内容,确定清空对话吗?',
negativeText: '取消',
positiveText: '确定',
title: t('common_module.dialogue_module.clear_message_dialog_title'),
content: t('common_module.dialogue_module.clear_message_dialog_content'),
negativeText: t('common_module.cancel_btn_text'),
positiveText: t('common_module.confirm_btn_text'),
onPositiveClick: () => {
footerInputRef.value?.blockMessageResponse()
messageList.value = []
window.$message.success('清空成功')
window.$message.success(t('common_module.clear_success_message'))
},
})
}
......@@ -68,7 +71,9 @@ function handleUpdateContinueQuestionStatus(status: 'default' | 'close') {
<template>
<div class="flex h-full min-w-[300px] flex-1 flex-col overflow-hidden bg-[#f2f5f9]">
<p class="mb-[18px] px-5 py-[18px] text-base">预览与调试</p>
<p class="mb-[18px] px-5 py-[18px] text-base">
{{ t('personal_space_module.agent_module.agent_setting_module.agent_config_module.preview') }}
</p>
<div class="flex w-full flex-1 overflow-hidden">
<div v-show="messageList.length === 0" class="flex w-full">
......
<script lang="ts" setup>
import { reactive } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { createChannelPublishColumn } from '../columns'
import { INDEX_URLS } from '@/config/base-url'
import useTableScrollY from '@/composables/useTableScrollY'
import { copyToClip } from '@/utils/copy'
const { t } = useI18n()
const { pageContentWrapRef, tableContentY } = useTableScrollY()
const router = useRouter()
......@@ -37,7 +40,9 @@ function handleAccessPage() {
function handleCopyShareLink() {
const channelUrl = `${INDEX_URLS[window.ENV || 'DEV']}share/web_source/${router.currentRoute.value.params.agentId}`
copyToClip(channelUrl)
window.$message.success('链接复制成功,快分享给你的好友吧!')
window.$message.success(
t('personal_space_module.agent_module.agent_setting_module.agent_publish_module.copy_share_url_success_message'),
)
}
</script>
......
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import CustomModal from '@/components/custom-modal/custom-modal.vue'
import CustomIcon from '@/components/custom-icon/custom-icon.vue'
......@@ -14,6 +15,8 @@ interface Emits {
(e: 'confirm', value: string): void
}
const { t } = useI18n()
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
......@@ -65,27 +68,47 @@ function handleConfirm(inputType: 'random' | 'input') {
<template #content>
<div class="mb-3 flex h-8 w-full items-center rounded bg-[#FFF4E6] px-4">
<CustomIcon icon="ep:warning-filled" class="mr-2 h-4 w-4 text-[#FFA500]" />
<span>生成结果将覆盖当前的配置内容,请确认是否继续生成</span>
<span>
{{
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.auto_config_modal_module.generate_tip_message',
)
}}
</span>
</div>
<NInput
v-model:value="autoConfigInputValue"
type="textarea"
:rows="10"
:disabled="false"
placeholder="请告诉我你想创建一个什么样的应用,大模型将为你自动生成"
:placeholder="
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.auto_config_modal_module.auto_config_input_placeholder',
)
"
class="rounded-lg!"
/>
</template>
<template #footer>
<div class="flex w-full items-center justify-end">
<NButton class="h-[32px]! rounded-md! px-6!" @click="handleCloseModal"> 取 消 </NButton>
<NButton class="h-[32px]! rounded-md! px-6!" @click="handleCloseModal">
{{
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.auto_config_modal_module.cancel_btn_text',
)
}}
</NButton>
<NButton
:loading="isRandomBtnLoading"
class="h-[32px]! rounded-md! px-6! ml-4!"
@click="handleConfirm('random')"
>
随机生成
{{
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.auto_config_modal_module.random_generate_btn_text',
)
}}
</NButton>
<NButton
:loading="isInputBtnLoading"
......@@ -94,7 +117,11 @@ function handleConfirm(inputType: 'random' | 'input') {
class="h-[32px]! px-6! rounded-md! ml-4!"
@click="handleConfirm('input')"
>
AI生成
{{
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.auto_config_modal_module.ai_generate_btn_text',
)
}}
</NButton>
</div>
</template>
......
<script lang="ts" setup>
import { inject } from 'vue'
import { Emitter } from 'mitt'
import { useI18n } from 'vue-i18n'
import CustomLoading from './custom-loading.vue'
interface Props {
continuousQuestionList: string[]
}
const { t } = useI18n()
defineProps<Props>()
const emitter = inject<Emitter<MittEvents>>('emitter')
......@@ -18,7 +21,7 @@ function handleSelectContinueQuestion(continueQuestion: string) {
<template>
<div class="pl-10 text-xs">
<p class="mb-3 mt-5 text-[#84868c]">你可以继续提问</p>
<p class="mb-3 mt-5 text-[#84868c]">{{ t('common_module.dialogue_module.continue_question_message') }}</p>
<div v-if="continuousQuestionList.length === 0" class="mt-4 px-4">
<CustomLoading />
</div>
......
<script setup lang="ts">
import { computed, inject, onUnmounted, ref } from 'vue'
import { Emitter } from 'mitt'
import { useI18n } from 'vue-i18n'
import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import { fetchCustomEventSource } from '@/composables/useEventSource'
import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
......@@ -10,6 +11,8 @@ interface Props {
continuousQuestionStatus: 'default' | 'close'
}
const { t } = useI18n()
const props = defineProps<Props>()
const emit = defineEmits<{
......@@ -26,7 +29,7 @@ const personalAppConfigStore = usePersonalAppConfigStore()
const emitter = inject<Emitter<MittEvents>>('emitter')
const inputeMessageContent = ref('')
const inputMessageContent = ref('')
const isAnswerResponseWait = ref(false)
......@@ -45,7 +48,7 @@ const isAllowClearMessage = computed(() => {
})
const isSendBtnDisabled = computed(() => {
return !inputeMessageContent.value.trim()
return !inputMessageContent.value.trim()
})
onUnmounted(() => {
......@@ -54,7 +57,7 @@ onUnmounted(() => {
})
emitter?.on('selectQuestion', (featuredQuestion) => {
inputeMessageContent.value = featuredQuestion
inputMessageContent.value = featuredQuestion
handleMessageSend()
})
......@@ -73,14 +76,14 @@ function handleEnterKeypress(event: KeyboardEvent) {
if (event.code === 'Enter' && !event.shiftKey) {
event.preventDefault()
if (!inputeMessageContent.value.trim() || isAnswerResponseWait.value) return ''
if (!inputMessageContent.value.trim() || isAnswerResponseWait.value) return ''
handleMessageSend()
}
}
function handleMessageSend() {
if (!inputeMessageContent.value.trim() || isAnswerResponseWait.value) return ''
if (!inputMessageContent.value.trim() || isAnswerResponseWait.value) return ''
const messages: {
content: {
......@@ -94,7 +97,7 @@ function handleMessageSend() {
}[] = []
emit('updateContinuousQuestionStatus', personalAppConfigStore.commConfig.continuousQuestionStatus)
emit('addMessageItem', { ...messageItemFactory(), textContent: inputeMessageContent.value })
emit('addMessageItem', { ...messageItemFactory(), textContent: inputMessageContent.value })
emit('updatePageScroll')
props.messageList.forEach((messageItem) => {
......@@ -112,7 +115,7 @@ function handleMessageSend() {
})
})
inputeMessageContent.value = ''
inputMessageContent.value = ''
isAnswerResponseWait.value = true
emit('addMessageItem', {
......@@ -213,14 +216,16 @@ defineExpose({
@click="handleClearAllMessage"
/>
</template>
<span class="text-xs">清空历史会话</span>
<span class="text-xs">
{{ t('common_module.dialogue_module.clear_message_popover_message') }}
</span>
</NPopover>
</div>
<div class="relative flex-1">
<NInput
v-model:value="inputeMessageContent"
placeholder="请输入你的问题进行提问"
v-model:value="inputMessageContent"
:placeholder="t('common_module.dialogue_module.question_input_placeholder')"
class="rounded-xl! shadow-[0_1px_#09122105,0_1px_1px_#09122105,0_3px_3px_#09122103,0_9px_9px_#09122103]! py-[4px] pr-[50px]"
@keypress="handleEnterKeypress"
/>
......@@ -233,7 +238,9 @@ defineExpose({
</div>
<div class="mt-[9px] pl-10">
<span class="text-xs text-[#84868c]">以上内容均由AI生成,仅供参考</span>
<span class="text-xs text-[#84868c]">
{{ t('common_module.dialogue_module.generate_warning_message') }}
</span>
</div>
</div>
</template>
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import CustomLoading from './custom-loading.vue'
import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
import MarkdownRender from '@/components/markdown-render/markdown-render.vue'
const personalAppConfigStore = usePersonalAppConfigStore()
interface Props {
role: 'user' | 'assistant'
messageItem: ConversationMessageItem
}
const { t } = useI18n()
defineProps<Props>()
const personalAppConfigStore = usePersonalAppConfigStore()
const useAvatar = 'https://mkp-dev.oss-cn-shenzhen.aliyuncs.com/data/upload/20240827/1724728478476.png'
const assistantAvatar = personalAppConfigStore.baseInfo.agentAvatar
</script>
......@@ -36,7 +40,11 @@ const assistantAvatar = personalAppConfigStore.baseInfo.agentAvatar
<div v-else>
<p class="break-all">
<MarkdownRender
:raw-text-content="messageItem.isEmptyContent ? '[空内容]' : messageItem.textContent"
:raw-text-content="
messageItem.isEmptyContent
? t('common_module.dialogue_module.empty_message_content')
: messageItem.textContent
"
:color="role === 'user' ? '#fff' : '#192338'"
/>
</p>
......
<script setup lang="ts">
import { computed, ref, watch, nextTick } from 'vue'
import { useI18n } from 'vue-i18n'
import CustomModal from '@/components/custom-modal/custom-modal.vue'
import { fetchCustomEventSource } from '@/composables/useEventSource'
import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
......@@ -17,6 +18,8 @@ interface Emits {
(e: 'confirm', value: string): void
}
const { t } = useI18n()
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
......@@ -117,7 +120,11 @@ function handleAdditionalPrompt() {
:btn-disabled="isDisabledBtn"
:width="640"
:height="610"
confirm-btn-text="使 用"
:confirm-btn-text="
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.optimize_system_modal_module.confirm_btn_text',
)
"
@close="handleCloseModal"
@confirm="handleAdditionalPrompt"
>
......@@ -135,7 +142,11 @@ function handleAdditionalPrompt() {
<div class="mt-2.5">
<NButton :disabled="generateAgentSystemLoading" class="rounded-md!" @click="handleGenerateAgentSystem">
重新生成
{{
t(
'personal_space_module.agent_module.agent_setting_module.agent_config_module.optimize_system_modal_module.regenerate_btn_text',
)
}}
</NButton>
</div>
</div>
......
......@@ -2,6 +2,7 @@
import { computed, h, onMounted, readonly, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { DropdownOption } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { sidebarMenus } from '@/router/index'
import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import { useUserStore } from '@/store/modules/user'
......@@ -9,6 +10,8 @@ import { usePersonalAppConfigStore } from '@/store/modules/personal-app-config'
import { formatDateTime } from '@/utils/date-formatter'
import { fetchPublishApplication } from '@/apis/agent-application'
const { t } = useI18n()
const defaultAvatar = 'https://gsst-poe-sit.gz.bcebos.com/data/20240910/1725952917468.png'
interface Emits {
......@@ -24,7 +27,7 @@ const personalAppConfigStore = usePersonalAppConfigStore()
const avatarOptions = readonly([
{
label: '退出登录',
label: () => h('span', {}, t('sidebar_module.dropdown_module.logout')),
key: 'logout',
icon: () => h(CustomIcon, { icon: 'teenyicons:logout-solid' }),
},
......@@ -43,11 +46,11 @@ const publishBtnLoading = ref(false)
const agentAppOptionList = [
{
value: 'config',
label: '配置',
label: 'personal_space_module.agent_module.agent_setting_module.agent_options_module.config',
},
{
value: 'publish',
label: '发布',
label: 'personal_space_module.agent_module.agent_setting_module.agent_options_module.publish',
},
]
......@@ -69,7 +72,9 @@ const isShowModifiedTime = computed(() => {
})
const publishBtnText = computed(() => {
return personalAppConfigStore.baseInfo.agentPublishStatus === 'publish' ? '更新发布' : '发 布'
return personalAppConfigStore.baseInfo.agentPublishStatus === 'publish'
? t('personal_space_module.agent_module.agent_setting_module.update_publish_btn_text')
: t('personal_space_module.agent_module.agent_setting_module.publish_btn_text')
})
const isShowPublishBtn = computed(() => {
......@@ -136,7 +141,7 @@ function handleSwtichAgentAppOption(currentTabKey: string) {
async function handlePublishApplication() {
if (!personalAppConfig.value.baseInfo.agentTitle) {
window.$message.warning('应用名称不能为空')
window.$message.warning(t('personal_space_module.agent_module.agent_setting_module.missing_agent_title_message'))
return
}
......@@ -145,7 +150,7 @@ async function handlePublishApplication() {
const res = await fetchPublishApplication(personalAppConfig.value).finally(() => (publishBtnLoading.value = false))
if (res.code === 0) {
window.$message.success('发布成功')
window.$message.success(t('common_module.publish_success_message'))
currentAgentAppTabKey.value = 'publish'
router.replace({
......@@ -186,20 +191,29 @@ async function handlePublishApplication() {
<NPopover trigger="hover">
<template #trigger>
<span class="line-clamp-1 max-w-[200px] break-words text-[#84868c]">
{{ personalAppConfigStore.baseInfo.agentDesc || '暂无描述' }}
{{
personalAppConfigStore.baseInfo.agentDesc ||
t('personal_space_module.agent_module.agent_setting_module.missing_agent_desc_message')
}}
</span>
</template>
<span>{{ personalAppConfigStore.baseInfo.agentDesc || '暂无描述' }}</span>
<span>
{{
personalAppConfigStore.baseInfo.agentDesc ||
t('personal_space_module.agent_module.agent_setting_module.missing_agent_desc_message')
}}
</span>
</NPopover>
<div
v-show="personalAppConfigStore.baseInfo.agentId"
class="ml-3 h-5 rounded bg-white px-2 leading-5 text-[#5c5f66]"
>
已变更
{{ t('personal_space_module.agent_module.agent_setting_module.modified') }}
</div>
<div v-show="isShowModifiedTime" class="ml-3 h-5 rounded-md bg-white px-2 leading-5 text-[#151b26]">
自动保存于 {{ formatDateTime(modifiedTime, 'HH:mm:ss') }}
{{ t('personal_space_module.agent_module.agent_setting_module.auto_save_in') }}
{{ formatDateTime(modifiedTime, 'HH:mm:ss') }}
</div>
</div>
</div>
......@@ -220,11 +234,11 @@ async function handlePublishApplication() {
>
<NPopover v-if="!isAllowClickPublish" trigger="hover">
<template #trigger>
{{ optionItem.label }}
{{ t(optionItem.label) }}
</template>
<span>请先完成发布</span>
<span> {{ t('personal_space_module.agent_module.agent_setting_module.please_finish_publish') }}</span>
</NPopover>
<div v-if="isAllowClickPublish">{{ optionItem.label }}</div>
<div v-if="isAllowClickPublish">{{ t(optionItem.label) }}</div>
</div>
</div>
......
......@@ -3,11 +3,14 @@ import { h } from 'vue'
import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import { PersonalAppConfigState } from '@/store/types/personal-app-config'
import { formatDateTime } from '@/utils/date-formatter'
import i18n from '@/locales'
const t = i18n.global.t
export function createPersonalAppColumn(handlePersonalAppTableAction: (actionType: string, agentId: string) => void) {
return [
{
title: '应用名称',
title: () => h('span', {}, t('personal_space_module.agent_module.agent_list_module.agent_title')),
key: 'agentTitle',
align: 'left',
ellipsis: {
......@@ -86,7 +89,7 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
},
},
{
title: '模型名称',
title: () => h('span', {}, t('personal_space_module.agent_module.agent_list_module.large_model')),
key: 'largeModel',
align: 'left',
ellipsis: {
......@@ -98,7 +101,7 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
},
},
{
title: '应用Id',
title: () => h('span', {}, t('personal_space_module.agent_module.agent_list_module.agent_id')),
key: 'agentId',
align: 'left',
ellipsis: {
......@@ -156,7 +159,7 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
},
},
{
title: '发布状态',
title: () => h('span', {}, t('personal_space_module.agent_module.agent_list_module.agent_publish_status')),
key: 'agentPublishStatus',
align: 'left',
ellipsis: {
......@@ -171,13 +174,13 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
switch (row.baseInfo.agentPublishStatus) {
case 'draft':
publicText = '未发布'
publicText = 'personal_space_module.agent_module.agent_list_module.draft_status'
publicIcon = 'gg:time'
bgColor = '#f2f5f9'
color = '#84868c'
break
case 'publish':
publicText = '已发布'
publicText = 'personal_space_module.agent_module.agent_list_module.publish_status'
publicIcon = 'gg:check-o'
bgColor = '#ecffe6'
color = '#30bf13'
......@@ -220,7 +223,7 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
color,
},
},
publicText,
t(publicText),
),
],
},
......@@ -233,7 +236,7 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
},
},
{
title: '最近编辑时间',
title: () => h('span', {}, t('personal_space_module.agent_module.agent_list_module.modified_time')),
key: 'modifiedTime',
align: 'left',
ellipsis: {
......@@ -245,7 +248,7 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
},
},
{
title: '发布渠道',
title: () => h('span', {}, t('personal_space_module.agent_module.agent_list_module.channel')),
key: 'channel',
align: 'left',
ellipsis: {
......@@ -287,7 +290,8 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
},
),
default: () => h('span', {}, '查看发布详情'),
default: () =>
h('span', {}, t('personal_space_module.agent_module.agent_list_module.channel_popover_text')),
},
)
: '--',
......@@ -295,7 +299,7 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
},
},
{
title: '操作',
title: () => h('span', {}, t('common_module.data_table_module.action')),
key: 'action',
align: 'left',
ellipsis: {
......@@ -312,7 +316,7 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
className: 'text-theme-color cursor-pointer hover:opacity-80',
onClick: () => handlePersonalAppTableAction('edit', row.baseInfo.agentId),
},
{ default: () => '编辑' },
{ default: () => t('common_module.data_table_module.edit') },
),
h(
'span',
......@@ -321,7 +325,7 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
className: 'text-theme-color cursor-pointer hover:opacity-80',
onClick: () => handlePersonalAppTableAction('copy', row.baseInfo.agentId),
},
{ default: () => '复制' },
{ default: () => t('common_module.data_table_module.copy') },
),
h(
'span',
......@@ -330,7 +334,7 @@ export function createPersonalAppColumn(handlePersonalAppTableAction: (actionTyp
className: 'cursor-pointer hover:opacity-80',
onClick: () => handlePersonalAppTableAction('delete', row.baseInfo.agentId),
},
{ default: () => '删除' },
{ default: () => t('common_module.data_table_module.delete') },
),
]
},
......
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import CustomPagination, { PaginationInfo } from '@/components/custom-pagination/custom-pagination.vue'
import { createPersonalAppColumn } from './columns.ts'
......@@ -14,6 +15,8 @@ import {
import { PersonalAppConfigState } from '@/store/types/personal-app-config.ts'
import { copyToClip } from '@/utils/copy.ts'
const { t } = useI18n()
const router = useRouter()
const { pageContentWrapRef, tableContentY } = useTableScrollY(48 + 32 + 16 + 16 + 28)
......@@ -31,6 +34,7 @@ const agentAppList = ref<PersonalAppConfigState[]>([])
const agentSearchInputValue = ref('')
const agentAppListTableLoading = ref(false)
const emptyTableText = ref(t('personal_space_module.agent_module.agent_list_module.empty_agent_list'))
const isLoadingPagination = computed(() => {
return tableContentY.value > 0
......@@ -50,6 +54,9 @@ async function handleGetApplicationList() {
if (res.code === 0) {
agentAppList.value = 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('personal_space_module.agent_module.agent_list_module.empty_agent_list')
}
}
......@@ -75,7 +82,7 @@ function handleClickPersonalAppTableAction(actionType: string, agentId: string)
function handleCopyAgentId(agentId: string) {
copyToClip(agentId)
window.$message.success('复制成功')
window.$message.success(t('common_module.copy_success_message'))
}
function handleOpenPublishDetail(agentId: string) {
......@@ -106,7 +113,7 @@ async function handleCopyPersonalApp(agentId: string) {
const payload = res.data
payload.baseInfo.agentId = ''
payload.baseInfo.agentTitle += '的副本'
payload.baseInfo.agentTitle += t('personal_space_module.agent_module.agent_list_module.agent_copy')
payload.baseInfo.agentPublishStatus = 'draft'
await fetchSaveAgentApplication(payload)
......@@ -117,14 +124,14 @@ async function handleCopyPersonalApp(agentId: string) {
function handleDeletePersonalApp(agentId: string) {
window.$dialog.warning({
title: '确定要删除选中的应用吗?',
content: '删除后,如需再次使用,请重新创建',
negativeText: '取消',
positiveText: '确定',
title: t('personal_space_module.agent_module.agent_list_module.delete_agent_dialog_title'),
content: t('personal_space_module.agent_module.agent_list_module.delete_agent_dialog_content'),
negativeText: t('common_module.cancel_btn_text'),
positiveText: t('common_module.confirm_btn_text'),
onPositiveClick: async () => {
const res = await fetchDeleteApplication(agentId)
if (res.code === 0) {
window.$message.success('删除成功')
window.$message.success(t('common_module.delete_success_message'))
agentAppList.value.length === 1 && (pagingInfo.value.pageNo = pagingInfo.value.pageNo - 1)
await handleGetApplicationList()
}
......@@ -157,7 +164,7 @@ async function handleGetApplicationListUpdatePageSize(pageSize: number) {
<div class="mb-4 flex justify-end">
<NInput
v-model:value="agentSearchInputValue"
placeholder="请输入应用名称或描述"
:placeholder="t('personal_space_module.agent_module.agent_list_module.search_agent_placeholder')"
class="w-[256px]! h-[32px]!"
@keypress="handleEnterKeypress"
>
......@@ -186,7 +193,7 @@ async function handleGetApplicationListUpdatePageSize(pageSize: number) {
<div :style="{ height: tableContentY + 'px' }" class="flex items-center justify-center">
<div class="flex flex-col items-center justify-center">
<img src="@/assets/images/empty.png" alt="empty" class="mb-2 h-[160px] w-[230px]" />
<p class="text-base text-[#84868c]">暂无应用</p>
<p class="text-base text-[#84868c]">{{ emptyTableText }}</p>
</div>
</div>
</template>
......
<script setup lang="ts">
import { h, readonly, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { Plus, ApplicationTwo } from '@icon-park/vue-next'
// import CreateKnowledgeModal, {
// KnowledgeFormDataInterface,
// } from './personal-knowledge/components/create-knowledge-modal.vue'
// import { fetchCreateKnowledge } from '@/apis/knowledge'
const { t } = useI18n()
const currentRoute = useRoute()
const router = useRouter()
......@@ -11,7 +18,7 @@ const routerNameValue = ref(currentRoute.name)
const personalSpaceModuleList = [
{
routeName: 'PersonalSpaceApp',
label: '应用',
label: 'personal_space_module.tab_module.agent',
},
// {
// routeName: 'PersonalSpaceKnowledge',
......@@ -21,7 +28,7 @@ const personalSpaceModuleList = [
const addPersonalSpaceOptions = readonly([
{
label: '应用',
label: () => h('div', {}, t('personal_space_module.dropdown_module.create_agent')),
key: 'addAgent',
icon: () => h(ApplicationTwo, { theme: 'outline', size: 16, fill: '#333' }),
......@@ -33,6 +40,9 @@ const addPersonalSpaceOptions = readonly([
// },
])
const showCreateKnowledgeModal = ref(false)
// const createKnowledgeBtnLoading = ref(false)
watch(
() => currentRoute.fullPath,
() => {
......@@ -49,8 +59,32 @@ function handleSelectAddType(type: string) {
case 'addAgent':
router.push({ name: 'PersonalAppSetting' })
break
case 'addKnowledge':
showCreateKnowledgeModal.value = true
break
}
}
// async function handleCreateKnowledgeNextStep(createKnowledgeData: KnowledgeFormDataInterface) {
// createKnowledgeBtnLoading.value = true
// const res = await fetchCreateKnowledge<{ id: number }>({
// knowledgeName: createKnowledgeData.knowledgeName,
// desc: createKnowledgeData.knowledgeDesc,
// })
// if (res.code === 0) {
// router.push({
// name: 'UploadKnowledge',
// params: {
// id: res.data.id,
// type: createKnowledgeData.knowledgeType + '-' + createKnowledgeData.knowledgeImportType,
// },
// })
// showCreateKnowledgeModal.value = false
// createKnowledgeBtnLoading.value = false
// }
// }
</script>
<template>
......@@ -59,7 +93,7 @@ function handleSelectAddType(type: string) {
<div class="flex flex-col">
<div class="mb-6 flex items-center">
<img src="@/assets/images/personal-icon.png" />
<p class="ml-[5px] text-lg">个人空间</p>
<p class="ml-[5px] text-lg">{{ t('personal_space_module.title') }}</p>
</div>
<ul class="mb-4 flex">
......@@ -74,7 +108,7 @@ function handleSelectAddType(type: string) {
]"
@click="handleChangeRoute(personalSpaceModuleItem.routeName)"
>
{{ personalSpaceModuleItem.label }}
{{ t(personalSpaceModuleItem.label) }}
</li>
</ul>
</div>
......@@ -83,7 +117,7 @@ function handleSelectAddType(type: string) {
<NDropdown trigger="hover" :options="addPersonalSpaceOptions" @select="handleSelectAddType">
<NButton type="primary" :bordered="false" :focusable="false" class="w-[75px]!">
<Plus theme="outline" size="16" fill="#fff" :stroke-width="4" />
<span class="ml-1 text-sm">新建</span>
<span class="ml-1 text-sm">{{ t('personal_space_module.create_btn_text') }}</span>
</NButton>
</NDropdown>
</div>
......@@ -96,6 +130,12 @@ function handleSelectAddType(type: string) {
</Transition>
</RouterView>
</div>
<!-- <CreateKnowledgeModal
v-model:is-show-modal="showCreateKnowledgeModal"
:btn-loading="createKnowledgeBtnLoading"
@confirm="handleCreateKnowledgeNextStep"
/> -->
</div>
</template>
......
<script lang="ts" setup>
import { inject } from 'vue'
import { Emitter } from 'mitt'
import { useI18n } from 'vue-i18n'
import CustomLoading from './custom-loading.vue'
import { useLayoutConfig } from '@/composables/useLayoutConfig'
......@@ -8,6 +9,8 @@ interface Props {
continuousQuestionList: string[]
}
const { t } = useI18n()
defineProps<Props>()
const { isMobile } = useLayoutConfig()
......@@ -21,7 +24,7 @@ function handleSelectContinueQuestion(continueQuestion: string) {
<template>
<div class="text-xs" :class="isMobile ? 'pl-0' : 'pl-10'">
<p class="mb-3 mt-5 text-[#84868c]">你可以继续提问</p>
<p class="mb-3 mt-5 text-[#84868c]">{{ t('common_module.dialogue_module.continue_question_message') }}</p>
<div v-if="continuousQuestionList.length === 0" class="mt-4 px-4">
<CustomLoading />
</div>
......
<script setup lang="ts">
import { computed, inject, onMounted, onUnmounted, ref } from 'vue'
import { Emitter } from 'mitt'
import { useI18n } from 'vue-i18n'
import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import { fetchCustomEventSource } from '@/composables/useEventSource'
import { useUserStore } from '@/store/modules/user'
......@@ -13,6 +14,8 @@ interface Props {
continuousQuestionStatus: 'default' | 'close'
}
const { t } = useI18n()
const props = defineProps<Props>()
const emit = defineEmits<{
......@@ -32,7 +35,7 @@ const userStore = useUserStore()
const emitter = inject<Emitter<MittEvents>>('emitter')
const inputeMessageContent = ref('')
const inputMessageContent = ref('')
const isAnswerResponseWait = ref(false)
......@@ -47,11 +50,11 @@ const isAllowClearMessage = computed(() => {
})
const isSendBtnDisabled = computed(() => {
return !inputeMessageContent.value.trim()
return !inputMessageContent.value.trim()
})
const inputPlaceholder = computed(() => {
return isLogin.value ? '请输入你的问题进行提问' : ''
return isLogin.value ? t('common_module.dialogue_module.question_input_placeholder') : ''
})
const isCreateContinueQuestions = computed(() => {
......@@ -61,11 +64,11 @@ const isCreateContinueQuestions = computed(() => {
onMounted(() => {
emitter?.on('selectQuestion', (featuredQuestion) => {
if (!isLogin.value) {
window.$message.warning('请先登录')
window.$message.warning(t('share_agent_module.not_login_text'))
return
}
inputeMessageContent.value = featuredQuestion
inputMessageContent.value = featuredQuestion
handleMessageSend()
})
})
......@@ -90,7 +93,7 @@ function handleEnterKeypress(event: KeyboardEvent) {
if (event.code === 'Enter' && !event.shiftKey) {
event.preventDefault()
if (!inputeMessageContent.value.trim() || isAnswerResponseWait.value) return ''
if (!inputMessageContent.value.trim() || isAnswerResponseWait.value) return ''
handleMessageSend()
}
......@@ -98,14 +101,14 @@ function handleEnterKeypress(event: KeyboardEvent) {
function handleMessageSend() {
if (!isLogin.value) {
window.$message.warning('请先登录')
window.$message.warning(t('share_agent_module.not_login_text'))
return
}
if (!inputeMessageContent.value.trim() || isAnswerResponseWait.value) return ''
if (!inputMessageContent.value.trim() || isAnswerResponseWait.value) return ''
emit('resetContinueQuestionList')
emit('addMessageItem', { ...messageItemFactory(), textContent: inputeMessageContent.value })
emit('addMessageItem', { ...messageItemFactory(), textContent: inputMessageContent.value })
emit('updatePageScroll')
emit('addMessageItem', {
......@@ -116,11 +119,11 @@ function handleMessageSend() {
})
emit('updatePageScroll')
const input = inputeMessageContent.value
const input = inputMessageContent.value
const currentMessageIndex = props.messageList.length - 1
let replyTextContent = ''
isAnswerResponseWait.value = true
inputeMessageContent.value = ''
inputMessageContent.value = ''
controller = new AbortController()
......@@ -214,13 +217,13 @@ defineExpose({
@click="handleClearAllMessage"
/>
</template>
<span class="text-xs">清空历史会话</span>
<span class="text-xs"> {{ t('common_module.dialogue_module.clear_message_popover_message') }}</span>
</NPopover>
</div>
<div class="relative flex-1">
<NInput
v-model:value="inputeMessageContent"
v-model:value="inputMessageContent"
:placeholder="inputPlaceholder"
:disabled="!isLogin"
class="rounded-xl! shadow-[0_1px_#09122105,0_1px_1px_#09122105,0_3px_3px_#09122103,0_9px_9px_#09122103]! py-[4px] pr-[50px]"
......@@ -233,15 +236,19 @@ defineExpose({
/>
<div v-show="!isLogin" class="absolute left-3 top-[5px] flex h-[34px] items-center text-[#84868c]">
请先
<span class="text-theme-color cursor-pointer px-1 hover:opacity-80" @click="handleToLogin">登录</span>
后开始提问
{{ t('share_agent_module.please') }}
<span class="text-theme-color cursor-pointer px-1 hover:opacity-80" @click="handleToLogin">
{{ t('share_agent_module.login') }}
</span>
{{ t('share_agent_module.after_action') }}
</div>
</div>
</div>
<div class="mt-[9px]">
<span class="flex w-full justify-center text-xs text-[#b8babf]">以上内容均由AI生成,仅供参考</span>
<span class="flex w-full justify-center text-xs text-[#b8babf]">
{{ t('common_module.dialogue_module.generate_warning_message') }}
</span>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import CustomLoading from './custom-loading.vue'
import MarkdownRender from '@/components/markdown-render/markdown-render.vue'
import { PersonalAppConfigState } from '@/store/types/personal-app-config'
......@@ -11,6 +12,8 @@ interface Props {
agentApplicationConfig: PersonalAppConfigState
}
const { t } = useI18n()
const props = defineProps<Props>()
const { isMobile } = useLayoutConfig()
......@@ -56,7 +59,11 @@ const assistantAvatar = computed(() => {
<div v-else>
<p class="break-all">
<MarkdownRender
:raw-text-content="messageItem.isEmptyContent ? '[空内容]' : messageItem.textContent"
:raw-text-content="
messageItem.isEmptyContent
? t('common_module.dialogue_module.empty_message_content')
: messageItem.textContent
"
:color="role === 'user' ? '#fff' : '#192338'"
/>
</p>
......
<script setup lang="ts">
import { useUserStore } from '@/store/modules/user'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
interface Props {
agentTitle: string
}
const { t } = useI18n()
defineProps<Props>()
const emit = defineEmits<{
......@@ -38,10 +41,10 @@ function handleToLogin() {
class="rounded-md! h-[32px]! text-xs! w-[80px]!"
@click="handleToCreateApplication"
>
创建应用
{{ t('share_agent_module.create_agent_btn_text') }}
</NButton>
<NButton v-show="!isLogin" type="primary" class="rounded-md! h-[32px]! text-xs! w-[80px]!" @click="handleToLogin">
<span class="text-xs">立即登录</span>
<span class="text-xs"> {{ t('share_agent_module.login_btn_text') }}</span>
</NButton>
</div>
</header>
......
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import { useUserStore } from '@/store/modules/user'
import { PersonalAppConfigState } from '@/store/types/personal-app-config'
......@@ -9,6 +10,8 @@ interface Props {
agentApplicationConfig: PersonalAppConfigState
}
const { t } = useI18n()
defineProps<Props>()
const emit = defineEmits<{
......@@ -57,7 +60,10 @@ function handleToLogin() {
<p v-show="isLogin" class="mr-4 line-clamp-1 max-w-[120px] break-words break-all">
{{ userStore.userInfo.nickName }}
</p>
<span>发布于 {{ formatDateTime(agentApplicationConfig.modifiedTime) }}</span>
<span>
{{ t('share_agent_module.publish_time_in') }}
{{ formatDateTime(agentApplicationConfig.modifiedTime) }}
</span>
</div>
</div>
</div>
......@@ -68,10 +74,11 @@ function handleToLogin() {
type="primary"
class="rounded-md! h-[32px]! w-[100px]!"
@click="handleToCreateApplication"
>创建应用</NButton
>
{{ t('share_agent_module.create_agent_btn_text') }}
</NButton>
<NButton v-show="!isLogin" type="primary" class="rounded-md! h-[32px]! w-[100px]!" @click="handleToLogin">
立即登录
{{ t('share_agent_module.login_btn_text') }}
</NButton>
</div>
</header>
......
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import PageHeader from './components/mobile-page-header.vue'
import Preamble from './components/preamble.vue'
import MessageList from './components/message-list.vue'
......@@ -11,6 +12,8 @@ import { defaultPersonalAppConfigState } from '@/store/modules/personal-app-conf
import { fetchCreateContinueQuestions, fetchCreateDialogues, fetchGetApplicationInfo } from '@/apis/agent-application'
import { useLayoutConfig } from '@/composables/useLayoutConfig'
const { t } = useI18n()
const router = useRouter()
const userStore = useUserStore()
......@@ -83,9 +86,9 @@ function handleToLoginPage() {
function handleCreateApplicationPage() {
window.$dialog.info({
title: '温馨提示',
content: '为保证您的体验,请通过pc端访问',
positiveText: '我知道啦',
title: t('share_agent_module.create_agent_dialogue_title'),
content: t('share_agent_module.create_agent_dialogue_content'),
positiveText: t('share_agent_module.create_agent_dialogue_positive_text'),
})
}
......@@ -111,14 +114,14 @@ function handleUpdatePageScroll() {
function handleClearAllMessage() {
window.$dialog.warning({
title: '确认要清空对话吗?',
content: '清空对话将清空区域所有历史对话内容,确定清空对话吗?',
negativeText: '取消',
positiveText: '确定',
title: t('common_module.dialogue_module.clear_message_dialog_title'),
content: t('common_module.dialogue_module.clear_message_dialog_content'),
negativeText: t('common_module.cancel_btn_text'),
positiveText: t('common_module.confirm_btn_text'),
onPositiveClick: () => {
footerInputRef.value?.blockMessageResponse()
messageList.value = []
window.$message.success('清空成功')
window.$message.success(t('common_module.clear_success_message'))
},
})
}
......
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import PageHeader from './components/web-page-header.vue'
import Preamble from './components/preamble.vue'
import MessageList from './components/message-list.vue'
......@@ -11,6 +12,8 @@ import { defaultPersonalAppConfigState } from '@/store/modules/personal-app-conf
import { useUserStore } from '@/store/modules/user'
import { useLayoutConfig } from '@/composables/useLayoutConfig'
const { t } = useI18n()
const router = useRouter()
const userStore = useUserStore()
......@@ -115,14 +118,14 @@ function handleUpdatePageScroll() {
function handleClearAllMessage() {
window.$dialog.warning({
title: '确认要清空对话吗?',
content: '清空对话将清空区域所有历史对话内容,确定清空对话吗?',
negativeText: '取消',
positiveText: '确定',
title: t('common_module.dialogue_module.clear_message_dialog_title'),
content: t('common_module.dialogue_module.clear_message_dialog_content'),
negativeText: t('common_module.cancel_btn_text'),
positiveText: t('common_module.confirm_btn_text'),
onPositiveClick: () => {
footerInputRef.value?.blockMessageResponse()
messageList.value = []
window.$message.success('清空成功')
window.$message.success(t('common_module.clear_success_message'))
},
})
}
......
......@@ -6,5 +6,198 @@ declare namespace I18n {
agent_welcome_message: string
agent_description: string
}
common_module: {
cancel_btn_text: string
confirm_btn_text: string
copy_success_message: string
delete_success_message: string
save_success_message: string
edit_success_message: string
publish_success_message: string
clear_success_message: string
dialogue_module: {
continue_question_message: string
empty_message_content: string
question_input_placeholder: string
generate_warning_message: string
clear_message_popover_message: string
clear_message_dialog_title: string
clear_message_dialog_content: string
}
data_table_module: {
action: string
edit: string
copy: string
delete: string
}
pagination_module: {
page_no: string
page_size: string
page_unit: string
total: string
goto: string
}
}
router_title_module: {
login: string
server_error: string
universal: string
home: string
personal: string
app_setting: string
agent_application: string
share_application: string
}
sidebar_module: {
create_application_btn_text: string
login_btn_text: string
not_login_text: string
dropdown_module: {
logout: string
}
}
personal_space_module: {
title: string
create_btn_text: string
dropdown_module: {
create_agent: string
}
tab_module: {
agent: string
agent_module: {
agent_list_module: {
search_agent_placeholder: string
agent_title: string
large_model: string
agent_id: string
agent_publish_status: string
draft_status: string
publish_status: string
modified_time: string
channel: string
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
}
}
agent_setting_module: {
modified: string
auto_save_in: string
update_publish_btn_text: string
publish_btn_text: string
please_finish_publish: string
missing_agent_title_message: string
missing_agent_desc_message: string
agent_options_module: {
config: string
publish: string
}
agent_config_module: {
stop_generate: string
generating_config_message: string
title: string
ai_auto_config: string
question_answer_model: string
question_answer_model_desc: string
topP: string
topP_popover_message: string
communication_turn: string
communication_turn_popover_message: string
agent_setting: string
base_info: string
agent_title_input_placeholder: string
agent_title_input_rule_message: string
agent_desc_input_placeholder: string
update_avatar: string
ai_generate: string
agent_system_prompt: string
agent_system_popover_message: string
optimize_agent_system_prompt: string
optimize_agent_system_popover_message: string
agent_system_template: string
agent_system_template_message: string
agent_system_input_placeholder: string
ability_expand: string
knowledge: string
knowledge_base: string
knowledge_base_desc: string
dialogue: string
preamble: string
preamble_input_placeholder: string
featured_questions: string
featured_questions_input_placeholder: string
continuous_question: string
continuous_question_popover_message: string
continuous_question_default: string
continuous_question_default_desc: string
continuous_question_close: string
continuous_question_close_desc: string
preview: string
avatar_oversize_message: string
generate_format_error_message: string
auto_config_modal_module: {
modal_title: string
generate_tip_message: string
auto_config_input_placeholder: string
cancel_btn_text: string
random_generate_btn_text: string
ai_generate_btn_text: string
}
optimize_system_modal_module: {
modal_title: string
confirm_btn_text: string
regenerate_btn_text: string
}
}
agent_publish_module: {
channel: string
web_channel_name: string
web_channel_desc: string
publish_status: string
published: string
publish_time_label: string
access_page: string
share_link: string
copy_share_url_success_message: string
}
}
}
}
share_agent_module: {
not_login_text: string
please: string
login: string
after_action: string
create_agent_btn_text: string
login_btn_text: string
publish_time_in: string
create_agent_dialogue_title: string
create_agent_dialogue_content: string
create_agent_dialogue_positive_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