mirror of
https://github.com/HuLaSpark/HuLa.git
synced 2026-08-29 03:46:16 +08:00
feat(component): ✨ 新增GPT页面设置功能
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@
|
||||
<title>HuLa</title>
|
||||
|
||||
<!--引入iconpark图标库-->
|
||||
<script defer src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/svg_30895_93.eea70ae0cbccb2d5c48884bf0db72efb.js"></script>
|
||||
<script defer src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/svg_30895_95.0ab6745fae3ccd4f96f945bab1f8bd0d.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
Generated
+650
-728
File diff suppressed because it is too large
Load Diff
@@ -4,17 +4,17 @@ use window_shadows::set_shadow;
|
||||
/// 设置窗口属性
|
||||
pub fn set_window_attribute<R: Runtime>(app: &tauri::App<R>) {
|
||||
for (_, window) in app.windows() {
|
||||
// 设置窗口阴影和圆角
|
||||
// 设置窗口阴影和圆角 win11默认有圆角效果,这里win10需要取舍阴影效果,阴影效果导致win10窗口拖动卡顿
|
||||
#[cfg(any(windows, target_os = "macos"))]
|
||||
set_shadow(&window, true).unwrap();
|
||||
|
||||
// // 设置窗口的磨砂背景
|
||||
// #[cfg(target_os = "macos")]
|
||||
// window_vibrancy::apply_acrylic(&window, Some((255, 255, 255, 1)))
|
||||
// .expect("Unsupported platform! 'apply_vibrancy' is only supported on macOS");
|
||||
//
|
||||
// #[cfg(target_os = "windows")]
|
||||
// window_vibrancy::apply_acrylic(&window, Some((255, 255, 255, 1)))
|
||||
// .expect("Unsupported platform! 'apply_blur' is only supported on Windows");
|
||||
// // 设置窗口的磨砂背景
|
||||
// #[cfg(target_os = "macos")]
|
||||
// window_vibrancy::apply_acrylic(&window, NSVisualEffectMaterial::Sidebar)
|
||||
// .expect("Unsupported platform! 'apply_vibrancy' is only supported on macOS");
|
||||
//
|
||||
// #[cfg(target_os = "windows")]
|
||||
// window_vibrancy::apply_acrylic(&window, Some((255, 255, 255, 1)))
|
||||
// .expect("Unsupported platform! 'apply_blur' is only supported on Windows");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +105,14 @@ const commonTheme: GlobalThemeOverrides = {
|
||||
iconColorLoading: '#13987f',
|
||||
loadingColor: '#13987f',
|
||||
borderRadius: '8px'
|
||||
},
|
||||
Slider: {
|
||||
handleSize: '12px',
|
||||
fontSize: '10px',
|
||||
markFontSize: '8px',
|
||||
fillColor: '#13987f',
|
||||
fillColorHover: '#13987f',
|
||||
indicatorBorderRadius: '8px'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-1
@@ -44,7 +44,19 @@ const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/robot',
|
||||
name: 'robot',
|
||||
component: () => import('@/views/home-window/robot/index.vue')
|
||||
component: () => import('@/views/home-window/robot/index.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '/chat',
|
||||
name: 'chat',
|
||||
component: () => import('@/views/home-window/robot/views/Chat.vue')
|
||||
},
|
||||
{
|
||||
path: '/chatSettings',
|
||||
name: 'chatSettings',
|
||||
component: () => import('@/views/home-window/robot/views/chatSettings/index.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/mail',
|
||||
|
||||
Vendored
-1
@@ -34,7 +34,6 @@ declare module 'vue' {
|
||||
NDropdown: (typeof import('naive-ui'))['NDropdown']
|
||||
NEllipsis: (typeof import('naive-ui'))['NEllipsis']
|
||||
NFlex: (typeof import('naive-ui'))['NFlex']
|
||||
NGradientText: (typeof import('naive-ui'))['NGradientText']
|
||||
NIcon: (typeof import('naive-ui'))['NIcon']
|
||||
NIconWrapper: (typeof import('naive-ui'))['NIconWrapper']
|
||||
NImage: (typeof import('naive-ui'))['NImage']
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
<template>
|
||||
<n-flex vertical :size="0" class="flex-1 truncate shadow-md select-none text-[--text-color]">
|
||||
<!-- 右上角操作栏 -->
|
||||
<ActionBar class="w-full" :shrink="false" :current-label="appWindow.label" :top-win-label="appWindow.label" />
|
||||
<!-- 主体内容 -->
|
||||
<main>
|
||||
<div class="flex flex-1 truncate p-[14px_20px] justify-between items-center gap-50px">
|
||||
<n-flex :size="10" vertical class="truncate">
|
||||
<p
|
||||
v-if="!isEdit"
|
||||
@click="handleEdit"
|
||||
class="text-(22px [--chat-text-color]) truncate font-bold hover:underline cursor-pointer">
|
||||
{{ currentChat.title }}
|
||||
</p>
|
||||
<n-input
|
||||
v-else
|
||||
@blur="handleBlur"
|
||||
ref="inputInstRef"
|
||||
v-model:value="currentChat.title"
|
||||
clearable
|
||||
placeholder="输入标题"
|
||||
type="text"
|
||||
size="tiny"
|
||||
style="width: 200px"
|
||||
class="h-22px lh-22px rounded-6px">
|
||||
</n-input>
|
||||
<p class="text-(14px #707070)">共0条对话</p>
|
||||
</n-flex>
|
||||
|
||||
<n-flex class="min-w-fit">
|
||||
<div class="right-btn" @click="handleEdit">
|
||||
<svg><use href="#edit"></use></svg>
|
||||
</div>
|
||||
|
||||
<div class="right-btn">
|
||||
<svg><use href="#Sharing"></use></svg>
|
||||
</div>
|
||||
</n-flex>
|
||||
</div>
|
||||
<div class="h-1px bg-[--line-color]"></div>
|
||||
|
||||
<!-- 聊天信息框 -->
|
||||
<div class="w-full shadow-inner p-[28px_16px] box-border" style="height: calc(100vh - 300px)">
|
||||
<n-flex :size="6">
|
||||
<n-avatar
|
||||
class="rounded-8px"
|
||||
src="https://img1.baidu.com/it/u=3613958228,3522035000&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500" />
|
||||
<n-flex vertical justify="space-between">
|
||||
<p class="text-(12px [--chat-text-color])">GPT-4</p>
|
||||
|
||||
<!-- 气泡样式 -->
|
||||
<ContextMenu>
|
||||
<div style="white-space: pre-wrap" class="bubble">
|
||||
<span v-html="'你好,我是GPT4机器人,很高兴为您服务。'"></span>
|
||||
</div>
|
||||
</ContextMenu>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</div>
|
||||
|
||||
<div class="h-1px bg-[--line-color]"></div>
|
||||
<!-- 下半部分输入框以及功能栏 -->
|
||||
<n-flex vertical :size="6" class="size-full p-[14px_22px] box-border shadow-inner">
|
||||
<n-flex :size="26" class="options">
|
||||
<n-popover v-for="(item, index) in features" :key="index" trigger="hover" :show-arrow="false" placement="top">
|
||||
<template #trigger>
|
||||
<svg><use :href="`#${item.icon}`"></use></svg>
|
||||
</template>
|
||||
<p>{{ item.label }}</p>
|
||||
</n-popover>
|
||||
</n-flex>
|
||||
|
||||
<div class="flex flex-col items-end gap-6px">
|
||||
<MsgInput />
|
||||
</div>
|
||||
</n-flex>
|
||||
</main>
|
||||
</n-flex>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { appWindow } from '@tauri-apps/api/window'
|
||||
import { useWindowState } from '@/hooks/useWindowState.ts'
|
||||
import MsgInput from '@/components/rightBox/MsgInput.vue'
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { InputInst } from 'naive-ui'
|
||||
|
||||
useWindowState(appWindow.label)
|
||||
/** 是否是编辑模式 */
|
||||
const isEdit = ref(false)
|
||||
const inputInstRef = ref<InputInst | null>(null)
|
||||
/** 当前聊天的标题和id */
|
||||
const currentChat = ref({
|
||||
id: 0,
|
||||
title: ''
|
||||
})
|
||||
const features = ref([
|
||||
{
|
||||
icon: 'SmilingFace',
|
||||
label: '所有人物'
|
||||
},
|
||||
{
|
||||
icon: 'MagicWand',
|
||||
label: '快捷指令'
|
||||
},
|
||||
{
|
||||
icon: 'explosion',
|
||||
label: '增强插件'
|
||||
},
|
||||
{
|
||||
icon: 'robot-action',
|
||||
label: 'GPT4'
|
||||
}
|
||||
])
|
||||
|
||||
const handleBlur = () => {
|
||||
isEdit.value = false
|
||||
if (currentChat.value.title === '') {
|
||||
currentChat.value.title = '新的聊天'
|
||||
}
|
||||
Mitt.emit('update-chat-title', { title: currentChat.value.title, id: currentChat.value.id })
|
||||
}
|
||||
|
||||
const handleEdit = () => {
|
||||
isEdit.value = true
|
||||
nextTick(() => {
|
||||
inputInstRef.value?.select()
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
Mitt.on('chat-active', (e) => {
|
||||
const { title, id } = e
|
||||
currentChat.value.title = title
|
||||
currentChat.value.id = id
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/scss/chat-main';
|
||||
.right-btn {
|
||||
@apply size-fit cursor-pointer bg-[--chat-bt-color] color-[--chat-text-color] rounded-8px shadow-md p-[10px_11px];
|
||||
svg {
|
||||
@apply size-18px;
|
||||
}
|
||||
}
|
||||
.options {
|
||||
svg {
|
||||
@apply size-24px cursor-pointer outline-none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -9,6 +9,6 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import Left from './components/Left.vue'
|
||||
import Right from './components/Right.vue'
|
||||
import Left from './layout/Left.vue'
|
||||
import Right from './layout/Right.vue'
|
||||
</script>
|
||||
|
||||
+95
-30
@@ -34,7 +34,7 @@
|
||||
</n-flex>
|
||||
<!-- 会话列表 -->
|
||||
<n-scrollbar ref="scrollbar" style="max-height: calc(100vh - 266px); padding-right: 8px">
|
||||
<VueDraggable v-model="chatList" :animation="150" target=".sort-target">
|
||||
<VueDraggable dragClass="outline-none" v-model="chatList" :animation="150" target=".sort-target">
|
||||
<TransitionGroup name="list" tag="div" style="padding: 4px" class="sort-target flex flex-col-center gap-12px">
|
||||
<n-flex
|
||||
vertical
|
||||
@@ -44,24 +44,30 @@
|
||||
@click="handleActive(item)"
|
||||
:class="{ 'outline-dashed outline-2 outline-#13987f outline-offset-1': activeItem === item.id }"
|
||||
class="chat-item">
|
||||
<div class="absolute flex flex-col gap-14px w-full p-[8px_14px] box-border">
|
||||
<n-flex justify="space-between" align="center" :size="0" class="leading-22px">
|
||||
<n-ellipsis
|
||||
style="width: calc(100% - 20px)"
|
||||
class="text-(14px [--chat-text-color]) truncate font-semibold select-none">
|
||||
{{ item.title }}
|
||||
</n-ellipsis>
|
||||
<svg
|
||||
@click.stop="deleteChat(item)"
|
||||
class="color-[--chat-text-color] size-20px opacity-0 absolute right-0px top-4px">
|
||||
<use href="#squareClose"></use>
|
||||
</svg>
|
||||
</n-flex>
|
||||
<n-flex justify="space-between" align="center" :size="0" class="text-(12px #909090)">
|
||||
<p>0条对话</p>
|
||||
<p>{{ item.time }}</p>
|
||||
</n-flex>
|
||||
</div>
|
||||
<ContextMenu
|
||||
:menu="menuList"
|
||||
:special-menu="specialMenuList"
|
||||
class="msg-box w-full h-75px mb-5px"
|
||||
@select="$event.click(item)">
|
||||
<div class="absolute flex flex-col gap-14px w-full p-[8px_14px] box-border">
|
||||
<n-flex justify="space-between" align="center" :size="0" class="leading-22px">
|
||||
<n-ellipsis
|
||||
style="width: calc(100% - 20px)"
|
||||
class="text-(14px [--chat-text-color]) truncate font-semibold select-none">
|
||||
{{ item.title }}
|
||||
</n-ellipsis>
|
||||
<svg
|
||||
@click.stop="deleteChat(item)"
|
||||
class="color-[--chat-text-color] size-20px opacity-0 absolute right-0px top-4px">
|
||||
<use href="#squareClose"></use>
|
||||
</svg>
|
||||
</n-flex>
|
||||
<n-flex justify="space-between" align="center" :size="0" class="text-(12px #909090)">
|
||||
<p>0条对话</p>
|
||||
<p>{{ item.time }}</p>
|
||||
</n-flex>
|
||||
</div>
|
||||
</ContextMenu>
|
||||
</n-flex>
|
||||
</TransitionGroup>
|
||||
</VueDraggable>
|
||||
@@ -70,10 +76,20 @@
|
||||
|
||||
<!-- 底部选项栏 -->
|
||||
<n-flex justify="space-between" align="center" class="m-[auto_4px_10px_4px]">
|
||||
<div
|
||||
class="bg-[--chat-bt-color] color-[--chat-text-color] size-fit p-[8px_9px] rounded-8px shadow-md cursor-pointer">
|
||||
<svg class="size-18px"><use href="#settings"></use></svg>
|
||||
</div>
|
||||
<n-flex :size="12" align="center">
|
||||
<div
|
||||
@click="jump"
|
||||
class="bg-[--chat-bt-color] color-[--chat-text-color] size-fit p-[8px_9px] rounded-8px shadow-md cursor-pointer">
|
||||
<svg class="size-18px"><use href="#settings"></use></svg>
|
||||
</div>
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://github.com/nongyehong/HuLa-IM-Tauri"
|
||||
class="bg-[--chat-bt-color] color-[--chat-text-color] size-fit p-[8px_9px] rounded-8px shadow-md cursor-pointer">
|
||||
<svg class="size-18px"><use href="#github"></use></svg>
|
||||
</a>
|
||||
</n-flex>
|
||||
|
||||
<n-flex
|
||||
:size="4"
|
||||
@@ -92,6 +108,7 @@ import { storeToRefs } from 'pinia'
|
||||
import { NIcon, VirtualListInst } from 'naive-ui'
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { VueDraggable } from 'vue-draggable-plus'
|
||||
import router from '@/router'
|
||||
|
||||
const settingStore = setting()
|
||||
const { login } = storeToRefs(settingStore)
|
||||
@@ -119,14 +136,56 @@ const chatList = ref([
|
||||
time: '2022-01-01 12:00:00'
|
||||
}
|
||||
])
|
||||
const menuList = ref<OPT.RightMenu[]>([
|
||||
{
|
||||
label: '置顶',
|
||||
icon: 'topping',
|
||||
click: (item: any) => {
|
||||
const index = chatList.value.findIndex((e) => e.id === item.id)
|
||||
// 实现置顶功能
|
||||
if (index !== 0) {
|
||||
// 交换元素位置
|
||||
const temp = chatList.value[index]
|
||||
chatList.value[index] = chatList.value[0]
|
||||
chatList.value[0] = temp
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '打开独立聊天窗口',
|
||||
icon: 'freezing-line-column',
|
||||
click: (item: any) => {
|
||||
console.log(item)
|
||||
}
|
||||
}
|
||||
])
|
||||
const specialMenuList = ref<OPT.RightMenu[]>([
|
||||
{
|
||||
label: '删除',
|
||||
icon: 'delete',
|
||||
click: (item: any) => {
|
||||
deleteChat(item)
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
/** 跳转到设置 */
|
||||
const jump = () => {
|
||||
router.push('/chatSettings')
|
||||
activeItem.value = 0
|
||||
}
|
||||
|
||||
/** 选中会话 */
|
||||
const handleActive = (item: any) => {
|
||||
activeItem.value = item.id
|
||||
nextTick(() => {
|
||||
Mitt.emit('chat-active', item)
|
||||
router.push('/chat').then(() => {
|
||||
nextTick(() => {
|
||||
Mitt.emit('chat-active', item)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/** 添加会话 */
|
||||
const add = () => {
|
||||
const id = chatList.value.length + 1
|
||||
chatList.value.push({ id: id, title: `新的聊天${id}`, time: '2022-01-01 12:00:00' })
|
||||
@@ -136,6 +195,7 @@ const add = () => {
|
||||
})
|
||||
}
|
||||
|
||||
/** 删除会话 */
|
||||
const deleteChat = (item: any) => {
|
||||
// 根据key找到items中对应的下标
|
||||
const index = chatList.value.indexOf(item)
|
||||
@@ -153,18 +213,20 @@ const deleteChat = (item: any) => {
|
||||
nextTick(() => {
|
||||
add()
|
||||
// 选择新增的元素
|
||||
// TODO 这里没有传输数据 (nyh -> 2024-06-27 18:52:11)
|
||||
activeItem.value = chatList.value[0].id
|
||||
handleActive(chatList.value[0])
|
||||
window.$message.success(`已删除 ${item.title}`, {
|
||||
icon: () => h(NIcon, null, { default: () => h('svg', null, [h('use', { href: '#face' })]) })
|
||||
})
|
||||
})
|
||||
}
|
||||
// 如果我们删除的是最后一个元素,则需要选中前一个元素
|
||||
activeItem.value = chatList.value[chatList.value.length - 1].id
|
||||
handleActive(chatList.value[chatList.value.length - 1])
|
||||
}
|
||||
window.$message.success(`已删除 ${item.title}`, {
|
||||
icon: () => h(NIcon, null, { default: () => h('svg', null, [h('use', { href: '#face' })]) })
|
||||
})
|
||||
}
|
||||
window.$message.success(`已删除 ${item.title}`, {
|
||||
icon: () => h(NIcon, null, { default: () => h('svg', null, [h('use', { href: '#face' })]) })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +240,9 @@ onMounted(() => {
|
||||
}
|
||||
})
|
||||
})
|
||||
Mitt.on('return-chat', () => {
|
||||
handleActive(chatList.value[0])
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<n-flex vertical :size="0" class="flex-1 truncate shadow-md select-none text-[--text-color]">
|
||||
<!-- 右上角操作栏 -->
|
||||
<ActionBar class="w-full" :shrink="false" :current-label="appWindow.label" :top-win-label="appWindow.label" />
|
||||
|
||||
<RouterView />
|
||||
</n-flex>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { appWindow } from '@tauri-apps/api/window'
|
||||
import { useWindowState } from '@/hooks/useWindowState.ts'
|
||||
|
||||
useWindowState(appWindow.label)
|
||||
</script>
|
||||
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<!-- 主体内容 -->
|
||||
<main>
|
||||
<div class="flex truncate p-[14px_20px] justify-between items-center gap-50px">
|
||||
<n-flex :size="10" vertical class="truncate">
|
||||
<p
|
||||
v-if="!isEdit"
|
||||
@click="handleEdit"
|
||||
class="text-(22px [--chat-text-color]) truncate font-bold hover:underline cursor-pointer">
|
||||
{{ currentChat.title }}
|
||||
</p>
|
||||
<n-input
|
||||
v-else
|
||||
@blur="handleBlur"
|
||||
ref="inputInstRef"
|
||||
v-model:value="currentChat.title"
|
||||
clearable
|
||||
placeholder="输入标题"
|
||||
type="text"
|
||||
size="tiny"
|
||||
style="width: 200px"
|
||||
class="h-22px lh-22px rounded-6px">
|
||||
</n-input>
|
||||
<p class="text-(14px #707070)">共0条对话</p>
|
||||
</n-flex>
|
||||
|
||||
<n-flex class="min-w-fit">
|
||||
<div class="right-btn" @click="handleEdit">
|
||||
<svg><use href="#edit"></use></svg>
|
||||
</div>
|
||||
|
||||
<div class="right-btn">
|
||||
<svg><use href="#Sharing"></use></svg>
|
||||
</div>
|
||||
</n-flex>
|
||||
</div>
|
||||
<div class="h-1px bg-[--line-color]"></div>
|
||||
|
||||
<!-- 聊天信息框 -->
|
||||
<div class="w-full shadow-inner p-[28px_16px] box-border" style="height: calc(100vh - 300px)">
|
||||
<n-flex :size="6">
|
||||
<n-avatar
|
||||
class="rounded-8px"
|
||||
src="https://img1.baidu.com/it/u=3613958228,3522035000&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500" />
|
||||
<n-flex vertical justify="space-between">
|
||||
<p class="text-(12px [--chat-text-color])">GPT-4</p>
|
||||
|
||||
<!-- 气泡样式 -->
|
||||
<ContextMenu>
|
||||
<div style="white-space: pre-wrap" class="bubble select-text">
|
||||
<span v-html="'你好,我是GPT4机器人,很高兴为您服务。'"></span>
|
||||
</div>
|
||||
</ContextMenu>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</div>
|
||||
|
||||
<div class="h-1px bg-[--line-color]"></div>
|
||||
<!-- 下半部分输入框以及功能栏 -->
|
||||
<n-flex vertical :size="6" class="size-full p-[14px_22px] box-border shadow-inner">
|
||||
<n-flex :size="26" class="options">
|
||||
<n-popover v-for="(item, index) in features" :key="index" trigger="hover" :show-arrow="false" placement="top">
|
||||
<template #trigger>
|
||||
<svg><use :href="`#${item.icon}`"></use></svg>
|
||||
</template>
|
||||
<p>{{ item.label }}</p>
|
||||
</n-popover>
|
||||
</n-flex>
|
||||
|
||||
<div class="flex flex-col items-end gap-6px">
|
||||
<MsgInput />
|
||||
</div>
|
||||
</n-flex>
|
||||
</main>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import MsgInput from '@/components/rightBox/MsgInput.vue'
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { InputInst } from 'naive-ui'
|
||||
|
||||
/** 是否是编辑模式 */
|
||||
const isEdit = ref(false)
|
||||
const inputInstRef = ref<InputInst | null>(null)
|
||||
/** 当前聊天的标题和id */
|
||||
const currentChat = ref({
|
||||
id: 0,
|
||||
title: ''
|
||||
})
|
||||
const features = ref([
|
||||
{
|
||||
icon: 'SmilingFace',
|
||||
label: '所有人物'
|
||||
},
|
||||
{
|
||||
icon: 'MagicWand',
|
||||
label: '快捷指令'
|
||||
},
|
||||
{
|
||||
icon: 'explosion',
|
||||
label: '增强插件'
|
||||
},
|
||||
{
|
||||
icon: 'robot-action',
|
||||
label: 'GPT4'
|
||||
}
|
||||
])
|
||||
|
||||
const handleBlur = () => {
|
||||
isEdit.value = false
|
||||
if (currentChat.value.title === '') {
|
||||
currentChat.value.title = '新的聊天'
|
||||
}
|
||||
Mitt.emit('update-chat-title', { title: currentChat.value.title, id: currentChat.value.id })
|
||||
}
|
||||
|
||||
const handleEdit = () => {
|
||||
isEdit.value = true
|
||||
nextTick(() => {
|
||||
inputInstRef.value?.select()
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
Mitt.on('chat-active', (e) => {
|
||||
const { title, id } = e
|
||||
currentChat.value.title = title
|
||||
currentChat.value.id = id
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
@import '@/styles/scss/chat-main';
|
||||
.right-btn {
|
||||
@apply size-fit cursor-pointer bg-[--chat-bt-color] color-[--chat-text-color] rounded-8px shadow-md p-[10px_11px];
|
||||
svg {
|
||||
@apply size-18px;
|
||||
}
|
||||
}
|
||||
.options {
|
||||
svg {
|
||||
@apply size-24px cursor-pointer outline-none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,45 @@
|
||||
import pkg from '~/package.json'
|
||||
import { Button, Select, Slider, Switch } from './model.tsx'
|
||||
|
||||
type ChatConfig = {
|
||||
system: {
|
||||
title: string
|
||||
description?: string
|
||||
features: JSX.Element
|
||||
}[]
|
||||
}
|
||||
|
||||
export const content: ChatConfig = {
|
||||
system: [
|
||||
{
|
||||
title: `当前版本:${pkg.version}`,
|
||||
description: '已是最新版本',
|
||||
features: Button('检查更新', 'refresh')
|
||||
},
|
||||
{
|
||||
title: '发送键',
|
||||
features: Select([
|
||||
{ label: 'Enter', value: 'Enter' },
|
||||
{ label: 'Ctrl + Enter', value: 'Ctrl+Enter' }
|
||||
])
|
||||
},
|
||||
{
|
||||
title: '主题',
|
||||
features: Select([
|
||||
{ label: '亮色', value: 'light' },
|
||||
{ label: '暗黑模式', value: 'dark' },
|
||||
{ label: '跟随系统', value: 'auto' }
|
||||
])
|
||||
},
|
||||
{
|
||||
title: '字体大小',
|
||||
description: '聊天内容的字体大小',
|
||||
features: Slider(20, 12)
|
||||
},
|
||||
{
|
||||
title: '自动生成标题',
|
||||
description: '根据对话内容生成合适的标题',
|
||||
features: Switch()
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="flex truncate p-[14px_20px] justify-between items-center gap-50px">
|
||||
<n-flex :size="10" vertical class="truncate">
|
||||
<p class="text-(22px [--chat-text-color]) truncate font-bold">设置</p>
|
||||
<p class="text-(14px #707070)">所有设置选项</p>
|
||||
</n-flex>
|
||||
|
||||
<n-flex class="min-w-fit">
|
||||
<div @click="handleClose" class="right-btn">
|
||||
<svg><use href="#close"></use></svg>
|
||||
</div>
|
||||
</n-flex>
|
||||
</div>
|
||||
<div class="h-1px bg-[--line-color]"></div>
|
||||
|
||||
<!-- 设置的主体内容 -->
|
||||
<div class="flex flex-1 shadow-inner p-20px">
|
||||
<n-flex vertical class="w-full h-fit border-(solid 1px [--line-color]) shadow-md rounded-8px p-10px">
|
||||
<n-flex vertical justify="center" v-for="(item, index) in content.system" :key="index">
|
||||
<n-flex justify="space-between" :size="0" align="center" class="p-8px">
|
||||
<n-flex vertical :size="4">
|
||||
<p class="text-(15px [--chat-text-color]) font-bold">{{ item.title }}</p>
|
||||
<p v-if="item.description" class="text-(12px [--chat-text-color])">{{ item.description }}</p>
|
||||
</n-flex>
|
||||
|
||||
<component :is="item.features" />
|
||||
</n-flex>
|
||||
|
||||
<div v-if="index !== content.system.length - 1" class="h-1px bg-[--line-color]"></div>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="tsx">
|
||||
import router from '@/router'
|
||||
import Mitt from '@/utils/Bus.ts'
|
||||
import { content } from './config.tsx'
|
||||
|
||||
const handleClose = () => {
|
||||
router.push('/chat').then(() => {
|
||||
nextTick(() => {
|
||||
Mitt.emit('return-chat')
|
||||
})
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.right-btn {
|
||||
@apply size-fit cursor-pointer bg-[--chat-bt-color] color-[--chat-text-color] rounded-8px shadow-md p-[10px_11px];
|
||||
svg {
|
||||
@apply size-18px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,48 @@
|
||||
import { NButton, NFlex, NSelect, NSlider, NSwitch } from 'naive-ui'
|
||||
|
||||
export const Button = (title: string, icon: string) => {
|
||||
return (
|
||||
<>
|
||||
<NButton quaternary>
|
||||
<NFlex justify="center" align="center" size={6}>
|
||||
<svg class={'size-16px'}>
|
||||
<use href={`#${icon}`}></use>
|
||||
</svg>
|
||||
{title}
|
||||
</NFlex>
|
||||
</NButton>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const Select = (content: any[]) => {
|
||||
return (
|
||||
<>
|
||||
<NSelect class={'w-120px rounded-8px'} options={content} value={content[0].value}></NSelect>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const Slider = (max: number, min: number) => {
|
||||
const formatTooltip = (value: number) => `${value}px`
|
||||
return (
|
||||
<>
|
||||
<NSlider
|
||||
class={'w-160px'}
|
||||
defaultValue={14}
|
||||
formatTooltip={formatTooltip}
|
||||
showTooltip={true}
|
||||
max={max}
|
||||
min={min}
|
||||
step={1}></NSlider>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const Switch = () => {
|
||||
return (
|
||||
<>
|
||||
<NSwitch></NSwitch>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user