布局先提交一波
This commit is contained in:
20
index.html
20
index.html
@@ -1,13 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8"/>
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
<title>Vite + Vue</title>
|
<title>语言模型聊天</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script type="module" src="/src/main.js"></script>
|
<script type="module" src="/src/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
2305
package-lock.json
generated
2305
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,10 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"axios": "^1.4.0",
|
||||||
|
"element-plus": "^2.3.4",
|
||||||
|
"sass": "^1.62.1",
|
||||||
|
"sass-loader": "^13.2.2",
|
||||||
"vue": "^3.2.47"
|
"vue": "^3.2.47"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
69
src/App.vue
69
src/App.vue
@@ -1,33 +1,44 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app" @mousedown="windowMove(true)" @mouseup="windowMove(false)">
|
<div id="app">
|
||||||
<Home/>
|
<el-row class="home">
|
||||||
|
<chat class="fill" :config="setting"/>
|
||||||
|
<settings class="mar-l16" v-show="showSettings" v-model="setting"/>
|
||||||
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {isPc} from '@/util/util.js'
|
import Chat from "./components/chat";
|
||||||
import Home from './view/home.vue'
|
import Settings from "./components/settings";
|
||||||
|
import {ChatGPT} from "./utils/models";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {Settings, Chat},
|
||||||
Home
|
data() {
|
||||||
|
return {
|
||||||
|
showSettings: true,
|
||||||
|
setting: {
|
||||||
|
model: new ChatGPT()
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
windowMove(canMove) {
|
handleResize() {
|
||||||
if (isPc()) {
|
console.log("App handleResize")
|
||||||
import("electron").then(({ipcRenderer}) => {
|
this.showSettings = window.innerWidth > 1150;
|
||||||
ipcRenderer.send('window-move-open', canMove ?? false);
|
}
|
||||||
});
|
},
|
||||||
}
|
created() {
|
||||||
},
|
window.addEventListener('resize', this.handleResize)
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
window.removeEventListener('resize', this.handleResize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import url(./assets/font/iconfont.css);
|
|
||||||
|
|
||||||
@each $v in (333, 666, 888, 999, '26f', 'f46') {
|
@each $v in (333, 666, 888, 999, '26f', 'f46') {
|
||||||
.color-#{$v} {
|
.color-#{$v} {
|
||||||
color: \##{$v};
|
color: \##{$v};
|
||||||
@@ -79,17 +90,6 @@ export default {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
|
||||||
font-family: "iconfont" !important;
|
|
||||||
font-style: normal;
|
|
||||||
font-size: 25px;
|
|
||||||
vertical-align: middle;
|
|
||||||
color: rgb(117, 120, 137);
|
|
||||||
transition: .3s;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -102,7 +102,20 @@ export default {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
.home {
|
||||||
display: none; /* Chrome Safari */
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
padding: 16px;
|
||||||
|
background-color: #272A37;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fill {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
4
src/assets/clear.svg
Normal file
4
src/assets/clear.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" data-v-ea893728="">
|
||||||
|
<path fill="#fff"
|
||||||
|
d="M352 192V95.936a32 32 0 0 1 32-32h256a32 32 0 0 1 32 32V192h256a32 32 0 1 1 0 64H96a32 32 0 0 1 0-64h256zm64 0h192v-64H416v64zM192 960a32 32 0 0 1-32-32V256h704v672a32 32 0 0 1-32 32H192zm224-192a32 32 0 0 0 32-32V416a32 32 0 0 0-64 0v320a32 32 0 0 0 32 32zm192 0a32 32 0 0 0 32-32V416a32 32 0 0 0-64 0v320a32 32 0 0 0 32 32z"></path>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 461 B |
@@ -1,40 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
msg: String,
|
|
||||||
})
|
|
||||||
|
|
||||||
const count = ref(0)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<h1>{{ msg }}</h1>
|
|
||||||
|
|
||||||
<div class="card">
|
|
||||||
<button type="button" @click="count++">count is {{ count }}</button>
|
|
||||||
<p>
|
|
||||||
Edit
|
|
||||||
<code>components/HelloWorld.vue</code> to test HMR
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Check out
|
|
||||||
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
|
|
||||||
>create-vue</a
|
|
||||||
>, the official Vue + Vite starter
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Install
|
|
||||||
<a href="https://github.com/vuejs/language-tools" target="_blank">Volar</a>
|
|
||||||
in your IDE for a better DX
|
|
||||||
</p>
|
|
||||||
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.read-the-docs {
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
123
src/components/chat.vue
Normal file
123
src/components/chat.vue
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<template>
|
||||||
|
<section class="chat">
|
||||||
|
<el-row align="middle">
|
||||||
|
<div class="modelInfo">
|
||||||
|
<img :src="config.model.avatar" alt=""/>
|
||||||
|
<div class="fill mar-l8">
|
||||||
|
<b v-text="config.model.name"/>
|
||||||
|
<div class="desc" v-text="config.model.desc"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-row justify="end" class="fill mar-l8">
|
||||||
|
<div class="clear-icon"/>
|
||||||
|
<!-- todo 聊天操作栏-->
|
||||||
|
</el-row>
|
||||||
|
</el-row>
|
||||||
|
<thinking-bar v-show="loading"/>
|
||||||
|
<chat-content class="fill"/>
|
||||||
|
<chat-input/>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ChatContent from "../components/chatContent";
|
||||||
|
import ChatInput from "../components/chatInput";
|
||||||
|
import ThinkingBar from "../components/thinkingBar";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "chat",
|
||||||
|
components: {ChatContent, ChatInput, ThinkingBar},
|
||||||
|
props: {
|
||||||
|
config: {default: () => ({})}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleResize() {
|
||||||
|
if (window.innerWidth <= 700) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
document.querySelectorAll('.chat-content')[0].style.height = '93%';
|
||||||
|
this.buttonStatus = false
|
||||||
|
const textareaMsg = document.getElementById("textareaMsg");
|
||||||
|
textareaMsg.style.marginLeft = "0px";
|
||||||
|
this.personInfoSpan = [14, 0, 10];
|
||||||
|
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
|
||||||
|
if (isMobile) {
|
||||||
|
document.querySelectorAll('.chatInputs')[0].style.margin = '0%';
|
||||||
|
} else {
|
||||||
|
document.querySelectorAll('.chatInputs')[0].style.margin = '3%';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
document.querySelectorAll('.chat-content')[0].style.height = '88%';
|
||||||
|
this.buttonStatus = true
|
||||||
|
this.personInfoSpan = [1, 17, 6];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
window.addEventListener('resize', this.handleResize)
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
window.removeEventListener('resize', this.handleResize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.chat {
|
||||||
|
color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.modelInfo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 1.4;
|
||||||
|
|
||||||
|
& > img {
|
||||||
|
border: 2px solid #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 4px;
|
||||||
|
width: 45px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
b {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
color: #999;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-icon {
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 40px;
|
||||||
|
background-size: 24px 24px;
|
||||||
|
background-image: url("../assets/clear.svg");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: top center;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: .6;
|
||||||
|
padding-top: 24px;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
font-size: 12px;
|
||||||
|
content: "清空历史";
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
94
src/components/chatContent.vue
Normal file
94
src/components/chatContent.vue
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<section class="chatContent" @scroll="onScroll">
|
||||||
|
<div class="chat-wrapper" v-for="item in list" :key="item.id">
|
||||||
|
<div class="chat-friend" v-if="item.uid !== 'jcm'">
|
||||||
|
<div class="chat-text" v-if="item.chatType == 0">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="2">
|
||||||
|
<svg t="1679666016648" @click="$copy(item.msg, '已复制')" class="icon" viewBox="0 0 1024 1024"
|
||||||
|
version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6241" width="22" height="22">
|
||||||
|
<path
|
||||||
|
d="M661.333333 234.666667A64 64 0 0 1 725.333333 298.666667v597.333333a64 64 0 0 1-64 64h-469.333333A64 64 0 0 1 128 896V298.666667a64 64 0 0 1 64-64z m-21.333333 85.333333H213.333333v554.666667h426.666667v-554.666667z m191.829333-256a64 64 0 0 1 63.744 57.856l0.256 6.144v575.701333a42.666667 42.666667 0 0 1-85.034666 4.992l-0.298667-4.992V149.333333H384a42.666667 42.666667 0 0 1-42.368-37.674666L341.333333 106.666667a42.666667 42.666667 0 0 1 37.674667-42.368L384 64h447.829333z"
|
||||||
|
fill="#909399" p-id="6242"></path>
|
||||||
|
</svg>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="21">
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<markdown-it-vue :content="item.msg.trim()"/>
|
||||||
|
</div>
|
||||||
|
<div class="chat-img" v-if="item.chatType == 1">
|
||||||
|
<img :src="item.msg" alt="表情" v-if="item.extend.imgType == 1" style="width: 100px; height: 100px"/>
|
||||||
|
<el-image style="border-radius: 10px" :src="item.msg" :preview-src-list="srcImgList" v-else>
|
||||||
|
</el-image>
|
||||||
|
</div>
|
||||||
|
<div class="chat-img" v-if="item.chatType == 2">
|
||||||
|
<div class="word-file">
|
||||||
|
<FileCard :fileType="item.extend.fileType" :file="item.msg"></FileCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-time">
|
||||||
|
<img :src="item.headImg" alt=""/>
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
<span>{{ item.time }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chat-me" v-else>
|
||||||
|
<div class="chat-text" v-if="item.chatType == 0">
|
||||||
|
<span style="font-size:16px">{{ item.msg }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="chat-img" v-if="item.chatType == 1">
|
||||||
|
<img :src="item.msg" alt="表情" v-if="item.extend.imgType == 1" style="width: 100px; height: 100px"/>
|
||||||
|
<el-image style="max-width: 300px; border-radius: 10px" :src="item.msg" :preview-src-list="srcImgList"
|
||||||
|
v-else>
|
||||||
|
</el-image>
|
||||||
|
</div>
|
||||||
|
<div class="chat-img" v-if="item.chatType == 2">
|
||||||
|
<div class="word-file">
|
||||||
|
<FileCard :fileType="item.extend.fileType" :file="item.msg"></FileCard>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-time">
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
<span>{{ item.time }}</span>
|
||||||
|
<img :src="item.headImg" alt=""/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "chatContent",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
list:[]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onScroll() {
|
||||||
|
const scrollDom = this.$el;
|
||||||
|
const scrollTop = scrollDom.scrollTop;
|
||||||
|
const offsetHeight = scrollDom.offsetHeight;
|
||||||
|
const scrollHeight = scrollDom.scrollHeight;
|
||||||
|
// 当滚动到底部,设置 isAutoScroll 为 true
|
||||||
|
this.isAutoScroll = scrollTop + offsetHeight === scrollHeight;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.chatContent {
|
||||||
|
background: #323644;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
22
src/components/chatInput.vue
Normal file
22
src/components/chatInput.vue
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<section class="chatInput">
|
||||||
|
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "chatInput",
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
created() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.chatInput {
|
||||||
|
}
|
||||||
|
</style>
|
||||||
30
src/components/settings.vue
Normal file
30
src/components/settings.vue
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<template>
|
||||||
|
<section class="settings">
|
||||||
|
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "settings",
|
||||||
|
model: {
|
||||||
|
prop: "settings",
|
||||||
|
event: "input"
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
settings: {default: () => ({})}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
created() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.settings {
|
||||||
|
min-width: 400px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
83
src/components/thinkingBar.vue
Normal file
83
src/components/thinkingBar.vue
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<template>
|
||||||
|
<section class="thinkingBar"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "thinkingBar",
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.thinkingBar {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 16px;
|
||||||
|
height: 2px;
|
||||||
|
background-image: linear-gradient(to right, #eea2a2 0%, #bbc1bf 19%, #57c6e1 42%, #b49fda 79%, #7ac5d8 100%);
|
||||||
|
background-size: 100%;
|
||||||
|
animation: shrink-and-expand 2s ease-in-out infinite;
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 50%;
|
||||||
|
height: 100%;
|
||||||
|
background: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
border-top-left-radius: 2px;
|
||||||
|
border-bottom-left-radius: 2px;
|
||||||
|
left: 0;
|
||||||
|
transform-origin: left;
|
||||||
|
animation: shrink-left 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border-top-left-radius: 2px;
|
||||||
|
border-bottom-left-radius: 2px;
|
||||||
|
right: 0;
|
||||||
|
transform-origin: right;
|
||||||
|
animation: shrink-right 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shrink-and-expand {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scaleX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shrink-left {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
50% {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
50.1%,
|
||||||
|
100% {
|
||||||
|
transform: scaleX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shrink-right {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
50% {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
50.1%,
|
||||||
|
100% {
|
||||||
|
transform: scaleX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
26
src/main.js
26
src/main.js
@@ -1,20 +1,10 @@
|
|||||||
import { createApp } from 'vue'
|
import ElementPlus from 'element-plus'
|
||||||
import './style.css'
|
import 'element-plus/dist/index.css'
|
||||||
|
import {createApp} from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import ElementUI from 'element-ui';
|
import axios from "./utils/axios";
|
||||||
import VueRouter from 'vue-router'
|
|
||||||
import 'element-ui/lib/theme-chalk/index.css';
|
|
||||||
import router from './router/index'
|
|
||||||
import { copyToClipboard } from '@/util/util'
|
|
||||||
import i18n from '@/config/i18n'
|
|
||||||
Vue.use(VueRouter)
|
|
||||||
Vue.config.productionTip = false
|
|
||||||
Vue.use(ElementUI);
|
|
||||||
|
|
||||||
/**
|
const app = createApp(App)
|
||||||
* 复制
|
app.config.globalProperties.$http = axios
|
||||||
*/
|
app.use(ElementPlus)
|
||||||
const ins = createApp(App)
|
app.mount('#app')
|
||||||
ins.use(VueRouter)
|
|
||||||
ins.use(ElementUI)
|
|
||||||
ins.mount('#app')
|
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
:root {
|
|
||||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
||||||
line-height: 1.5;
|
|
||||||
font-weight: 400;
|
|
||||||
|
|
||||||
color-scheme: light dark;
|
|
||||||
color: rgba(255, 255, 255, 0.87);
|
|
||||||
background-color: #242424;
|
|
||||||
|
|
||||||
font-synthesis: none;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #646cff;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: #535bf2;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #646cff;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: #535bf2;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
display: flex;
|
|
||||||
place-items: center;
|
|
||||||
min-width: 320px;
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 3.2em;
|
|
||||||
line-height: 1.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 0.6em 1.2em;
|
|
||||||
font-size: 1em;
|
|
||||||
font-weight: 500;
|
|
||||||
font-family: inherit;
|
|
||||||
background-color: #1a1a1a;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: border-color 0.25s;
|
|
||||||
}
|
|
||||||
button:hover {
|
|
||||||
border-color: #646cff;
|
|
||||||
}
|
|
||||||
button:focus,
|
|
||||||
button:focus-visible {
|
|
||||||
outline: 4px auto -webkit-focus-ring-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
padding: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app {
|
|
||||||
max-width: 1280px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 2rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: light) {
|
|
||||||
:root {
|
|
||||||
color: #213547;
|
|
||||||
background-color: #ffffff;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: #747bff;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
6
src/utils/axios.js
Normal file
6
src/utils/axios.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const ins = axios.create({
|
||||||
|
|
||||||
|
})
|
||||||
|
export default ins
|
||||||
7
src/utils/env.js
Normal file
7
src/utils/env.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export const OPEN_AI_KEY = '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'
|
||||||
|
//ai头像
|
||||||
|
export const AI_AVATAR = "https://th.bing.com/th?id=ODL.3e2fbff4543f0d3632d34be6d02adc93&w=100&h=100&c=12&pcl=faf9f7&o=6&dpr=1.5&pid=13.1"
|
||||||
|
//用户头像
|
||||||
|
export const USER_AVATAR = "https://avatars.githubusercontent.com/u/20533272?v=4"
|
||||||
|
|
||||||
|
|
||||||
31
src/utils/models.js
Normal file
31
src/utils/models.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import {AI_AVATAR} from "./env";
|
||||||
|
|
||||||
|
class BaseModel {
|
||||||
|
constructor(props) {
|
||||||
|
for (const k in props) {
|
||||||
|
this[k] = props[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ChatGPT extends BaseModel {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
avatar: AI_AVATAR,
|
||||||
|
name: 'ChatGPT',
|
||||||
|
id: "gpt-3.5-turbo",
|
||||||
|
desc: "ChatGPT-3.5所基于的模型"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ChatGLM extends BaseModel {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
avatar: AI_AVATAR,
|
||||||
|
name: 'ChatGLM',
|
||||||
|
id: "chatglm-6b",
|
||||||
|
desc: "ChatGLM-6B所基于的模型"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/utils/tools.js
Normal file
25
src/utils/tools.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* 复制到剪切板
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function copyToClipboard(content) {
|
||||||
|
const clipboardData = window.clipboardData
|
||||||
|
if (clipboardData) {
|
||||||
|
clipboardData.clearData()
|
||||||
|
clipboardData.setData('Text', content)
|
||||||
|
return true
|
||||||
|
} else if (document.execCommand) {
|
||||||
|
const el = document.createElement('textarea')
|
||||||
|
el.value = content
|
||||||
|
el.setAttribute('readonly', '')
|
||||||
|
el.style.position = 'absolute'
|
||||||
|
el.style.left = '-9999px'
|
||||||
|
document.body.appendChild(el)
|
||||||
|
el.select()
|
||||||
|
document.execCommand('copy')
|
||||||
|
document.body.removeChild(el)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,15 @@
|
|||||||
import { defineConfig } from 'vite'
|
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import {defineConfig} from 'vite'
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [vue()],
|
plugins: [vue()],
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.mjs', '.js', '.mts', '.json', '.vue']
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
open: true,
|
||||||
|
host: '0.0.0.0',
|
||||||
|
port: 10109
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user