Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8abb0439f6 | ||
|
50501a73cd | ||
|
73a46b08dc | ||
|
cdafe30d33 | ||
|
2e0cb8a084 | ||
|
ef0d0af2e4 |
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -2,7 +2,7 @@
|
|||||||
"prettier.enable": false,
|
"prettier.enable": false,
|
||||||
"editor.formatOnSave": false,
|
"editor.formatOnSave": false,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": "explicit"
|
"source.fixAll.eslint": true
|
||||||
},
|
},
|
||||||
"eslint.validate": [
|
"eslint.validate": [
|
||||||
"javascript",
|
"javascript",
|
||||||
|
70
auto-imports.d.ts
vendored
70
auto-imports.d.ts
vendored
@ -1,70 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
/* prettier-ignore */
|
|
||||||
// @ts-nocheck
|
|
||||||
// noinspection JSUnusedGlobalSymbols
|
|
||||||
// Generated by unplugin-auto-import
|
|
||||||
export {}
|
|
||||||
declare global {
|
|
||||||
const EffectScope: typeof import('vue')['EffectScope']
|
|
||||||
const computed: typeof import('vue')['computed']
|
|
||||||
const createApp: typeof import('vue')['createApp']
|
|
||||||
const customRef: typeof import('vue')['customRef']
|
|
||||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
|
||||||
const defineComponent: typeof import('vue')['defineComponent']
|
|
||||||
const effectScope: typeof import('vue')['effectScope']
|
|
||||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
|
||||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
|
||||||
const h: typeof import('vue')['h']
|
|
||||||
const inject: typeof import('vue')['inject']
|
|
||||||
const isProxy: typeof import('vue')['isProxy']
|
|
||||||
const isReactive: typeof import('vue')['isReactive']
|
|
||||||
const isReadonly: typeof import('vue')['isReadonly']
|
|
||||||
const isRef: typeof import('vue')['isRef']
|
|
||||||
const markRaw: typeof import('vue')['markRaw']
|
|
||||||
const nextTick: typeof import('vue')['nextTick']
|
|
||||||
const onActivated: typeof import('vue')['onActivated']
|
|
||||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
|
||||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
|
||||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
|
||||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
|
||||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
|
||||||
const onMounted: typeof import('vue')['onMounted']
|
|
||||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
|
||||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
|
||||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
|
||||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
|
||||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
|
||||||
const onUpdated: typeof import('vue')['onUpdated']
|
|
||||||
const provide: typeof import('vue')['provide']
|
|
||||||
const reactive: typeof import('vue')['reactive']
|
|
||||||
const readonly: typeof import('vue')['readonly']
|
|
||||||
const ref: typeof import('vue')['ref']
|
|
||||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
|
||||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
|
||||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
|
||||||
const shallowRef: typeof import('vue')['shallowRef']
|
|
||||||
const toRaw: typeof import('vue')['toRaw']
|
|
||||||
const toRef: typeof import('vue')['toRef']
|
|
||||||
const toRefs: typeof import('vue')['toRefs']
|
|
||||||
const toValue: typeof import('vue')['toValue']
|
|
||||||
const triggerRef: typeof import('vue')['triggerRef']
|
|
||||||
const unref: typeof import('vue')['unref']
|
|
||||||
const useAttrs: typeof import('vue')['useAttrs']
|
|
||||||
const useCssModule: typeof import('vue')['useCssModule']
|
|
||||||
const useCssVars: typeof import('vue')['useCssVars']
|
|
||||||
const useDialog: typeof import('naive-ui')['useDialog']
|
|
||||||
const useLoadingBar: typeof import('naive-ui')['useLoadingBar']
|
|
||||||
const useMessage: typeof import('naive-ui')['useMessage']
|
|
||||||
const useNotification: typeof import('naive-ui')['useNotification']
|
|
||||||
const useSlots: typeof import('vue')['useSlots']
|
|
||||||
const watch: typeof import('vue')['watch']
|
|
||||||
const watchEffect: typeof import('vue')['watchEffect']
|
|
||||||
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
|
||||||
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
|
||||||
}
|
|
||||||
// for type re-export
|
|
||||||
declare global {
|
|
||||||
// @ts-ignore
|
|
||||||
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
|
|
||||||
import('vue')
|
|
||||||
}
|
|
34
components.d.ts
vendored
34
components.d.ts
vendored
@ -1,34 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
/* prettier-ignore */
|
|
||||||
// @ts-nocheck
|
|
||||||
// Generated by unplugin-vue-components
|
|
||||||
// Read more: https://github.com/vuejs/core/pull/3399
|
|
||||||
export {}
|
|
||||||
|
|
||||||
declare module 'vue' {
|
|
||||||
export interface GlobalComponents {
|
|
||||||
About: typeof import('./src/components/common/Setting/About.vue')['default']
|
|
||||||
Advanced: typeof import('./src/components/common/Setting/Advanced.vue')['default']
|
|
||||||
Button: typeof import('./src/components/common/HoverButton/Button.vue')['default']
|
|
||||||
General: typeof import('./src/components/common/Setting/General.vue')['default']
|
|
||||||
GithubSite: typeof import('./src/components/custom/GithubSite.vue')['default']
|
|
||||||
HoverButton: typeof import('./src/components/common/HoverButton/index.vue')['default']
|
|
||||||
NaiveProvider: typeof import('./src/components/common/NaiveProvider/index.vue')['default']
|
|
||||||
NButton: typeof import('naive-ui')['NButton']
|
|
||||||
NCheckbox: typeof import('naive-ui')['NCheckbox']
|
|
||||||
NImage: typeof import('naive-ui')['NImage']
|
|
||||||
NImageGroup: typeof import('naive-ui')['NImageGroup']
|
|
||||||
NInput: typeof import('naive-ui')['NInput']
|
|
||||||
NModal: typeof import('naive-ui')['NModal']
|
|
||||||
NPageHeader: typeof import('naive-ui')['NPageHeader']
|
|
||||||
NPopover: typeof import('naive-ui')['NPopover']
|
|
||||||
NSpace: typeof import('naive-ui')['NSpace']
|
|
||||||
NUpload: typeof import('naive-ui')['NUpload']
|
|
||||||
PromptStore: typeof import('./src/components/common/PromptStore/index.vue')['default']
|
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
|
||||||
Setting: typeof import('./src/components/common/Setting/index.vue')['default']
|
|
||||||
SvgIcon: typeof import('./src/components/common/SvgIcon/index.vue')['default']
|
|
||||||
UserAvatar: typeof import('./src/components/common/UserAvatar/index.vue')['default']
|
|
||||||
}
|
|
||||||
}
|
|
@ -12,10 +12,10 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
"prod": "vite --mode prod",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"build-prod": "vite build --mode prod",
|
"build-prod": "vite build --mode prod",
|
||||||
"prod": "vite --mode prod",
|
|
||||||
"type-check": "vue-tsc --noEmit",
|
"type-check": "vue-tsc --noEmit",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "eslint . --fix",
|
||||||
|
@ -100,9 +100,6 @@ devDependencies:
|
|||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^18.14.6
|
specifier: ^18.14.6
|
||||||
version: 18.14.6
|
version: 18.14.6
|
||||||
'@vicons/ionicons5':
|
|
||||||
specifier: ^0.12.0
|
|
||||||
version: 0.12.0
|
|
||||||
'@vitejs/plugin-vue':
|
'@vitejs/plugin-vue':
|
||||||
specifier: ^4.0.0
|
specifier: ^4.0.0
|
||||||
version: 4.0.0(vite@4.2.0)(vue@3.2.47)
|
version: 4.0.0(vite@4.2.0)(vue@3.2.47)
|
||||||
@ -2479,10 +2476,6 @@ packages:
|
|||||||
eslint-visitor-keys: 3.3.0
|
eslint-visitor-keys: 3.3.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@vicons/ionicons5@0.12.0:
|
|
||||||
resolution: {integrity: sha512-Iy1EUVRpX0WWxeu1VIReR1zsZLMc4fqpt223czR+Rpnrwu7pt46nbnC2ycO7ItI/uqDLJxnbcMC7FujKs9IfFA==}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@vitejs/plugin-vue@4.0.0(vite@4.2.0)(vue@3.2.47):
|
/@vitejs/plugin-vue@4.0.0(vite@4.2.0)(vue@3.2.47):
|
||||||
resolution: {integrity: sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA==}
|
resolution: {integrity: sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
@ -7696,7 +7689,6 @@ packages:
|
|||||||
|
|
||||||
/workbox-google-analytics@6.6.0:
|
/workbox-google-analytics@6.6.0:
|
||||||
resolution: {integrity: sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==}
|
resolution: {integrity: sha512-p4DJa6OldXWd6M9zRl0H6vB9lkrmqYFkRQ2xEiNdBFp9U0LhsGO7hsBscVEyH9H2/3eZZt8c97NB2FD9U2NJ+Q==}
|
||||||
deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained
|
|
||||||
dependencies:
|
dependencies:
|
||||||
workbox-background-sync: 6.6.0
|
workbox-background-sync: 6.6.0
|
||||||
workbox-core: 6.6.0
|
workbox-core: 6.6.0
|
||||||
|
52
src/App.vue
52
src/App.vue
@ -1,4 +1,4 @@
|
|||||||
<script setup>
|
<script setup >
|
||||||
import { NConfigProvider } from 'naive-ui'
|
import { NConfigProvider } from 'naive-ui'
|
||||||
import { NaiveProvider } from '@/components/common'
|
import { NaiveProvider } from '@/components/common'
|
||||||
import { useTheme } from '@/hooks/useTheme'
|
import { useTheme } from '@/hooks/useTheme'
|
||||||
@ -7,46 +7,44 @@ import zhCN from 'ant-design-vue/es/locale/zh_CN';
|
|||||||
|
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const { language } = useLanguage()
|
const { language } = useLanguage()
|
||||||
import { Local } from './utils/storage/storage.js'
|
import {Local} from './utils/storage/storage.js'
|
||||||
/* const props = window.$wujie?.props;
|
/* const props = window.$wujie?.props;
|
||||||
/!* if (props){
|
/!* if (props){
|
||||||
Local.set('token',props.token)
|
Local.set('token',props.token)
|
||||||
Local.set('mode',props.mode)
|
Local.set('mode',props.mode)
|
||||||
Local.set('userInfo',props.userInfo)
|
Local.set('userInfo',props.userInfo)
|
||||||
Local.set('isGPT4',props.isGPT4)
|
Local.set('isGPT4',props.isGPT4)
|
||||||
} *!/ */
|
} *!/ */
|
||||||
|
|
||||||
const themeOverrides = {
|
const themeOverrides = {
|
||||||
common: {
|
common: {
|
||||||
primaryColorHover: '#764CF6',
|
primaryColorHover:Local.get('setting-info')?.themeColor?.split("@")?.[1]??'#764CF6',
|
||||||
primaryColor: '#764CF6'
|
primaryColor:Local.get('setting-info')?.themeColor?.split("@")?.[1]??'#764CF6',
|
||||||
},
|
},
|
||||||
Button: {
|
Button: {
|
||||||
textColor: '#764CF6'
|
textColor: Local.get('setting-info')?.themeColor?.split("@")?.[1]??'#764CF6',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NConfigProvider class="h-full" :theme="theme" :theme-overrides="themeOverrides" :locale="language">
|
<NConfigProvider
|
||||||
|
class="h-full"
|
||||||
|
:theme="theme"
|
||||||
|
:theme-overrides="themeOverrides"
|
||||||
|
:locale="language"
|
||||||
|
>
|
||||||
<a-config-provider :locale="zhCN">
|
<a-config-provider :locale="zhCN">
|
||||||
<NaiveProvider>
|
<NaiveProvider>
|
||||||
<RouterView />
|
<RouterView />
|
||||||
</NaiveProvider>
|
</NaiveProvider>
|
||||||
</a-config-provider>
|
</a-config-provider>
|
||||||
</NConfigProvider>
|
</NConfigProvider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root{
|
||||||
--el-color-primary: #764CF6 !important;
|
--el-color-primary:#764CF6!important;
|
||||||
}
|
}
|
||||||
|
.n-layout-scroll-container{
|
||||||
.n-layout-scroll-container {
|
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
.n-message-container{
|
|
||||||
top: 60px !important;
|
|
||||||
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -49,27 +49,3 @@ export const uploadFormData = (data) => {
|
|||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 登录
|
|
||||||
export const loginApi = (data) => {
|
|
||||||
return request({
|
|
||||||
url: '/user/login',
|
|
||||||
method: 'post',
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 获取验证码
|
|
||||||
export const getCode = (data) => {
|
|
||||||
return request({
|
|
||||||
url: '/user/send',
|
|
||||||
method: 'post',
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 菜单
|
|
||||||
export const getMenuApi = (data) => {
|
|
||||||
return request({
|
|
||||||
url: '/rule/rules',
|
|
||||||
method: 'post',
|
|
||||||
data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
@ -29,8 +29,8 @@ export default {
|
|||||||
stopResponding: 'Stop Responding',
|
stopResponding: 'Stop Responding',
|
||||||
},
|
},
|
||||||
chat: {
|
chat: {
|
||||||
newChatButton: '',
|
newChatButton: 'New Chat',
|
||||||
newChatTitle: '',
|
newChatTitle: 'New Chat',
|
||||||
placeholder: 'Ask me anything...(Shift + Enter = line break, "/" to trigger prompts)',
|
placeholder: 'Ask me anything...(Shift + Enter = line break, "/" to trigger prompts)',
|
||||||
placeholderMobile: 'Ask me anything...',
|
placeholderMobile: 'Ask me anything...',
|
||||||
copy: 'Copy',
|
copy: 'Copy',
|
||||||
|
@ -29,8 +29,8 @@ export default {
|
|||||||
stopResponding: '停止响应',
|
stopResponding: '停止响应',
|
||||||
},
|
},
|
||||||
chat: {
|
chat: {
|
||||||
newChatButton: '',
|
newChatButton: '新建聊天',
|
||||||
newChatTitle: '',
|
newChatTitle: '新建聊天',
|
||||||
placeholder: '来说点什么吧...(Shift + Enter = 换行)',
|
placeholder: '来说点什么吧...(Shift + Enter = 换行)',
|
||||||
placeholderMobile: '来说点什么...',
|
placeholderMobile: '来说点什么...',
|
||||||
copy: '复制',
|
copy: '复制',
|
||||||
|
@ -8,7 +8,7 @@ import Antd from "ant-design-vue";
|
|||||||
import "ant-design-vue/dist/reset.css";
|
import "ant-design-vue/dist/reset.css";
|
||||||
import ElementPlus from 'element-plus'
|
import ElementPlus from 'element-plus'
|
||||||
import 'element-plus/dist/index.css'
|
import 'element-plus/dist/index.css'
|
||||||
import './utils/auto-update'
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
setupAssets()
|
setupAssets()
|
||||||
|
@ -18,26 +18,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/login',
|
|
||||||
name: 'login',
|
|
||||||
component: () => import('@/views/login/index.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/mine',
|
|
||||||
name: 'mine',
|
|
||||||
component: () => import('@/views/mine/index.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/serveInfo',
|
|
||||||
name: 'serveInfo',
|
|
||||||
component: () => import('@/views/info/serveInfo.vue'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/privateInfo',
|
|
||||||
name: 'privateInfo',
|
|
||||||
component: () => import('@/views/info/privateInfo.vue'),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/404',
|
path: '/404',
|
||||||
name: '404',
|
name: '404',
|
||||||
|
@ -11,6 +11,7 @@ const currentListUuid=ref('')
|
|||||||
const isStop = ref(false);
|
const isStop = ref(false);
|
||||||
const isGPT4 = ref(false);
|
const isGPT4 = ref(false);
|
||||||
const loading=ref(false)
|
const loading=ref(false)
|
||||||
|
const show=ref(false)
|
||||||
const getDataList = async () => {
|
const getDataList = async () => {
|
||||||
const data = {
|
const data = {
|
||||||
page: 1,
|
page: 1,
|
||||||
@ -18,7 +19,7 @@ const currentListUuid=ref('')
|
|||||||
}
|
}
|
||||||
const res=await getSessionList(data)
|
const res=await getSessionList(data)
|
||||||
if (res.code===0){
|
if (res.code===0){
|
||||||
dataList.value=res.data.data
|
dataList.value=res.data.data??[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const detailData=ref([])
|
const detailData=ref([])
|
||||||
@ -45,7 +46,7 @@ const currentListUuid=ref('')
|
|||||||
conversationOpt:null,
|
conversationOpt:null,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
detailData.value=res.data
|
detailData.value=res.data??[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const createSessionStore=async ()=>{
|
const createSessionStore=async ()=>{
|
||||||
@ -64,5 +65,5 @@ const currentListUuid=ref('')
|
|||||||
//getDataList()
|
//getDataList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { sessionDetail,currentListUuid ,gptMode,getDataList,dataList,getSessionDetail,createSessionStore,deleteSession,isStop,isGPT4,loading};
|
return {show, sessionDetail,currentListUuid ,gptMode,getDataList,dataList,getSessionDetail,createSessionStore,deleteSession,isStop,isGPT4,loading};
|
||||||
});
|
});
|
||||||
|
@ -1,60 +0,0 @@
|
|||||||
import {ElMessage, ElMessageBox} from 'element-plus'
|
|
||||||
|
|
||||||
let lastSrcs;
|
|
||||||
|
|
||||||
const scriptReg = /\<script.*src=["'](?<src>[^"']+)/gm;
|
|
||||||
|
|
||||||
// 获取最新的 script src
|
|
||||||
async function extractNewScripts() {
|
|
||||||
const html = await fetch("/?_timestamp=" + Date.now()).then((res) =>
|
|
||||||
res.text()
|
|
||||||
);
|
|
||||||
scriptReg.lastIndex = 0;
|
|
||||||
let result = [];
|
|
||||||
let match;
|
|
||||||
while ((match = scriptReg.exec(html))) {
|
|
||||||
result.push(match.groups.src);
|
|
||||||
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
// 判断是否需要更新
|
|
||||||
async function needUpdate() {
|
|
||||||
const newScripts = await extractNewScripts();
|
|
||||||
if (!lastSrcs) {
|
|
||||||
lastSrcs = newScripts;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let result = false;
|
|
||||||
if (newScripts.length !== lastSrcs.length) {
|
|
||||||
result = true;
|
|
||||||
} else {
|
|
||||||
for (let i = 0; i < newScripts.length; i++) {
|
|
||||||
if (newScripts[i] !== lastSrcs[i]) {
|
|
||||||
result = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastSrcs = newScripts;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
// 间隔五分钟
|
|
||||||
const DURATION = 1000 * 10 ;
|
|
||||||
function autoRefresh() {
|
|
||||||
setTimeout(async () => {
|
|
||||||
const willUpdate = await needUpdate();
|
|
||||||
if (willUpdate) {
|
|
||||||
ElMessageBox.confirm('点击确定刷新页面,取消则继续使用旧版本', '提示!', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning'
|
|
||||||
}).then(async () => {
|
|
||||||
location.reload();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
autoRefresh();
|
|
||||||
}, DURATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
autoRefresh();
|
|
@ -2,15 +2,11 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { ElLoading } from 'element-plus'
|
import { ElLoading } from 'element-plus'
|
||||||
import {Local} from '@/utils/storage/storage.js'
|
import {Local} from '@/utils/storage/storage.js'
|
||||||
import { router } from '@/router'
|
|
||||||
const ms = useMessage()
|
|
||||||
const request = axios.create({
|
const request = axios.create({
|
||||||
baseURL:import.meta.env.VITE_APP_API_BASE_URL,
|
baseURL:import.meta.env.VITE_APP_API_BASE_URL,
|
||||||
timeout:60 * 60 * 1000
|
timeout:60000
|
||||||
});
|
});
|
||||||
let loading
|
let loading
|
||||||
let isRefreshing = false;
|
|
||||||
let refreshSubscribers = [];
|
|
||||||
request.interceptors.request.use((config)=>{
|
request.interceptors.request.use((config)=>{
|
||||||
if (config.loading!==false){
|
if (config.loading!==false){
|
||||||
loading=ElLoading.service({
|
loading=ElLoading.service({
|
||||||
@ -22,72 +18,10 @@ request.interceptors.request.use((config)=>{
|
|||||||
config.headers.Authorization =Local.get('token')
|
config.headers.Authorization =Local.get('token')
|
||||||
return config;
|
return config;
|
||||||
});
|
});
|
||||||
request.interceptors.response.use(async (res)=>{
|
request.interceptors.response.use((res)=>{
|
||||||
// 如果返回401,说明token过期,需要重新登录
|
|
||||||
if (res && res.data.code === 401) {
|
|
||||||
console.log("token过期");
|
|
||||||
return getRefreshToken(res);
|
|
||||||
}
|
|
||||||
loading?.close()
|
loading?.close()
|
||||||
return res.data;
|
return res.data;
|
||||||
},()=>{
|
},()=>{
|
||||||
loading?.close()
|
loading?.close()
|
||||||
});
|
});
|
||||||
// 获取刷新token,刷新token成功后重新请求
|
|
||||||
const getRefreshToken = async (response) => {
|
|
||||||
console.log("刷新token",isRefreshing);
|
|
||||||
if (!isRefreshing) {
|
|
||||||
isRefreshing = true;
|
|
||||||
const refreshToken = Local.get("RefreshToken");
|
|
||||||
if (refreshToken) {
|
|
||||||
try {
|
|
||||||
const data = { refreshToken };
|
|
||||||
const res = await fetch(
|
|
||||||
import.meta.env.VITE_APP_API_BASE_URL+"/user/refresh/token",
|
|
||||||
{
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const responseData = await res.json(); // Parse the response body as JSON
|
|
||||||
if (responseData.code === 200) {
|
|
||||||
console.log("刷新token成功");
|
|
||||||
Local.set("token", responseData.data.Token);
|
|
||||||
Local.set("userInfo", responseData.data.AccountInfo);
|
|
||||||
Local.set("RefreshToken", responseData.data.RefreshToken);
|
|
||||||
|
|
||||||
return Promise.resolve(request(response.config));
|
|
||||||
} else {
|
|
||||||
// 重新登录
|
|
||||||
await router.push('/login');
|
|
||||||
responseData.message = responseData.message || responseData.msg;
|
|
||||||
loading?.close()
|
|
||||||
return Promise.reject(responseData);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
loading?.close()
|
|
||||||
return Promise.reject(error);
|
|
||||||
} finally {
|
|
||||||
loading?.close()
|
|
||||||
isRefreshing = false;
|
|
||||||
refreshSubscribers.forEach((callback) => callback());
|
|
||||||
refreshSubscribers = [];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 重新登录
|
|
||||||
await router.push('/login')
|
|
||||||
loading?.close()
|
|
||||||
return Promise.reject(response);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
refreshSubscribers.push(() => {
|
|
||||||
resolve(request(response.config));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
export default request;
|
export default request;
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
import { computed, nextTick } from 'vue'
|
import { computed, nextTick } from 'vue'
|
||||||
import { HoverButton, SvgIcon } from '@/components/common'
|
import { HoverButton, SvgIcon } from '@/components/common'
|
||||||
import { useAppStore, useChatStore } from '@/store'
|
import { useAppStore, useChatStore } from '@/store'
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import AvatarComponent from '../Message/Avatar.vue'
|
|
||||||
interface Props {
|
interface Props {
|
||||||
usingContext: boolean
|
usingContext: boolean
|
||||||
}
|
}
|
||||||
@ -16,7 +15,7 @@ interface Emit {
|
|||||||
defineProps<Props>()
|
defineProps<Props>()
|
||||||
|
|
||||||
const emit = defineEmits<Emit>()
|
const emit = defineEmits<Emit>()
|
||||||
const router = useRouter()
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const chatStore = useChatStore()
|
const chatStore = useChatStore()
|
||||||
|
|
||||||
@ -40,38 +39,39 @@ function handleExport() {
|
|||||||
function handleClear() {
|
function handleClear() {
|
||||||
emit('handleClear')
|
emit('handleClear')
|
||||||
}
|
}
|
||||||
// 我的
|
|
||||||
function goMine() {
|
|
||||||
router.push('/mine')
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<header style="padding-top: 30px;"
|
<header
|
||||||
class="sticky top-0 left-0 right-0 z-30 border-b dark:border-neutral-800 bg-white/80 dark:bg-black/20 backdrop-blur">
|
class="sticky top-0 left-0 right-0 z-30 border-b dark:border-neutral-800 bg-white/80 dark:bg-black/20 backdrop-blur"
|
||||||
|
>
|
||||||
<div class="relative flex items-center justify-between min-w-0 overflow-hidden h-14">
|
<div class="relative flex items-center justify-between min-w-0 overflow-hidden h-14">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<button class="flex items-center justify-center w-11 h-11" @click="handleUpdateCollapsed">
|
<button
|
||||||
|
class="flex items-center justify-center w-11 h-11"
|
||||||
|
@click="handleUpdateCollapsed"
|
||||||
|
>
|
||||||
<SvgIcon v-if="collapsed" class="text-2xl" icon="ri:align-justify" />
|
<SvgIcon v-if="collapsed" class="text-2xl" icon="ri:align-justify" />
|
||||||
<SvgIcon v-else class="text-2xl" icon="ri:align-right" />
|
<SvgIcon v-else class="text-2xl" icon="ri:align-right" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="flex-1 px-4 pr-6 overflow-hidden cursor-pointer select-none text-ellipsis whitespace-nowrap"
|
<h1
|
||||||
@dblclick="onScrollToTop">
|
class="flex-1 px-4 pr-6 overflow-hidden cursor-pointer select-none text-ellipsis whitespace-nowrap"
|
||||||
|
@dblclick="onScrollToTop"
|
||||||
|
>
|
||||||
{{ currentChatHistory?.title ?? '' }}
|
{{ currentChatHistory?.title ?? '' }}
|
||||||
</h1>
|
</h1>
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<!-- <HoverButton @click="handleExport">
|
<HoverButton @click="handleExport">
|
||||||
<span class="text-xl text-[#4f555e] dark:text-white">
|
<span class="text-xl text-[#4f555e] dark:text-white">
|
||||||
<SvgIcon icon="ri:download-2-line" />
|
<SvgIcon icon="ri:download-2-line" />
|
||||||
</span>
|
</span>
|
||||||
</HoverButton> -->
|
</HoverButton>
|
||||||
<!-- <HoverButton @click="handleClear">
|
<HoverButton @click="handleClear">
|
||||||
<span class="text-xl text-[#4f555e] dark:text-white">
|
<span class="text-xl text-[#4f555e] dark:text-white">
|
||||||
<SvgIcon icon="ri:delete-bin-line" />
|
<SvgIcon icon="ri:delete-bin-line" />
|
||||||
</span>
|
</span>
|
||||||
</HoverButton> -->
|
</HoverButton>
|
||||||
<AvatarComponent :image="true" @click="goMine" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
@ -1,25 +1,19 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import {ref} from 'vue'
|
||||||
import { NAvatar } from 'naive-ui'
|
import { NAvatar } from 'naive-ui'
|
||||||
|
const defaultAvatar=ref(JSON.parse(localStorage.getItem('userInfo')).Avatar)
|
||||||
|
|
||||||
const defaultAvatar = ref(JSON.parse(localStorage.getItem('userInfo'))?.Avatar || '')
|
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
image: Boolean
|
image: Boolean
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<template v-if="image">
|
<template v-if="image">
|
||||||
<NAvatar :src="defaultAvatar" :fallback-src="defaultAvatar" />
|
<NAvatar :src="defaultAvatar" :fallback-src="defaultAvatar" />
|
||||||
</template>
|
</template>
|
||||||
<span v-else class="text-[28px] dark:text-white">
|
<span v-else class="text-[28px] dark:text-white">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" aria-hidden="true" width="1em" height="1em">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" aria-hidden="true" width="1em" height="1em">
|
||||||
<path
|
<path d="M29.71,13.09A8.09,8.09,0,0,0,20.34,2.68a8.08,8.08,0,0,0-13.7,2.9A8.08,8.08,0,0,0,2.3,18.9,8,8,0,0,0,3,25.45a8.08,8.08,0,0,0,8.69,3.87,8,8,0,0,0,6,2.68,8.09,8.09,0,0,0,7.7-5.61,8,8,0,0,0,5.33-3.86A8.09,8.09,0,0,0,29.71,13.09Zm-12,16.82a6,6,0,0,1-3.84-1.39l.19-.11,6.37-3.68a1,1,0,0,0,.53-.91v-9l2.69,1.56a.08.08,0,0,1,.05.07v7.44A6,6,0,0,1,17.68,29.91ZM4.8,24.41a6,6,0,0,1-.71-4l.19.11,6.37,3.68a1,1,0,0,0,1,0l7.79-4.49V22.8a.09.09,0,0,1,0,.08L13,26.6A6,6,0,0,1,4.8,24.41ZM3.12,10.53A6,6,0,0,1,6.28,7.9v7.57a1,1,0,0,0,.51.9l7.75,4.47L11.85,22.4a.14.14,0,0,1-.09,0L5.32,18.68a6,6,0,0,1-2.2-8.18Zm22.13,5.14-7.78-4.52L20.16,9.6a.08.08,0,0,1,.09,0l6.44,3.72a6,6,0,0,1-.9,10.81V16.56A1.06,1.06,0,0,0,25.25,15.67Zm2.68-4-.19-.12-6.36-3.7a1,1,0,0,0-1.05,0l-7.78,4.49V9.2a.09.09,0,0,1,0-.09L19,5.4a6,6,0,0,1,8.91,6.21ZM11.08,17.15,8.38,15.6a.14.14,0,0,1-.05-.08V8.1a6,6,0,0,1,9.84-4.61L18,3.6,11.61,7.28a1,1,0,0,0-.53.91ZM12.54,14,16,12l3.47,2v4L16,20l-3.47-2Z" fill="currentColor" />
|
||||||
d="M29.71,13.09A8.09,8.09,0,0,0,20.34,2.68a8.08,8.08,0,0,0-13.7,2.9A8.08,8.08,0,0,0,2.3,18.9,8,8,0,0,0,3,25.45a8.08,8.08,0,0,0,8.69,3.87,8,8,0,0,0,6,2.68,8.09,8.09,0,0,0,7.7-5.61,8,8,0,0,0,5.33-3.86A8.09,8.09,0,0,0,29.71,13.09Zm-12,16.82a6,6,0,0,1-3.84-1.39l.19-.11,6.37-3.68a1,1,0,0,0,.53-.91v-9l2.69,1.56a.08.08,0,0,1,.05.07v7.44A6,6,0,0,1,17.68,29.91ZM4.8,24.41a6,6,0,0,1-.71-4l.19.11,6.37,3.68a1,1,0,0,0,1,0l7.79-4.49V22.8a.09.09,0,0,1,0,.08L13,26.6A6,6,0,0,1,4.8,24.41ZM3.12,10.53A6,6,0,0,1,6.28,7.9v7.57a1,1,0,0,0,.51.9l7.75,4.47L11.85,22.4a.14.14,0,0,1-.09,0L5.32,18.68a6,6,0,0,1-2.2-8.18Zm22.13,5.14-7.78-4.52L20.16,9.6a.08.08,0,0,1,.09,0l6.44,3.72a6,6,0,0,1-.9,10.81V16.56A1.06,1.06,0,0,0,25.25,15.67Zm2.68-4-.19-.12-6.36-3.7a1,1,0,0,0-1.05,0l-7.78,4.49V9.2a.09.09,0,0,1,0-.09L19,5.4a6,6,0,0,1,8.91,6.21ZM11.08,17.15,8.38,15.6a.14.14,0,0,1-.05-.08V8.1a6,6,0,0,1,9.84-4.61L18,3.6,11.61,7.28a1,1,0,0,0-.53.91ZM12.54,14,16,12l3.47,2v4L16,20l-3.47-2Z"
|
|
||||||
fill="currentColor" />
|
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
import {uploadFormData, uploadImg} from "@/api/api";
|
import {uploadFormData, uploadImg} from "@/api/api";
|
||||||
import {Local} from "@/utils/storage/storage";
|
import {Local} from "@/utils/storage/storage";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import {computed, onMounted, onUnmounted, ref, watch,onBeforeMount} from 'vue'
|
import {computed, onMounted, onUnmounted, ref, watch} from 'vue'
|
||||||
import {useRouter} from 'vue-router'
|
import {useRoute} from 'vue-router'
|
||||||
import {AreaChartOutlined, PlusOutlined} from '@ant-design/icons-vue';
|
import {AreaChartOutlined, PlusOutlined} from '@ant-design/icons-vue';
|
||||||
import html2canvas from 'html2canvas'
|
import html2canvas from 'html2canvas'
|
||||||
import {Message} from './components'
|
import {Message} from './components'
|
||||||
@ -23,7 +23,6 @@ import {sessionDetailForSetup} from '@/store'
|
|||||||
import StopSvg from '@/assets/RecordStop12Regular.svg'
|
import StopSvg from '@/assets/RecordStop12Regular.svg'
|
||||||
const sessionDetailData = sessionDetailForSetup()
|
const sessionDetailData = sessionDetailForSetup()
|
||||||
let controller = new AbortController()
|
let controller = new AbortController()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
sessionDetail: dataSources,
|
sessionDetail: dataSources,
|
||||||
currentListUuid,
|
currentListUuid,
|
||||||
@ -32,7 +31,7 @@ const {
|
|||||||
isGPT4,
|
isGPT4,
|
||||||
loading
|
loading
|
||||||
} = storeToRefs(sessionDetailData)
|
} = storeToRefs(sessionDetailData)
|
||||||
const router = useRouter()
|
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
const ms = useMessage()
|
const ms = useMessage()
|
||||||
const chatStore = useChatStore()
|
const chatStore = useChatStore()
|
||||||
@ -94,7 +93,6 @@ function handleSubmit() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
} */
|
} */
|
||||||
|
|
||||||
const API_URL = `${import.meta.env.VITE_APP_API_BASE_URL}/chat/completion`;
|
const API_URL = `${import.meta.env.VITE_APP_API_BASE_URL}/chat/completion`;
|
||||||
const createParams = () => {
|
const createParams = () => {
|
||||||
const messages = dataSources.value.map((x) => {
|
const messages = dataSources.value.map((x) => {
|
||||||
@ -135,7 +133,6 @@ const handleResponseStream = async (reader) => {
|
|||||||
} = await reader.read();
|
} = await reader.read();
|
||||||
if (!done) {
|
if (!done) {
|
||||||
let decoded = new TextDecoder().decode(value);
|
let decoded = new TextDecoder().decode(value);
|
||||||
console.log(decoded,'decoded')
|
|
||||||
let decodedArray = decoded.split("data: ");
|
let decodedArray = decoded.split("data: ");
|
||||||
for (const decoded of decodedArray) {
|
for (const decoded of decodedArray) {
|
||||||
if (decoded !== "") {
|
if (decoded !== "") {
|
||||||
@ -160,56 +157,6 @@ const handleResponseStream = async (reader) => {
|
|||||||
await handleResponseStream(reader);
|
await handleResponseStream(reader);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let isRefreshing = false;
|
|
||||||
let refreshSubscribers = [];
|
|
||||||
// 获取刷新token,刷新token成功后重新请求
|
|
||||||
const getRefreshToken = async (response) => {
|
|
||||||
if (!isRefreshing) {
|
|
||||||
isRefreshing = true;
|
|
||||||
const refreshToken = Local.get("RefreshToken");
|
|
||||||
if (refreshToken) {
|
|
||||||
try {
|
|
||||||
const data = { refreshToken };
|
|
||||||
const res = await fetch(
|
|
||||||
import.meta.env.VITE_APP_API_BASE_URL+"/user/refresh/token",
|
|
||||||
{
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const responseData = await res.json(); // Parse the response body as JSON
|
|
||||||
if (responseData.code === 200) {
|
|
||||||
Local.set("token", responseData.data.Token);
|
|
||||||
Local.set("userInfo", responseData.data.AccountInfo);
|
|
||||||
Local.set("RefreshToken", responseData.data.RefreshToken);
|
|
||||||
location.reload();
|
|
||||||
} else {
|
|
||||||
// 重新登录
|
|
||||||
await router.push('/login');
|
|
||||||
responseData.message = responseData.message || responseData.msg;
|
|
||||||
return Promise.reject(responseData);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return Promise.reject(error);
|
|
||||||
} finally {
|
|
||||||
isRefreshing = false;
|
|
||||||
refreshSubscribers.forEach((callback) => callback());
|
|
||||||
refreshSubscribers = [];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 重新登录
|
|
||||||
await router.push('/login')
|
|
||||||
return Promise.reject(response);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const sendDataStream = async () => {
|
const sendDataStream = async () => {
|
||||||
const params = createParams();
|
const params = createParams();
|
||||||
fileList.value = []
|
fileList.value = []
|
||||||
@ -234,18 +181,12 @@ const sendDataStream = async () => {
|
|||||||
Authorization: Local.get('token'),
|
Authorization: Local.get('token'),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.log(response,'response')
|
|
||||||
const contentType = response.headers.get('Content-Type');
|
const contentType = response.headers.get('Content-Type');
|
||||||
if (!contentType || !contentType.includes('application/json')) {
|
if (!contentType || !contentType.includes('application/json')) {
|
||||||
const reader = response.body.getReader();
|
const reader = response.body.getReader();
|
||||||
dataSources.value[dataSources.value.length - 1].text = ''
|
dataSources.value[dataSources.value.length - 1].text = ''
|
||||||
await handleResponseStream(reader);
|
await handleResponseStream(reader);
|
||||||
}else{
|
|
||||||
const responseData = await response.json();
|
|
||||||
if (responseData.code === 401) {
|
|
||||||
await getRefreshToken(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('发生错误:', error);
|
console.error('发生错误:', error);
|
||||||
@ -393,12 +334,8 @@ const footerClass = computed(() => {
|
|||||||
})
|
})
|
||||||
const isShowBottom=ref(false)
|
const isShowBottom=ref(false)
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
||||||
if(!Local.get('token')){
|
|
||||||
router.push('/login')
|
|
||||||
}
|
|
||||||
scrollRef.value.addEventListener('scroll', function() {
|
scrollRef.value.addEventListener('scroll', function() {
|
||||||
if (scrollRef.value.scrollTop + scrollRef.value.clientHeight +100>= scrollRef.value.scrollHeight) {
|
if (scrollRef.value.scrollTop + scrollRef.value.clientHeight>= scrollRef.value.scrollHeight) {
|
||||||
isShowBottom.value=false
|
isShowBottom.value=false
|
||||||
}else {
|
}else {
|
||||||
isShowBottom.value=true
|
isShowBottom.value=true
|
||||||
@ -487,6 +424,7 @@ watch(dataSources,()=>{
|
|||||||
loading.value=false
|
loading.value=false
|
||||||
scrollToBottom('auto')
|
scrollToBottom('auto')
|
||||||
})
|
})
|
||||||
|
const inputKey=ref(1)
|
||||||
const customRequest = async (file) => {
|
const customRequest = async (file) => {
|
||||||
console.log(file,'file')
|
console.log(file,'file')
|
||||||
const res = await uploadImg({
|
const res = await uploadImg({
|
||||||
@ -531,7 +469,7 @@ const customRequest = async (file) => {
|
|||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<div id="scrollRef" ref="scrollRef" class="h-full overflow-hidden overflow-y-auto">
|
<div id="scrollRef" ref="scrollRef" class="h-full overflow-hidden overflow-y-auto">
|
||||||
<div
|
<div
|
||||||
id="image-wrapper"
|
id="image-wrapper"
|
||||||
class="w-full max-w-screen-xl m-auto dark:bg-[#101014]"
|
class="w-full max-w-screen-xl m-auto dark:bg-[#101014]"
|
||||||
@ -548,7 +486,7 @@ const customRequest = async (file) => {
|
|||||||
<div>
|
<div>
|
||||||
<Message
|
<Message
|
||||||
v-for="(item, index) of dataSources"
|
v-for="(item, index) of dataSources"
|
||||||
:key="index"
|
:key="item.dateTime"
|
||||||
:date-time="item.dateTime"
|
:date-time="item.dateTime"
|
||||||
:text="item.text"
|
:text="item.text"
|
||||||
:fileList="item.fileList"
|
:fileList="item.fileList"
|
||||||
@ -573,7 +511,7 @@ const customRequest = async (file) => {
|
|||||||
<footer :class="footerClass">
|
<footer :class="footerClass">
|
||||||
<div class="w-full max-w-screen-xl m-auto">
|
<div class="w-full max-w-screen-xl m-auto">
|
||||||
<div class="flex items-center justify-center space-x-2" style="flex-wrap: initial">
|
<div class="flex items-center justify-center space-x-2" style="flex-wrap: initial">
|
||||||
<NPopover v-if="gptMode==='gpt-4o'" trigger="click" :show="visible1">
|
<NPopover trigger="click" :show="visible1">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<HoverButton @click="visible1=!visible1">
|
<HoverButton @click="visible1=!visible1">
|
||||||
<span class="text-xl text-[#4f555e] dark:text-white"
|
<span class="text-xl text-[#4f555e] dark:text-white"
|
||||||
@ -585,7 +523,6 @@ const customRequest = async (file) => {
|
|||||||
</template>
|
</template>
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
<NUpload
|
<NUpload
|
||||||
|
|
||||||
:max-count="1"
|
:max-count="1"
|
||||||
:default-file-list="fileList1"
|
:default-file-list="fileList1"
|
||||||
name="file"
|
name="file"
|
||||||
@ -678,17 +615,21 @@ const customRequest = async (file) => {
|
|||||||
@keypress="handleEnter"
|
@keypress="handleEnter"
|
||||||
/> -->
|
/> -->
|
||||||
|
|
||||||
<NInput
|
<NInput
|
||||||
style="width:75%"
|
v-memo="[prompt]"
|
||||||
ref="inputRef"
|
style="width:75%"
|
||||||
v-model:value="prompt"
|
:key="inputKey"
|
||||||
type="textarea"
|
ref="inputRef"
|
||||||
size="large"
|
v-model:value="prompt"
|
||||||
:placeholder="placeholder"
|
type="textarea"
|
||||||
:autosize="{ minRows: 1, maxRows: isMobile ? 4 : 8 }"
|
size="large"
|
||||||
@keypress="handleEnter"
|
:placeholder="placeholder"
|
||||||
>
|
:autosize="{ minRows: 1, maxRows: isMobile ? 4 : 8 }"
|
||||||
</NInput>
|
@keypress="handleEnter"
|
||||||
|
>
|
||||||
|
</NInput>
|
||||||
|
|
||||||
|
|
||||||
<NButton color="#8a2be2" type="primary" size="large" :disabled="buttonDisabled" @click="handleSubmit">
|
<NButton color="#8a2be2" type="primary" size="large" :disabled="buttonDisabled" @click="handleSubmit">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<span class="dark:text-black" v-if="!loading">
|
<span class="dark:text-black" v-if="!loading">
|
||||||
|
@ -51,7 +51,7 @@ const show=ref(false)
|
|||||||
<template>
|
<template>
|
||||||
<NScrollbar class="px-4">
|
<NScrollbar class="px-4">
|
||||||
<div class="flex flex-col gap-2 text-sm mb-1">
|
<div class="flex flex-col gap-2 text-sm mb-1">
|
||||||
<template v-if="!dataList?.length">
|
<template v-if="!dataList.length">
|
||||||
<div class="flex flex-col items-center mt-4 text-center text-neutral-300">
|
<div class="flex flex-col items-center mt-4 text-center text-neutral-300">
|
||||||
<SvgIcon icon="ri:inbox-line" class="mb-2 text-3xl" />
|
<SvgIcon icon="ri:inbox-line" class="mb-2 text-3xl" />
|
||||||
<span>{{ $t('common.noData') }}</span>
|
<span>{{ $t('common.noData') }}</span>
|
||||||
|
@ -60,7 +60,6 @@ const getMobileClass = computed(() => {
|
|||||||
return {
|
return {
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
zIndex: 50,
|
zIndex: 50,
|
||||||
paddingTop: '30px',
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {}
|
||||||
@ -75,13 +74,6 @@ const mobileSafeArea = computed(() => {
|
|||||||
return {}
|
return {}
|
||||||
})
|
})
|
||||||
const options = () => {
|
const options = () => {
|
||||||
if (!Local.get('ruleBtn')) {
|
|
||||||
return [{
|
|
||||||
label: 'GPT-3.5',
|
|
||||||
value: 'gpt-3.5-turbo',
|
|
||||||
permission: 'gpt-3.5-btn'
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
return Local.get('ruleBtn').find(x => x === 'gpt-4-btn') ? [{
|
return Local.get('ruleBtn').find(x => x === 'gpt-4-btn') ? [{
|
||||||
label: 'GPT-3.5',
|
label: 'GPT-3.5',
|
||||||
value: 'gpt-3.5-turbo',
|
value: 'gpt-3.5-turbo',
|
||||||
@ -117,7 +109,7 @@ watch(
|
|||||||
<template>
|
<template>
|
||||||
<NLayoutSider
|
<NLayoutSider
|
||||||
:collapsed="collapsed"
|
:collapsed="collapsed"
|
||||||
:collapsed-width="0"
|
:collapsed-width="15"
|
||||||
:width="270"
|
:width="270"
|
||||||
:show-trigger="isMobile ? false : 'arrow-circle'"
|
:show-trigger="isMobile ? false : 'arrow-circle'"
|
||||||
collapse-mode="transform"
|
collapse-mode="transform"
|
||||||
|
11
src/views/chat/test.vue
Normal file
11
src/views/chat/test.vue
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,246 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { NButton, } from 'naive-ui'
|
|
||||||
import { useRouter, } from 'vue-router'
|
|
||||||
import { Local } from "@/utils/storage/storage";
|
|
||||||
import { loginApi, getCode, getMenuApi } from "@/api/api";
|
|
||||||
import { ref, onMounted, onUnmounted } from 'vue'
|
|
||||||
const router = useRouter()
|
|
||||||
const ms = useMessage()
|
|
||||||
// 登录方式
|
|
||||||
const isCode = ref(false);
|
|
||||||
const username = ref('')
|
|
||||||
const password = ref('')
|
|
||||||
const code = ref('')
|
|
||||||
const checked = ref(false)
|
|
||||||
// 获取CD
|
|
||||||
const leftTime = ref(60);
|
|
||||||
// 能否获取验证码
|
|
||||||
const canSend = ref(true);
|
|
||||||
const printTextWrod = ref(["FONCHAT", "Let's Chat", "Let's Create", "Let's Go"])
|
|
||||||
const backgroundColor = ref(['red', 'blue', '#f3f4f6', '#f3f4f6'])
|
|
||||||
let printInterval = null
|
|
||||||
onMounted(() => {
|
|
||||||
textEffect()
|
|
||||||
})
|
|
||||||
onUnmounted(() => {
|
|
||||||
clearInterval(printInterval)
|
|
||||||
})
|
|
||||||
// 解决离开页面文字堆叠
|
|
||||||
document.addEventListener('visibilitychange', function () {
|
|
||||||
if (document.hidden) {
|
|
||||||
clearInterval(printInterval)
|
|
||||||
} else {
|
|
||||||
clearInterval(printInterval)
|
|
||||||
document.querySelector('#chat').innerText = ''
|
|
||||||
textEffect()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 文字特效逻辑
|
|
||||||
function textEffect() {
|
|
||||||
printText(printTextWrod.value[0])
|
|
||||||
let index = 1
|
|
||||||
printInterval = setInterval(() => {
|
|
||||||
if (index >= printTextWrod.value.length) {
|
|
||||||
index = 0
|
|
||||||
}
|
|
||||||
printText(printTextWrod.value[index])
|
|
||||||
index++
|
|
||||||
document.querySelector('#chat').innerText = ''
|
|
||||||
}, 2500)
|
|
||||||
}
|
|
||||||
function login() {
|
|
||||||
router.push('/')
|
|
||||||
}
|
|
||||||
// 切换登录
|
|
||||||
const changeLogin = () => {
|
|
||||||
password.value = '';
|
|
||||||
code.value = '';
|
|
||||||
isCode.value = !isCode.value;
|
|
||||||
};
|
|
||||||
// 获取验证码
|
|
||||||
const getCodeNum = async () => {
|
|
||||||
if (!username.value) {
|
|
||||||
ms.error('请输入手机号码')
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let data = {
|
|
||||||
TelNum: username.value
|
|
||||||
}
|
|
||||||
const res = await getCode(
|
|
||||||
data
|
|
||||||
)
|
|
||||||
if (res.status === 0) {
|
|
||||||
ms.success('验证码已发送,请注意查收')
|
|
||||||
// 倒计时逻辑
|
|
||||||
canSend.value = false;
|
|
||||||
let timer = setInterval(() => {
|
|
||||||
leftTime.value--;
|
|
||||||
if (leftTime.value <= 0) {
|
|
||||||
canSend.value = true;
|
|
||||||
clearInterval(timer);
|
|
||||||
leftTime.value = 60;
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
ms.error(res.msg)
|
|
||||||
canSend.value = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 登录
|
|
||||||
const goLogin = async () => {
|
|
||||||
if (!checked.value) {
|
|
||||||
ms.error('请先同意协议')
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!username.value) {
|
|
||||||
ms.error('请输入手机号码')
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!password.value && !isCode.value) {
|
|
||||||
ms.error('请输入密码')
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!code.value && isCode.value) {
|
|
||||||
ms.error('请输入验证码')
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let data = {
|
|
||||||
TelNum: username.value,
|
|
||||||
Password: password.value,
|
|
||||||
Code: code.value
|
|
||||||
}
|
|
||||||
const res = await loginApi(
|
|
||||||
data
|
|
||||||
)
|
|
||||||
if (res.status === 0) {
|
|
||||||
ms.success('登录成功')
|
|
||||||
Local.set("userInfo", res.data.AccountInfo);
|
|
||||||
Local.set("token", res.data.Token);
|
|
||||||
Local.set("RefreshToken", res.data.RefreshToken);
|
|
||||||
await getMenu();
|
|
||||||
} else {
|
|
||||||
ms.error(res.msg)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 获取菜单
|
|
||||||
const getMenu = async () => {
|
|
||||||
const res = await getMenuApi({})
|
|
||||||
if (res.status === 0) {
|
|
||||||
let ruleBtn = [];
|
|
||||||
if (res.data.MyButtonAuths) {
|
|
||||||
ruleBtn = await res.data.MyButtonAuths.map((i) => {
|
|
||||||
return i.Url;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Local.set("ruleBtn", ruleBtn);
|
|
||||||
router.push('/')
|
|
||||||
} else {
|
|
||||||
ms.error(res.msg)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 跳转服务协议
|
|
||||||
const goServeInfo = () => {
|
|
||||||
router.push('/serveInfo')
|
|
||||||
};
|
|
||||||
// 跳转隐私权政策
|
|
||||||
const goPrivateInfo = () => {
|
|
||||||
router.push('/privateInfo')
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function printText(content, speed = 70) {
|
|
||||||
let dom = document.querySelector('#chat')
|
|
||||||
let index = 0
|
|
||||||
setCursorStatus(dom, 'typing')
|
|
||||||
let printInterval = setInterval(() => {
|
|
||||||
dom.innerText += content[index]
|
|
||||||
index++
|
|
||||||
if (index >= content.length) {
|
|
||||||
setCursorStatus(dom, 'end')
|
|
||||||
clearInterval(printInterval)
|
|
||||||
}
|
|
||||||
}, speed)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function setCursorStatus(dom, status) {
|
|
||||||
const classList = {
|
|
||||||
loading: 'typing blinker',
|
|
||||||
typing: 'typing',
|
|
||||||
end: '',
|
|
||||||
}
|
|
||||||
dom.className = classList[status]
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="flex h-full main-box">
|
|
||||||
<div class="px-4 m-auto space-y-4 max-[400px]">
|
|
||||||
<p style="padding: 10px;text-align: center;font-size: 26px;font-weight: bolder;" id="chat"></p>
|
|
||||||
<n-input round size="large" v-model:value="username" type="text" placeholder="请输入用户名" />
|
|
||||||
<n-input round size="large" v-if="!isCode" v-model:value="password" show-password-on="click" type="password"
|
|
||||||
placeholder="请输入密码" />
|
|
||||||
<n-input round size="large" v-if="isCode" v-model:value="code" type="text" placeholder="请输入验证码">
|
|
||||||
<template #suffix>
|
|
||||||
<div v-if="canSend" class="get-code" @click="getCodeNum">获取验证码</div>
|
|
||||||
<div v-else class="get-code">{{ leftTime }}s</div>
|
|
||||||
</template>
|
|
||||||
</n-input>
|
|
||||||
<div class="text-center">
|
|
||||||
<NButton size="large" circle type="primary" @click="goLogin" style="width: 250px;">
|
|
||||||
登录
|
|
||||||
</NButton>
|
|
||||||
<div v-if="!isCode" @click="changeLogin" style="margin-top: 20px; color: #7f71a5ff;cursor: pointer;">切换验证码登录
|
|
||||||
</div>
|
|
||||||
<div v-else @click="changeLogin" style="margin-top: 20px; color: #7f71a5ff;cursor: pointer;">切换账号密码登录</div>
|
|
||||||
<div class="check">
|
|
||||||
<n-checkbox v-model:checked="checked">
|
|
||||||
|
|
||||||
</n-checkbox>
|
|
||||||
<div class="txt">已阅读并同意
|
|
||||||
<text class="col" @click="goServeInfo">《平台服务协议》</text>
|
|
||||||
<text class="col" @click="goPrivateInfo">《隐私权政策》</text>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.main-box {
|
|
||||||
background-color: #f3f4f6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.get-code {
|
|
||||||
color: #764cf6ff;
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.check {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.txt {
|
|
||||||
font-size: 22rpx;
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col {
|
|
||||||
color: #5c9fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.typing::after {
|
|
||||||
content: '●';
|
|
||||||
}
|
|
||||||
|
|
||||||
.blinker::after {
|
|
||||||
animation: blinker 1s step-end infinite;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,125 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { NButton } from 'naive-ui'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { ref, onMounted, onUnmounted } from 'vue'
|
|
||||||
import { Local } from "@/utils/storage/storage";
|
|
||||||
const router = useRouter()
|
|
||||||
const ms = useMessage()
|
|
||||||
const startX = ref(0)
|
|
||||||
const startY = ref(0)
|
|
||||||
const endX = ref(0)
|
|
||||||
const endY = ref(0)
|
|
||||||
|
|
||||||
function goBack() {
|
|
||||||
router.go(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleTouchStart(e) {
|
|
||||||
startX.value = e.touches[0].pageX
|
|
||||||
startY.value = e.touches[0].pageY
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleTouchMove(e) {
|
|
||||||
endX.value = e.touches[0].pageX
|
|
||||||
endY.value = e.touches[0].pageY
|
|
||||||
if (endX.value - startX.value > 50 && Math.abs(endY.value - startY.value) < 50) {
|
|
||||||
goBack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function showTips() {
|
|
||||||
ms.warning('请拨打客服电话18051299227进行注销')
|
|
||||||
}
|
|
||||||
function logOut() {
|
|
||||||
Local.clear()
|
|
||||||
router.push('/login')
|
|
||||||
}
|
|
||||||
onMounted(() => {
|
|
||||||
document.addEventListener('touchstart', handleTouchStart, false)
|
|
||||||
document.addEventListener('touchmove', handleTouchMove, false)
|
|
||||||
})
|
|
||||||
onUnmounted(() => {
|
|
||||||
document.removeEventListener('touchstart', handleTouchStart, false)
|
|
||||||
document.removeEventListener('touchmove', handleTouchMove, false)
|
|
||||||
})
|
|
||||||
// 跳转服务协议
|
|
||||||
const goServeInfo = () => {
|
|
||||||
router.push('/serveInfo')
|
|
||||||
};
|
|
||||||
// 跳转隐私权政策
|
|
||||||
const goPrivateInfo = () => {
|
|
||||||
router.push('/privateInfo')
|
|
||||||
};
|
|
||||||
const userInfo = ref(JSON.parse(localStorage.getItem('userInfo')))
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="flex h-full">
|
|
||||||
<div class="header">
|
|
||||||
<n-page-header subtitle="" @back="goBack"></n-page-header>
|
|
||||||
</div>
|
|
||||||
<div class="w-full bg-white shadow-lg rounded-2xl dark:bg-gray-800 mt-40 ">
|
|
||||||
<div class="flex flex-col items-center justify-center p-4 -mt-16">
|
|
||||||
<a href="#" class="relative block">
|
|
||||||
<img alt="profil" :src="userInfo.Avatar" class="mx-auto object-cover rounded-full h-16 w-16 " />
|
|
||||||
</a>
|
|
||||||
<p class="mt-2 text-xl font-medium text-gray-800 dark:text-white">
|
|
||||||
{{ userInfo.NickName }}
|
|
||||||
</p>
|
|
||||||
<p class="flex items-center text-xs text-gray-400">
|
|
||||||
<svg width="10" height="10" fill="currentColor" class="w-4 h-4 mr-2" viewBox="0 0 1792 1792"
|
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path
|
|
||||||
d="M491 1536l91-91-235-235-91 91v107h128v128h107zm523-928q0-22-22-22-10 0-17 7l-542 542q-7 7-7 17 0 22 22 22 10 0 17-7l542-542q7-7 7-17zm-54-192l416 416-832 832h-416v-416zm683 96q0 53-37 90l-166 166-416-416 166-165q36-38 90-38 53 0 91 38l235 234q37 39 37 91z">
|
|
||||||
</path>
|
|
||||||
</svg>
|
|
||||||
{{ userInfo.JobNum }}
|
|
||||||
</p>
|
|
||||||
<p class="text-xs text-gray-400">
|
|
||||||
{{ userInfo.DepartmentName }}
|
|
||||||
</p>
|
|
||||||
<div class="flex items-center justify-between w-full gap-4 mt-8">
|
|
||||||
<button type="button" style="background-color:#f0a020 ;" @click="logOut"
|
|
||||||
class="py-2 px-4 focus:ring-indigo-500 focus:ring-offset-indigo-200 text-white w-full transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 rounded-lg ">
|
|
||||||
退出登录
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between w-full gap-4 mt-8">
|
|
||||||
<button type="button" style="background-color: #FF0000;" @click="showTips"
|
|
||||||
class="py-2 px-4 focus:ring-indigo-500 focus:ring-offset-indigo-200 text-white w-full transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 rounded-lg ">
|
|
||||||
注销账号
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="txt">
|
|
||||||
<text class="col" @click="goServeInfo">《平台服务协议》</text>
|
|
||||||
<text class="col" @click="goPrivateInfo">《隐私权政策》</text>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.header {
|
|
||||||
width: 100%;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 999;
|
|
||||||
padding: 50px 20px 10px 20px;
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
}
|
|
||||||
.check {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.txt {
|
|
||||||
font-size: 22rpx;
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-top: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col {
|
|
||||||
color: #5c9fff;
|
|
||||||
}
|
|
||||||
</style>
|
|
Loading…
Reference in New Issue
Block a user