mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-11-09 02:33:42 +08:00
新增复制按钮图标来复制 ChatGPT 回复内容。Golang 后端实现为每个用户订阅聊天角色功能
This commit is contained in:
@@ -393,6 +393,17 @@ func (s *Server) GetChatHistoryHandle(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
session := s.ChatSession[sessionId]
|
session := s.ChatSession[sessionId]
|
||||||
|
user, err := GetUser(session.Username)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: "Invalid args"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := user.ChatRoles[data.Role]; !ok || v != 1 {
|
||||||
|
c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: "No permission to access the history of role " + data.Role})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
history, err := GetChatHistory(session.Username, data.Role)
|
history, err := GetChatHistory(session.Username, data.Role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: "No history message"})
|
c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: "No history message"})
|
||||||
|
|||||||
@@ -2,16 +2,18 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"net/http"
|
"net/http"
|
||||||
"openai/types"
|
"openai/types"
|
||||||
"openai/utils"
|
"openai/utils"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) TestHandle(c *gin.Context) {
|
func (s *Server) TestHandle(c *gin.Context) {
|
||||||
roles := types.GetDefaultChatRole()
|
roles := types.GetDefaultChatRole()
|
||||||
for _, v := range roles {
|
for _, v := range roles {
|
||||||
PutChatRole(v)
|
_ = PutChatRole(v)
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, types.BizVo{Code: types.Success, Data: GetChatRoles()})
|
c.JSON(http.StatusOK, types.BizVo{Code: types.Success, Data: GetChatRoles()})
|
||||||
|
|
||||||
@@ -81,10 +83,11 @@ func (s *Server) SetDebugHandle(c *gin.Context) {
|
|||||||
// AddUserHandle 添加 Username
|
// AddUserHandle 添加 Username
|
||||||
func (s *Server) AddUserHandle(c *gin.Context) {
|
func (s *Server) AddUserHandle(c *gin.Context) {
|
||||||
var data struct {
|
var data struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
MaxCalls int `json:"max_calls"`
|
MaxCalls int `json:"max_calls"`
|
||||||
EnableHistory bool `json:"enable_history"`
|
EnableHistory bool `json:"enable_history"`
|
||||||
Term int `json:"term"` // 有效期
|
Term int `json:"term"` // 有效期
|
||||||
|
ChatRoles []string `json:"chat_roles"` // 订阅角色
|
||||||
}
|
}
|
||||||
err := json.NewDecoder(c.Request.Body).Decode(&data)
|
err := json.NewDecoder(c.Request.Body).Decode(&data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -105,12 +108,28 @@ func (s *Server) AddUserHandle(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var chatRoles = make(map[string]int)
|
||||||
|
if len(data.ChatRoles) > 0 {
|
||||||
|
if data.ChatRoles[0] == "all" { // 所有的角色
|
||||||
|
roles := GetChatRoles()
|
||||||
|
for key := range roles {
|
||||||
|
chatRoles[key] = 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, key := range data.ChatRoles {
|
||||||
|
chatRoles[key] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
user := types.User{
|
user := types.User{
|
||||||
Name: data.Name,
|
Name: data.Name,
|
||||||
MaxCalls: data.MaxCalls,
|
MaxCalls: data.MaxCalls,
|
||||||
RemainingCalls: data.MaxCalls,
|
RemainingCalls: data.MaxCalls,
|
||||||
EnableHistory: data.EnableHistory,
|
EnableHistory: data.EnableHistory,
|
||||||
Term: data.Term,
|
Term: data.Term,
|
||||||
|
ChatRoles: chatRoles,
|
||||||
Status: true}
|
Status: true}
|
||||||
err = PutUser(user)
|
err = PutUser(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -124,10 +143,11 @@ func (s *Server) AddUserHandle(c *gin.Context) {
|
|||||||
// BatchAddUserHandle 批量生成 Username
|
// BatchAddUserHandle 批量生成 Username
|
||||||
func (s *Server) BatchAddUserHandle(c *gin.Context) {
|
func (s *Server) BatchAddUserHandle(c *gin.Context) {
|
||||||
var data struct {
|
var data struct {
|
||||||
Number int `json:"number"`
|
Number int `json:"number"`
|
||||||
MaxCalls int `json:"max_calls"`
|
MaxCalls int `json:"max_calls"`
|
||||||
EnableHistory bool `json:"enable_history"`
|
EnableHistory bool `json:"enable_history"`
|
||||||
Term int `json:"term"`
|
Term int `json:"term"`
|
||||||
|
ChatRoles []string `json:"chat_roles"`
|
||||||
}
|
}
|
||||||
err := json.NewDecoder(c.Request.Body).Decode(&data)
|
err := json.NewDecoder(c.Request.Body).Decode(&data)
|
||||||
if err != nil || data.MaxCalls <= 0 {
|
if err != nil || data.MaxCalls <= 0 {
|
||||||
@@ -135,6 +155,21 @@ func (s *Server) BatchAddUserHandle(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var chatRoles = make(map[string]int)
|
||||||
|
if len(data.ChatRoles) > 0 {
|
||||||
|
if data.ChatRoles[0] == "all" { // 所有的角色
|
||||||
|
roles := GetChatRoles()
|
||||||
|
for key := range roles {
|
||||||
|
chatRoles[key] = 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, key := range data.ChatRoles {
|
||||||
|
chatRoles[key] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
var users = make([]types.User, 0)
|
var users = make([]types.User, 0)
|
||||||
for i := 0; i < data.Number; i++ {
|
for i := 0; i < data.Number; i++ {
|
||||||
name := utils.RandString(12)
|
name := utils.RandString(12)
|
||||||
@@ -148,6 +183,7 @@ func (s *Server) BatchAddUserHandle(c *gin.Context) {
|
|||||||
RemainingCalls: data.MaxCalls,
|
RemainingCalls: data.MaxCalls,
|
||||||
EnableHistory: data.EnableHistory,
|
EnableHistory: data.EnableHistory,
|
||||||
Term: data.Term,
|
Term: data.Term,
|
||||||
|
ChatRoles: chatRoles,
|
||||||
Status: true}
|
Status: true}
|
||||||
err = PutUser(user)
|
err = PutUser(user)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -204,6 +240,24 @@ func (s *Server) SetUserHandle(c *gin.Context) {
|
|||||||
if v, ok := data["api_key"]; ok {
|
if v, ok := data["api_key"]; ok {
|
||||||
user.ApiKey = v.(string)
|
user.ApiKey = v.(string)
|
||||||
}
|
}
|
||||||
|
if v, ok := data["chat_roles"]; ok {
|
||||||
|
if roles, ok := v.([]interface{}); ok {
|
||||||
|
chatRoles := make(map[string]int)
|
||||||
|
if roles[0] == "all" {
|
||||||
|
roles := GetChatRoles()
|
||||||
|
for key := range roles {
|
||||||
|
chatRoles[key] = 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, key := range roles {
|
||||||
|
key := strings.TrimSpace(fmt.Sprintf("%v", key))
|
||||||
|
chatRoles[key] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user.ChatRoles = chatRoles
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
err = PutUser(*user)
|
err = PutUser(*user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -299,12 +353,24 @@ func (s *Server) ListApiKeysHandle(c *gin.Context) {
|
|||||||
|
|
||||||
// GetChatRoleListHandle 获取聊天角色列表
|
// GetChatRoleListHandle 获取聊天角色列表
|
||||||
func (s *Server) GetChatRoleListHandle(c *gin.Context) {
|
func (s *Server) GetChatRoleListHandle(c *gin.Context) {
|
||||||
|
sessionId := c.GetHeader(types.TokenName)
|
||||||
|
session := s.ChatSession[sessionId]
|
||||||
|
user, err := GetUser(session.Username)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: "Hacker Access!!!"})
|
||||||
|
return
|
||||||
|
}
|
||||||
var rolesOrder = []string{"gpt", "teacher", "translator", "english_trainer", "weekly_report", "girl_friend",
|
var rolesOrder = []string{"gpt", "teacher", "translator", "english_trainer", "weekly_report", "girl_friend",
|
||||||
"kong_zi", "lu_xun", "steve_jobs", "elon_musk", "red_book", "dou_yin", "programmer",
|
"kong_zi", "lu_xun", "steve_jobs", "elon_musk", "red_book", "dou_yin", "programmer",
|
||||||
"seller", "good_comment", "psychiatrist", "artist"}
|
"seller", "good_comment", "psychiatrist", "artist"}
|
||||||
var res = make([]interface{}, 0)
|
var res = make([]interface{}, 0)
|
||||||
var roles = GetChatRoles()
|
var roles = GetChatRoles()
|
||||||
for _, k := range rolesOrder {
|
for _, k := range rolesOrder {
|
||||||
|
// 确认当前用户是否订阅了当前角色
|
||||||
|
if v, ok := user.ChatRoles[k]; !ok || v != 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if v, ok := roles[k]; ok && v.Enable {
|
if v, ok := roles[k]; ok && v.Enable {
|
||||||
res = append(res, struct {
|
res = append(res, struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
|
|||||||
@@ -14,15 +14,16 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
MaxCalls int `json:"max_calls"` // 最多调用次数,如果为 0 则表示不限制
|
MaxCalls int `json:"max_calls"` // 最多调用次数,如果为 0 则表示不限制
|
||||||
RemainingCalls int `json:"remaining_calls"` // 剩余调用次数
|
RemainingCalls int `json:"remaining_calls"` // 剩余调用次数
|
||||||
EnableHistory bool `json:"enable_history"` // 是否启用聊天记录
|
EnableHistory bool `json:"enable_history"` // 是否启用聊天记录
|
||||||
Status bool `json:"status"` // 当前状态
|
Status bool `json:"status"` // 当前状态
|
||||||
Term int `json:"term" default:"30"` // 会员有效期,单位:天
|
Term int `json:"term" default:"30"` // 会员有效期,单位:天
|
||||||
ActiveTime int64 `json:"active_time"` // 激活时间
|
ActiveTime int64 `json:"active_time"` // 激活时间
|
||||||
ExpiredTime int64 `json:"expired_time"` // 到期时间
|
ExpiredTime int64 `json:"expired_time"` // 到期时间
|
||||||
ApiKey string `json:"api_key"` // OpenAI API KEY
|
ApiKey string `json:"api_key"` // OpenAI API KEY
|
||||||
|
ChatRoles map[string]int `json:"chat_roles"` // 当前用户已订阅的聊天角色 map[role_key] => 0/1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chat configs struct
|
// Chat configs struct
|
||||||
|
|||||||
@@ -6,7 +6,24 @@
|
|||||||
|
|
||||||
<div class="chat-item">
|
<div class="chat-item">
|
||||||
<div class="triangle"></div>
|
<div class="triangle"></div>
|
||||||
<div class="content reply-content" :data-clipboard-text="orgContent" v-html="content"></div>
|
<div class="content-box">
|
||||||
|
<div class="content" v-html="content"></div>
|
||||||
|
<div class="tool-box">
|
||||||
|
<el-tooltip
|
||||||
|
class="box-item"
|
||||||
|
effect="dark"
|
||||||
|
content="复制回答"
|
||||||
|
placement="top"
|
||||||
|
>
|
||||||
|
<el-button type="info" class="copy-reply" :data-clipboard-text="orgContent" plain>
|
||||||
|
<el-icon>
|
||||||
|
<DocumentCopy/>
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -14,9 +31,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import {defineComponent} from "vue"
|
import {defineComponent} from "vue"
|
||||||
import {randString} from "@/utils/libs";
|
import {randString} from "@/utils/libs";
|
||||||
|
import {DocumentCopy} from "@element-plus/icons-vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ChatReply',
|
name: 'ChatReply',
|
||||||
|
components: {DocumentCopy},
|
||||||
props: {
|
props: {
|
||||||
content: {
|
content: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -70,28 +89,45 @@ export default defineComponent({
|
|||||||
top: 13px;
|
top: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content-box {
|
||||||
min-height 20px;
|
|
||||||
word-break break-word;
|
|
||||||
padding: 8px 10px;
|
|
||||||
color var(--content-color)
|
|
||||||
background-color: #fff;
|
|
||||||
font-size: var(--content-font-size);
|
|
||||||
border-radius: 5px;
|
|
||||||
|
|
||||||
p:last-child {
|
display flex
|
||||||
margin-bottom: 0
|
flex-direction row
|
||||||
|
|
||||||
|
.content {
|
||||||
|
min-height 20px;
|
||||||
|
word-break break-word;
|
||||||
|
padding: 8px 10px;
|
||||||
|
color var(--content-color)
|
||||||
|
background-color: #fff;
|
||||||
|
font-size: var(--content-font-size);
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
p:last-child {
|
||||||
|
margin-bottom: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
p:first-child {
|
||||||
|
margin-top 0
|
||||||
|
}
|
||||||
|
|
||||||
|
p > code {
|
||||||
|
color #cc0000
|
||||||
|
background-color #f1f1f1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p:first-child {
|
.tool-box {
|
||||||
margin-top 0
|
padding-left 10px;
|
||||||
}
|
font-size 16px;
|
||||||
|
|
||||||
p > code {
|
.el-button {
|
||||||
color #cc0000
|
height 20px
|
||||||
background-color #f1f1f1
|
padding 5px 2px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'free', path: '/free', component: ChatFree, meta: {
|
name: 'free', path: '/free', component: ChatFree, meta: {
|
||||||
title: 'ChatGPT 免费版'
|
title: 'ChatGPT 通用免费版'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ export default defineComponent({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const clipboard = new Clipboard('.reply-content');
|
const clipboard = new Clipboard('.copy-reply');
|
||||||
clipboard.on('success', () => {
|
clipboard.on('success', () => {
|
||||||
ElMessage.success('复制成功!');
|
ElMessage.success('复制成功!');
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,19 +3,20 @@
|
|||||||
<div class="sidebar" id="sidebar">
|
<div class="sidebar" id="sidebar">
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li class="new-chat"><a>
|
<li class="new-chat" @click="newChat"><a>
|
||||||
<span class="icon"><el-icon><Plus/></el-icon></span>
|
<span class="icon"><el-icon><Plus/></el-icon></span>
|
||||||
<span class="text">新建会话</span>
|
<span class="text">新建会话</span>
|
||||||
<span class="btn" @click="toggleSidebar"><el-button size="small" type="info" circle><el-icon><CloseBold/></el-icon></el-button></span>
|
<span class="btn" @click="toggleSidebar"><el-button size="small" type="info" circle><el-icon><CloseBold/></el-icon></el-button></span>
|
||||||
</a></li>
|
</a></li>
|
||||||
<li><a>
|
<li v-for="session in sessionList" :key="session.id"><a>
|
||||||
<span class="icon"><el-icon><ChatRound/></el-icon></span>
|
<span class="icon"><el-icon><ChatRound/></el-icon></span>
|
||||||
<span class="text">会话一</span>
|
<span class="text">{{ session.title }}</span>
|
||||||
</a></li>
|
<span class="btn">
|
||||||
<li class="active"><a>
|
<el-icon title="编辑"><Edit/></el-icon>
|
||||||
<span class="icon"><el-icon><ChatRound/></el-icon></span>
|
<el-icon title="删除会话"><Delete/></el-icon>
|
||||||
<span class="text">会话二</span>
|
</span>
|
||||||
</a></li>
|
</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
@@ -121,7 +122,16 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {defineComponent, nextTick} from "vue"
|
import {defineComponent, nextTick} from "vue"
|
||||||
import {ChatRound, CloseBold, Fold, Lock, Plus, RefreshRight, VideoPause} from "@element-plus/icons-vue";
|
import {
|
||||||
|
ChatRound,
|
||||||
|
CloseBold,
|
||||||
|
Delete, Edit,
|
||||||
|
Fold,
|
||||||
|
Lock,
|
||||||
|
Plus,
|
||||||
|
RefreshRight,
|
||||||
|
VideoPause
|
||||||
|
} from "@element-plus/icons-vue";
|
||||||
import {httpGet, httpPost} from "@/utils/http";
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
import hl from "highlight.js";
|
import hl from "highlight.js";
|
||||||
import ChatReply from "@/components/ChatReply.vue";
|
import ChatReply from "@/components/ChatReply.vue";
|
||||||
@@ -134,7 +144,19 @@ import Clipboard from "clipboard";
|
|||||||
// 免费版 ChatGPT
|
// 免费版 ChatGPT
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ChatFree',
|
name: 'ChatFree',
|
||||||
components: {CloseBold, Lock, VideoPause, RefreshRight, ChatPrompt, ChatReply, ChatRound, Plus, Fold},
|
components: {
|
||||||
|
Edit,
|
||||||
|
Delete,
|
||||||
|
CloseBold,
|
||||||
|
Lock,
|
||||||
|
VideoPause,
|
||||||
|
RefreshRight,
|
||||||
|
ChatPrompt,
|
||||||
|
ChatReply,
|
||||||
|
ChatRound,
|
||||||
|
Plus,
|
||||||
|
Fold
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
chatData: [],
|
chatData: [],
|
||||||
@@ -144,6 +166,10 @@ export default defineComponent({
|
|||||||
showLoginDialog: false,
|
showLoginDialog: false,
|
||||||
role: 'gpt',
|
role: 'gpt',
|
||||||
replyIcon: 'images/avatar/gpt.png', // 回复信息的头像
|
replyIcon: 'images/avatar/gpt.png', // 回复信息的头像
|
||||||
|
sessionList: [{
|
||||||
|
id: randString(32),
|
||||||
|
title: '响应式页面布局代码'
|
||||||
|
}], // 会话列表
|
||||||
|
|
||||||
showStopGenerate: false,
|
showStopGenerate: false,
|
||||||
showReGenerate: false,
|
showReGenerate: false,
|
||||||
@@ -164,7 +190,7 @@ export default defineComponent({
|
|||||||
mounted() {
|
mounted() {
|
||||||
this.fetchChatHistory();
|
this.fetchChatHistory();
|
||||||
|
|
||||||
const clipboard = new Clipboard('.reply-content');
|
const clipboard = new Clipboard('.copy-reply');
|
||||||
clipboard.on('success', () => {
|
clipboard.on('success', () => {
|
||||||
ElMessage.success('复制成功!');
|
ElMessage.success('复制成功!');
|
||||||
})
|
})
|
||||||
@@ -455,6 +481,11 @@ export default defineComponent({
|
|||||||
toggleSidebar: function () {
|
toggleSidebar: function () {
|
||||||
document.getElementById("sidebar").classList.toggle('show');
|
document.getElementById("sidebar").classList.toggle('show');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 新建会话
|
||||||
|
newChat: function () {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -510,8 +541,26 @@ export default defineComponent({
|
|||||||
overflow hidden
|
overflow hidden
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
//display none
|
||||||
|
|
||||||
|
position absolute
|
||||||
|
right 0;
|
||||||
|
top 2px;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
margin-left 5px;
|
||||||
|
color #9f9f9f
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon:hover {
|
||||||
|
color #ffffff
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
li.active {
|
li.active {
|
||||||
@@ -521,11 +570,17 @@ export default defineComponent({
|
|||||||
li.new-chat {
|
li.new-chat {
|
||||||
border: 1px solid #4A4B4D;
|
border: 1px solid #4A4B4D;
|
||||||
|
|
||||||
.btn {
|
a {
|
||||||
display none
|
.btn {
|
||||||
position absolute
|
display none
|
||||||
right -2px;
|
right -2px;
|
||||||
top -2px;
|
top -2px;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
margin-left 0;
|
||||||
|
color #ffffff
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,6 +733,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.row-center {
|
||||||
|
justify-content center
|
||||||
|
}
|
||||||
|
|
||||||
/* 移动端适配 */
|
/* 移动端适配 */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.chat-free-page {
|
.chat-free-page {
|
||||||
|
|||||||
@@ -439,8 +439,8 @@ export default defineComponent({
|
|||||||
hl.highlightElement(block)
|
hl.highlightElement(block)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}).catch(() => {
|
}).catch((e) => {
|
||||||
// console.error(e.message)
|
console.error(e.message)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user