This commit is contained in:
lv 2025-08-31 10:58:22 +08:00
parent 86e1a600a7
commit 4a090425c8
11 changed files with 259 additions and 53 deletions

View File

@ -2,9 +2,9 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/images/logo.png" />
<!--<link rel="preload" as="image" href="/src/assets/images/hero-bg.jpg" fetchpriority="high">-->
<link rel="preload" as="image" href="images/hero-bg.jpg" fetchpriority="high">
<link rel="preload" as="image" href="images/logo.png" fetchpriority="high">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>优阅工作室</title>

View File

@ -2,48 +2,58 @@
<t-space v-if="isVisible1" align="center" @click="visibleModelessDrag = true" class="ai_style" >
<img :src="aiImg" alt="勤怠登录页面" width="36px" height="36px">
</t-space>
<t-dialog
v-model:visible="visibleModelessDrag"
:footer="false"
id ="abc"
header="AI助手"
mode="modeless"
showOverlay="true"
draggable
:on-confirm="() => (visibleModelessDrag = false)"
>
<template #body>
<t-chat
layout="both"
style="height: 600px;"
:z-index="3000"
:data="chatList"
:clear-history="chatList.length > 0 && !isStreamLoad"
:text-loading="loading"
:is-stream-load="isStreamLoad"
@on-action="operation"
@clear="clearConfirm"
>
<!-- eslint-disable-next-line vue/no-unused-vars -->
<template #actions="{ item, index }">
<t-chat-action
:content="item.content"
:operation-btn="['good', 'bad', 'replay', 'copy']"
@operation="handleOperation"
/>
</template>
<template #footer>
<t-chat-input v-model="inputValue" :stop-disabled="isStreamLoad" @send="inputEnter" @stop="onStop"> </t-chat-input>
</template>
</t-chat>
</template>
</t-dialog>
<t-config-provider :global-config="globalConfig">
<t-dialog
v-model:visible="visibleModelessDrag"
:footer="false"
id ="abc"
:header="t('ai.title')"
mode="modeless"
showOverlay="true"
draggable
:on-confirm="() => (visibleModelessDrag = false)"
>
<template #body>
<t-chat
layout="both"
style="height: 600px;"
:z-index="3000"
:data="chatList"
:clear-history="chatList.length > 0 && !isStreamLoad"
:text-loading="loading"
:is-stream-load="isStreamLoad"
@on-action="operation"
@clear="clearConfirm"
>
<template #actions="{ item, index }">
<t-chat-action
:content="item.content"
:operation-btn="['good', 'bad', 'replay', 'copy']"
@operation="handleOperation"
/>
</template>
<template #footer>
<t-chat-input v-model="inputValue" :stop-disabled="isStreamLoad" @send="inputEnter" @stop="onStop"> </t-chat-input>
</template>
</t-chat>
</template>
</t-dialog>
</t-config-provider>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
<script setup lang="ts">
import { ref, onMounted, onUnmounted,inject, watch, computed} from 'vue'
import aiImg from '@/assets/ai_img.png'
const visibleModelessDrag = ref(false);
import { useLanguageStore } from '../../store/language'
import { MockSSEResponse } from './ChatAi';
import { globalConfig } from '../../locales/globalConfig'
const visibleModelessDrag = ref(false);
const fetchCancel = ref(null);
const loading = ref(false);
const isStreamLoad = ref(false);
@ -51,6 +61,9 @@ const chatRef = ref(null);
const isShowToBottom = ref(false);
const inputValue = ref('');
const store = useLanguageStore()
// /
const isVisible1 = ref(false)
@ -63,25 +76,48 @@ const handleScroll1 = () => {
};
//
const t = inject<(key: string) => string>('t') || ((key) => key)
//
onMounted(() => {
window.addEventListener('scroll', handleScroll1)
})
//
onUnmounted(() => {
window.removeEventListener('scroll', handleScroll)
window.removeEventListener('scroll', handleScroll1)
})
//
const clearHistoryBtnText = computed(() => {
return t('ai.clearHistory')
})
//
const getFormattedDateTime = ():string => {
const now = new Date();
const year = now.getFullYear().toString().slice(-2); //
const month = (now.getMonth() + 1).toString().padStart(2, '0'); // 0+1
const day = now.getDate().toString().padStart(2, '0');
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
return `[${year}-${month}-${day} ${hours}:${minutes}]`;
};
//
const chatList = ref([
{
avatar: 'https://tdesign.gtimg.com/site/chat-avatar.png',
name: 'youyueAI',
datetime: '今天16:38',
content: '我是你的ai助手有什么可以帮你的。',
datetime: getFormattedDateTime(),
content: t('ai.initContent'),
role: 'assistant',
}
]);
@ -105,6 +141,11 @@ const chatList = ref([
// role: 'user',
// },
// ]);
const handleOperation = function (type, options) {
console.log('handleOperation', type, options);
};
@ -173,6 +214,25 @@ const fetchSSE = async (fetchFn, options) => {
};
//
watch(
() => store.currentLanguage,
(newLang: any, oldLang:any) => {
//
if (chatList.value.length > 0 && chatList.value[chatList.value.length-1].role === 'assistant') {
//
chatList.value[chatList.value.length-1].content = t('ai.initContent')
}
//
//
}
)
const displayText = ref('');
const fullText = ref('');
const isLoading = ref(true);

View File

@ -13,8 +13,8 @@ const messages = {
// 创建 i18n 实例
const i18n = createI18n({
legacy: false, // 使用 Composition API必须设置为 false
locale: 'zh', // 默认语言
fallbackLocale: 'ja', // 回退语言
locale: 'ja', // 默认语言
fallbackLocale: 'zh', // 回退语言
messages
})

View File

@ -1,3 +1,4 @@
import enUs from 'tdesign-vue-next/es/locale/en_US';
export default {
nav: {
home: 'Home',
@ -41,4 +42,10 @@ export default {
timeline: {
title: 'Company History',
},
ai:{
title: 'AIチャット',
initContent: 'こんにちは、何かお手伝いできることはありますか?',
clearHistory: '履歴をクリア',
},
...enUs.chat
}

View File

@ -0,0 +1,55 @@
// 导入所需的语言包
import zhConfig from 'tdesign-vue-next/es/locale/zh_CN';
import enConfig from 'tdesign-vue-next/es/locale/en_US';
import jaConfig from 'tdesign-vue-next/es/locale/ja_JP';
import { merge } from 'lodash-es';
// 全局特性配置,引入英文语言配置包 enConfig
import { ref, watch, computed } from 'vue';
import { useLanguageStore } from '../store/language'
const store = useLanguageStore()
const currentLanguage = computed(() => store.currentLanguage)
// 定义支持的语言类型
// export type Language = 'zh-CN' | 'en-US' | 'ja-JP';
export type Language = 'zh' | 'en' | 'ja';
// 基础自定义配置
const customConfig: GlobalConfigProvider = {
calendar: {},
table: {},
pagination: {},
chat:{},
// 可以添加更多自定义配置
};
// 语言包映射
const localeMap = {
'zh': zhConfig,
'en': enConfig,
'ja': jaConfig,
};
// 响应式全局配置
const globalConfig:GlobalConfigProvider = ref<GlobalConfigProvider>(
merge({}, localeMap[currentLanguage.value], customConfig)
);
// 当语言变化时更新全局配置
watch(currentLanguage, (newLang) => {
// 更新全局配置
globalConfig.value = merge({}, localeMap[newLang], customConfig);
console.log(globalConfig.value)
});
export {
currentLanguage,
globalConfig
};

View File

@ -0,0 +1,54 @@
// 导入所需的语言包
import zhConfig from 'tdesign-vue-next/es/locale/zh_CN';
import enConfig from 'tdesign-vue-next/es/locale/en_US';
import jaConfig from 'tdesign-vue-next/es/locale/ja_JP';
import { merge } from 'lodash-es';
import { type GlobalConfigProvider } from 'tdesign-vue-next';
import { ref, watch, computed } from 'vue';
import { useLanguageStore } from '../store/language'
const store = useLanguageStore()
const currentLanguage = computed(() => store.currentLanguage)
// 定义支持的语言类型
// export type Language = 'zh-CN' | 'en-US' | 'ja-JP';
export type Language = 'zh' | 'en' | 'ja';
// 基础自定义配置
const customConfig: GlobalConfigProvider = {
calendar: {},
table: {},
pagination: {},
chat:{},
// 可以添加更多自定义配置
};
// 语言包映射
const localeMap = {
'zh': zhConfig,
'en': enConfig,
'ja': jaConfig,
};
// 响应式全局配置
const globalConfig = ref<GlobalConfigProvider>(
merge({}, localeMap[currentLanguage.value], customConfig)
);
// 当语言变化时更新全局配置
watch(currentLanguage, (newLang) => {
// 更新全局配置
globalConfig.value = merge({}, localeMap[newLang], customConfig);
console.log(globalConfig.value)
});
export {
currentLanguage,
globalConfig
};

View File

@ -1,3 +1,5 @@
import jaJP from 'tdesign-vue-next/es/locale/ja_JP';
export default {
nav: {
name:'優閲スタジオ',
@ -117,6 +119,13 @@ export default {
timeline: {
title: 'タイムライン',
},
ai:{
title: 'AIチャット',
initContent: 'こんにちは、何かお手伝いできることはありますか?',
clearHistory: '履歴をクリア',
},
chat: {
...jaJP.chat
}
}

View File

@ -1,3 +1,6 @@
import znCh from 'tdesign-vue-next/es/locale/zh_CN';
export default {
nav: {
name:'优阅工作室',
@ -113,4 +116,13 @@ export default {
timeline: {
title: '项目经历',
},
ai:{
title: 'AI助手',
initContent: '我是你的ai助手有什么可以帮你的。',
clearHistory: "清空历史记录11",
},
chat: {
...znCh.chat
}
}

View File

@ -3,8 +3,6 @@ import './style.css'
import App from './App.vue'
import router from './router/index.ts' // 确保路径正确
// 引入Pinia
import { createPinia } from 'pinia'
// 引入TDesign UI组件库
@ -12,7 +10,6 @@ import TDesign from 'tdesign-vue-next'
import TDesignChat from '@tdesign-vue-next/chat'; // 引入chat组件
import 'tdesign-vue-next/es/style/index.css'
const app = createApp(App)
// 必须先 use(router),再挂载
app.use(router)
@ -20,10 +17,16 @@ app.use(router)
// 使用Pinia
app.use(createPinia())
// 使用TDesign
app.use(TDesign)
app.use(TDesignChat)
app.mount('#app')
// 临时打印路由列表,确认配置是否生效

View File

@ -2,7 +2,6 @@ import { defineStore } from 'pinia'
import zh from '../locales/zh'
import ja from '../locales/ja'
// 获取浏览器语言
function getBrowserLanguage() {
// 获取浏览器主语言(如从 "zh-CN" 中提取 "zh-CN" 或从 "zh-TW" 中提取 "zh-TW"
@ -11,7 +10,7 @@ function getBrowserLanguage() {
return 'zh';
}
// 默认返回英语
return 'en';
return 'ja';
}
const lang = getBrowserLanguage()
export const useLanguageStore = defineStore('language', {

View File

@ -3,5 +3,12 @@
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
],
"compilerOptions": {
"moduleResolution": "Node",
"baseUrl": ".",
"paths": {
"*": ["node_modules/*"]
}
}
}