feat: add top navbar for front page

This commit is contained in:
RockYang 2024-05-16 20:10:00 +08:00
parent 5a8fe5a6cf
commit d98b08d7cd
22 changed files with 836 additions and 633 deletions

47
web/package-lock.json generated
View File

@ -24,14 +24,16 @@
"markdown-it-mathjax": "^2.0.0", "markdown-it-mathjax": "^2.0.0",
"markmap-common": "^0.16.0", "markmap-common": "^0.16.0",
"markmap-lib": "^0.16.1", "markmap-lib": "^0.16.1",
"markmap-toolbar": "^0.17.0",
"markmap-view": "^0.16.0", "markmap-view": "^0.16.0",
"md-editor-v3": "^2.2.1", "md-editor-v3": "^2.2.1",
"mitt": "^3.0.1",
"pinia": "^2.1.4", "pinia": "^2.1.4",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
"qs": "^6.11.1", "qs": "^6.11.1",
"sortablejs": "^1.15.0", "sortablejs": "^1.15.0",
"three": "^0.128.0", "three": "^0.128.0",
"v3-waterfall": "^1.2.1", "v3-waterfall": "^1.3.3",
"vant": "^4.5.0", "vant": "^4.5.0",
"vue": "^3.2.13", "vue": "^3.2.13",
"vue-router": "^4.0.15" "vue-router": "^4.0.15"
@ -8335,6 +8337,18 @@
"js-yaml": "bin/js-yaml.js" "js-yaml": "bin/js-yaml.js"
} }
}, },
"node_modules/markmap-toolbar": {
"version": "0.17.0",
"resolved": "https://registry.npmmirror.com/markmap-toolbar/-/markmap-toolbar-0.17.0.tgz",
"integrity": "sha512-zRkg+pYtjDefJ4lSG0KownAN3eqkJcrTei+HbobBWsWTsc7qdUMn2Ewd97SFHCkGoo1nrG0aW7dzDP6lHWuDkw==",
"dependencies": {
"@babel/runtime": "^7.22.6",
"@gera2ld/jsx-dom": "^2.2.2"
},
"peerDependencies": {
"markmap-common": "*"
}
},
"node_modules/markmap-view": { "node_modules/markmap-view": {
"version": "0.16.0", "version": "0.16.0",
"resolved": "https://registry.npmmirror.com/markmap-view/-/markmap-view-0.16.0.tgz", "resolved": "https://registry.npmmirror.com/markmap-view/-/markmap-view-0.16.0.tgz",
@ -8592,6 +8606,11 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/mitt": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz",
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
},
"node_modules/mkdirp": { "node_modules/mkdirp": {
"version": "0.5.6", "version": "0.5.6",
"resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz", "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz",
@ -11513,9 +11532,9 @@
} }
}, },
"node_modules/v3-waterfall": { "node_modules/v3-waterfall": {
"version": "1.2.1", "version": "1.3.3",
"resolved": "https://registry.npmmirror.com/v3-waterfall/-/v3-waterfall-1.2.1.tgz", "resolved": "https://registry.npmmirror.com/v3-waterfall/-/v3-waterfall-1.3.3.tgz",
"integrity": "sha512-zjfT1FuHupsAahvS4mr3Yb8k2SHB8srW6st+/cBXwrsyhbCcj8Qhb1QtNUuEIx/tbpLQrMpxtJunZXkaKBfAEA==" "integrity": "sha512-jUmp0xpHGkEcUxaYKGRtI5b2NvogxI/UrfoCLmpTi0UbQndDdqjwufxJvWwiJjwZQyOIPpnq9ZOFtkBwxchq3Q=="
}, },
"node_modules/v8-compile-cache": { "node_modules/v8-compile-cache": {
"version": "2.3.0", "version": "2.3.0",
@ -19059,6 +19078,15 @@
} }
} }
}, },
"markmap-toolbar": {
"version": "0.17.0",
"resolved": "https://registry.npmmirror.com/markmap-toolbar/-/markmap-toolbar-0.17.0.tgz",
"integrity": "sha512-zRkg+pYtjDefJ4lSG0KownAN3eqkJcrTei+HbobBWsWTsc7qdUMn2Ewd97SFHCkGoo1nrG0aW7dzDP6lHWuDkw==",
"requires": {
"@babel/runtime": "^7.22.6",
"@gera2ld/jsx-dom": "^2.2.2"
}
},
"markmap-view": { "markmap-view": {
"version": "0.16.0", "version": "0.16.0",
"resolved": "https://registry.npmmirror.com/markmap-view/-/markmap-view-0.16.0.tgz", "resolved": "https://registry.npmmirror.com/markmap-view/-/markmap-view-0.16.0.tgz",
@ -19264,6 +19292,11 @@
"yallist": "^4.0.0" "yallist": "^4.0.0"
} }
}, },
"mitt": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz",
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
},
"mkdirp": { "mkdirp": {
"version": "0.5.6", "version": "0.5.6",
"resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz", "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz",
@ -21507,9 +21540,9 @@
"dev": true "dev": true
}, },
"v3-waterfall": { "v3-waterfall": {
"version": "1.2.1", "version": "1.3.3",
"resolved": "https://registry.npmmirror.com/v3-waterfall/-/v3-waterfall-1.2.1.tgz", "resolved": "https://registry.npmmirror.com/v3-waterfall/-/v3-waterfall-1.3.3.tgz",
"integrity": "sha512-zjfT1FuHupsAahvS4mr3Yb8k2SHB8srW6st+/cBXwrsyhbCcj8Qhb1QtNUuEIx/tbpLQrMpxtJunZXkaKBfAEA==" "integrity": "sha512-jUmp0xpHGkEcUxaYKGRtI5b2NvogxI/UrfoCLmpTi0UbQndDdqjwufxJvWwiJjwZQyOIPpnq9ZOFtkBwxchq3Q=="
}, },
"v8-compile-cache": { "v8-compile-cache": {
"version": "2.3.0", "version": "2.3.0",

View File

@ -14,7 +14,7 @@
"compressorjs": "^1.2.1", "compressorjs": "^1.2.1",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"echarts": "^5.5.0", "echarts": "^5.5.0",
"element-plus": "^2.3.0", "element-plus": "^2.4.0",
"good-storage": "^1.1.1", "good-storage": "^1.1.1",
"highlight.js": "^11.7.0", "highlight.js": "^11.7.0",
"json-bigint": "^1.0.0", "json-bigint": "^1.0.0",

View File

@ -1,12 +1,11 @@
<template> <template>
<el-config-provider :locale="zhCn"> <el-config-provider>
<router-view/> <router-view/>
</el-config-provider> </el-config-provider>
</template> </template>
<script setup> <script setup>
import {ElConfigProvider} from 'element-plus'; import {ElConfigProvider} from 'element-plus';
import zhCn from 'element-plus/es/locale/lang/zh-cn';
const debounce = (fn, delay) => { const debounce = (fn, delay) => {
let timer let timer

View File

@ -1,6 +1,6 @@
.page-apps { .page-apps {
background-color: #282c34; background-color: #282c34;
height 100vh height 100%
.title { .title {
text-align center text-align center

View File

@ -1,313 +1,378 @@
#app { #app {
height: 100%; height: 100%;
} }
#app .common-layout { #app .common-layout {
height: 100%; height: 100%;
} }
#app .common-layout .el-aside { #app .common-layout .el-aside {
background-color: #252526; background-color: #252526;
} }
#app .common-layout .el-aside .title-box { #app .common-layout .el-aside .title-box {
padding: 6px 10px; padding: 6px 10px;
display: flex; display: flex;
color: #fff; color: #fff;
font-size: 20px; font-size: 20px;
} }
#app .common-layout .el-aside .title-box span { #app .common-layout .el-aside .title-box span {
padding-top: 5px; padding-top: 5px;
padding-left: 10px; padding-left: 10px;
} }
#app .common-layout .el-aside .chat-list { #app .common-layout .el-aside .chat-list {
display: flex; display: flex;
flex-flow: column; flex-flow: column;
background-color: #28292a; background-color: #28292a;
border-top: 1px solid #2f3032; border-top: 1px solid #2f3032;
border-right: 1px solid #2f3032; border-right: 1px solid #2f3032;
} }
#app .common-layout .el-aside .chat-list .search-box { #app .common-layout .el-aside .chat-list .search-box {
flex-wrap: wrap; flex-wrap: wrap;
padding: 10px 15px; padding: 10px 15px;
} }
#app .common-layout .el-aside .chat-list .search-box .el-input__wrapper { #app .common-layout .el-aside .chat-list .search-box .el-input__wrapper {
background-color: #363535; background-color: #363535;
box-shadow: none; box-shadow: none;
} }
#app .common-layout .el-aside .chat-list ::-webkit-scrollbar { #app .common-layout .el-aside .chat-list ::-webkit-scrollbar {
width: 0; width: 0;
height: 0; height: 0;
background-color: transparent; background-color: transparent;
} }
#app .common-layout .el-aside .chat-list .content { #app .common-layout .el-aside .chat-list .content {
width: 100%; width: 100%;
overflow-y: scroll; overflow-y: scroll;
} }
#app .common-layout .el-aside .chat-list .content .chat-list-item { #app .common-layout .el-aside .chat-list .content .chat-list-item {
display: flex; display: flex;
width: 100%; width: 100%;
justify-content: flex-start; justify-content: flex-start;
padding: 8px 12px; padding: 8px 12px;
cursor: pointer; cursor: pointer;
} }
#app .common-layout .el-aside .chat-list .content .chat-list-item:hover { #app .common-layout .el-aside .chat-list .content .chat-list-item:hover {
background-color: #343540; background-color: #343540;
} }
#app .common-layout .el-aside .chat-list .content .chat-list-item .avatar { #app .common-layout .el-aside .chat-list .content .chat-list-item .avatar {
width: 28px; width: 28px;
height: 28px; height: 28px;
border-radius: 50%; border-radius: 50%;
} }
#app .common-layout .el-aside .chat-list .content .chat-list-item .chat-title-input { #app .common-layout .el-aside .chat-list .content .chat-list-item .chat-title-input {
font-size: 14px; font-size: 14px;
margin-top: 4px; margin-top: 4px;
margin-left: 10px; margin-left: 10px;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
width: 190px; width: 190px;
} }
#app .common-layout .el-aside .chat-list .content .chat-list-item .chat-title { #app .common-layout .el-aside .chat-list .content .chat-list-item .chat-title {
color: #c1c1c1; color: #c1c1c1;
padding: 5px 10px; padding: 5px 10px;
max-width: 220px; max-width: 220px;
font-size: 14px; font-size: 14px;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
#app .common-layout .el-aside .chat-list .content .chat-list-item .btn { #app .common-layout .el-aside .chat-list .content .chat-list-item .btn {
display: none; display: none;
position: absolute; position: absolute;
right: 2px; right: 2px;
top: 16px; top: 16px;
color: #fff; color: #fff;
} }
#app .common-layout .el-aside .chat-list .content .chat-list-item .btn .el-icon { #app .common-layout .el-aside .chat-list .content .chat-list-item .btn .el-icon {
margin-right: 8px; margin-right: 8px;
} }
#app .common-layout .el-aside .chat-list .content .chat-list-item.active { #app .common-layout .el-aside .chat-list .content .chat-list-item.active {
background-color: #343540; background-color: #343540;
} }
#app .common-layout .el-aside .chat-list .content .chat-list-item.active .btn { #app .common-layout .el-aside .chat-list .content .chat-list-item.active .btn {
display: inline; display: inline;
} }
#app .common-layout .el-aside .tool-box { #app .common-layout .el-aside .tool-box {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;
padding: 0 20px 10px 20px; padding: 0 20px 10px 20px;
border-top: 1px solid #3c3c3c; border-top: 1px solid #3c3c3c;
} }
#app .common-layout .el-aside .tool-box .user-info { #app .common-layout .el-aside .tool-box .user-info {
width: 100%; width: 100%;
padding-top: 10px; padding-top: 10px;
} }
#app .common-layout .el-aside .tool-box .user-info .el-dropdown-link { #app .common-layout .el-aside .tool-box .user-info .el-dropdown-link {
width: 100%; width: 100%;
cursor: pointer; cursor: pointer;
display: flex; display: flex;
} }
#app .common-layout .el-aside .tool-box .user-info .el-dropdown-link .el-image { #app .common-layout .el-aside .tool-box .user-info .el-dropdown-link .el-image {
width: 20px; width: 20px;
height: 20px; height: 20px;
border-radius: 5px; border-radius: 5px;
} }
#app .common-layout .el-aside .tool-box .user-info .el-dropdown-link .username { #app .common-layout .el-aside .tool-box .user-info .el-dropdown-link .username {
display: flex; display: flex;
line-height: 22px; line-height: 22px;
width: 230px; width: 230px;
padding-left: 10px; padding-left: 10px;
} }
#app .common-layout .el-aside .tool-box .user-info .el-dropdown-link .el-icon { #app .common-layout .el-aside .tool-box .user-info .el-dropdown-link .el-icon {
color: #ccc; color: #ccc;
line-height: 24px; line-height: 24px;
} }
#app .common-layout .el-main { #app .common-layout .el-main {
overflow: hidden; overflow: hidden;
--el-main-padding: 0; --el-main-padding: 0;
margin: 0; margin: 0;
} }
#app .common-layout .el-main .chat-head { #app .common-layout .el-main .chat-head {
width: 100%; width: 100%;
height: 50px; height: 50px;
background-color: #28292a; background-color: #28292a;
} }
#app .common-layout .el-main .chat-head .chat-config { #app .common-layout .el-main .chat-head .chat-config {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding-top: 10px; padding-top: 10px;
} }
#app .common-layout .el-main .chat-head .chat-config .role-select-label { #app .common-layout .el-main .chat-head .chat-config .role-select-label {
color: #fff; color: #fff;
} }
#app .common-layout .el-main .chat-head .chat-config .el-select { #app .common-layout .el-main .chat-head .chat-config .el-select {
max-width: 150px; max-width: 150px;
margin-right: 10px; margin-right: 10px;
} }
#app .common-layout .el-main .chat-head .chat-config .role-select { #app .common-layout .el-main .chat-head .chat-config .role-select {
max-width: 130px; max-width: 130px;
} }
#app .common-layout .el-main .chat-head .chat-config .el-button .el-icon { #app .common-layout .el-main .chat-head .chat-config .el-button .el-icon {
margin-right: 5px; margin-right: 5px;
} }
#app .common-layout .el-main .chat-head .iconfont { #app .common-layout .el-main .chat-head .iconfont {
margin-right: 5px; margin-right: 5px;
} }
#app .common-layout .el-main .chat-head .is-circle { #app .common-layout .el-main .chat-head .is-circle {
margin-left: 5px; margin-left: 5px;
} }
#app .common-layout .el-main .chat-head .is-circle .iconfont { #app .common-layout .el-main .chat-head .is-circle .iconfont {
margin-right: 0; margin-right: 0;
} }
#app .common-layout .el-main .right-box {
min-width: 0; #app .common-layout .el-main .chat-box {
flex: 1; min-width: 0;
background-color: #fff; flex: 1;
border-left: 1px solid #4f4f4f; background-color: #fff;
border-left: 1px solid #4f4f4f;
} }
#app .common-layout .el-main .right-box #container {
overflow: hidden; #app .common-layout .el-main .chat-box #container {
width: 100%; overflow: hidden;
width: 100%;
} }
#app .common-layout .el-main .right-box #container ::-webkit-scrollbar {
width: 0; #app .common-layout .el-main .chat-box #container ::-webkit-scrollbar {
height: 0; width: 0;
background-color: transparent; height: 0;
background-color: transparent;
} }
#app .common-layout .el-main .right-box #container .chat-box {
overflow-y: scroll; #app .common-layout .el-main .chat-box #container .chat-box {
--content-font-size: 16px; overflow-y: scroll;
--content-color: #c1c1c1; --content-font-size: 16px;
font-family: 'Microsoft YaHei', '微软雅黑', Arial, sans-serif; --content-color: #c1c1c1;
padding: 0 0 50px 0; font-family: 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
padding: 0 0 50px 0;
} }
#app .common-layout .el-main .right-box #container .chat-box .chat-line {
font-size: 14px; #app .common-layout .el-main .chat-box #container .chat-box .chat-line {
display: flex; font-size: 14px;
align-items: flex-start; display: flex;
align-items: flex-start;
} }
#app .common-layout .el-main .right-box #container .re-generate {
position: relative; #app .common-layout .el-main .chat-box #container .re-generate {
display: flex; position: relative;
justify-content: center; display: flex;
justify-content: center;
} }
#app .common-layout .el-main .right-box #container .re-generate .btn-box {
position: absolute; #app .common-layout .el-main .chat-box #container .re-generate .btn-box {
bottom: 10px; position: absolute;
bottom: 10px;
} }
#app .common-layout .el-main .right-box #container .re-generate .btn-box .el-button .el-icon {
margin-right: 5px; #app .common-layout .el-main .chat-box #container .re-generate .btn-box .el-button .el-icon {
margin-right: 5px;
} }
#app .common-layout .el-main .right-box #container .input-box {
background-color: #fff; #app .common-layout .el-main .chat-box #container .input-box {
display: flex; background-color: #fff;
justify-content: center; display: flex;
align-items: center; justify-content: center;
box-shadow: 0 2px 15px rgba(0,0,0,0.1); align-items: center;
padding: 0 15px; box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1);
padding: 0 15px;
} }
#app .common-layout .el-main .right-box #container .input-box .input-container {
width: 100%; #app .common-layout .el-main .chat-box #container .input-box .input-container {
margin: 0; width: 100%;
border: none; margin: 0;
padding: 10px 0; border: none;
display: flex; padding: 10px 0;
justify-content: center; display: flex;
position: relative; justify-content: center;
position: relative;
} }
#app .common-layout .el-main .right-box #container .input-box .input-container .el-textarea .el-textarea__inner::-webkit-scrollbar {
width: 0; #app .common-layout .el-main .chat-box #container .input-box .input-container .el-textarea .el-textarea__inner::-webkit-scrollbar {
height: 0; width: 0;
height: 0;
} }
#app .common-layout .el-main .right-box #container .input-box .input-container .select-file {
position: absolute; #app .common-layout .el-main .chat-box #container .input-box .input-container .select-file {
right: 48px; position: absolute;
top: 20px; right: 48px;
top: 20px;
} }
#app .common-layout .el-main .right-box #container .input-box .input-container .send-btn {
position: absolute; #app .common-layout .el-main .chat-box #container .input-box .input-container .send-btn {
right: 12px; position: absolute;
top: 20px; right: 12px;
top: 20px;
} }
#app .common-layout .el-main .right-box #container .input-box .input-container .send-btn .el-button {
padding: 8px 5px; #app .common-layout .el-main .chat-box #container .input-box .input-container .send-btn .el-button {
border-radius: 6px; padding: 8px 5px;
background: #19c37d; border-radius: 6px;
color: #fff; background: #19c37d;
font-size: 20px; color: #fff;
font-size: 20px;
} }
#app .common-layout .el-main .right-box #container::-webkit-scrollbar {
width: 0; #app .common-layout .el-main .chat-box #container::-webkit-scrollbar {
height: 0; width: 0;
height: 0;
} }
#app .el-message-box { #app .el-message-box {
width: 90%; width: 90%;
max-width: 420px; max-width: 420px;
} }
#app .el-message { #app .el-message {
min-width: 100px; min-width: 100px;
max-width: 600px; max-width: 600px;
} }
.el-select-dropdown__wrap .el-select-dropdown__item .role-option { .el-select-dropdown__wrap .el-select-dropdown__item .role-option {
display: flex; display: flex;
flex-flow: row; flex-flow: row;
margin-top: 8px; margin-top: 8px;
} }
.el-select-dropdown__wrap .el-select-dropdown__item .role-option .el-image { .el-select-dropdown__wrap .el-select-dropdown__item .role-option .el-image {
width: 20px; width: 20px;
height: 20px; height: 20px;
border-radius: 50%; border-radius: 50%;
} }
.el-select-dropdown__wrap .el-select-dropdown__item .role-option span { .el-select-dropdown__wrap .el-select-dropdown__item .role-option span {
margin-left: 5px; margin-left: 5px;
height: 20px; height: 20px;
line-height: 20px; line-height: 20px;
} }
.account { .account {
display: flex; display: flex;
background-color: #90ffc2; background-color: #90ffc2;
color: #000; color: #000;
width: 100%; width: 100%;
border-radius: 10px; border-radius: 10px;
padding: 10px; padding: 10px;
} }
.account .vip-logo .el-image { .account .vip-logo .el-image {
width: 40px; width: 40px;
height: 40px; height: 40px;
border-radius: 100%; border-radius: 100%;
background-color: #fff; background-color: #fff;
} }
.account .vip-info { .account .vip-info {
padding: 0 10px 0 10px; padding: 0 10px 0 10px;
} }
.account .vip-info h4, .account .vip-info h4,
.account .vip-info p { .account .vip-info p {
margin: 0; margin: 0;
} }
.account .vip-info h4 { .account .vip-info h4 {
font-weight: bold; font-weight: bold;
font-size: 16px; font-size: 16px;
} }
.account .vip-info p { .account .vip-info p {
color: #333; color: #333;
} }
.account .pay-btn { .account .pay-btn {
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: right; justify-content: right;
align-items: center; align-items: center;
} }
.el-overlay-dialog .el-dialog .el-dialog__body .notice { .el-overlay-dialog .el-dialog .el-dialog__body .notice {
padding: 0 20px 0 20px; padding: 0 20px 0 20px;
line-height: 1.8; line-height: 1.8;
} }
.el-overlay-dialog .el-dialog .el-dialog__body .notice .el-text { .el-overlay-dialog .el-dialog .el-dialog__body .notice .el-text {
font-size: 16px; font-size: 16px;
} }
.dialog-service { .dialog-service {
text-align: center; text-align: center;
} }
.dialog-service .el-image { .dialog-service .el-image {
width: 360px; width: 360px;
} }

