mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-18 01:06:39 +08:00
feat: optimize chat page data list style, support list style and chat style
This commit is contained in:
parent
6998dd7af4
commit
a692cf1338
@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [
|
||||||
'@vue.css/cli-plugin-babel/preset'
|
'@vue/cli-plugin-babel/preset'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -2,27 +2,27 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout {
|
#app .chat-page {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-aside {
|
#app .chat-page .el-aside {
|
||||||
background-color: #252526;
|
background-color: #252526;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-aside .title-box {
|
#app .chat-page .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 .chat-page .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 .chat-page .el-aside .chat-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
background-color: #28292a;
|
background-color: #28292a;
|
||||||
@ -30,28 +30,28 @@
|
|||||||
border-right: 1px solid #2f3032;
|
border-right: 1px solid #2f3032;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-aside .chat-list .search-box {
|
#app .chat-page .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 .chat-page .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 .chat-page .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 .chat-page .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 .chat-page .el-aside .chat-list .content .chat-list-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
@ -59,17 +59,17 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-aside .chat-list .content .chat-list-item:hover {
|
#app .chat-page .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 .chat-page .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 .chat-page .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;
|
||||||
@ -79,7 +79,7 @@
|
|||||||
width: 190px;
|
width: 190px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-aside .chat-list .content .chat-list-item .chat-title {
|
#app .chat-page .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;
|
||||||
@ -89,7 +89,7 @@
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-aside .chat-list .content .chat-list-item .btn {
|
#app .chat-page .el-aside .chat-list .content .chat-list-item .btn {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 2px;
|
right: 2px;
|
||||||
@ -97,19 +97,19 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-aside .chat-list .content .chat-list-item .btn .el-icon {
|
#app .chat-page .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 .chat-page .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 .chat-page .el-aside .chat-list .content .chat-list-item.active .btn {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-aside .tool-box {
|
#app .chat-page .el-aside .tool-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -117,48 +117,48 @@
|
|||||||
border-top: 1px solid #3c3c3c;
|
border-top: 1px solid #3c3c3c;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-aside .tool-box .user-info {
|
#app .chat-page .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 .chat-page .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 .chat-page .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 .chat-page .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 .chat-page .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 .chat-page .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 .chat-page .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 .chat-page .el-main .chat-head .chat-config {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -166,54 +166,54 @@
|
|||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-head .chat-config .role-select-label {
|
#app .chat-page .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 .chat-page .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 .chat-page .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 .chat-page .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 .chat-page .el-main .chat-head .iconfont {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-head .is-circle {
|
#app .chat-page .el-main .chat-head .is-circle {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-head .is-circle .iconfont {
|
#app .chat-page .el-main .chat-head .is-circle .iconfont {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box {
|
#app .chat-page .el-main .chat-box {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-left: 1px solid #4f4f4f;
|
border-left: 1px solid #4f4f4f;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container {
|
#app .chat-page .el-main .chat-box #container {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container ::-webkit-scrollbar {
|
#app .chat-page .el-main .chat-box #container ::-webkit-scrollbar {
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container .chat-box {
|
#app .chat-page .el-main .chat-box #container .chat-box {
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
--content-font-size: 16px;
|
--content-font-size: 16px;
|
||||||
--content-color: #c1c1c1;
|
--content-color: #c1c1c1;
|
||||||
@ -221,28 +221,28 @@
|
|||||||
padding: 0 0 50px 0;
|
padding: 0 0 50px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container .chat-box .chat-line {
|
#app .chat-page .el-main .chat-box #container .chat-box .chat-line {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container .re-generate {
|
#app .chat-page .el-main .chat-box #container .re-generate {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container .re-generate .btn-box {
|
#app .chat-page .el-main .chat-box #container .re-generate .btn-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container .re-generate .btn-box .el-button .el-icon {
|
#app .chat-page .el-main .chat-box #container .re-generate .btn-box .el-button .el-icon {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container .input-box {
|
#app .chat-page .el-main .chat-box #container .input-box {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -251,7 +251,7 @@
|
|||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container .input-box .input-container {
|
#app .chat-page .el-main .chat-box #container .input-box .input-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border: none;
|
border: none;
|
||||||
@ -261,24 +261,24 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container .input-box .input-container .el-textarea .el-textarea__inner::-webkit-scrollbar {
|
#app .chat-page .el-main .chat-box #container .input-box .input-container .el-textarea .el-textarea__inner::-webkit-scrollbar {
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container .input-box .input-container .select-file {
|
#app .chat-page .el-main .chat-box #container .input-box .input-container .select-file {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 48px;
|
right: 48px;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container .input-box .input-container .send-btn {
|
#app .chat-page .el-main .chat-box #container .input-box .input-container .send-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 12px;
|
right: 12px;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container .input-box .input-container .send-btn .el-button {
|
#app .chat-page .el-main .chat-box #container .input-box .input-container .send-btn .el-button {
|
||||||
padding: 8px 5px;
|
padding: 8px 5px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: #19c37d;
|
background: #19c37d;
|
||||||
@ -286,7 +286,7 @@
|
|||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app .common-layout .el-main .chat-box #container::-webkit-scrollbar {
|
#app .chat-page .el-main .chat-box #container::-webkit-scrollbar {
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ $borderColor = #4676d0;
|
|||||||
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.common-layout {
|
.chat-page {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
// left side
|
// left side
|
||||||
@ -156,6 +156,20 @@ $borderColor = #4676d0;
|
|||||||
max-width 130px;
|
max-width 130px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.setting {
|
||||||
|
padding 5px
|
||||||
|
border-radius 5px
|
||||||
|
cursor pointer
|
||||||
|
.iconfont {
|
||||||
|
font-size 18px
|
||||||
|
color #19c37d
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background #D5FAD3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.el-button {
|
.el-button {
|
||||||
.el-icon {
|
.el-icon {
|
||||||
margin-right 5px;
|
margin-right 5px;
|
||||||
|
@ -1,11 +1,49 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="chat-line chat-line-prompt">
|
<div class="chat-line chat-line-prompt-list" v-if="listStyle === 'list'">
|
||||||
|
<div class="chat-line-inner">
|
||||||
|
<div class="chat-icon">
|
||||||
|
<img :src="data.icon" alt="User"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-item">
|
||||||
|
<div v-if="files.length > 0" class="file-list-box">
|
||||||
|
<div v-for="file in files">
|
||||||
|
<div class="image" v-if="isImage(file.ext)">
|
||||||
|
<el-image :src="file.url" fit="cover"/>
|
||||||
|
</div>
|
||||||
|
<div class="item" v-else>
|
||||||
|
<div class="icon">
|
||||||
|
<el-image :src="GetFileIcon(file.ext)" fit="cover" />
|
||||||
|
</div>
|
||||||
|
<div class="body">
|
||||||
|
<div class="title">
|
||||||
|
<el-link :href="file.url" target="_blank" style="--el-font-weight-primary:bold">{{file.name}}</el-link>
|
||||||
|
</div>
|
||||||
|
<div class="info">
|
||||||
|
<span>{{GetFileType(file.ext)}}</span>
|
||||||
|
<span>{{FormatFileSize(file.size)}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content" v-html="content"></div>
|
||||||
|
<div class="bar" v-if="data.created_at > 0">
|
||||||
|
<span class="bar-item"><el-icon><Clock/></el-icon> {{ dateFormat(data.created_at) }}</span>
|
||||||
|
<span class="bar-item">tokens: {{ finalTokens }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-line chat-line-prompt-chat" v-else>
|
||||||
<div class="chat-line-inner">
|
<div class="chat-line-inner">
|
||||||
<div class="chat-icon">
|
<div class="chat-icon">
|
||||||
<img :src="icon" alt="User"/>
|
<img :src="data.icon" alt="User"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chat-item">
|
<div class="chat-item">
|
||||||
|
|
||||||
<div v-if="files.length > 0" class="file-list-box">
|
<div v-if="files.length > 0" class="file-list-box">
|
||||||
<div v-for="file in files">
|
<div v-for="file in files">
|
||||||
<div class="image" v-if="isImage(file.ext)">
|
<div class="image" v-if="isImage(file.ext)">
|
||||||
@ -27,14 +65,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" v-html="content"></div>
|
<div class="content-wrapper">
|
||||||
<div class="bar" v-if="createdAt">
|
<div class="content" v-html="content"></div>
|
||||||
<span class="bar-item"><el-icon><Clock/></el-icon> {{ createdAt }}</span>
|
</div>
|
||||||
<!-- <span class="bar-item">Tokens: {{ finalTokens }}</span>-->
|
<div class="bar" v-if="data.created_at > 0">
|
||||||
|
<span class="bar-item"><el-icon><Clock/></el-icon> {{ dateFormat(data.created_at) }}</span>
|
||||||
|
<span class="bar-item">tokens: {{ finalTokens }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -43,7 +82,7 @@ import {onMounted, ref} from "vue"
|
|||||||
import {Clock} from "@element-plus/icons-vue";
|
import {Clock} from "@element-plus/icons-vue";
|
||||||
import {httpPost} from "@/utils/http";
|
import {httpPost} from "@/utils/http";
|
||||||
import hl from "highlight.js";
|
import hl from "highlight.js";
|
||||||
import {isImage, processPrompt, substr} from "@/utils/libs";
|
import {dateFormat, isImage, processPrompt} from "@/utils/libs";
|
||||||
import {FormatFileSize, GetFileIcon, GetFileType} from "@/store/system";
|
import {FormatFileSize, GetFileIcon, GetFileType} from "@/store/system";
|
||||||
|
|
||||||
const mathjaxPlugin = require('markdown-it-mathjax3')
|
const mathjaxPlugin = require('markdown-it-mathjax3')
|
||||||
@ -73,41 +112,35 @@ const md = require('markdown-it')({
|
|||||||
});
|
});
|
||||||
md.use(mathjaxPlugin)
|
md.use(mathjaxPlugin)
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
content: {
|
data: {
|
||||||
type: String,
|
type: Object,
|
||||||
default: '',
|
default: {
|
||||||
|
content: '',
|
||||||
|
created_at: '',
|
||||||
|
tokens: 0,
|
||||||
|
model: '',
|
||||||
|
icon: '',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
icon: {
|
listStyle: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'images/user-icon.png',
|
default: 'list',
|
||||||
},
|
|
||||||
createdAt: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
tokens: {
|
|
||||||
type: Number,
|
|
||||||
default: 0,
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const finalTokens = ref(props.tokens)
|
const finalTokens = ref(props.data.tokens)
|
||||||
const content =ref(processPrompt(props.content))
|
const content =ref(processPrompt(props.data.content))
|
||||||
const files = ref([])
|
const files = ref([])
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!finalTokens.value) {
|
if (!finalTokens.value) {
|
||||||
httpPost("/api/chat/tokens", {text: props.content, model: props.model}).then(res => {
|
httpPost("/api/chat/tokens", {text: props.data.content, model: props.data.model}).then(res => {
|
||||||
finalTokens.value = res.data;
|
finalTokens.value = res.data;
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const linkRegex = /(https?:\/\/\S+)/g;
|
const linkRegex = /(https?:\/\/\S+)/g;
|
||||||
const links = props.content.match(linkRegex);
|
const links = props.data.content.match(linkRegex);
|
||||||
if (links) {
|
if (links) {
|
||||||
httpPost("/api/upload/list", {urls: links}).then(res => {
|
httpPost("/api/upload/list", {urls: links}).then(res => {
|
||||||
files.value = res.data
|
files.value = res.data
|
||||||
@ -124,131 +157,263 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style lang="stylus">
|
<style lang="stylus">
|
||||||
@import '@/assets/css/markdown/vue.css';
|
@import '@/assets/css/markdown/vue.css';
|
||||||
.chat-line-prompt {
|
.chat-page,.chat-export {
|
||||||
background-color #ffffff;
|
.chat-line-prompt-list {
|
||||||
justify-content: center;
|
background-color #ffffff;
|
||||||
width 100%
|
justify-content: center;
|
||||||
padding-bottom: 1.5rem;
|
width 100%
|
||||||
padding-top: 1.5rem;
|
padding-bottom: 1.5rem;
|
||||||
border-bottom: 1px solid #d9d9e3;
|
padding-top: 1.5rem;
|
||||||
|
border-bottom: 1px solid #d9d9e3;
|
||||||
|
|
||||||
.chat-line-inner {
|
.chat-line-inner {
|
||||||
display flex;
|
display flex;
|
||||||
width 100%;
|
width 100%;
|
||||||
max-width 900px;
|
max-width 900px;
|
||||||
padding-left 10px;
|
padding-left 10px;
|
||||||
|
|
||||||
.chat-icon {
|
.chat-icon {
|
||||||
margin-right 20px;
|
margin-right 20px;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-item {
|
|
||||||
width 100%
|
|
||||||
padding: 0 5px 0 0;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.file-list-box {
|
|
||||||
display flex
|
|
||||||
flex-flow column
|
|
||||||
.image {
|
|
||||||
display flex
|
|
||||||
flex-flow row
|
|
||||||
margin-right 10px
|
|
||||||
position relative
|
|
||||||
|
|
||||||
.el-image {
|
|
||||||
border 1px solid #e3e3e3
|
|
||||||
border-radius 10px
|
|
||||||
margin-bottom 10px
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.item {
|
}
|
||||||
display flex
|
|
||||||
flex-flow row
|
.chat-item {
|
||||||
border-radius 10px
|
width 100%
|
||||||
background-color #ffffff
|
padding: 0 5px 0 0;
|
||||||
border 1px solid #e3e3e3
|
overflow: hidden;
|
||||||
padding 6px
|
|
||||||
margin-bottom 10px
|
.file-list-box {
|
||||||
|
display flex
|
||||||
|
flex-flow column
|
||||||
|
.image {
|
||||||
|
display flex
|
||||||
|
flex-flow row
|
||||||
|
margin-right 10px
|
||||||
|
position relative
|
||||||
|
|
||||||
.icon {
|
|
||||||
.el-image {
|
.el-image {
|
||||||
width 40px
|
border 1px solid #e3e3e3
|
||||||
height 40px
|
border-radius 10px
|
||||||
|
margin-bottom 10px
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.body {
|
.item {
|
||||||
margin-left 8px
|
display flex
|
||||||
font-size 14px
|
flex-flow row
|
||||||
.title {
|
border-radius 10px
|
||||||
font-weight bold
|
background-color #ffffff
|
||||||
line-height 24px
|
border 1px solid #e3e3e3
|
||||||
color #0D0D0D
|
padding 6px
|
||||||
}
|
margin-bottom 10px
|
||||||
.info {
|
|
||||||
color #B4B4B4
|
|
||||||
|
|
||||||
span {
|
.icon {
|
||||||
margin-right 10px
|
.el-image {
|
||||||
|
width 40px
|
||||||
|
height 40px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.body {
|
||||||
|
margin-left 8px
|
||||||
|
font-size 14px
|
||||||
|
.title {
|
||||||
|
font-weight bold
|
||||||
|
line-height 24px
|
||||||
|
color #0D0D0D
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
color #B4B4B4
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-right 10px
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
word-break break-word;
|
word-break break-word;
|
||||||
padding: 6px 10px;
|
padding: 0;
|
||||||
color #374151;
|
color #374151;
|
||||||
font-size: var(--content-font-size);
|
font-size: var(--content-font-size);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
margin 10px 0
|
margin 10px 0
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height 1.5
|
||||||
|
}
|
||||||
|
|
||||||
|
p:last-child {
|
||||||
|
margin-bottom: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
p:first-child {
|
||||||
|
margin-top 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
.bar {
|
||||||
line-height 1.5
|
padding 10px 10px 10px 0;
|
||||||
}
|
|
||||||
|
|
||||||
p:last-child {
|
.bar-item {
|
||||||
margin-bottom: 0
|
background-color #f7f7f8;
|
||||||
}
|
color #888
|
||||||
|
padding 3px 5px;
|
||||||
|
margin-right 10px;
|
||||||
|
border-radius 5px;
|
||||||
|
|
||||||
p:first-child {
|
.el-icon {
|
||||||
margin-top 0
|
position relative
|
||||||
}
|
top 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bar {
|
|
||||||
padding 10px;
|
|
||||||
|
|
||||||
.bar-item {
|
|
||||||
background-color #f7f7f8;
|
|
||||||
color #888
|
|
||||||
padding 3px 5px;
|
|
||||||
margin-right 10px;
|
|
||||||
border-radius 5px;
|
|
||||||
|
|
||||||
.el-icon {
|
|
||||||
position relative
|
|
||||||
top 2px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-line-prompt-chat {
|
||||||
|
background-color #ffffff;
|
||||||
|
justify-content: center;
|
||||||
|
width 100%
|
||||||
|
padding-bottom: 1.5rem;
|
||||||
|
padding-top: 1.5rem;
|
||||||
|
|
||||||
|
.chat-line-inner {
|
||||||
|
display flex;
|
||||||
|
width 100%;
|
||||||
|
padding 0 25px;
|
||||||
|
|
||||||
|
.chat-icon {
|
||||||
|
margin-right 20px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-item {
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.file-list-box {
|
||||||
|
display flex
|
||||||
|
flex-flow column
|
||||||
|
.image {
|
||||||
|
display flex
|
||||||
|
flex-flow row
|
||||||
|
margin-right 10px
|
||||||
|
position relative
|
||||||
|
|
||||||
|
.el-image {
|
||||||
|
border 1px solid #e3e3e3
|
||||||
|
border-radius 10px
|
||||||
|
margin-bottom 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.item {
|
||||||
|
display flex
|
||||||
|
flex-flow row
|
||||||
|
border-radius 10px
|
||||||
|
background-color #ffffff
|
||||||
|
border 1px solid #e3e3e3
|
||||||
|
padding 6px
|
||||||
|
margin-bottom 10px
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
.el-image {
|
||||||
|
width 40px
|
||||||
|
height 40px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.body {
|
||||||
|
margin-left 8px
|
||||||
|
font-size 14px
|
||||||
|
.title {
|
||||||
|
font-weight bold
|
||||||
|
line-height 24px
|
||||||
|
color #0D0D0D
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
color #B4B4B4
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-right 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.content-wrapper {
|
||||||
|
display flex
|
||||||
|
.content {
|
||||||
|
word-break break-word;
|
||||||
|
padding: 1rem
|
||||||
|
color #222222;
|
||||||
|
font-size: var(--content-font-size);
|
||||||
|
overflow: auto;
|
||||||
|
background-color #98e165
|
||||||
|
border-radius: 0 10px 10px 10px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 600px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin 10px 0
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height 1.5
|
||||||
|
}
|
||||||
|
|
||||||
|
p:last-child {
|
||||||
|
margin-bottom: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
p:first-child {
|
||||||
|
margin-top 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.bar {
|
||||||
|
padding 10px 10px 10px 0;
|
||||||
|
|
||||||
|
.bar-item {
|
||||||
|
color #888
|
||||||
|
padding 3px 5px;
|
||||||
|
margin-right 10px;
|
||||||
|
border-radius 5px;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
position relative
|
||||||
|
top 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="chat-line chat-line-reply">
|
<div class="chat-line chat-line-reply-list" v-if="listStyle === 'list'">
|
||||||
<div class="chat-line-inner">
|
<div class="chat-line-inner">
|
||||||
<div class="chat-icon">
|
<div class="chat-icon">
|
||||||
<img :src="data.icon" alt="ChatGPT">
|
<img :src="data.icon" alt="ChatGPT">
|
||||||
@ -9,7 +9,7 @@
|
|||||||
<div class="content" v-html="data.content"></div>
|
<div class="content" v-html="data.content"></div>
|
||||||
<div class="bar" v-if="data.created_at">
|
<div class="bar" v-if="data.created_at">
|
||||||
<span class="bar-item"><el-icon><Clock/></el-icon> {{ dateFormat(data.created_at) }}</span>
|
<span class="bar-item"><el-icon><Clock/></el-icon> {{ dateFormat(data.created_at) }}</span>
|
||||||
<!-- <span class="bar-item">Tokens: {{ tokens }}</span>-->
|
<span class="bar-item">tokens: {{ data.tokens }}</span>
|
||||||
<span class="bar-item">
|
<span class="bar-item">
|
||||||
<el-tooltip
|
<el-tooltip
|
||||||
class="box-item"
|
class="box-item"
|
||||||
@ -61,6 +61,59 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-line chat-line-reply-chat" v-else>
|
||||||
|
<div class="chat-line-inner">
|
||||||
|
<div class="chat-icon">
|
||||||
|
<img :src="data.icon" alt="ChatGPT">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chat-item">
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<div class="content" v-html="data.content"></div>
|
||||||
|
</div>
|
||||||
|
<div class="bar" v-if="data.created_at">
|
||||||
|
<span class="bar-item"><el-icon><Clock/></el-icon> {{ dateFormat(data.created_at) }}</span>
|
||||||
|
<span class="bar-item">tokens: {{ data.tokens }}</span>
|
||||||
|
<span class="bar-item bg">
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="复制回答"
|
||||||
|
placement="bottom"
|
||||||
|
>
|
||||||
|
<el-icon class="copy-reply" :data-clipboard-text="data.orgContent">
|
||||||
|
<DocumentCopy/>
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
<span v-if="!readOnly">
|
||||||
|
<span class="bar-item bg" @click="reGenerate(data.prompt)">
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="重新生成"
|
||||||
|
placement="bottom"
|
||||||
|
>
|
||||||
|
<el-icon><Refresh/></el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="bar-item bg" @click="synthesis(data.orgContent)">
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="生成语音朗读"
|
||||||
|
placement="bottom"
|
||||||
|
>
|
||||||
|
<i class="iconfont icon-speaker"></i>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -71,12 +124,22 @@ import {dateFormat} from "@/utils/libs";
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {},
|
default: {
|
||||||
|
icon: "",
|
||||||
|
content: "",
|
||||||
|
created_at: "",
|
||||||
|
tokens: 0,
|
||||||
|
orgContent: ""
|
||||||
|
},
|
||||||
},
|
},
|
||||||
readOnly: {
|
readOnly: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
}
|
},
|
||||||
|
listStyle: {
|
||||||
|
type: String,
|
||||||
|
default: 'list',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const emits = defineEmits(['regen']);
|
const emits = defineEmits(['regen']);
|
||||||
@ -98,8 +161,8 @@ const reGenerate = (prompt) => {
|
|||||||
|
|
||||||
<style lang="stylus">
|
<style lang="stylus">
|
||||||
@import '@/assets/css/markdown/vue.css';
|
@import '@/assets/css/markdown/vue.css';
|
||||||
.common-layout {
|
.chat-page,.chat-export {
|
||||||
.chat-line-reply {
|
.chat-line-reply-list {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background-color: rgba(247, 247, 248, 1);
|
background-color: rgba(247, 247, 248, 1);
|
||||||
width 100%
|
width 100%
|
||||||
@ -127,13 +190,13 @@ const reGenerate = (prompt) => {
|
|||||||
.chat-item {
|
.chat-item {
|
||||||
width 100%
|
width 100%
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 0 0 0 5px;
|
padding: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
min-height 20px;
|
min-height 20px;
|
||||||
word-break break-word;
|
word-break break-word;
|
||||||
padding: 0 10px;
|
padding: 0
|
||||||
color #374151;
|
color #374151;
|
||||||
font-size: var(--content-font-size);
|
font-size: var(--content-font-size);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
@ -237,7 +300,7 @@ const reGenerate = (prompt) => {
|
|||||||
|
|
||||||
|
|
||||||
.bar {
|
.bar {
|
||||||
padding 10px;
|
padding 10px 10px 10px 0;
|
||||||
|
|
||||||
.bar-item {
|
.bar-item {
|
||||||
background-color #e7e7e8;
|
background-color #e7e7e8;
|
||||||
@ -273,6 +336,186 @@ const reGenerate = (prompt) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-line-reply-chat {
|
||||||
|
justify-content: center;
|
||||||
|
width 100%
|
||||||
|
padding-bottom: 1.5rem;
|
||||||
|
padding-top: 1.5rem;
|
||||||
|
|
||||||
|
.chat-line-inner {
|
||||||
|
display flex;
|
||||||
|
padding 0 25px;
|
||||||
|
width 100%
|
||||||
|
flex-flow row-reverse
|
||||||
|
|
||||||
|
.chat-icon {
|
||||||
|
margin-left 20px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 50%
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-item {
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.content-wrapper {
|
||||||
|
display flex
|
||||||
|
flex-flow row-reverse
|
||||||
|
.content {
|
||||||
|
min-height 20px;
|
||||||
|
word-break break-word;
|
||||||
|
padding: 1rem
|
||||||
|
color #374151;
|
||||||
|
font-size: var(--content-font-size);
|
||||||
|
overflow auto;
|
||||||
|
background-color #F5F5F5
|
||||||
|
border-radius: 10px 0 10px 10px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 600px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height 1.5
|
||||||
|
|
||||||
|
code {
|
||||||
|
color #374151
|
||||||
|
background-color #e7e7e8
|
||||||
|
padding 0 3px;
|
||||||
|
border-radius 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p:last-child {
|
||||||
|
margin-bottom: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
p:first-child {
|
||||||
|
margin-top 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-container {
|
||||||
|
position relative
|
||||||
|
display flex
|
||||||
|
|
||||||
|
.hljs {
|
||||||
|
border-radius 10px
|
||||||
|
width 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-code-btn {
|
||||||
|
position: absolute;
|
||||||
|
right 10px
|
||||||
|
top 10px
|
||||||
|
cursor pointer
|
||||||
|
font-size 12px
|
||||||
|
color #c1c1c1
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color #20a0ff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-name {
|
||||||
|
position absolute;
|
||||||
|
right 10px
|
||||||
|
bottom 20px
|
||||||
|
padding 2px 6px 4px 6px
|
||||||
|
background-color #444444
|
||||||
|
border-radius 10px
|
||||||
|
color #00e0e0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 设置表格边框
|
||||||
|
|
||||||
|
table {
|
||||||
|
width 100%
|
||||||
|
margin-bottom 1rem
|
||||||
|
color #212529
|
||||||
|
border-collapse collapse;
|
||||||
|
border 1px solid #dee2e6;
|
||||||
|
background-color #ffffff
|
||||||
|
|
||||||
|
thead {
|
||||||
|
th {
|
||||||
|
border 1px solid #dee2e6
|
||||||
|
vertical-align: bottom
|
||||||
|
border-bottom: 2px solid #dee2e6
|
||||||
|
padding 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
border 1px solid #dee2e6
|
||||||
|
padding 10px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 代码快
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
margin 0
|
||||||
|
background-color: #ebfffe;
|
||||||
|
padding: 0.8rem 1.5rem;
|
||||||
|
border-left: 0.5rem solid;
|
||||||
|
border-color: #026863;
|
||||||
|
color: #2c3e50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar {
|
||||||
|
padding 10px 10px 10px 0;
|
||||||
|
|
||||||
|
.bar-item {
|
||||||
|
color #888
|
||||||
|
padding 3px 5px;
|
||||||
|
margin-right 10px;
|
||||||
|
border-radius 5px;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
position relative
|
||||||
|
top 2px;
|
||||||
|
cursor pointer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-item.bg {
|
||||||
|
background-color #e7e7e8
|
||||||
|
cursor pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
height 20px
|
||||||
|
padding 5px 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-box {
|
||||||
|
font-size 16px;
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
height 20px
|
||||||
|
padding 5px 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
50
web/src/components/ChatSetting.vue
Normal file
50
web/src/components/ChatSetting.vue
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
class="config-dialog"
|
||||||
|
v-model="showDialog"
|
||||||
|
:close-on-click-modal="true"
|
||||||
|
:before-close="close"
|
||||||
|
style="max-width: 600px"
|
||||||
|
title="聊天配置"
|
||||||
|
>
|
||||||
|
<div class="chat-setting">
|
||||||
|
<el-form :model="data" label-width="100px" label-position="left">
|
||||||
|
<el-form-item label="聊天样式:">
|
||||||
|
<el-radio-group v-model="data.style" @change="(val) => {store.setChatListStyle(val)}">
|
||||||
|
<el-radio value="list">列表样式</el-radio>
|
||||||
|
<el-radio value="chat">对话样式</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {computed, ref} from "vue"
|
||||||
|
import {useSharedStore} from "@/store/sharedata";
|
||||||
|
const store = useSharedStore();
|
||||||
|
|
||||||
|
const data = ref({
|
||||||
|
style: store.chatListStyle,
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const props = defineProps({
|
||||||
|
show: Boolean,
|
||||||
|
});
|
||||||
|
|
||||||
|
const showDialog = computed(() => {
|
||||||
|
return props.show
|
||||||
|
})
|
||||||
|
const emits = defineEmits(['hide']);
|
||||||
|
const close = function () {
|
||||||
|
emits('hide', false);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.chat-setting {
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,13 +1,19 @@
|
|||||||
import {defineStore} from 'pinia';
|
import {defineStore} from 'pinia';
|
||||||
|
import Storage from 'good-storage'
|
||||||
|
|
||||||
export const useSharedStore = defineStore('shared', {
|
export const useSharedStore = defineStore('shared', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
showLoginDialog: false
|
showLoginDialog: false,
|
||||||
|
chatListStyle: Storage.get("chat_list_style","chat")
|
||||||
}),
|
}),
|
||||||
getters: {},
|
getters: {},
|
||||||
actions: {
|
actions: {
|
||||||
setShowLoginDialog(value) {
|
setShowLoginDialog(value) {
|
||||||
this.showLoginDialog = value;
|
this.showLoginDialog = value;
|
||||||
|
},
|
||||||
|
setChatListStyle(value) {
|
||||||
|
this.chatListStyle = value;
|
||||||
|
Storage.set("chat_list_style", value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -6,22 +6,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-for="item in chatData" :key="item.id">
|
<div v-for="item in chatData" :key="item.id">
|
||||||
<chat-prompt
|
<chat-prompt v-if="item.type==='prompt'" :data="item" list-style="list"/>
|
||||||
v-if="item.type==='prompt'"
|
<chat-reply v-else-if="item.type==='reply'" :data="item" :read-only="true" list-style="list"/>
|
||||||
:icon="item.icon"
|
|
||||||
:created-at="dateFormat(item['created_at'])"
|
|
||||||
:tokens="item['tokens']"
|
|
||||||
:model="item['model']"
|
|
||||||
:content="item.content"/>
|
|
||||||
<chat-reply v-else-if="item.type==='reply'"
|
|
||||||
:data="item" :read-only="true"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div><!-- end chat box -->
|
</div><!-- end chat box -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
import {dateFormat} from "@/utils/libs";
|
|
||||||
import ChatReply from "@/components/ChatReply.vue";
|
import ChatReply from "@/components/ChatReply.vue";
|
||||||
import ChatPrompt from "@/components/ChatPrompt.vue";
|
import ChatPrompt from "@/components/ChatPrompt.vue";
|
||||||
import {nextTick, onMounted, ref} from "vue";
|
import {nextTick, onMounted, ref} from "vue";
|
||||||
@ -98,7 +90,7 @@ onMounted(() => {
|
|||||||
padding 0 20px
|
padding 0 20px
|
||||||
|
|
||||||
.chat-box {
|
.chat-box {
|
||||||
width 800px;
|
width 100%;
|
||||||
// 变量定义
|
// 变量定义
|
||||||
--content-font-size: 16px;
|
--content-font-size: 16px;
|
||||||
--content-color: #c1c1c1;
|
--content-color: #c1c1c1;
|
||||||
@ -110,57 +102,13 @@ onMounted(() => {
|
|||||||
text-align center
|
text-align center
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-line {
|
||||||
.chat-line-prompt {
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
|
|
||||||
.chat-line-inner {
|
.chat-line-inner {
|
||||||
.chat-icon {
|
max-width 800px
|
||||||
margin-right: 0
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
padding-top: 0
|
|
||||||
font-size 16px;
|
|
||||||
|
|
||||||
p:first-child {
|
|
||||||
margin-top 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-line-reply {
|
|
||||||
padding-top: 1.5rem;
|
|
||||||
|
|
||||||
.chat-line-inner {
|
|
||||||
display flex
|
|
||||||
|
|
||||||
.bar-item {
|
|
||||||
background-color: #f7f7f8;
|
|
||||||
color: #888;
|
|
||||||
padding: 3px 5px;
|
|
||||||
margin-right: 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-icon {
|
|
||||||
margin-right: 20px
|
|
||||||
|
|
||||||
img {
|
|
||||||
width 30px
|
|
||||||
height 30px
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 1px
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-item {
|
|
||||||
img {
|
|
||||||
max-width 90%
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="common-layout">
|
<div class="chat-page">
|
||||||
<el-container>
|
<el-container>
|
||||||
<el-aside>
|
<el-aside>
|
||||||
<div class="chat-list">
|
<div class="chat-list">
|
||||||
@ -99,6 +99,12 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
|
||||||
|
<span class="setting" @click="showChatSetting = true">
|
||||||
|
<el-tooltip class="box-item" effect="dark" content="对话设置">
|
||||||
|
<i class="iconfont icon-config"></i>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@ -109,13 +115,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-for="item in chatData" :key="item.id" v-else>
|
<div v-for="item in chatData" :key="item.id" v-else>
|
||||||
<chat-prompt
|
<chat-prompt
|
||||||
v-if="item.type==='prompt'"
|
v-if="item.type==='prompt'" :data="item" :list-style="listStyle"/>
|
||||||
:icon="item.icon"
|
<chat-reply v-else-if="item.type==='reply'" :data="item" @regen="reGenerate" :read-only="false" :list-style="listStyle"/>
|
||||||
:created-at="dateFormat(item['created_at'])"
|
|
||||||
:tokens="item['tokens']"
|
|
||||||
:model="getModelValue(modelID)"
|
|
||||||
:content="item.content"/>
|
|
||||||
<chat-reply v-else-if="item.type==='reply'" :data="item" @regen="reGenerate" :read-only="false"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div><!-- end chat box -->
|
</div><!-- end chat box -->
|
||||||
|
|
||||||
@ -187,21 +188,21 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<ChatSetting :show="showChatSetting" @hide="showChatSetting = false"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import {nextTick, onMounted, onUnmounted, ref} from 'vue'
|
import {nextTick, onMounted, onUnmounted, ref, watch} 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 {Delete, Edit, More, Plus, Promotion, Search, Share, VideoPause} from '@element-plus/icons-vue'
|
import {Delete, Edit, More, Plus, Promotion, Search, Share, VideoPause} from '@element-plus/icons-vue'
|
||||||
import 'highlight.js/styles/a11y-dark.css'
|
import 'highlight.js/styles/a11y-dark.css'
|
||||||
import {
|
import {
|
||||||
dateFormat,
|
|
||||||
isMobile,
|
isMobile,
|
||||||
processContent,
|
processContent,
|
||||||
processPrompt,
|
|
||||||
randString,
|
randString,
|
||||||
removeArrayItem,
|
removeArrayItem,
|
||||||
UUID
|
UUID
|
||||||
@ -217,6 +218,7 @@ import Welcome from "@/components/Welcome.vue";
|
|||||||
import {useSharedStore} from "@/store/sharedata";
|
import {useSharedStore} from "@/store/sharedata";
|
||||||
import FileSelect from "@/components/FileSelect.vue";
|
import FileSelect from "@/components/FileSelect.vue";
|
||||||
import FileList from "@/components/FileList.vue";
|
import FileList from "@/components/FileList.vue";
|
||||||
|
import ChatSetting from "@/components/ChatSetting.vue";
|
||||||
|
|
||||||
const title = ref('ChatGPT-智能助手');
|
const title = ref('ChatGPT-智能助手');
|
||||||
const models = ref([])
|
const models = ref([])
|
||||||
@ -243,6 +245,12 @@ const notice = ref("")
|
|||||||
const noticeKey = ref("SYSTEM_NOTICE")
|
const noticeKey = ref("SYSTEM_NOTICE")
|
||||||
const store = useSharedStore();
|
const store = useSharedStore();
|
||||||
const row = ref(1)
|
const row = ref(1)
|
||||||
|
const showChatSetting = ref(false)
|
||||||
|
const listStyle = ref(store.chatListStyle)
|
||||||
|
watch(() => store.chatListStyle, (newValue) => {
|
||||||
|
listStyle.value = newValue
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
if (isMobile()) {
|
if (isMobile()) {
|
||||||
router.replace("/mobile/chat")
|
router.replace("/mobile/chat")
|
||||||
@ -757,6 +765,7 @@ const sendMessage = function () {
|
|||||||
id: randString(32),
|
id: randString(32),
|
||||||
icon: loginUser.value.avatar,
|
icon: loginUser.value.avatar,
|
||||||
content: content,
|
content: content,
|
||||||
|
model: getModelValue(modelID.value),
|
||||||
created_at: new Date().getTime() / 1000,
|
created_at: new Date().getTime() / 1000,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ import {checkSession} from "@/action/session";
|
|||||||
import {removeUserToken} from "@/store/session";
|
import {removeUserToken} from "@/store/session";
|
||||||
import LoginDialog from "@/components/LoginDialog.vue";
|
import LoginDialog from "@/components/LoginDialog.vue";
|
||||||
import {useSharedStore} from "@/store/sharedata";
|
import {useSharedStore} from "@/store/sharedata";
|
||||||
import ConfigDialog from "@/components/ConfigDialog.vue";
|
import ConfigDialog from "@/components/UserInfoDialog.vue";
|
||||||
import {showMessageError} from "@/utils/dialog";
|
import {showMessageError} from "@/utils/dialog";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -153,7 +153,7 @@
|
|||||||
v-model="showChatItemDialog"
|
v-model="showChatItemDialog"
|
||||||
title="对话详情"
|
title="对话详情"
|
||||||
>
|
>
|
||||||
<div class="chat-box common-layout">
|
<div class="chat-box chat-page">
|
||||||
<div v-for="item in messages" :key="item.id">
|
<div v-for="item in messages" :key="item.id">
|
||||||
<chat-prompt
|
<chat-prompt
|
||||||
v-if="item.type==='prompt'"
|
v-if="item.type==='prompt'"
|
||||||
|
Loading…
Reference in New Issue
Block a user