mirror of
https://gitee.com/HuLaSpark/HuLa.git
synced 2024-12-01 19:28:07 +08:00
feat(component): ✨ 新增GPT欢迎页面,完善设置页面
This commit is contained in:
parent
058b91d7af
commit
9b771e02ec
@ -7,7 +7,7 @@
|
||||
<title>HuLa</title>
|
||||
|
||||
<!--引入iconpark图标库-->
|
||||
<script defer src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/svg_30895_95.0ab6745fae3ccd4f96f945bab1f8bd0d.js"></script>
|
||||
<script defer src="https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/svg_30895_97.8e01ce86874358e3d6e87829c9ed23c6.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -115,7 +115,7 @@ export const useChatMain = (activeItem?: SessionItem) => {
|
||||
...commonMenuList.value,
|
||||
{
|
||||
label: '另存为',
|
||||
icon: 'download',
|
||||
icon: 'Importing',
|
||||
click: (item: any) => {
|
||||
console.log(item)
|
||||
}
|
||||
@ -142,7 +142,7 @@ export const useChatMain = (activeItem?: SessionItem) => {
|
||||
...commonMenuList.value,
|
||||
{
|
||||
label: '另存为',
|
||||
icon: 'download',
|
||||
icon: 'Importing',
|
||||
click: (item: any) => {
|
||||
console.log(item)
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ export const useMsgInput = (messageInputDom: Ref) => {
|
||||
})
|
||||
}
|
||||
},
|
||||
{ label: '另存为', icon: 'download', disabled: true },
|
||||
{ label: '另存为', icon: 'Importing', disabled: true },
|
||||
{ label: '全部选择', icon: 'check-one' }
|
||||
])
|
||||
|
||||
|
@ -46,6 +46,11 @@ const routes: Array<RouteRecordRaw> = [
|
||||
name: 'robot',
|
||||
component: () => import('@/views/home-window/robot/index.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '/welcome',
|
||||
name: 'welcome',
|
||||
component: () => import('@/views/home-window/robot/views/Welcome.vue')
|
||||
},
|
||||
{
|
||||
path: '/chat',
|
||||
name: 'chat',
|
||||
|
@ -75,7 +75,7 @@
|
||||
}
|
||||
/** emoji回复气泡的样式 */
|
||||
.emoji-reply-bubble {
|
||||
@apply relative rounded-50px p-[4px_8px] cursor-pointer select-none bg-#13987F66 text-14px w-fit border-(1px solid #13987F);
|
||||
@apply relative rounded-50px p-[4px_8px] cursor-pointer select-none bg-#13987F66 text-14px w-fit border-(1px solid #13987F) shadow-md;
|
||||
}
|
||||
/** 跳转到回复内容时候显示的样式 */
|
||||
.active-reply {
|
||||
|
@ -199,6 +199,26 @@ const add = () => {
|
||||
const deleteChat = (item: any) => {
|
||||
// 根据key找到items中对应的下标
|
||||
const index = chatList.value.indexOf(item)
|
||||
|
||||
/**
|
||||
* 删除最后一个元素后触发新增元素的函数
|
||||
* @param isActive 是否选中新增的元素
|
||||
*/
|
||||
function triggeringAdd(isActive?: boolean) {
|
||||
if (chatList.value.length === 0) {
|
||||
nextTick(() => {
|
||||
add()
|
||||
// 选择新增的元素
|
||||
if (isActive) {
|
||||
handleActive(chatList.value[0])
|
||||
window.$message.success(`已删除 ${item.title}`, {
|
||||
icon: () => h(NIcon, null, { default: () => h('svg', null, [h('use', { href: '#face' })]) })
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找到了对应的元素,则移除
|
||||
if (index !== -1) {
|
||||
const removeItem = chatList.value.splice(index, 1)[0]
|
||||
@ -208,22 +228,15 @@ const deleteChat = (item: any) => {
|
||||
activeItem.value = chatList.value[index].id
|
||||
handleActive(chatList.value[index])
|
||||
} else {
|
||||
// 如果是最后一个元素则触发新增
|
||||
if (chatList.value.length === 0) {
|
||||
nextTick(() => {
|
||||
add()
|
||||
// 选择新增的元素
|
||||
handleActive(chatList.value[0])
|
||||
window.$message.success(`已删除 ${item.title}`, {
|
||||
icon: () => h(NIcon, null, { default: () => h('svg', null, [h('use', { href: '#face' })]) })
|
||||
})
|
||||
})
|
||||
}
|
||||
// 如果选中chatList,并且是最后一个元素则触发新增
|
||||
triggeringAdd(true)
|
||||
// 如果我们删除的是最后一个元素,则需要选中前一个元素
|
||||
activeItem.value = chatList.value[chatList.value.length - 1].id
|
||||
handleActive(chatList.value[chatList.value.length - 1])
|
||||
}
|
||||
}
|
||||
// 如果是最后一个元素则触发新增
|
||||
triggeringAdd()
|
||||
window.$message.success(`已删除 ${item.title}`, {
|
||||
icon: () => h(NIcon, null, { default: () => h('svg', null, [h('use', { href: '#face' })]) })
|
||||
})
|
||||
@ -231,8 +244,10 @@ const deleteChat = (item: any) => {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
/** 默认选择第一个聊天内容 */
|
||||
handleActive(chatList.value[0])
|
||||
// /** 默认选择第一个聊天内容 */
|
||||
// handleActive(chatList.value[0])
|
||||
/** 刚加载的时候默认跳转到欢迎页面 */
|
||||
router.push('/welcome')
|
||||
Mitt.on('update-chat-title', (e) => {
|
||||
chatList.value.filter((item) => {
|
||||
if (item.id === e.id) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<!-- 主体内容 -->
|
||||
<!-- // TODO 考虑是否需要添加一个欢迎页面,而不是直接使用聊天窗口 (nyh -> 2024-07-01 10:44:14)-->
|
||||
<main>
|
||||
<div class="flex truncate p-[14px_20px] justify-between items-center gap-50px">
|
||||
<n-flex :size="10" vertical class="truncate">
|
||||
|
100
src/views/home-window/robot/views/Welcome.vue
Normal file
100
src/views/home-window/robot/views/Welcome.vue
Normal file
@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<n-flex vertical :size="50" align="center" justify="center" class="flex flex-1">
|
||||
<!-- logo -->
|
||||
<img class="w-275px h-125px drop-shadow-2xl" src="@/assets/logo/hula.png" alt="" />
|
||||
|
||||
<n-flex vertical justify="center" :size="16" class="p-[40px_20px]">
|
||||
<p class="text-(14px [--chat-text-color])">你可以尝试使用以下功能:</p>
|
||||
<n-flex align="center" :size="16">
|
||||
<n-flex
|
||||
vertical
|
||||
v-for="(item, index) in examplesList"
|
||||
:key="index"
|
||||
justify="center"
|
||||
:size="12"
|
||||
class="examples">
|
||||
<p class="text-(14px [--chat-text-color]) font-bold">{{ item.title }}</p>
|
||||
<component :is="item.content" />
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
</template>
|
||||
<script setup lang="tsx">
|
||||
import { NFlex } from 'naive-ui'
|
||||
|
||||
type Example = {
|
||||
title: string
|
||||
content: JSX.Element
|
||||
}[]
|
||||
const avatars = [
|
||||
'https://avatars.githubusercontent.com/u/20943608?s=60&v=4',
|
||||
'https://avatars.githubusercontent.com/u/46394163?s=60&v=4',
|
||||
'https://avatars.githubusercontent.com/u/39197136?s=60&v=4',
|
||||
'https://avatars.githubusercontent.com/u/19239641?s=60&v=4'
|
||||
]
|
||||
const examplesList: Example = [
|
||||
{
|
||||
title: 'AI搜索',
|
||||
content: (
|
||||
<NFlex vertical size={12}>
|
||||
{Array.from({ length: 3 }, (_, index) => (
|
||||
<NFlex key={index} class={'examples-item'}>
|
||||
<img class={'rounded-12px w-55px h-45px object-fill'} src={avatars[2]} alt="" />
|
||||
<NFlex vertical justify="center" class={'text-(12px [--chat-text-color]) truncate flex-1'}>
|
||||
<p class="truncate w-full">你好,我是机器人小助手,很高兴为你服务。</p>
|
||||
<p>你最近怎么样?</p>
|
||||
</NFlex>
|
||||
|
||||
<svg
|
||||
style={{ filter: 'drop-shadow(0 0 0.6em #13987f)' }}
|
||||
class="color-#13987f p-[10px_4px] size-26px opacity-0 absolute top-1/2 right--14px transform -translate-x-1/2 -translate-y-1/2">
|
||||
<use href="#Up-GPT"></use>
|
||||
</svg>
|
||||
</NFlex>
|
||||
))}
|
||||
</NFlex>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '情感消息',
|
||||
content: (
|
||||
<NFlex vertical size={12}>
|
||||
{Array.from({ length: 3 }, (_, index) => (
|
||||
<NFlex key={index} class={'examples-item'}>
|
||||
<img class={'rounded-12px w-55px h-45px object-fill'} src={avatars[1]} alt="" />
|
||||
<NFlex vertical justify="center" class={'text-(12px [--chat-text-color]) truncate flex-1'}>
|
||||
<p class="truncate w-full">你好,我是机器人小助手,很高兴为你服务。</p>
|
||||
<p>你最近怎么样?</p>
|
||||
</NFlex>
|
||||
|
||||
<svg
|
||||
style={{ filter: 'drop-shadow(0 0 0.6em #13987f)' }}
|
||||
class="color-#13987f p-[10px_4px] size-26px opacity-0 absolute top-1/2 right--14px transform -translate-x-1/2 -translate-y-1/2">
|
||||
<use href="#Up-GPT"></use>
|
||||
</svg>
|
||||
</NFlex>
|
||||
))}
|
||||
</NFlex>
|
||||
)
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.examples {
|
||||
@apply w-300px h-fit rounded-12px p-10px box-border cursor-pointer border-(solid 1px [--line-color]) shadow-md;
|
||||
}
|
||||
.examples-item {
|
||||
@apply relative rounded-12px p-6px box-border cursor-pointer transition-all duration-600 ease-in-out;
|
||||
svg {
|
||||
@apply transition-all duration-600 ease-in-out;
|
||||
}
|
||||
&:hover {
|
||||
@apply bg-[--chat-hover-color];
|
||||
svg {
|
||||
@apply opacity-100;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,35 +1,46 @@
|
||||
import pkg from '~/package.json'
|
||||
import { Button, Select, Slider, Switch } from './model.tsx'
|
||||
import { Button, Select, Slider, Switch, Input, InputNumber } from './model.tsx'
|
||||
import { NFlex } from 'naive-ui'
|
||||
|
||||
type ConfigItemType = 'system' | 'record' | 'identity' | 'cueWords' | 'APIAddress' | 'model' | 'clear'
|
||||
type ChatConfig = {
|
||||
system: {
|
||||
[key in ConfigItemType]: {
|
||||
title: string
|
||||
description?: string
|
||||
features: JSX.Element
|
||||
}[]
|
||||
}
|
||||
|
||||
/** chat 设置面板配置 */
|
||||
export const content: ChatConfig = {
|
||||
system: [
|
||||
{
|
||||
title: `当前版本:${pkg.version}`,
|
||||
description: '已是最新版本',
|
||||
features: Button('检查更新', 'refresh')
|
||||
features: <Button title={'检查更新'} icon={'refresh'} />
|
||||
},
|
||||
{
|
||||
title: '发送键',
|
||||
features: Select([
|
||||
{ label: 'Enter', value: 'Enter' },
|
||||
{ label: 'Ctrl + Enter', value: 'Ctrl+Enter' }
|
||||
])
|
||||
features: (
|
||||
<Select
|
||||
content={[
|
||||
{ label: 'Enter', value: 'Enter' },
|
||||
{ label: 'Ctrl + Enter', value: 'Ctrl+Enter' }
|
||||
]}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '主题',
|
||||
features: Select([
|
||||
{ label: '亮色', value: 'light' },
|
||||
{ label: '暗黑模式', value: 'dark' },
|
||||
{ label: '跟随系统', value: 'auto' }
|
||||
])
|
||||
features: (
|
||||
<Select
|
||||
content={[
|
||||
{ label: '亮色', value: 'light' },
|
||||
{ label: '暗黑模式', value: 'dark' },
|
||||
{ label: '跟随系统', value: 'auto' }
|
||||
]}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '字体大小',
|
||||
@ -39,7 +50,150 @@ export const content: ChatConfig = {
|
||||
{
|
||||
title: '自动生成标题',
|
||||
description: '根据对话内容生成合适的标题',
|
||||
features: Switch()
|
||||
features: <Switch active={false} />
|
||||
}
|
||||
],
|
||||
record: [
|
||||
{
|
||||
title: '云端数据',
|
||||
description: '还没有进行同步',
|
||||
features: <Button title={'配置'} icon={'setting-config'} />
|
||||
},
|
||||
{
|
||||
title: '本地数据',
|
||||
description: '1 次对话,0条消息,0条提示词,0个身份',
|
||||
features: (
|
||||
<NFlex align={'center'}>
|
||||
<Button title={'导入'} icon={'Export'} />
|
||||
<Button title={'导出'} icon={'Importing'} />
|
||||
</NFlex>
|
||||
)
|
||||
}
|
||||
],
|
||||
identity: [
|
||||
{
|
||||
title: '身份启动页',
|
||||
description: '新建聊天时,展示身份启动页',
|
||||
features: <Switch active={true} />
|
||||
},
|
||||
{
|
||||
title: '隐藏内置身份',
|
||||
description: '在所有身份列表中隐藏内置身份',
|
||||
features: <Switch active={false} />
|
||||
}
|
||||
],
|
||||
cueWords: [
|
||||
{
|
||||
title: '禁用提示词自动补全',
|
||||
description: '在输入框开头输入/即可触发自动补全',
|
||||
features: <Switch active={false} />
|
||||
},
|
||||
{
|
||||
title: '自定义提示词列表',
|
||||
description: '内置 285 条,用户定义0条',
|
||||
features: <Button title={'编辑'} icon={'edit'} />
|
||||
}
|
||||
],
|
||||
APIAddress: [
|
||||
{
|
||||
title: '模型服务商',
|
||||
description: '切换不同的服务商',
|
||||
features: (
|
||||
<Select
|
||||
content={[
|
||||
{ label: 'openAi', value: 'openAi' },
|
||||
{ label: 'Azure', value: 'Azure' },
|
||||
{ label: 'Google', value: 'Google' }
|
||||
]}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '接口地址',
|
||||
description: '除默认地址外,必须包含 http(s)://',
|
||||
features: <Input value={'www.baidu.com'} />
|
||||
},
|
||||
{
|
||||
title: 'API Key',
|
||||
description: '使用自定义 OpenAI key 统过密码访问限制',
|
||||
features: <Input value={'123456'} isPassword={true} />
|
||||
}
|
||||
],
|
||||
model: [
|
||||
{
|
||||
title: '模型(model)',
|
||||
features: (
|
||||
<Select
|
||||
content={[
|
||||
{ label: 'gpt-3.5-turbo', value: 'gpt-3.5-turbo' },
|
||||
{ label: 'gpt-4o', value: 'gpt-4o' },
|
||||
{ label: 'gpt-4-32k', value: 'gpt-4-32k' },
|
||||
{ label: 'gpt-4-turbo', value: 'gpt-4-turbo' }
|
||||
]}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '随机性(temperature)',
|
||||
description: '值越大,回复越随机',
|
||||
features: <Slider min={0} max={10} value={5} />
|
||||
},
|
||||
{
|
||||
title: '核采样(top_p)',
|
||||
description: '与随机性类似,但不要和随机性一起更改',
|
||||
features: <Slider min={0} max={10} value={5} />
|
||||
},
|
||||
{
|
||||
title: '单次回复限制(max_tokens)',
|
||||
description: '单次交互所用的最大 Token 数',
|
||||
features: <InputNumber value={4000} min={2000} max={10000} />
|
||||
},
|
||||
{
|
||||
title: '话题新鲜度(presence_penalty)',
|
||||
description: '值越大,越有可能扩展到新话题',
|
||||
features: <Slider min={0} max={10} value={5} />
|
||||
},
|
||||
{
|
||||
title: '频率惩罚度(frequency_penalty)',
|
||||
description: '值越大,越有可能降低重复字词',
|
||||
features: <Slider min={0} max={10} value={5} />
|
||||
},
|
||||
{
|
||||
title: '注入系统级提示信息',
|
||||
description: '强制给每次请求的消息列表开头添加一个模拟 ChatGPT 的系统提示',
|
||||
features: <Switch active={false} />
|
||||
},
|
||||
{
|
||||
title: '用户输入预处理',
|
||||
description: '用户最新的一条消息会埴充到此模板',
|
||||
features: <Input value={'input'} />
|
||||
},
|
||||
{
|
||||
title: '附带历史消息数',
|
||||
description: '每次请求携带的历史消息数',
|
||||
features: <Slider min={0} max={10} value={5} />
|
||||
},
|
||||
{
|
||||
title: '历史消息长度压缩阈值',
|
||||
description: '当未压缩的历史消息超过该值时,将进行压缩',
|
||||
features: <InputNumber value={1000} min={0} max={5000} />
|
||||
},
|
||||
{
|
||||
title: '历史摘要',
|
||||
description: '自动压缩聊天记录并作为上下文发送',
|
||||
features: <Switch active={true} />
|
||||
}
|
||||
],
|
||||
clear: [
|
||||
{
|
||||
title: '重置所有设置',
|
||||
description: '重置所有设置项回默认值',
|
||||
features: <Button title={'立即重置'} isSecondary={true} />
|
||||
},
|
||||
{
|
||||
title: '清除所有数据',
|
||||
description: '清除所有聊天、设置数据',
|
||||
features: <Button title={'立即清除'} isSecondary={true} />
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -14,24 +14,28 @@
|
||||
<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 bg-[--bg-setting-item] 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-scrollbar style="max-height: calc(100vh - 104px)">
|
||||
<n-flex vertical :size="20" class="p-[20px_0] shadow-inner">
|
||||
<div v-for="(key, index) in content" :key="index" class="flex flex-1 p-[0_20px]">
|
||||
<n-flex
|
||||
vertical
|
||||
class="w-full h-fit bg-[--bg-setting-item] border-(solid 1px [--line-color]) shadow-md rounded-8px p-10px">
|
||||
<n-flex vertical justify="center" v-for="(item, index) in key" :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 !== key.length - 1" class="h-1px bg-[--line-color]"></div>
|
||||
</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>
|
||||
</div>
|
||||
</n-flex>
|
||||
</div>
|
||||
</n-scrollbar>
|
||||
</template>
|
||||
<script setup lang="tsx">
|
||||
import router from '@/router'
|
||||
@ -53,7 +57,4 @@ const handleClose = () => {
|
||||
@apply size-18px;
|
||||
}
|
||||
}
|
||||
:deep(.n-button:not(.n-button--disabled):hover) {
|
||||
color: revert;
|
||||
}
|
||||
</style>
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
NSelect,
|
||||
NSlider,
|
||||
NSwitch,
|
||||
NInput,
|
||||
NInputNumber,
|
||||
NConfigProvider,
|
||||
GlobalThemeOverrides
|
||||
@ -18,42 +19,65 @@ const commonTheme: GlobalThemeOverrides = {
|
||||
borderDisabled: '1px solid #ccc',
|
||||
borderFocus: '1px solid #ccc',
|
||||
boxShadowFocus: '1px solid #ccc'
|
||||
},
|
||||
Button: {
|
||||
textColorHover: '#red'
|
||||
}
|
||||
}
|
||||
|
||||
export const Button = (title: string, icon: string) => {
|
||||
return (
|
||||
<>
|
||||
<NButton quaternary size={'small'}>
|
||||
<NFlex justify="center" align="center" size={6}>
|
||||
<svg class={'size-12px'}>
|
||||
<use href={`#${icon}`}></use>
|
||||
</svg>
|
||||
<p class={'text-12px'}>{title}</p>
|
||||
</NFlex>
|
||||
export const Button = defineComponent(
|
||||
(props: { title: string; icon?: string; isSecondary?: boolean }) => {
|
||||
const loading = ref(false)
|
||||
const handleClick = () => {
|
||||
loading.value = true
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 1000)
|
||||
}
|
||||
return () => (
|
||||
<NButton
|
||||
loading={loading.value}
|
||||
onClick={handleClick}
|
||||
type={props.isSecondary ? 'error' : 'default'}
|
||||
quaternary={!props.isSecondary}
|
||||
secondary={props.isSecondary}
|
||||
size={'small'}>
|
||||
{{
|
||||
icon: () =>
|
||||
props.icon ? (
|
||||
<svg class={'size-12px'}>
|
||||
<use href={`#${props.icon}`}></use>
|
||||
</svg>
|
||||
) : (
|
||||
void 0
|
||||
),
|
||||
default: () => props.title
|
||||
}}
|
||||
</NButton>
|
||||
</>
|
||||
)
|
||||
}
|
||||
)
|
||||
},
|
||||
{
|
||||
props: ['title', 'icon', 'isSecondary']
|
||||
}
|
||||
)
|
||||
|
||||
export const Select = (content: any[]) => {
|
||||
return (
|
||||
<>
|
||||
export const Select = defineComponent(
|
||||
(props: { content: any[] }) => {
|
||||
const v = ref(props.content[0].value)
|
||||
return () => (
|
||||
<NSelect
|
||||
class={'w-120px rounded-8px'}
|
||||
consistentMenuWidth={false}
|
||||
size={'small'}
|
||||
options={content}
|
||||
value={content[0].value}></NSelect>
|
||||
</>
|
||||
)
|
||||
}
|
||||
v-model:value={v.value}
|
||||
options={props.content}
|
||||
value={props.content[0].value}></NSelect>
|
||||
)
|
||||
},
|
||||
{
|
||||
props: ['content']
|
||||
}
|
||||
)
|
||||
|
||||
export const Slider = defineComponent(
|
||||
(props: { value: number; max: number; min: number }) => {
|
||||
(props: { value: number; max: number; min: number; isDecimal?: boolean }) => {
|
||||
const v = ref(props.value)
|
||||
const formatTooltip = (value: number) => `${value}px`
|
||||
return () => (
|
||||
@ -66,8 +90,7 @@ export const Slider = defineComponent(
|
||||
formatTooltip={formatTooltip}
|
||||
v-model:value={v.value}
|
||||
max={props.max}
|
||||
min={props.min}
|
||||
step={1}></NSlider>
|
||||
min={props.min}></NSlider>
|
||||
</NFlex>
|
||||
)
|
||||
},
|
||||
@ -76,15 +99,52 @@ export const Slider = defineComponent(
|
||||
}
|
||||
)
|
||||
|
||||
export const Switch = () => {
|
||||
return (
|
||||
<>
|
||||
<NSwitch class={'text-(12px [--chat-text-color])'} size={'small'}>
|
||||
export const Switch = defineComponent(
|
||||
(props: { active: boolean }) => {
|
||||
const v = ref(props.active)
|
||||
return () => (
|
||||
<NSwitch v-model:value={v.value} class={'text-(12px [--chat-text-color])'} size={'small'}>
|
||||
{{
|
||||
checked: () => '开启',
|
||||
unchecked: () => '关闭'
|
||||
}}
|
||||
</NSwitch>
|
||||
</>
|
||||
)
|
||||
}
|
||||
)
|
||||
},
|
||||
{
|
||||
props: ['active']
|
||||
}
|
||||
)
|
||||
|
||||
export const Input = defineComponent(
|
||||
(props: { value: string; isPassword?: boolean }) => {
|
||||
const v = ref(props.value)
|
||||
return () => (
|
||||
<NConfigProvider themeOverrides={commonTheme}>
|
||||
<NInput
|
||||
style={{ width: '160px' }}
|
||||
v-model:value={v.value}
|
||||
type={props.isPassword ? 'password' : 'text'}
|
||||
size={'small'}
|
||||
showPasswordOn={'click'}></NInput>
|
||||
</NConfigProvider>
|
||||
)
|
||||
},
|
||||
{ props: ['value', 'isPassword'] }
|
||||
)
|
||||
|
||||
export const InputNumber = defineComponent(
|
||||
(props: { value: number; max: number; min: number }) => {
|
||||
const v = ref(props.value)
|
||||
return () => (
|
||||
<NInputNumber
|
||||
style={{ width: '120px', borderRadius: '10px', border: '1px solid #ccc' }}
|
||||
min={props.min}
|
||||
max={props.max}
|
||||
v-model:value={v.value}
|
||||
step={100}
|
||||
size={'small'}></NInputNumber>
|
||||
)
|
||||
},
|
||||
{ props: ['value'] }
|
||||
)
|
||||
|
@ -4,7 +4,7 @@
|
||||
<ActionBar :max-w="false" :shrink="false" />
|
||||
|
||||
<n-flex justify="center" class="mt-15px">
|
||||
<img src="@/assets/logo/hula.png" class="w-140px h-60px" alt="" />
|
||||
<img src="@/assets/logo/hula.png" class="w-140px h-60px drop-shadow-xl" alt="" />
|
||||
</n-flex>
|
||||
|
||||
<!-- 二维码 -->
|
||||
|
Loading…
Reference in New Issue
Block a user