s
This commit is contained in:
parent
b7f46d1c22
commit
bf5f9f7752
2
.env
2
.env
@ -2,8 +2,6 @@
|
||||
VITE_GLOB_API_URL=/api
|
||||
|
||||
VITE_APP_API_BASE_URL=http://114.218.158.24:9020
|
||||
https://erpapi.fontree.cn#正式
|
||||
http://114.218.158.24:9020#测试
|
||||
# Whether long replies are supported, which may result in higher API fees
|
||||
VITE_GLOB_OPEN_LONG_REPLY=true
|
||||
|
||||
|
9
.env.prod
Normal file
9
.env.prod
Normal file
@ -0,0 +1,9 @@
|
||||
# Glob API URL
|
||||
VITE_GLOB_API_URL=/api
|
||||
|
||||
VITE_APP_API_BASE_URL=https://erpapi.fontree.cn
|
||||
# Whether long replies are supported, which may result in higher API fees
|
||||
VITE_GLOB_OPEN_LONG_REPLY=true
|
||||
|
||||
# When you want to use PWA
|
||||
VITE_GLOB_APP_PWA=false
|
2757
package-lock.json
generated
2757
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,9 +12,9 @@
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check build-only",
|
||||
"build": "run-p build-only",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"build-only": "vite build --mode prod",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
@ -65,9 +65,12 @@
|
||||
"less": "^4.1.3",
|
||||
"lint-staged": "^13.1.2",
|
||||
"markdown-it-link-attributes": "^4.0.1",
|
||||
"node-sass": "^9.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8.4.21",
|
||||
"rimraf": "^4.3.0",
|
||||
"sass": "^1.70.0",
|
||||
"sass-loader": "^14.1.0",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"typescript": "~4.9.5",
|
||||
"unplugin-auto-import": "^0.17.5",
|
||||
|
@ -8,13 +8,13 @@ import zhCN from 'ant-design-vue/es/locale/zh_CN';
|
||||
const { theme } = useTheme()
|
||||
const { language } = useLanguage()
|
||||
import {Local} from './utils/storage/storage.js'
|
||||
const props = window.$wujie?.props;
|
||||
if (props){
|
||||
/* const props = window.$wujie?.props;
|
||||
/!* if (props){
|
||||
Local.set('token',props.token)
|
||||
Local.set('mode',props.mode)
|
||||
Local.set('userInfo',props.userInfo)
|
||||
Local.set('isGPT4',props.isGPT4)
|
||||
}
|
||||
} *!/ */
|
||||
const themeOverrides = {
|
||||
common: {
|
||||
primaryColorHover:'#764CF6',
|
||||
|
1
src/assets/RecordStop12Regular.svg
Normal file
1
src/assets/RecordStop12Regular.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 12 12"><g fill="none"><path d="M5 4a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H5zm6 2A5 5 0 1 1 1 6a5 5 0 0 1 10 0zm-1 0a4 4 0 1 0-8 0a4 4 0 0 0 8 0z" fill="currentColor"></path></g></svg>
|
After Width: | Height: | Size: 303 B |
@ -1,8 +1,8 @@
|
||||
import {createSession, getSessionList, postRequest, sessionDetailReq} from "@/api/api";
|
||||
import {useScroll} from "@/views/chat/hooks/useScroll";
|
||||
import dayjs from "dayjs";
|
||||
import { ref } from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
export const sessionDetailForSetup = defineStore('session', () => {
|
||||
const sessionDetail = ref([]);
|
||||
const currentListUuid=ref('')
|
||||
@ -10,6 +10,7 @@ const currentListUuid=ref('')
|
||||
const dataList = ref([]);
|
||||
const isStop = ref(false);
|
||||
const isGPT4 = ref(false);
|
||||
const loading=ref(false)
|
||||
const getDataList = async () => {
|
||||
const data = {
|
||||
page: 1,
|
||||
@ -63,5 +64,5 @@ const currentListUuid=ref('')
|
||||
getDataList()
|
||||
}
|
||||
}
|
||||
return { sessionDetail,currentListUuid ,gptMode,getDataList,dataList,getSessionDetail,createSessionStore,deleteSession,isStop,isGPT4};
|
||||
return { sessionDetail,currentListUuid ,gptMode,getDataList,dataList,getSessionDetail,createSessionStore,deleteSession,isStop,isGPT4,loading};
|
||||
});
|
||||
|
@ -69,6 +69,7 @@ function addCopyEvents() {
|
||||
const copyBtn = textRef.value.querySelectorAll('.code-block-header__copy')
|
||||
copyBtn.forEach((btn) => {
|
||||
btn.addEventListener('click', () => {
|
||||
console.log(btn.parentElement?.nextElementSibling?.textContent,'btn.parentElement?.nextElementSibling?.textContent')
|
||||
const code = btn.parentElement?.nextElementSibling?.textContent
|
||||
if (code) {
|
||||
copyToClip(code).then(() => {
|
||||
|
@ -12,10 +12,15 @@ interface ScrollReturn {
|
||||
|
||||
export function useScroll(): ScrollReturn {
|
||||
const scrollRef = ref<ScrollElement>(null)
|
||||
const scrollToBottom = async () => {
|
||||
const scrollToBottom = async (value:ScrollBehavior) => {
|
||||
await nextTick()
|
||||
if (scrollRef.value)
|
||||
scrollRef.value.scrollTop = scrollRef.value.scrollHeight
|
||||
if (scrollRef.value){
|
||||
scrollRef.value.scrollTo({
|
||||
top: scrollRef.value.scrollHeight, // 滚动到底部
|
||||
behavior: value// 滚动行为平滑过渡
|
||||
});
|
||||
}
|
||||
/* scrollRef.value.scrollTop = scrollRef.value.scrollHeight */
|
||||
}
|
||||
|
||||
const scrollToTop = async () => {
|
||||
|
@ -20,7 +20,7 @@ import {t} from '@/locales'
|
||||
import {UploadOutlined} from '@ant-design/icons-vue';
|
||||
import {storeToRefs} from 'pinia'
|
||||
import {sessionDetailForSetup} from '@/store'
|
||||
|
||||
import StopSvg from '@/assets/RecordStop12Regular.svg'
|
||||
const sessionDetailData = sessionDetailForSetup()
|
||||
let controller = new AbortController()
|
||||
const {
|
||||
@ -28,7 +28,8 @@ const {
|
||||
currentListUuid,
|
||||
gptMode,
|
||||
isStop,
|
||||
isGPT4
|
||||
isGPT4,
|
||||
loading
|
||||
} = storeToRefs(sessionDetailData)
|
||||
|
||||
const dialog = useDialog()
|
||||
@ -51,7 +52,6 @@ const {
|
||||
toggleUsingContext
|
||||
} = useUsingContext()
|
||||
const prompt = ref('')
|
||||
const loading = ref(false)
|
||||
const inputRef = ref(null)
|
||||
|
||||
// 添加PromptStore
|
||||
@ -68,19 +68,32 @@ dataSources.value.forEach((item, index) => {
|
||||
})
|
||||
|
||||
function handleSubmit() {
|
||||
dataSources.value.push({
|
||||
dateTime: dayjs().format('YYYY/MM/DD HH:mm:ss'),
|
||||
text: prompt.value,
|
||||
inversion: true,
|
||||
error: false,
|
||||
fileList: fileList.value.map(x => x.url),
|
||||
loading: false
|
||||
})
|
||||
sendDataStream()
|
||||
if (loading.value){
|
||||
handleStop()
|
||||
}else {
|
||||
dataSources.value.push({
|
||||
dateTime: dayjs().format('YYYY/MM/DD HH:mm:ss'),
|
||||
text: prompt.value?.trim(),
|
||||
inversion: true,
|
||||
error: false,
|
||||
fileList: fileList.value.map(x => x.url),
|
||||
loading: false
|
||||
})
|
||||
sendDataStream()
|
||||
scrollToBottom('smooth')
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
//一键滚动到底部,一键滚动到顶部逻辑未完善
|
||||
/* const isTopBottom=()=>{
|
||||
if ( scrollRef.value.scrollTop ===0){
|
||||
|
||||
}
|
||||
} */
|
||||
|
||||
const API_URL = `${import.meta.env.VITE_APP_API_BASE_URL}/chat/completion`;
|
||||
|
||||
const createParams = () => {
|
||||
const messages = dataSources.value.map((x) => {
|
||||
return {
|
||||
@ -160,7 +173,6 @@ const sendDataStream = async () => {
|
||||
});
|
||||
visible.value = false
|
||||
try {
|
||||
loading.value = true
|
||||
const response = await fetch(API_URL, {
|
||||
method: "POST",
|
||||
timeout: 10000,
|
||||
@ -271,7 +283,7 @@ function handleEnter(event) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleStop(item) {
|
||||
function handleStop() {
|
||||
if (loading.value) {
|
||||
loading.value = false
|
||||
isStop.value = true
|
||||
@ -312,7 +324,7 @@ const placeholder = computed(() => {
|
||||
})
|
||||
|
||||
const buttonDisabled = computed(() => {
|
||||
return loading.value || !prompt.value || prompt.value.trim() === ''
|
||||
return prompt.value.trim() === '' &&!loading.value
|
||||
})
|
||||
|
||||
const footerClass = computed(() => {
|
||||
@ -322,14 +334,35 @@ const footerClass = computed(() => {
|
||||
}
|
||||
return classes
|
||||
})
|
||||
|
||||
const isShowBottom=ref(false)
|
||||
onMounted(() => {
|
||||
|
||||
scrollToBottom()
|
||||
scrollRef.value.addEventListener('scroll', function() {
|
||||
if (scrollRef.value.scrollTop + scrollRef.value.clientHeight +100>= scrollRef.value.scrollHeight) {
|
||||
isShowBottom.value=false
|
||||
}else {
|
||||
isShowBottom.value=true
|
||||
}
|
||||
});
|
||||
if (inputRef.value && !isMobile.value) {
|
||||
inputRef.value?.focus()
|
||||
}
|
||||
})
|
||||
const currentColor = ref('#ff0000'); // 初始颜色红色
|
||||
const colors = ['#ff0000', '#ffffff']; // 颜色数组(红色和白色)
|
||||
let intervalId = null;
|
||||
|
||||
// 计时器函数
|
||||
const changeColor = () => {
|
||||
currentColor.value = currentColor.value === colors[0] ? colors[1] : colors[0];
|
||||
};
|
||||
|
||||
watch(loading,()=>{
|
||||
if (loading.value){
|
||||
intervalId = setInterval(changeColor, 1000);
|
||||
}else {
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
})
|
||||
const fileList = ref([]);
|
||||
onUnmounted(() => {
|
||||
if (loading.value) {
|
||||
@ -345,7 +378,6 @@ function getBase64(file) {
|
||||
reader.onerror = error => reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
const previewVisible = ref(false);
|
||||
const previewImage = ref('');
|
||||
const previewTitle = ref('');
|
||||
@ -394,7 +426,10 @@ const upItemImage1 = async (file) => {
|
||||
sendDataStream()
|
||||
}
|
||||
}
|
||||
|
||||
watch(dataSources,()=>{
|
||||
loading.value=false
|
||||
scrollToBottom('auto')
|
||||
})
|
||||
const customRequest = async (file) => {
|
||||
const res = await uploadImg({
|
||||
file: file.file,
|
||||
@ -417,9 +452,10 @@ const customRequest = async (file) => {
|
||||
@handle-clear="handleClear"
|
||||
/>
|
||||
<main class="flex-1 overflow-hidden">
|
||||
<div class="shortcut-arrow">
|
||||
<transition name="fade">
|
||||
<div class="shortcut-arrow" v-if="isShowBottom">
|
||||
<div class="top">
|
||||
<n-button @click="scrollToBottom" type="primary" dashed circle>
|
||||
<n-button @click="scrollToBottom('smooth')" type="primary" dashed circle>
|
||||
<template #icon>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512">
|
||||
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48"
|
||||
@ -433,7 +469,7 @@ const customRequest = async (file) => {
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</transition>
|
||||
|
||||
<div id="scrollRef" ref="scrollRef" class="h-full overflow-hidden overflow-y-auto">
|
||||
<div
|
||||
@ -462,12 +498,12 @@ const customRequest = async (file) => {
|
||||
@delete="handleDelete(index)"
|
||||
/>
|
||||
<div class="sticky bottom-0 left-0 flex justify-center">
|
||||
<NButton v-if="loading" type="warning" @click="handleStop(item)">
|
||||
<!-- <NButton v-if="loading" type="warning" @click="handleStop(item)">
|
||||
<template #icon>
|
||||
<SvgIcon icon="ri:stop-circle-line"/>
|
||||
</template>
|
||||
停止响应
|
||||
</NButton>
|
||||
</NButton>-->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -559,10 +595,15 @@ const customRequest = async (file) => {
|
||||
/>
|
||||
</template>
|
||||
</NAutoComplete>
|
||||
<NButton color="#8a2be2" type="primary" :disabled="buttonDisabled" @click="handleSubmit">
|
||||
<NButton color="#8a2be2" type="primary" :disabled="buttonDisabled" @click="handleSubmit">
|
||||
<template #icon>
|
||||
<span class="dark:text-black">
|
||||
<SvgIcon icon="ri:send-plane-fill"/>
|
||||
<span class="dark:text-black" v-if="!loading">
|
||||
<SvgIcon icon="ri:send-plane-fill"/>
|
||||
</span>
|
||||
|
||||
<span class="dark:text-black" v-if="loading">
|
||||
<svg style="width:100%;height:100%;" xmlns="http://www.w3.org/2000/svg" :style="{color:currentColor}" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 12 12"><g fill="none"><path d="M5 4a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H5zm6 2A5 5 0 1 1 1 6a5 5 0 0 1 10 0zm-1 0a4 4 0 1 0-8 0a4 4 0 0 0 8 0z" fill="currentColor"></path></g></svg>
|
||||
|
||||
</span>
|
||||
</template>
|
||||
</NButton>
|
||||
@ -572,13 +613,19 @@ const customRequest = async (file) => {
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity 0.4s ease-in-out;
|
||||
}
|
||||
.fade-enter-from, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
.shortcut-arrow {
|
||||
width: min-content;
|
||||
height: min-content;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
left: 50%;
|
||||
bottom: 90px;
|
||||
bottom: 100px;
|
||||
.top {
|
||||
transform: rotate(270deg) translateX(-50%);
|
||||
width: min-content;
|
||||
|
@ -1,128 +1,160 @@
|
||||
<script setup>
|
||||
import {createSession} from "@/api/api";
|
||||
import {Local} from "@/utils/storage/storage";
|
||||
import {storeToRefs} from "pinia";
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { NButton, NLayoutSider, useDialog,NSelect } from 'naive-ui'
|
||||
import {computed, ref, watch} from 'vue'
|
||||
import {NButton, NLayoutSider, useDialog, NSelect} from 'naive-ui'
|
||||
import List from './List.vue'
|
||||
import Footer from './Footer.vue'
|
||||
import { useAppStore, useChatStore } from '@/store'
|
||||
import { useBasicLayout } from '@/hooks/useBasicLayout'
|
||||
import { PromptStore, SvgIcon } from '@/components/common'
|
||||
import { t } from '@/locales'
|
||||
import {useAppStore, useChatStore} from '@/store'
|
||||
import {useBasicLayout} from '@/hooks/useBasicLayout'
|
||||
import {PromptStore, SvgIcon} from '@/components/common'
|
||||
import {t} from '@/locales'
|
||||
import {sessionDetailForSetup} from "@/store";
|
||||
const sessionDetailData=sessionDetailForSetup()
|
||||
const {sessionDetail, dataList,gptMode,currentListUuid,isGPT4 } = storeToRefs(sessionDetailData)
|
||||
|
||||
const sessionDetailData = sessionDetailForSetup()
|
||||
const {
|
||||
sessionDetail,
|
||||
dataList,
|
||||
gptMode,
|
||||
currentListUuid,
|
||||
isGPT4
|
||||
} = storeToRefs(sessionDetailData)
|
||||
const appStore = useAppStore()
|
||||
const chatStore = useChatStore()
|
||||
|
||||
const dialog = useDialog()
|
||||
|
||||
const { isMobile } = useBasicLayout()
|
||||
const {isMobile} = useBasicLayout()
|
||||
const show = ref(false)
|
||||
|
||||
const collapsed = computed(() => appStore.siderCollapsed)
|
||||
|
||||
async function handleAdd() {
|
||||
await sessionDetailForSetup().createSessionStore()
|
||||
sessionDetail.value=[]
|
||||
await chatStore.setActive(currentListUuid.value)
|
||||
await sessionDetailForSetup().createSessionStore()
|
||||
sessionDetail.value = []
|
||||
await chatStore.setActive(currentListUuid.value)
|
||||
}
|
||||
|
||||
function handleUpdateCollapsed() {
|
||||
appStore.setSiderCollapsed(!collapsed.value)
|
||||
appStore.setSiderCollapsed(!collapsed.value)
|
||||
}
|
||||
|
||||
function handleClearAll() {
|
||||
dialog.warning({
|
||||
title: t('chat.deleteMessage'),
|
||||
content: t('chat.clearHistoryConfirm'),
|
||||
positiveText: t('common.yes'),
|
||||
negativeText: t('common.no'),
|
||||
onPositiveClick: () => {
|
||||
chatStore.clearHistory()
|
||||
if (isMobile.value)
|
||||
appStore.setSiderCollapsed(true)
|
||||
},
|
||||
})
|
||||
dialog.warning({
|
||||
title: t('chat.deleteMessage'),
|
||||
content: t('chat.clearHistoryConfirm'),
|
||||
positiveText: t('common.yes'),
|
||||
negativeText: t('common.no'),
|
||||
onPositiveClick: () => {
|
||||
chatStore.clearHistory()
|
||||
if (isMobile.value) {
|
||||
appStore.setSiderCollapsed(true)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const getMobileClass = computed(() => {
|
||||
if (isMobile.value) {
|
||||
return {
|
||||
position: 'fixed',
|
||||
zIndex: 50,
|
||||
}
|
||||
}
|
||||
return {}
|
||||
if (isMobile.value) {
|
||||
return {
|
||||
position: 'fixed',
|
||||
zIndex: 50,
|
||||
}
|
||||
}
|
||||
return {}
|
||||
})
|
||||
|
||||
const mobileSafeArea = computed(() => {
|
||||
if (isMobile.value) {
|
||||
return {
|
||||
paddingBottom: 'env(safe-area-inset-bottom)',
|
||||
}
|
||||
}
|
||||
return {}
|
||||
})
|
||||
const options=ref([{ label: 'GPT-3.5', value: 'gpt-3.5-turbo' },
|
||||
{ label: 'GPT-4.0', value: 'gpt-4-1106-preview' ,permission:'isGPT4'},
|
||||
{ label: 'GPT-V', value: 'gpt-4-vision-preview',permission:'isGPT4' }])
|
||||
setTimeout(()=>{
|
||||
if (localStorage.getItem('isGPT4')!=='true'){
|
||||
options.value=options.value.filter(item=>item.permission!=='isGPT4')
|
||||
if (isMobile.value) {
|
||||
return {
|
||||
paddingBottom: 'env(safe-area-inset-bottom)',
|
||||
}
|
||||
}
|
||||
},1000)
|
||||
return {}
|
||||
})
|
||||
const options = () => {
|
||||
return Local.get('ruleBtn').find(x => x === 'gpt-4-btn') ? [{
|
||||
label: 'GPT-3.5',
|
||||
value: 'gpt-3.5-turbo',
|
||||
permission: 'gpt-3.5-btn'
|
||||
},
|
||||
{
|
||||
label: 'GPT-4.0',
|
||||
value: 'gpt-4-1106-preview',
|
||||
permission: 'gpt-4-btn'
|
||||
},
|
||||
{
|
||||
label: 'GPT-V',
|
||||
value: 'gpt-4-vision-preview',
|
||||
permission: 'gpt-4-btn'
|
||||
}] : [{
|
||||
label: 'GPT-4.0',
|
||||
value: 'gpt-4-1106-preview',
|
||||
permission: 'gpt-4-btn'
|
||||
},
|
||||
{
|
||||
label: 'GPT-V',
|
||||
value: 'gpt-4-vision-preview',
|
||||
permission: 'gpt-4-btn'
|
||||
}]
|
||||
}
|
||||
watch(
|
||||
isMobile,
|
||||
(val) => {
|
||||
appStore.setSiderCollapsed(val)
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
flush: 'post',
|
||||
},
|
||||
isMobile,
|
||||
(val) => {
|
||||
appStore.setSiderCollapsed(val)
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
flush: 'post',
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NLayoutSider
|
||||
:collapsed="collapsed"
|
||||
:collapsed-width="15"
|
||||
:width="270"
|
||||
:show-trigger="isMobile ? false : 'arrow-circle'"
|
||||
collapse-mode="transform"
|
||||
position="absolute"
|
||||
bordered
|
||||
:style="getMobileClass"
|
||||
@update-collapsed="handleUpdateCollapsed"
|
||||
>
|
||||
<div class="flex flex-col h-full" :style="mobileSafeArea">
|
||||
<main class="flex flex-col flex-1 min-h-0">
|
||||
<div class="p-4" style="display: flex">
|
||||
<NButton color="#764CF6" style="flex:0.9;display: flex;justify-content: center;align-items: center;margin-right: auto" dashed block @click="handleAdd">
|
||||
新建会话
|
||||
</NButton>
|
||||
<div style="width: 110px">
|
||||
<n-select v-model:value="gptMode" :options="options" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 min-h-0 pb-4 overflow-hidden">
|
||||
<List />
|
||||
</div>
|
||||
<!-- <div class="flex items-center p-4 space-x-4">
|
||||
<div class="flex-1">
|
||||
<NButton block @click="show = true">
|
||||
{{ $t('store.siderButton') }}
|
||||
</NButton>
|
||||
</div>
|
||||
<NButton @click="handleClearAll">
|
||||
<SvgIcon icon="ri:close-circle-line" />
|
||||
</NButton>
|
||||
</div>-->
|
||||
</main>
|
||||
<!-- <Footer />-->
|
||||
</div>
|
||||
</NLayoutSider>
|
||||
<template v-if="isMobile">
|
||||
<div v-show="!collapsed" class="fixed inset-0 z-40 w-full h-full bg-black/40" @click="handleUpdateCollapsed" />
|
||||
</template>
|
||||
<PromptStore v-model:visible="show" />
|
||||
<NLayoutSider
|
||||
:collapsed="collapsed"
|
||||
:collapsed-width="15"
|
||||
:width="270"
|
||||
:show-trigger="isMobile ? false : 'arrow-circle'"
|
||||
collapse-mode="transform"
|
||||
position="absolute"
|
||||
bordered
|
||||
:style="getMobileClass"
|
||||
@update-collapsed="handleUpdateCollapsed"
|
||||
>
|
||||
<div class="flex flex-col h-full" :style="mobileSafeArea">
|
||||
<main class="flex flex-col flex-1 min-h-0">
|
||||
<div class="p-4" style="display: flex">
|
||||
<NButton color="#764CF6"
|
||||
style="flex:0.9;display: flex;justify-content: center;align-items: center;margin-right: auto" dashed
|
||||
block @click="handleAdd"
|
||||
>
|
||||
新建会话
|
||||
</NButton>
|
||||
<div style="width: 110px">
|
||||
<n-select v-model:value="gptMode" :options="options()"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 min-h-0 pb-4 overflow-hidden">
|
||||
<List/>
|
||||
</div>
|
||||
<!-- <div class="flex items-center p-4 space-x-4">
|
||||
<div class="flex-1">
|
||||
<NButton block @click="show = true">
|
||||
{{ $t('store.siderButton') }}
|
||||
</NButton>
|
||||
</div>
|
||||
<NButton @click="handleClearAll">
|
||||
<SvgIcon icon="ri:close-circle-line" />
|
||||
</NButton>
|
||||
</div>-->
|
||||
</main>
|
||||
<!-- <Footer />-->
|
||||
</div>
|
||||
</NLayoutSider>
|
||||
<template v-if="isMobile">
|
||||
<div v-show="!collapsed" class="fixed inset-0 z-40 w-full h-full bg-black/40" @click="handleUpdateCollapsed"/>
|
||||
</template>
|
||||
<PromptStore v-model:visible="show"/>
|
||||
</template>
|
||||
|
Loading…
Reference in New Issue
Block a user