配置语言

This commit is contained in:
lzp
2026-03-03 11:10:43 +08:00
parent 84cc6a5607
commit 0e5b3049b6
11 changed files with 260 additions and 105 deletions

View File

@@ -55,3 +55,33 @@ export const getProjectList = (params) => {
params params
}) })
} }
/**
* 修改项目信息
* @param id 项目id
* @param data 修改项目信息参数
* @param data.name 项目名称
* @param data.type 项目类型
* @param data.region 项目区域
* @param data.style 项目风格
* @param data.temperature 项目温度
* @returns 修改项目信息
*/
export const updateProject = (id: string, data: Object) => {
return request({
url: `/api/project/${id}`,
method: 'put',
data
})
}
/**
* 删除项目
* @param id 项目id
* @returns 删除项目
*/
export const deleteProject = (id: string) => {
return request({
url: `/api/project/${id}`,
method: 'delete',
})
}

View File

@@ -26,6 +26,7 @@ export class StateManager {
} }
constructor(options) { constructor(options) {
this.vueFlow = options.vueFlow this.vueFlow = options.vueFlow
this.zoom = ref(1)
this.nodes = ref<NodesItem[]>([]); this.nodes = ref<NodesItem[]>([]);
this.nodes_ = computed(() => { this.nodes_ = computed(() => {
return this.nodes.value.map((node, index) => { return this.nodes.value.map((node, index) => {
@@ -61,7 +62,6 @@ export class StateManager {
return arr return arr
}) })
this.zoom = ref(1)
} }
/** 添加节点 */ /** 添加节点 */
addNode(node: NodesItem) { addNode(node: NodesItem) {

View File

@@ -22,11 +22,11 @@
<p></p> <p></p>
<div class="btn" @click="onSetting"> <div class="btn" @click="onSetting">
<span class="icon"><svg-icon name="setting" size="18" /></span> <span class="icon"><svg-icon name="setting" size="18" /></span>
<span class="label">Settings</span> <span class="label">{{ $t('Home.setting') }}</span>
</div> </div>
<div class="btn" @click="onLogout"> <div class="btn" @click="onLogout">
<span class="icon"><svg-icon name="logout" size="18" /></span> <span class="icon"><svg-icon name="logout" size="18" /></span>
<span class="label">Log out</span> <span class="label">{{ $t('Home.logout') }}</span>
</div> </div>
</div> </div>
</el-popover> </el-popover>

View File

@@ -60,7 +60,45 @@ export default {
history: 'History', history: 'History',
today: 'Today', today: 'Today',
yesterday: 'Yesterday', yesterday: 'Yesterday',
earlierChat: 'Earlier Chat' earlierChat: 'Earlier Chat',
rename: 'Rename',
delete: 'Delete',
setting: 'Setting',
logout: 'Logout',
general: 'General',
profile: 'Profile',
learnMore: 'Learn More',
userName: 'User Name',
email: 'Email',
language: 'Language',
logoutDevice: 'Log out on this device',
region: 'Region',
role: 'Role',
currentAgentProfile: 'Current Agent Profile',
currentNotificationFrequency: 'Current Notification Frequency',
timesPerHour: '{time} times per hour',
userAgreement: 'User Agreement',
privacyPolicy: 'Privacy Policy',
view: 'View',
},
Country:{
unitedStates: 'United States',
singapore: 'Singapore',
australia: 'Australia',
southKorea: 'South Korea',
china: 'China',
italy: 'Italy',
france: 'France',
japan: 'Japan',
canada: 'Canada',
germany: 'Germany',
},
Role: {
designer: 'Designer',
student: 'Student',
teacher: 'Teacher',
parent: 'Parent',
other: 'Other',
}, },
Input: { Input: {
placeholder: 'Please input', placeholder: 'Please input',

View File

@@ -61,7 +61,45 @@ export default {
history: '历史记录', history: '历史记录',
today: '今天', today: '今天',
yesterday: '昨天', yesterday: '昨天',
earlierChat: '更早的' earlierChat: '更早的',
rename: '重命名',
delete: '删除',
setting: '设置',
logout: '退出登录',
general: '通用',
profile: '个人资料',
learnMore: '了解更多',
userName: '用户名',
email: '邮箱',
language: '语言',
logoutDevice: '退出当前设备',
region: '地区',
role: '角色',
currentAgentProfile: '当前智能体个人资料',
currentNotificationFrequency: '当前通知频率',
timesPerHour: '{time} 次/小时',
userAgreement: '用户协议',
privacyPolicy: '隐私政策',
view: '查看',
},
Country: {
unitedStates: '美国',
singapore: '新加坡',
australia: '澳大利亚',
southKorea: '韩国',
china: '中国',
italy: '意大利',
france: '法国',
japan: '日本',
canada: '加拿大',
germany: '德国',
},
Role: {
designer: '设计师',
student: '学生',
teacher: '教师',
parent: '家长',
other: '其他',
}, },
Input: { Input: {
placeholder: '请输入', placeholder: '请输入',
@@ -121,10 +159,10 @@ export default {
restore: '恢复', restore: '恢复',
newChat: '新建对话', newChat: '新建对话',
delete: '删除', delete: '删除',
deleteChat:'删除对话?', deleteChat: '删除对话?',
deleteHint:'删除后将无法恢复该对话。', deleteHint: '删除后将无法恢复该对话。',
restoreChat:'恢复对话?', restoreChat: '恢复对话?',
restoreHint:'恢复后将显示该对话。', restoreHint: '恢复后将显示该对话。',
cancel: '取消', cancel: '取消',
Confirm: '确认', Confirm: '确认',
export: '导出', export: '导出',

View File

@@ -16,7 +16,7 @@
<span class="title" v-show="!isCollapse">{{ $t('Home.home') }}</span> <span class="title" v-show="!isCollapse">{{ $t('Home.home') }}</span>
</div> --> </div> -->
<div class="menu-item" @click="onTest"> <div class="menu-item" @click="onTest">
<span class="title" v-show="!isCollapse">TEST</span> <span class="title">TEST</span>
</div> </div>
<div class="menu-item" @click="onHistory" :class="{ active: showHistory }"> <div class="menu-item" @click="onHistory" :class="{ active: showHistory }">
<span class="icon"><svg-icon name="history" size="24" /></span> <span class="icon"><svg-icon name="history" size="24" /></span>
@@ -34,18 +34,33 @@
@click="onClickHistoryItem(item)" @click="onClickHistoryItem(item)"
:class="{ active: item.id == id }" :class="{ active: item.id == id }"
> >
<span>{{ item.name }}</span> <input
v-show="item.edit"
type="text"
:value="item.name"
ref="inputRef"
:input-id="item.id"
@click.stop
@keyup.enter="(e) => onEnterHistoryItem(e, item)"
@blur="(e) => onBlurHistoryItem(e, item)"
/>
<span class="label" v-show="!item.edit">{{ item.name }}</span>
<el-popover <el-popover
placement="right" placement="right"
trigger="click" trigger="click"
popper-style="padding: 1rem 0.5rem;" popper-style="padding: 1rem 0.5rem;"
v-model:visible="item.visible"
> >
<template #reference> <template #reference>
<span @click.stop class="icon"><svg-icon name="more" size="16" /></span> <span @click.stop class="icon"><svg-icon name="more" size="16" /></span>
</template> </template>
<div class="history-item-menu"> <div class="history-item-menu">
<div class="rename" @click="onRenameHistoryItem(item)">Rename</div> <div class="rename" @click="onRenameHistoryItem(item)">
<div class="delete" @click="onDeleteHistoryItem(item)">Delete</div> {{ $t('Home.rename') }}
</div>
<div class="delete" @click="onDeleteHistoryItem(item)">
{{ $t('Home.delete') }}
</div>
</div> </div>
</el-popover> </el-popover>
</div> </div>
@@ -55,10 +70,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from 'vue' import { computed, ref, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { getProjectList } from '@/api/agent' import { getProjectList, updateProject, deleteProject } from '@/api/agent'
import { FormatDate } from '@/utils/tools' import { FormatDate } from '@/utils/tools'
import MyEvent from '@/utils/myEvent' import MyEvent from '@/utils/myEvent'
const { t: $t } = useI18n() const { t: $t } = useI18n()
@@ -72,34 +87,47 @@
globalStore.setHomeLeftNavCollapse(!isCollapse.value) globalStore.setHomeLeftNavCollapse(!isCollapse.value)
} }
const showHistory = ref(true) const showHistory = ref(true)
const list = ref([])
const todayList = ref([])
const yesterdayList = ref([])
const earlierChatList = ref([])
const historyList = computed(() => { const historyList = computed(() => {
const list = [] const str = 'yyyyMMdd'
if (todayList.value.length > 0) { const today = FormatDate(Date.now(), str)
list.push({ const yesterday = FormatDate(Date.now() - 24 * 60 * 60 * 1000, str)
const todayList = []
const yesterdayList = []
const earlierChatList = []
list.value.forEach((item: any) => {
const date = FormatDate(item.updateTime * 1000, str)
if (date == today) {
todayList.push(item)
} else if (date == yesterday) {
yesterdayList.push(item)
} else {
earlierChatList.push(item)
}
})
const arr = []
if (todayList.length > 0) {
arr.push({
title: true, title: true,
name: $t('Home.today') name: $t('Home.today')
}) })
list.push(...todayList.value) arr.push(...todayList)
} }
if (yesterdayList.value.length > 0) { if (yesterdayList.length > 0) {
list.push({ arr.push({
title: true, title: true,
name: $t('Home.yesterday') name: $t('Home.yesterday')
}) })
list.push(...yesterdayList.value) arr.push(...yesterdayList)
} }
if (earlierChatList.value.length > 0) { if (earlierChatList.length > 0) {
list.push({ arr.push({
title: true, title: true,
name: $t('Home.earlierChat') name: $t('Home.earlierChat')
}) })
list.push(...earlierChatList.value) arr.push(...earlierChatList)
} }
return list return arr
}) })
const onCreateProject = () => { const onCreateProject = () => {
@@ -120,16 +148,37 @@
const onClickHistoryItem = (item: any) => { const onClickHistoryItem = (item: any) => {
router.push({ name: 'agent', params: { id: item.id } }) router.push({ name: 'agent', params: { id: item.id } })
} }
const inputRef = ref(null)
const onRenameHistoryItem = (item: any) => { const onRenameHistoryItem = (item: any) => {
// const index = historyList.value.findIndex((i: any) => i.id == item.id) item.visible = false
// if (index != -1) { item.edit = true
// } nextTick(() => {
inputRef.value.forEach((v: any) => {
const id = v.getAttribute('input-id')
if (id == item.id) v.focus()
})
})
}
const onEnterHistoryItem = (e: any, item: any) => {
e.target.blur()
}
const onBlurHistoryItem = (e: any, item: any) => {
item.edit = false
const name = e.target.value
if (!name) return console.warn('未输入名称,不允许重命名')
item.name = name
updateProject(item.id, { name }).then(() => {
GetProjectList()
})
} }
const onDeleteHistoryItem = (item: any) => { const onDeleteHistoryItem = (item: any) => {
// const index = historyList.value.findIndex((i: any) => i.id == item.id) item.visible = false
// if (index != -1) { deleteProject(item.id).then(() => {
// historyList.value.splice(index, 1) GetProjectList()
// } if (item.id == id.value) {
router.push({ name: 'mainInput' })
}
})
} }
const GetProjectList = async () => { const GetProjectList = async () => {
@@ -137,25 +186,13 @@
page: 1, page: 1,
size: 100 size: 100
}) })
const str = 'yyyyMMdd' list.value = []
const today = FormatDate(Date.now(), str) const arr = res.records || []
const yesterday = FormatDate(Date.now() - 24 * 60 * 60 * 1000, str) arr.forEach((item: any) => {
todayList.value = [] const obj = { ...item, edit: false, visible: false }
yesterdayList.value = [] list.value.push(obj)
earlierChatList.value = []
const list = res.records || []
list.forEach((item: any) => {
const obj = { ...item }
const date = FormatDate(obj.createTime * 1000, str)
if (date == today) {
todayList.value.push(obj)
} else if (date == yesterday) {
yesterdayList.value.push(obj)
} else {
earlierChatList.value.push(obj)
}
}) })
} }
MyEvent.add('updateProjectList', GetProjectList) MyEvent.add('updateProjectList', GetProjectList)
GetProjectList() GetProjectList()
</script> </script>
@@ -177,6 +214,7 @@
--collapse-top-padding: 4.6rem 0 0 0; --collapse-top-padding: 4.6rem 0 0 0;
--collapse-create-btn-width: 5.1rem; --collapse-create-btn-width: 5.1rem;
--collapse-menu-item-width: 50%; --collapse-menu-item-width: 50%;
--collapse-menu-item-icon-margin-right: 0;
} }
> .top { > .top {
display: flex; display: flex;
@@ -242,6 +280,7 @@
} }
> .icon { > .icon {
transition: transform 0.2s ease-in-out; transition: transform 0.2s ease-in-out;
margin-right: var(--collapse-menu-item-icon-margin-right, 1.6rem);
} }
&.active > .jiantou { &.active > .jiantou {
transform: rotate(90deg); transform: rotate(90deg);
@@ -288,6 +327,14 @@
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
} }
> input {
flex: 1;
width: 0;
height: 100%;
border: none;
outline: none;
background-color: transparent;
}
> .icon { > .icon {
width: 2.5rem; width: 2.5rem;
height: 2.5rem; height: 2.5rem;

View File

@@ -1,19 +1,19 @@
<template> <template>
<div> <div>
<div class="label">User Name</div> <div class="label">{{ $t('Home.userName') }}</div>
<div class="value">{{ userInfo?.username || '------' }}</div> <div class="value">{{ userInfo?.username || '------' }}</div>
</div> </div>
<div> <div>
<div class="label">Email</div> <div class="label">{{ $t('Home.email') }}</div>
<div class="value">{{ userInfo?.email || '------' }}</div> <div class="value">{{ userInfo?.email || '------' }}</div>
</div> </div>
<div> <div>
<div class="label">Language</div> <div class="label">{{ $t('Home.language') }}</div>
<dropdown-menu v-model="locale" :list="langs" @change="changeLang" /> <dropdown-menu v-model="locale" :list="langs" @change="changeLang" />
</div> </div>
<div> <div>
<div class="label">Log out on this device</div> <div class="label">{{ $t('Home.logoutDevice') }}</div>
<button class="logout-btn" @click="logout">Log out</button> <button class="logout-btn" @click="logout">{{ $t('Home.logout') }}</button>
</div> </div>
</template> </template>

View File

@@ -1,11 +1,11 @@
<template> <template>
<div> <div>
<div class="label">User Agreement</div> <div class="label">{{ $t('Home.userAgreement') }}</div>
<button @click="onClickUserAgreement">View</button> <button @click="onClickUserAgreement">{{ $t('Home.view') }}</button>
</div> </div>
<div> <div>
<div class="label">Privacy Policy</div> <div class="label">{{ $t('Home.privacyPolicy') }}</div>
<button @click="onClickPrivacy">View</button> <button @click="onClickPrivacy">{{ $t('Home.view') }}</button>
</div> </div>
</template> </template>

View File

@@ -1,22 +1,22 @@
<template> <template>
<div> <div>
<div class="label">Region</div> <div class="label">{{ $t('Home.region') }}</div>
<dropdown-menu v-model="base" :list="baseList" @change="changeBase" /> <dropdown-menu v-model="base" :list="baseList" @change="changeBase" />
</div> </div>
<div> <div>
<div class="label">Role</div> <div class="label">{{ $t('Home.role') }}</div>
<dropdown-menu v-model="role" :list="roles" @change="changeRole" /> <dropdown-menu v-model="role" :list="roles" @change="changeRole" />
</div> </div>
<div> <div>
<div class="label">Current Agent Profile</div> <div class="label">{{ $t('Home.currentAgentProfile') }}</div>
<div class="group"> <div class="group">
<span class="icon"><svg-icon name="xiang" size="20" color="#000" /></span> <span class="icon"><svg-icon name="xiang" size="20" color="#000" /></span>
<dropdown-menu v-model="agent" :list="agents" @change="changeAgent" /> <dropdown-menu v-model="agent" :list="agents" @change="changeAgent" />
</div> </div>
</div> </div>
<div> <div>
<div class="label">Current Notification Frequency</div> <div class="label">{{ $t('Home.currentNotificationFrequency') }}</div>
<div class="value">36 times per hour</div> <div class="value">{{ $t('Home.timesPerHour', { time: '36' }) }}</div>
</div> </div>
</template> </template>
@@ -27,19 +27,19 @@
import { UpdateUserProfile } from '@/api/user' import { UpdateUserProfile } from '@/api/user'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
const userInfoStore = useUserInfoStore() const userInfoStore = useUserInfoStore()
const { locale } = useI18n() const { t } = useI18n()
const base = ref(userInfoStore.state.userInfo.base) const base = ref(userInfoStore.state.userInfo.base)
const baseList = ref([ const baseList = ref([
{ label: 'United States', value: 'United States' }, { label: t('Country.unitedStates'), value: 'United States' },
{ label: 'Singapore', value: 'Singapore' }, { label: t('Country.singapore'), value: 'Singapore' },
{ label: 'Australia', value: 'Australia' }, { label: t('Country.australia'), value: 'Australia' },
{ label: 'South Korea', value: 'South Korea' }, { label: t('Country.southKorea'), value: 'South Korea' },
{ label: 'China', value: 'China' }, { label: t('Country.china'), value: 'China' },
{ label: 'Italy', value: 'Italy' }, { label: t('Country.italy'), value: 'Italy' },
{ label: 'France', value: 'France' }, { label: t('Country.france'), value: 'France' },
{ label: 'Japan', value: 'Japan' }, { label: t('Country.japan'), value: 'Japan' },
{ label: 'Canada', value: 'Canada' }, { label: t('Country.canada'), value: 'Canada' },
{ label: 'Germany', value: 'Germany' } { label: t('Country.germany'), value: 'Germany' }
]) ])
const changeBase = (value: string) => { const changeBase = (value: string) => {
onSubmit({ base: value }) onSubmit({ base: value })
@@ -47,17 +47,17 @@
const role = ref(userInfoStore.state.userInfo.role) const role = ref(userInfoStore.state.userInfo.role)
const roles = ref([ const roles = ref([
{ label: 'Designer', value: 'Designer' }, { label: t('Role.designer'), value: 'Designer' },
{ label: 'Student', value: 'Student' }, { label: t('Role.student'), value: 'Student' },
{ label: 'Teacher', value: 'Teacher' }, { label: t('Role.teacher'), value: 'Teacher' },
{ label: 'Parent', value: 'Parent' }, { label: t('Role.parent'), value: 'Parent' },
{ value: 'Other', label: 'Other' } { label: t('Role.other'), value: 'Other' }
]) ])
const changeRole = (value: string) => { const changeRole = (value: string) => {
onSubmit({ role: value }) onSubmit({ role: value })
} }
const agent = ref("Partner") const agent = ref('Partner')
const agents = ref([ const agents = ref([
{ label: 'Partner', value: 'Partner' }, { label: 'Partner', value: 'Partner' },
{ label: 'Observer', value: 'Observer' }, { label: 'Observer', value: 'Observer' },

View File

@@ -9,7 +9,7 @@
> >
<template #header="{ close }"> <template #header="{ close }">
<div class="setting-header"> <div class="setting-header">
<div class="title">Setting</div> <div class="title">{{ $t('Home.setting') }}</div>
<span class="close" @click="close"> <span class="close" @click="close">
<svg-icon name="close" size="10" color="#000" /> <svg-icon name="close" size="10" color="#000" />
</span> </span>
@@ -56,9 +56,9 @@
const nav = ref('setting') const nav = ref('setting')
const navs = shallowRef([ const navs = shallowRef([
{ icon: 'setting', label: 'General', component: General }, { icon: 'setting', label: $t('Home.general'), component: General },
{ icon: 'profile', label: 'Profile', component: Profile }, { icon: 'profile', label: $t('Home.profile'), component: Profile },
{ icon: 'learn-more', label: 'Learn more', component: LearnMore } { icon: 'learn-more', label: $t('Home.learnMore'), component: LearnMore }
]) ])
</script> </script>

View File

@@ -35,27 +35,29 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, reactive } from 'vue' import { computed, ref, reactive } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const router = useRouter() const router = useRouter()
const emit = defineEmits(['next']) const emit = defineEmits(['next'])
const data = reactive({ const data = reactive({
baseList: [ baseList: [
{ label: 'United States', value: 'United States' }, { label: t('Country.unitedStates'), value: 'United States' },
{ label: 'Singapore', value: 'Singapore' }, { label: t('Country.singapore'), value: 'Singapore' },
{ label: 'Australia', value: 'Australia' }, { label: t('Country.australia'), value: 'Australia' },
{ label: 'South Korea', value: 'South Korea' }, { label: t('Country.southKorea'), value: 'South Korea' },
{ label: 'China', value: 'China' }, { label: t('Country.china'), value: 'China' },
{ label: 'Italy', value: 'Italy' }, { label: t('Country.italy'), value: 'Italy' },
{ label: 'France', value: 'France' }, { label: t('Country.france'), value: 'France' },
{ label: 'Japan', value: 'Japan' }, { label: t('Country.japan'), value: 'Japan' },
{ label: 'Canada', value: 'Canada' }, { label: t('Country.canada'), value: 'Canada' },
{ label: 'Germany', value: 'Germany' } { label: t('Country.germany'), value: 'Germany' }
], ],
roleList: [ roleList: [
{ label: 'Designer', value: 'Designer' }, { label: t('Role.designer'), value: 'Designer' },
{ value: 'Student', label: 'Student' }, { label: t('Role.student'), value: 'Student' },
{ value: 'Teacher', label: 'Teacher' }, { label: t('Role.teacher'), value: 'Teacher' },
{ value: 'Parent', label: 'Parent' }, { label: t('Role.parent'), value: 'Parent' },
{ value: 'Other', label: 'Other' } { label: t('Role.other'), value: 'Other' }
], ],
base: 'China', base: 'China',
role: 'Student' role: 'Student'