View File

@ -10,35 +10,26 @@ $borderColor = #4676d0;
// left side // left side
.el-aside { .el-aside {
background-color: $sideBgColor; //background-color: $sideBgColor;
height 100vh padding 10px
width var(--el-aside-width, 320px)
.title-box {
padding: 6px 10px;
display: flex;
color: #ffffff;
font-size: 20px;
span {
padding-top: 5px;
padding-left: 10px;
}
}
.chat-list { .chat-list {
display: flex display: flex
flex-flow: column flex-flow: column
background-color: #28292A //background-color: $sideBgColor
border-top: 1px solid #2F3032 border-radius 10px
border-right: 1px solid #2F3032 padding 10px 0
.search-box { .search-box {
flex-wrap: wrap flex-wrap: wrap
padding: 10px 15px; padding: 10px 0;
//background-color #343540
.el-input__wrapper { .search-input {
background-color: #363535; --el-input-bg-color: #363535
--el-input-border-color: #464545
--el-input-focus-border-color: #47fff1
--el-input-hover-border-color: #2DA39A
box-shadow: none box-shadow: none
} }
} }
@ -52,9 +43,6 @@ $borderColor = #4676d0;
} }
.content { .content {
//display flex
//flex-wrap: wrap;
//flex-direction column
width: 100% width: 100%
overflow-y: scroll overflow-y: scroll
@ -65,14 +53,17 @@ $borderColor = #4676d0;
padding: 8px 12px padding: 8px 12px
//border-bottom: 1px solid #3c3c3c //border-bottom: 1px solid #3c3c3c
cursor: pointer cursor: pointer
border: 1px solid #3c3c3c
margin-bottom 6px
border-radius 5px
&:hover { &:hover {
background-color #343540 background-color #343540
} }
.avatar { .avatar {
width: 28px; width: 32px;
height: 28px; height: 32px;
border-radius: 50%; border-radius: 50%;
} }
@ -96,13 +87,17 @@ $borderColor = #4676d0;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.btn {
display none .chat-opt {
position: absolute; position: absolute;
right: 2px; right: 2px;
top: 16px; top: 16px;
color #ffffff color #ffffff
.el-dropdown-link {
color #ffffff
}
.el-icon { .el-icon {
margin-right 8px; margin-right 8px;
} }
@ -111,10 +106,7 @@ $borderColor = #4676d0;
.chat-list-item.active { .chat-list-item.active {
background-color: #343540; background-color: #343540;
border-color #21aa93
.btn {
display inline
}
} }
} }
} }
@ -126,37 +118,6 @@ $borderColor = #4676d0;
align-items: center; align-items: center;
padding 0 20px 10px 20px; padding 0 20px 10px 20px;
border-top 1px solid #3c3c3c; border-top 1px solid #3c3c3c;
.user-info {
width 100%
padding-top 10px;
.el-dropdown-link {
width 100%;
cursor: pointer
display flex
.el-image {
width: 20px;
height: 20px;
border-radius: 5px;
}
.username {
display flex
line-height 22px;
width 230px;
padding-left 10px;
}
.el-icon {
color: #cccccc;
line-height 24px;
}
}
}
} }
} }
@ -210,11 +171,12 @@ $borderColor = #4676d0;
} }
} }
.right-box {
.chat-box {
min-width: 0; min-width: 0;
flex: 1; flex: 1;
background-color: #ffffff background-color: var(--el-bg-color)
border-left: 1px solid #4f4f4f color var(--el-text-color-primary)
#container { #container {
overflow: hidden; overflow: hidden;

View File

@ -0,0 +1,156 @@
.home {
display: flex;
height 100vh
width 100%
flex-flow column
.header {
display flex
justify-content space-between
height 50px
line-height 50px
background-color #1E1F22
padding-right 20px
.banner {
display flex
.logo {
display flex
padding 5px
cursor pointer
.el-image {
width 40px
height 40px
}
}
.title {
display: flex;
color: #ffffff;
font-size: 20px;
padding 0 10px
}
}
.navbar {
.user-info {
width 100%
padding 5px 0;
.el-dropdown-link {
width 100%;
cursor: pointer
display flex
.el-image {
width: 36px;
height: 36px;
border-radius: 50%
}
.el-icon {
color: #cccccc;
line-height 24px;
}
}
}
}
}
.main {
width 100%
display flex
flex-flow row
.navigator {
display flex
flex-flow column
width 50px
padding 10px 1px
border-right: 1px solid #3c3c3c
background-color: #1E1F22
.nav-items {
margin-top: 10px;
padding 0 5px
li {
margin-bottom 15px
a {
color #DADBDC
border-radius 10px
width 40px
height 40px
display flex
justify-content center
align-items center
cursor pointer
background-color #414348
.el-image {
border-radius 10px
}
.iconfont {
font-size 20px
}
}
a:hover, a.active {
color #47fff1
background-color #0F7A71
}
.title {
font-size: 12px
padding-top: 5px
color: #e5e7eb;
text-align: center;
}
.active {
color #47fff1
}
}
}
}
.content {
width: 100%
box-sizing: border-box
background-color #282c34
}
}
}
.el-popper {
.more-menus {
li {
padding 10px 15px
cursor pointer
border-radius 5px
margin 5px 0
.el-image {
position: relative
top 5px
right 5px
}
&:hover {
background-color #f1f1f1
}
}
li.active {
background-color #f1f1f1
}
}
}

View File

@ -1,6 +1,6 @@
.page-mj { .page-mj {
background-color: #282c34; background-color: #282c34;
height 100vh height 100%
.inner { .inner {
display: flex; display: flex;
@ -235,7 +235,7 @@
.task-list-box { .task-list-box {
width 100% width 100%
padding 10px padding 0 10px 10px 10px
color #ffffff color #ffffff
overflow-x hidden overflow-x hidden

View File

@ -10,10 +10,12 @@
border 1px solid #454545 border 1px solid #454545
min-width 300px min-width 300px
max-width 300px max-width 300px
padding 10px padding 10px 10px 20px 10px
border-radius 10px border-radius 10px
color #ffffff; color #ffffff;
font-size 14px font-size 14px
height 100%
overflow auto
h2 { h2 {
font-weight: bold; font-weight: bold;
@ -83,7 +85,7 @@
.task-list-box { .task-list-box {
width 100% width 100%
padding 10px padding 0 10px 10px 10px
color #ffffff color #ffffff
overflow-x hidden overflow-x hidden

View File

@ -1,6 +1,6 @@
.page-mark-map { .page-mark-map {
background-color: #282c34; background-color: #282c34;
height 100vh height 100%
.inner { .inner {
display: flex; display: flex;
@ -24,6 +24,7 @@
} }
// //
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 0; width: 0;
height: 0; height: 0;
@ -64,21 +65,15 @@
} }
} }
.right-box {
.chat-box {
width 100% width 100%
.top-bar { .top-bar {
display flex display flex
justify-content space-between justify-content right
align-items center align-items center
padding 10px 20px 10px 10px
h2 {
color #ffffff
}
.el-button {
margin-right 20px
}
} }
.markdown { .markdown {

View File

@ -1,6 +1,6 @@
.member { .member {
background-color: #282c34; background-color: #282c34;
height 100vh height 100%
.el-dialog { .el-dialog {
.el-dialog__body { .el-dialog__body {

View File

@ -1,9 +1,6 @@
<template> <template>
<div> <div>
<div class="page-apps custom-scroll"> <div class="page-apps custom-scroll">
<div class="title">
AI 助手应用中心
</div>
<div class="inner" :style="{height: listBoxHeight + 'px'}"> <div class="inner" :style="{height: listBoxHeight + 'px'}">
<ItemList :items="list" v-if="list.length > 0" :gap="20" :width="250"> <ItemList :items="list" v-if="list.length > 0" :gap="20" :width="250">
<template #default="scope"> <template #default="scope">
@ -49,7 +46,7 @@ import {checkSession} from "@/action/session";
import {arrayContains, removeArrayItem, substr} from "@/utils/libs"; import {arrayContains, removeArrayItem, substr} from "@/utils/libs";
import {useRouter} from "vue-router"; import {useRouter} from "vue-router";
const listBoxHeight = window.innerHeight - 97 const listBoxHeight = window.innerHeight - 147
const list = ref([]) const list = ref([])
const showLoginDialog = ref(false) const showLoginDialog = ref(false)
const roles = ref([]) const roles = ref([])

View File

@ -1,13 +1,18 @@
<template> <template>
<div class="common-layout theme-white"> <div class="common-layout">
<el-container> <el-container>
<el-aside> <el-aside>
<div class="title-box">
<span>{{ title }}</span>
</div>
<div class="chat-list"> <div class="chat-list">
<el-button @click="newChat" color="#21aa93">
<el-icon style="margin-right: 5px">
<Plus/>
</el-icon>
新建对话
</el-button>
<div class="search-box"> <div class="search-box">
<el-input v-model="chatName" class="w-50 m-2" size="small" placeholder="搜索会话" @keyup="searchChat"> <el-input v-model="chatName" placeholder="搜索会话" @keyup="searchChat($event)" style=""
class="search-input">
<template #prefix> <template #prefix>
<el-icon class="el-input__icon"> <el-icon class="el-input__icon">
<Search/> <Search/>
@ -22,111 +27,125 @@
@click="changeChat(chat)"> @click="changeChat(chat)">
<el-image :src="chat.icon" class="avatar"/> <el-image :src="chat.icon" class="avatar"/>
<span class="chat-title-input" v-if="chat.edit"> <span class="chat-title-input" v-if="chat.edit">
<el-input v-model="tmpChatTitle" size="small" @keydown="titleKeydown($event, chat)" <el-input v-model="tmpChatTitle" size="small" @keydown="titleKeydown($event, chat)"
placeholder="请输入会话标题"/> :id="'chat-'+chat.chat_id"
</span> @blur="editConfirm(chat)"
@click="stopPropagation($event)"
placeholder="请输入标题"/>
</span>
<span v-else class="chat-title">{{ chat.title }}</span> <span v-else class="chat-title">{{ chat.title }}</span>
<span class="btn btn-check" v-if="chat.edit || chat.removing">
<el-icon @click="confirm($event, chat)"><Check/></el-icon> <span class="chat-opt">
<el-icon @click="cancel($event, chat)"><Close/></el-icon> <el-dropdown trigger="click">
</span> <span class="el-dropdown-link" @click="stopPropagation($event)">
<span class="btn" v-else> <el-icon><More/></el-icon>
<el-icon title="编辑" @click="editChatTitle($event, chat)"><Edit/></el-icon> </span>
<el-icon title="删除会话" @click="removeChat($event, chat)"><Delete/></el-icon> <template #dropdown>
</span> <el-dropdown-menu>
<el-dropdown-item :icon="Edit" @click="editChatTitle(chat)">重命名</el-dropdown-item>
<el-dropdown-item :icon="Delete"
style="--el-text-color-regular: var(--el-color-danger);
--el-dropdown-menuItem-hover-fill:#F8E1DE;
--el-dropdown-menuItem-hover-color: var(--el-color-danger)"
@click="removeChat(chat)">删除</el-dropdown-item>
<el-dropdown-item :icon="Share" @click="shareChat(chat)">分享</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</span>
</div> </div>
</el-row> </el-row>
</div> </div>
</div> </div>
<div class="tool-box"> <div class="tool-box">
<el-dropdown :hide-on-click="true" class="user-info" trigger="click" v-if="isLogin"> <!-- <el-dropdown :hide-on-click="true" class="user-info" trigger="click" v-if="isLogin">-->
<span class="el-dropdown-link"> <!-- <span class="el-dropdown-link">-->
<el-image :src="loginUser.avatar"/> <!-- <el-image :src="loginUser.avatar"/>-->
<span class="username">{{ loginUser.nickname }}</span> <!-- <span class="username">{{ loginUser.nickname }}</span>-->
<el-icon><ArrowDown/></el-icon> <!-- <el-icon><ArrowDown/></el-icon>-->
</span> <!-- </span>-->
<template #dropdown> <!-- <template #dropdown>-->
<el-dropdown-menu style="width: 296px;"> <!-- <el-dropdown-menu style="width: 296px;">-->
<el-dropdown-item @click="showConfig"> <!-- <el-dropdown-item @click="showConfig">-->
<el-icon> <!-- <el-icon>-->
<Tools/> <!-- <Tools/>-->
</el-icon> <!-- </el-icon>-->
<span>账户信息</span> <!-- <span>账户信息</span>-->
</el-dropdown-item> <!-- </el-dropdown-item>-->
<el-dropdown-item @click="clearAllChats"> <!-- <el-dropdown-item @click="clearAllChats">-->
<el-icon> <!-- <el-icon>-->
<Delete/> <!-- <Delete/>-->
</el-icon> <!-- </el-icon>-->
<span>清除所有会话</span> <!-- <span>清除所有会话</span>-->
</el-dropdown-item> <!-- </el-dropdown-item>-->
<el-dropdown-item @click="logout"> <!-- <el-dropdown-item @click="logout">-->
<i class="iconfont icon-logout"></i> <!-- <i class="iconfont icon-logout"></i>-->
<span>注销</span> <!-- <span>注销</span>-->
</el-dropdown-item> <!-- </el-dropdown-item>-->
<el-dropdown-item> <!-- <el-dropdown-item>-->
<i class="iconfont icon-github"></i> <!-- <i class="iconfont icon-github"></i>-->
<span> <!-- <span>-->
powered by <!-- powered by-->
<el-link type="primary" href="https://github.com/yangjian102621/chatgpt-plus" target="_blank">chatgpt-plus-v3</el-link> <!-- <el-link type="primary" href="https://github.com/yangjian102621/chatgpt-plus" target="_blank">chatgpt-plus-v3</el-link>-->
</span> <!-- </span>-->
</el-dropdown-item> <!-- </el-dropdown-item>-->
</el-dropdown-menu> <!-- </el-dropdown-menu>-->
</template> <!-- </template>-->
</el-dropdown> <!-- </el-dropdown>-->
</div> </div>
</el-aside> </el-aside>
<el-main v-loading="loading" element-loading-background="rgba(122, 122, 122, 0.3)"> <el-main v-loading="loading" element-loading-background="rgba(122, 122, 122, 0.3)">
<div class="chat-head"> <!-- <div class="chat-head">-->
<div class="chat-config"> <!-- <div class="chat-config">-->
<el-select v-model="roleId" filterable placeholder="角色" class="role-select" @change="_newChat" <!-- <el-select v-model="roleId" filterable placeholder="角色" class="role-select" @change="_newChat"-->
style="width:150px"> <!-- style="width:150px">-->
<el-option <!-- <el-option-->
v-for="item in roles" <!-- v-for="item in roles"-->
:key="item.id" <!-- :key="item.id"-->
:label="item.name" <!-- :label="item.name"-->
:value="item.id" <!-- :value="item.id"-->
> <!-- >-->
<div class="role-option"> <!-- <div class="role-option">-->
<el-image :src="item.icon"></el-image> <!-- <el-image :src="item.icon"></el-image>-->
<span>{{ item.name }}</span> <!-- <span>{{ item.name }}</span>-->
</div> <!-- </div>-->
</el-option> <!-- </el-option>-->
</el-select> <!-- </el-select>-->
<el-select v-model="modelID" placeholder="模型" @change="_newChat" :disabled="disableModel" <!-- <el-select v-model="modelID" placeholder="模型" @change="_newChat" :disabled="disableModel"-->
style="width:150px"> <!-- style="width:150px">-->
<el-option <!-- <el-option-->
v-for="item in models" <!-- v-for="item in models"-->
:key="item.id" <!-- :key="item.id"-->
:label="item.name" <!-- :label="item.name"-->
:value="item.id" <!-- :value="item.id"-->
> <!-- >-->
<span>{{ item.name }}</span> <!-- <span>{{ item.name }}</span>-->
<el-tag style="margin-left: 5px; position: relative; top:-2px" type="info" size="small">{{ <!-- <el-tag style="margin-left: 5px; position: relative; top:-2px" type="info" size="small">{{-->
item.power <!-- item.power-->
}}算力 <!-- }}算力-->
</el-tag> <!-- </el-tag>-->
</el-option> <!-- </el-option>-->
</el-select> <!-- </el-select>-->
<el-button type="primary" @click="newChat"> <!-- <el-button type="primary" @click="newChat">-->
<el-icon> <!-- <el-icon>-->
<Plus/> <!-- <Plus/>-->
</el-icon> <!-- </el-icon>-->
新建对话 <!-- 新建对话-->
</el-button> <!-- </el-button>-->
<el-button type="success" @click="exportChat" plain> <!-- <el-button type="success" @click="exportChat" plain>-->
<i class="iconfont icon-export"></i> <!-- <i class="iconfont icon-export"></i>-->
<span>导出会话</span> <!-- <span>导出会话</span>-->
</el-button> <!-- </el-button>-->
</div> <!-- </div>-->
</div> <!-- </div>-->
<div class="right-box" :style="{height: mainWinHeight+'px'}"> <div class="chat-box" :style="{height: mainWinHeight+'px'}">
<div> <div>
<div id="container"> <div id="container">
<div class="chat-box" id="chat-box" :style="{height: chatBoxHeight+'px'}"> <div class="chat-box" id="chat-box" :style="{height: chatBoxHeight+'px'}">
@ -207,7 +226,7 @@
<el-dialog <el-dialog
v-model="showNotice" v-model="showNotice"
:show-close="true" :show-close="true"
custom-class="notice-dialog" class="notice-dialog"
title="网站公告" title="网站公告"
> >
<div class="notice"> <div class="notice">
@ -232,19 +251,7 @@
import {nextTick, onMounted, onUnmounted, ref} from 'vue' import {nextTick, onMounted, onUnmounted, ref} from 'vue'
import ChatPrompt from "@/components/ChatPrompt.vue"; import ChatPrompt from "@/components/ChatPrompt.vue";
import ChatReply from "@/components/ChatReply.vue"; import ChatReply from "@/components/ChatReply.vue";
import { import {Delete, Edit, More, Plus, Promotion, RefreshRight, Search, Share, VideoPause} from '@element-plus/icons-vue'
ArrowDown,
Check,
Close,
Delete,
Edit,
Plus,
Promotion,
RefreshRight,
Search,
Tools,
VideoPause
} from '@element-plus/icons-vue'
import 'highlight.js/styles/a11y-dark.css' import 'highlight.js/styles/a11y-dark.css'
import {dateFormat, escapeHTML, isMobile, processContent, randString, removeArrayItem, UUID} from "@/utils/libs"; import {dateFormat, escapeHTML, isMobile, processContent, randString, removeArrayItem, UUID} from "@/utils/libs";
import {ElMessage, ElMessageBox} from "element-plus"; import {ElMessage, ElMessageBox} from "element-plus";
@ -414,9 +421,9 @@ const getRoleById = function (rid) {
} }
const resizeElement = function () { const resizeElement = function () {
chatBoxHeight.value = window.innerHeight - 51 - 82 - 38; chatBoxHeight.value = window.innerHeight - 50 - 82 - 38;
mainWinHeight.value = window.innerHeight - 51; mainWinHeight.value = window.innerHeight - 50;
leftBoxHeight.value = window.innerHeight - 43 - 47 - 45; leftBoxHeight.value = window.innerHeight - 90 - 45 - 82;
}; };
const _newChat = () => { const _newChat = () => {
@ -492,64 +499,73 @@ const loadChat = function (chat) {
} }
// //
const curOpt = ref('')
const tmpChatTitle = ref(''); const tmpChatTitle = ref('');
const editChatTitle = function (event, chat) { const editChatTitle = (chat) => {
event.stopPropagation();
chat.edit = true; chat.edit = true;
curOpt.value = 'edit';
tmpChatTitle.value = chat.title; tmpChatTitle.value = chat.title;
console.log(chat.chat_id)
nextTick(() => {
document.getElementById('chat-' + chat.chat_id).focus()
})
}; };
const titleKeydown = (e, chat) => { const titleKeydown = (e, chat) => {
if (e.keyCode === 13) { if (e.keyCode === 13) {
e.stopPropagation(); e.stopPropagation();
confirm(e, chat) editConfirm(chat)
} }
} }
const stopPropagation = (e) => {
e.stopPropagation();
}
// //
const confirm = function (event, chat) { const editConfirm = function (chat) {
event.stopPropagation(); if (tmpChatTitle.value === '') {
if (curOpt.value === 'edit') { return ElMessage.error("请输入会话标题!");
if (tmpChatTitle.value === '') { }
return ElMessage.error("请输入会话标题!"); if (!chat.chat_id) {
} return ElMessage.error("对话 ID 为空,请刷新页面再试!");
if (!chat.chat_id) { }
return ElMessage.error("对话 ID 为空,请刷新页面再试!"); if (tmpChatTitle.value === chat.title) {
} chat.edit = false;
httpPost('/api/chat/update', {chat_id: chat.chat_id, title: tmpChatTitle.value}).then(() => { return
chat.title = tmpChatTitle.value;
chat.edit = false;
}).catch(e => {
ElMessage.error("操作失败:" + e.message);
})
} else if (curOpt.value === 'remove') {
httpGet('/api/chat/remove?chat_id=' + chat.chat_id).then(() => {
chatList.value = removeArrayItem(chatList.value, chat, function (e1, e2) {
return e1.id === e2.id
})
//
newChat();
}).catch(e => {
ElMessage.error("操作失败:" + e.message);
})
} }
} httpPost('/api/chat/update', {chat_id: chat.chat_id, title: tmpChatTitle.value}).then(() => {
// chat.title = tmpChatTitle.value;
const cancel = function (event, chat) { chat.edit = false;
event.stopPropagation(); }).catch(e => {
chat.edit = false; ElMessage.error("操作失败:" + e.message);
chat.removing = false; })
}
}
// //
const removeChat = function (event, chat) { const removeChat = function (chat) {
event.stopPropagation(); ElMessageBox.confirm(
chat.removing = true; `该操作会删除"${chat.title}"`,
curOpt.value = 'remove'; '删除聊天',
{
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
httpGet('/api/chat/remove?chat_id=' + chat.chat_id).then(() => {
chatList.value = removeArrayItem(chatList.value, chat, function (e1, e2) {
return e1.id === e2.id
})
//
newChat();
}).catch(e => {
ElMessage.error("操作失败:" + e.message);
})
})
.catch(() => {
})
} }
const latexPlugin = require('markdown-it-latex2img') const latexPlugin = require('markdown-it-latex2img')
@ -886,27 +902,29 @@ const reGenerate = function () {
const chatName = ref('') const chatName = ref('')
// //
const searchChat = function () { const searchChat = function (e) {
if (chatName.value === '') { if (chatName.value === '') {
chatList.value = allChats.value chatList.value = allChats.value
return return
} }
const items = []; if (e.keyCode === 13) {
for (let i = 0; i < allChats.value.length; i++) { const items = [];
if (allChats.value[i].title.toLowerCase().indexOf(chatName.value.toLowerCase()) !== -1) { for (let i = 0; i < allChats.value.length; i++) {
items.push(allChats.value[i]); if (allChats.value[i].title.toLowerCase().indexOf(chatName.value.toLowerCase()) !== -1) {
items.push(allChats.value[i]);
}
} }
chatList.value = items;
} }
chatList.value = items;
} }
// //
const exportChat = () => { const shareChat = (chat) => {
if (!activeChat.value['chat_id']) { if (!chat.chat_id) {
return ElMessage.error("请先选中一个会话") return ElMessage.error("请先选中一个会话")
} }
const url = location.protocol + '//' + location.host + '/chat/export?chat_id=' + activeChat.value['chat_id'] const url = location.protocol + '//' + location.host + '/chat/export?chat_id=' + chat.chat_id
// console.log(url) // console.log(url)
window.open(url, '_blank'); window.open(url, '_blank');
} }

View File

@ -2,10 +2,10 @@
<div> <div>
<div class="page-dall"> <div class="page-dall">
<div class="inner custom-scroll"> <div class="inner custom-scroll">
<div class="sd-box"> <div class="sd-box" :style="{ height: paramBoxHeight + 'px' }">
<h2>DALL-E 创作中心</h2> <h2>DALL-E 创作中心</h2>
<div class="sd-params" :style="{ height: paramBoxHeight + 'px' }"> <div class="sd-params">
<el-form :model="params" label-width="80px" label-position="left"> <el-form :model="params" label-width="80px" label-position="left">
<div class="param-line" style="padding-top: 10px"> <div class="param-line" style="padding-top: 10px">
<el-form-item label="图片质量"> <el-form-item label="图片质量">
@ -235,8 +235,8 @@ import Clipboard from "clipboard";
import {checkSession} from "@/action/session"; import {checkSession} from "@/action/session";
import LoginDialog from "@/components/LoginDialog.vue"; import LoginDialog from "@/components/LoginDialog.vue";
const listBoxHeight = ref(window.innerHeight - 40) const listBoxHeight = ref(0)
const paramBoxHeight = ref(window.innerHeight - 150) const paramBoxHeight = ref(0)
const showLoginDialog = ref(false) const showLoginDialog = ref(false)
const isLogin = ref(false) const isLogin = ref(false)
const loading = ref(true) const loading = ref(true)
@ -244,9 +244,13 @@ const colWidth = ref(240)
const isOver = ref(false) const isOver = ref(false)
const previewURL = ref("") const previewURL = ref("")
const resizeElement = function () {
listBoxHeight.value = window.innerHeight - 90
paramBoxHeight.value = window.innerHeight - 110
};
resizeElement()
window.onresize = () => { window.onresize = () => {
listBoxHeight.value = window.innerHeight - 40 resizeElement()
paramBoxHeight.value = window.innerHeight - 150
} }
const qualities = [ const qualities = [
{name: "标准", value: "standard"}, {name: "标准", value: "standard"},

View File

@ -1,49 +1,103 @@
<template> <template>
<div class="home"> <div class="home">
<div class="navigator"> <div class="header">
<div class="logo"> <div class="banner">
<el-image :src="logo" @click="router.push('/')"/> <div class="logo">
<div class="divider"></div> <el-image :src="logo" @click="router.push('/')"/>
</div>
<div class="title">
<span>{{ title }}</span>
</div>
</div> </div>
<ul class="nav-items">
<li v-for="item in mainNavs" :key="item.url">
<a @click="changeNav(item)" :class="item.url === curPath ? 'active' : ''">
<el-image :src="item.icon" style="width: 30px;height: 30px"/>
</a>
<div :class="item.url === curPath ? 'title active' : 'title'">{{ item.name }}</div>
</li>
<el-popover <div class="navbar">
v-if="moreNavs.length > 0" <el-dropdown :hide-on-click="true" class="user-info" trigger="click" v-if="loginUser.id">
placement="right-end" <span class="el-dropdown-link">
trigger="hover" <el-image :src="loginUser.avatar"/>
> </span>
<template #reference> <template #dropdown>
<li> <el-dropdown-menu>
<a class="active"> <el-dropdown-item>
<el-image src="/images/menu/more.png" style="width: 30px;height: 30px"/> <el-icon>
</a> <UserFilled/>
</li> </el-icon>
<span class="username">{{ loginUser.nickname }}</span>
</el-dropdown-item>
<el-dropdown-item>
<i class="iconfont icon-book"></i>
<span>
<el-link type="primary" href="https://github.com/yangjian102621/chatgpt-plus" target="_blank">
用户手册
</el-link>
</span>
</el-dropdown-item>
<el-dropdown-item>
<i class="iconfont icon-github"></i>
<span>
<el-link type="primary" href="https://ai.r9it.com/docs/" target="_blank">
Geek-AI {{ version }}
</el-link>
</span>
</el-dropdown-item>
<el-dropdown-item @click="logout">
<i class="iconfont icon-logout"></i>
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</template> </template>
<template #default> </el-dropdown>
<ul class="more-menus"> </div>
<li v-for="item in moreNavs" :key="item.url" :class="item.url === curPath ? 'active' : ''"> </div>
<a @click="changeNav(item)"> <div class="main">
<el-image :src="item.icon" style="width: 20px;height: 20px"/> <div class="navigator">
<span :class="item.url === curPath ? 'title active' : 'title'">{{ item.name }}</span> <ul class="nav-items">
<li v-for="item in mainNavs" :key="item.url">
<el-tooltip
effect="light"
:content="item.name"
placement="right">
<a @click="changeNav(item)" :class="item.url === curPath ? 'active' : ''">
<el-image :src="item.icon" style="width: 30px;height: 30px"/>
</a>
</el-tooltip>
</li>
<el-popover
v-if="moreNavs.length > 0"
placement="right-end"
trigger="hover"
>
<template #reference>
<li>
<a class="active">
<el-image src="/images/menu/more.png" style="width: 30px;height: 30px"/>
</a> </a>
</li> </li>
</ul> </template>
</template> <template #default>
</el-popover> <ul class="more-menus">
</ul> <li v-for="item in moreNavs" :key="item.url" :class="item.url === curPath ? 'active' : ''">
</div> <a @click="changeNav(item)">
<div class="content"> <el-image :src="item.icon" style="width: 20px;height: 20px"/>
<router-view v-slot="{ Component }"> <span :class="item.url === curPath ? 'title active' : 'title'">{{ item.name }}</span>
<transition name="move" mode="out-in"> </a>
<component :is="Component"></component> </li>
</transition> </ul>
</router-view> </template>
</el-popover>
</ul>
</div>
<div class="content" :style="{height: mainWinHeight+'px'}">
<router-view v-slot="{ Component }">
<transition name="move" mode="out-in">
<component :is="Component"></component>
</transition>
</router-view>
</div>
</div> </div>
</div> </div>
</template> </template>
@ -54,12 +108,19 @@ import {useRouter} from "vue-router";
import {onMounted, ref} from "vue"; import {onMounted, ref} from "vue";
import {httpGet} from "@/utils/http"; import {httpGet} from "@/utils/http";
import {ElMessage} from "element-plus"; import {ElMessage} from "element-plus";
import {UserFilled} from "@element-plus/icons-vue";
import {checkSession} from "@/action/session";
import {removeUserToken} from "@/store/session";
const router = useRouter(); const router = useRouter();
const logo = ref('/images/logo.png'); const logo = ref('/images/logo.png');
const mainNavs = ref([]) const mainNavs = ref([])
const moreNavs = ref([]) const moreNavs = ref([])
const curPath = ref(router.currentRoute.value.path) const curPath = ref(router.currentRoute.value.path)
const title = ref("")
const mainWinHeight = window.innerHeight - 50
const loginUser = ref({})
const version = ref(process.env.VUE_APP_VERSION)
if (curPath.value === "/external") { if (curPath.value === "/external") {
curPath.value = router.currentRoute.value.query.url curPath.value = router.currentRoute.value.query.url
@ -75,7 +136,8 @@ const changeNav = (item) => {
onMounted(() => { onMounted(() => {
httpGet("/api/config/get?key=system").then(res => { httpGet("/api/config/get?key=system").then(res => {
logo.value = res.data['logo'] logo.value = res.data.logo
title.value = res.data.title
}).catch(e => { }).catch(e => {
ElMessage.error("获取系统配置失败:" + e.message) ElMessage.error("获取系统配置失败:" + e.message)
}) })
@ -83,7 +145,7 @@ onMounted(() => {
httpGet("/api/menu/list").then(res => { httpGet("/api/menu/list").then(res => {
mainNavs.value = res.data mainNavs.value = res.data
// //
const rows = Math.floor((window.innerHeight - 90) / 90) const rows = Math.floor((window.innerHeight - 90) / 60)
if (res.data.length > rows) { if (res.data.length > rows) {
mainNavs.value = res.data.slice(0, rows) mainNavs.value = res.data.slice(0, rows)
moreNavs.value = res.data.slice(rows) moreNavs.value = res.data.slice(rows)
@ -91,119 +153,24 @@ onMounted(() => {
}).catch(e => { }).catch(e => {
ElMessage.error("获取系统菜单失败:" + e.message) ElMessage.error("获取系统菜单失败:" + e.message)
}) })
checkSession().then(user => {
loginUser.value = user
}).catch(() => {
})
}) })
const logout = function () {
httpGet('/api/user/logout').then(() => {
removeUserToken()
router.push("/login")
}).catch(() => {
ElMessage.error('注销失败!');
})
}
</script> </script>
<style lang="stylus" scoped> <style lang="stylus" scoped>
@import '@/assets/iconfont/iconfont.css'; @import '@/assets/iconfont/iconfont.css';
.home { @import "@/assets/css/home.styl"
display: flex;
height 100vh
width 100%
.navigator {
display flex
flex-flow column
width 60px
padding 10px 6px
border-right: 1px solid #3c3c3c
background-color: #25272D
.logo {
display flex
flex-flow column
align-items center
cursor pointer
.el-image {
width 50px
height 50px
}
.divider {
border-bottom 1px solid #4A4A4A
width 80%
height 10px
}
}
.nav-items {
margin-top: 10px;
padding 0 5px
li {
margin-bottom 15px
a {
color #DADBDC
border-radius 10px
width 48px
height 48px
display flex
justify-content center
align-items center
cursor pointer
.el-image {
border-radius 10px
}
.iconfont {
font-size 20px
}
}
a:hover, a.active {
color #47fff1
background-color #0F7A71
}
.title {
font-size: 12px
padding-top: 5px
color: #e5e7eb;
text-align: center;
}
.active {
color #47fff1
}
}
}
}
.content {
width: 100%
height: 100vh
box-sizing: border-box
background-color #282c34
}
}
.el-popper {
.more-menus {
li {
padding 10px 15px
cursor pointer
border-radius 5px
margin 5px 0
.el-image {
position: relative
top 5px
right 5px
}
&:hover {
background-color #f1f1f1
}
}
li.active {
background-color #f1f1f1
}
}
}
</style> </style>

View File

@ -618,17 +618,22 @@ import {getSessionId} from "@/store/session";
import {copyObj, removeArrayItem} from "@/utils/libs"; import {copyObj, removeArrayItem} from "@/utils/libs";
import LoginDialog from "@/components/LoginDialog.vue"; import LoginDialog from "@/components/LoginDialog.vue";
const listBoxHeight = ref(window.innerHeight - 40) const listBoxHeight = ref(0)
const paramBoxHeight = ref(window.innerHeight - 150) const paramBoxHeight = ref(0)
const showLoginDialog = ref(false) const showLoginDialog = ref(false)
const loading = ref(true) const loading = ref(true)
const colWidth = ref(240) const colWidth = ref(240)
const previewURL = ref("") const previewURL = ref("")
const resizeElement = function () {
listBoxHeight.value = window.innerHeight - 80
paramBoxHeight.value = window.innerHeight - 190
};
resizeElement()
window.onresize = () => { window.onresize = () => {
listBoxHeight.value = window.innerHeight - 40 resizeElement()
paramBoxHeight.value = window.innerHeight - 150
} }
const rates = [ const rates = [
{css: "square", value: "1:1", text: "1:1", img: "/images/mj/rate_1_1.png"}, {css: "square", value: "1:1", text: "1:1", img: "/images/mj/rate_1_1.png"},
{css: "size1-2", value: "1:2", text: "1:2", img: "/images/mj/rate_1_2.png"}, {css: "size1-2", value: "1:2", text: "1:2", img: "/images/mj/rate_1_2.png"},

View File

@ -2,10 +2,10 @@
<div> <div>
<div class="page-sd"> <div class="page-sd">
<div class="inner custom-scroll"> <div class="inner custom-scroll">
<div class="sd-box"> <div class="sd-box" :style="{ height: paramBoxHeight + 'px' }">
<h2>Stable Diffusion 创作中心</h2> <h2>Stable Diffusion 创作中心</h2>
<div class="sd-params" :style="{ height: paramBoxHeight + 'px' }"> <div class="sd-params">
<el-form :model="params" label-width="80px" label-position="left"> <el-form :model="params" label-width="80px" label-position="left">
<div class="param-line" style="padding-top: 10px"> <div class="param-line" style="padding-top: 10px">
<el-form-item label="采样方法"> <el-form-item label="采样方法">
@ -513,8 +513,8 @@ import {useRouter} from "vue-router";
import {getSessionId} from "@/store/session"; import {getSessionId} from "@/store/session";
import LoginDialog from "@/components/LoginDialog.vue"; import LoginDialog from "@/components/LoginDialog.vue";
const listBoxHeight = ref(window.innerHeight - 40) const listBoxHeight = ref(0)
const paramBoxHeight = ref(window.innerHeight - 150) const paramBoxHeight = ref(0)
const fullImgHeight = ref(window.innerHeight - 60) const fullImgHeight = ref(window.innerHeight - 60)
const showTaskDialog = ref(false) const showTaskDialog = ref(false)
const item = ref({}) const item = ref({})
@ -523,9 +523,13 @@ const isLogin = ref(false)
const loading = ref(true) const loading = ref(true)
const colWidth = ref(240) const colWidth = ref(240)
const resizeElement = function () {
listBoxHeight.value = window.innerHeight - 80
paramBoxHeight.value = window.innerHeight - 110
};
resizeElement()
window.onresize = () => { window.onresize = () => {
listBoxHeight.value = window.innerHeight - 40 resizeElement()
paramBoxHeight.value = window.innerHeight - 150
} }
const samplers = ["Euler a", "DPM++ 2S a", "DPM++ 2M", "DPM++ SDE", "DPM++ 2M SDE", "UniPC", "Restart"] const samplers = ["Euler a", "DPM++ 2S a", "DPM++ 2M", "DPM++ SDE", "DPM++ 2M SDE", "UniPC", "Restart"]
const schedulers = ["Automatic", "Karras", "Exponential", "Uniform"] const schedulers = ["Automatic", "Karras", "Exponential", "Uniform"]

View File

@ -310,7 +310,7 @@ const data = ref({
const loading = ref(true) const loading = ref(true)
const isOver = ref(false) const isOver = ref(false)
const imgType = ref("mj") // const imgType = ref("mj") //
const listBoxHeight = window.innerHeight - 74 const listBoxHeight = window.innerHeight - 124
const colWidth = ref(240) const colWidth = ref(240)
const fullImgHeight = ref(window.innerHeight - 60) const fullImgHeight = ref(window.innerHeight - 60)
const showTaskDialog = ref(false) const showTaskDialog = ref(false)
@ -395,6 +395,7 @@ onUnmounted(() => {
}) })
const changeImgType = () => { const changeImgType = () => {
console.log(imgType.value)
document.getElementById('waterfall-box').scrollTo(0, 0) document.getElementById('waterfall-box').scrollTo(0, 0)
page.value = 0 page.value = 0
data.value = { data.value = {

View File

@ -163,7 +163,7 @@ const initData = () => {
display: flex; display: flex;
justify-content: center; justify-content: center;
background-color: #282c34; background-color: #282c34;
height 100vh height 100%
overflow-x hidden overflow-x hidden
overflow-y visible overflow-y visible
@ -176,6 +176,7 @@ const initData = () => {
h2 { h2 {
color #ffffff; color #ffffff;
text-align center
} }
.share-box { .share-box {

View File

@ -2,10 +2,10 @@
<div> <div>
<div class="page-mark-map"> <div class="page-mark-map">
<div class="inner custom-scroll"> <div class="inner custom-scroll">
<div class="mark-map-box"> <div class="mark-map-box" :style="{ height: leftBoxHeight + 'px' }">
<h2>思维导图创作中心</h2> <h2>思维导图创作中心</h2>
<div class="mark-map-params" :style="{ height: leftBoxHeight + 'px' }"> <div class="mark-map-params">
<el-form label-width="80px" label-position="left"> <el-form label-width="80px" label-position="left">
<div class="param-line"> <div class="param-line">
你的需求 你的需求
@ -69,9 +69,8 @@
</div> </div>
</div> </div>
<div class="right-box"> <div class="chat-box">
<div class="top-bar"> <div class="top-bar">
<h2>思维导图</h2>
<el-button @click="downloadImage" type="primary"> <el-button @click="downloadImage" type="primary">
<el-icon> <el-icon>
<Download/> <Download/>
@ -108,7 +107,7 @@ import {Download} from "@element-plus/icons-vue";
import {Toolbar} from 'markmap-toolbar'; import {Toolbar} from 'markmap-toolbar';
const leftBoxHeight = ref(window.innerHeight - 105) const leftBoxHeight = ref(window.innerHeight - 105)
const rightBoxHeight = ref(window.innerHeight - 85) const rightBoxHeight = ref(window.innerHeight - 115)
const prompt = ref("") const prompt = ref("")
const text = ref(`# Geek-AI 助手 const text = ref(`# Geek-AI 助手

View File

@ -1,9 +1,6 @@
<template> <template>
<div> <div>
<div class="member custom-scroll"> <div class="member custom-scroll">
<div class="title">
会员充值中心
</div>
<div class="inner" :style="{height: listBoxHeight + 'px'}"> <div class="inner" :style="{height: listBoxHeight + 'px'}">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="7"> <el-col :span="7">

View File

@ -1,8 +1,6 @@
<template> <template>
<div class="power-log" v-loading="loading"> <div class="power-log" v-loading="loading">
<div class="inner"> <div class="inner">
<h2>消费日志</h2>
<div class="list-box" :style="{height: listBoxHeight + 'px'}"> <div class="list-box" :style="{height: listBoxHeight + 'px'}">
<div class="handle-box"> <div class="handle-box">
<el-input v-model="query.model" placeholder="模型" class="handle-input mr10" clearable></el-input> <el-input v-model="query.model" placeholder="模型" class="handle-input mr10" clearable></el-input>