mirror of https://gitee.com/godoos/godoos.git
17 changed files with 1364 additions and 574 deletions
@ -1,71 +1,158 @@ |
|||
<script setup> |
|||
import { ref } from "vue"; |
|||
import { useChatStore } from "@/stores/chat"; |
|||
const store = useChatStore() |
|||
|
|||
</script> |
|||
|
|||
<template> |
|||
<div v-for="item in store.chatList"> |
|||
<div class="list-item" @click="store.changeChatList(item)" |
|||
:style="{ backgroundColor: item.id === store.targetUserId ? '#C4C4C4' : '' }"> |
|||
<div v-if="store.chatList.length > 0" v-for="item in store.chatList" :key="item.id"> |
|||
<div |
|||
class="list-item" |
|||
@click="store.changeChatList(item.id)" |
|||
:style="{ |
|||
backgroundColor: item.id === store.targetUserId ? '#C4C4C4' : '', |
|||
}" |
|||
> |
|||
<el-row> |
|||
<el-col :span="6"> |
|||
<el-avatar shape="square" :size="40" class="avatar" :src="item.avatar" /> |
|||
<el-avatar |
|||
shape="square" |
|||
:size="40" |
|||
class="avatar" |
|||
:src="item.avatar" |
|||
/> |
|||
</el-col> |
|||
<el-col :span="18"> |
|||
<el-row> |
|||
<el-col :span="18"> |
|||
<div class="previewName">{{ item.name }}</div> |
|||
<el-col :span="18" class="preview"> |
|||
<el-row class="preview-content"> |
|||
<el-col :span="18" class="preview-left"> |
|||
<div class="previewName">{{ item.nickname }}</div> |
|||
<div class="previewChat"> |
|||
<span v-if="item.previewType === 0">{{ item.previewMessage }}</span> |
|||
<span v-if="item.previewType === 1"> |
|||
{{ |
|||
item.targetUserId === id |
|||
? "你" |
|||
: '"' + item.nickname + '"' |
|||
}}撤回了一条消息 |
|||
</span> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="6"> |
|||
<div class="previewTime">{{ item.previewTimeFormat }}</div> |
|||
<el-col :span="6" class="preview-right"> |
|||
<div class="previewTime"> |
|||
{{ item.previewTimeFormat }} |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row> |
|||
<div v-if="item.previewType === 0" class="previewChat">{{ item.previewMessage }}</div> |
|||
<div v-if="item.previewType === 1" class="previewChat">{{ item.userId === id ? "你" : "\"" + item.name + |
|||
"\""}}撤回了一条消息</div> |
|||
</el-row> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
</div> |
|||
<div v-else class="emptyChat"> |
|||
<el-icon :size="60" class="chat-icon"> |
|||
<ChatSquare /> |
|||
</el-icon> |
|||
<p class="empty-message">暂无数据</p> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { useChatStore } from "@/stores/chat"; |
|||
import { ref } from "vue"; |
|||
|
|||
const store = useChatStore(); |
|||
const id = ref("1"); |
|||
|
|||
</script> |
|||
|
|||
<style scoped> |
|||
.list-item { |
|||
width: 100%; |
|||
height: 60px; |
|||
display: flex; |
|||
} |
|||
|
|||
.list-item:hover { |
|||
background-color: #D0D0D0; |
|||
background-color: #d0d0d0; |
|||
} |
|||
|
|||
.avatar { |
|||
margin: 10px |
|||
margin: 10px; |
|||
} |
|||
|
|||
.preview { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
height: 100%; |
|||
} |
|||
|
|||
.preview-content { |
|||
height: 100%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
width: 100%; |
|||
} |
|||
|
|||
.preview-left { |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
height: 100%; |
|||
} |
|||
|
|||
.previewName { |
|||
margin-top: 10px; |
|||
font-size: 15px; |
|||
margin-left: 10px; |
|||
font-size: 12px; |
|||
font-family: Arial, sans-serif; |
|||
line-height: 1.5; |
|||
overflow: hidden; /* 隐藏超出部分 */ |
|||
text-overflow: ellipsis; /* 显示为省略号 */ |
|||
white-space: nowrap; /* 不换行 */ |
|||
min-width: 100px; /* 最小宽度 */ |
|||
max-width: 100%; /* 最大宽度 */ |
|||
} |
|||
|
|||
.previewChat { |
|||
font-size: 14px; |
|||
height: 20px; |
|||
margin-left: 10px; |
|||
font-size: 10px; |
|||
font-family: Arial, sans-serif; |
|||
color: #999999; |
|||
overflow: hidden; /* 隐藏超出部分 */ |
|||
text-overflow: ellipsis; /* 显示为省略号 */ |
|||
white-space: nowrap; /* 不换行 */ |
|||
min-width: 90px; /* 最小宽度 */ |
|||
max-width: 100%; /* 最大宽度 */ |
|||
} |
|||
|
|||
.preview-right { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
height: 100%; |
|||
} |
|||
|
|||
.previewTime { |
|||
float: right; |
|||
margin-top: 10px; |
|||
margin-right: 10px; |
|||
font-size: 12px; |
|||
font-family: Arial, sans-serif; |
|||
color: #999999; |
|||
min-width: 30px; /* 最小宽度 */ |
|||
max-width: 100%; /* 最大宽度 */ |
|||
} |
|||
|
|||
.emptyChat { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
height: 100%; |
|||
margin: 120px auto; |
|||
text-align: center; |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.chat-icon { |
|||
color: #0078d4; |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.empty-message { |
|||
font-size: 16px; |
|||
color: #666666; |
|||
} |
|||
</style> |
|||
|
@ -0,0 +1,79 @@ |
|||
<template> |
|||
<div |
|||
v-if="store.targetUserId == null" |
|||
class="no-message-container" |
|||
> |
|||
<el-icon |
|||
:size="180" |
|||
color="#0078d7" |
|||
> |
|||
<ChatDotSquare /> |
|||
</el-icon> |
|||
<p>欢迎使用GodoOS</p> |
|||
</div> |
|||
<div |
|||
v-else |
|||
class="user-info-container" |
|||
> |
|||
<div class="user-details"> |
|||
<p>昵称: {{ store.targetUserInfo.nickname }}</p> |
|||
<p>邮箱: {{ store.targetUserInfo.email }}</p> |
|||
<p>电话: {{ store.targetUserInfo.phone }}</p> |
|||
<p>描述: {{ store.targetUserInfo.desc }}</p> |
|||
<p>工号: {{ store.targetUserInfo.jobNumber }}</p> |
|||
<p>工作地点: {{ store.targetUserInfo.workPlace }}</p> |
|||
<p>入职日期: {{ store.targetUserInfo.hiredDate }}</p> |
|||
</div> |
|||
<el-button |
|||
type="primary" |
|||
@click="sendMessage(store.targetUserId)" |
|||
>发送消息</el-button |
|||
> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { useChatStore } from "@/stores/chat"; |
|||
|
|||
const store = useChatStore(); |
|||
|
|||
const sendMessage = (id:number) => { |
|||
store.currentNavId = 0; |
|||
store.updateConversationList(id) |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.no-message-container { |
|||
height: 100%; |
|||
margin: 0px auto; |
|||
text-align: center; |
|||
font-size: 14px; |
|||
} |
|||
|
|||
.user-info-container { |
|||
height: 100%; |
|||
margin: 0px auto; |
|||
text-align: center; |
|||
font-size: 14px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.user-details { |
|||
margin-bottom: 20px; |
|||
text-align: left; |
|||
max-width: 300px; |
|||
} |
|||
|
|||
.user-details p { |
|||
margin: 5px 0; |
|||
} |
|||
|
|||
.el-button { |
|||
width: 100%; |
|||
max-width: 300px; |
|||
} |
|||
</style> |
@ -0,0 +1,106 @@ |
|||
package files |
|||
|
|||
import ( |
|||
"encoding/base64" |
|||
"encoding/json" |
|||
"godo/libs" |
|||
"net/http" |
|||
"strings" |
|||
) |
|||
|
|||
// 带加密读
|
|||
func HandleReadFile(w http.ResponseWriter, r *http.Request) { |
|||
|
|||
path := r.URL.Query().Get("path") |
|||
fPwd := r.Header.Get("fPwd") |
|||
hasPwd := IsHavePwd(fPwd) |
|||
|
|||
// 获取salt值
|
|||
salt := GetSalt(r) |
|||
|
|||
// 校验文件路径
|
|||
if err := validateFilePath(path); err != nil { |
|||
libs.HTTPError(w, http.StatusBadRequest, err.Error()) |
|||
return |
|||
} |
|||
|
|||
// 有密码校验密码
|
|||
if hasPwd { |
|||
if !CheckFilePwd(fPwd, salt) { |
|||
libs.HTTPError(w, http.StatusBadRequest, "密码错误") |
|||
return |
|||
} |
|||
} |
|||
|
|||
// 获取文件路径
|
|||
basePath, err := libs.GetOsDir() |
|||
if err != nil { |
|||
libs.HTTPError(w, http.StatusInternalServerError, err.Error()) |
|||
return |
|||
} |
|||
// 读取内容
|
|||
fileContent, err := ReadFile(basePath, path) |
|||
if err != nil { |
|||
libs.HTTPError(w, http.StatusNotFound, err.Error()) |
|||
return |
|||
} |
|||
|
|||
// 解密
|
|||
data, err := libs.DecryptData(fileContent, libs.EncryptionKey) |
|||
if err != nil { |
|||
libs.HTTPError(w, http.StatusInternalServerError, err.Error()) |
|||
return |
|||
} |
|||
|
|||
content := string(data) |
|||
// 检查文件内容是否以"link::"开头
|
|||
if !strings.HasPrefix(content, "link::") { |
|||
content = base64.StdEncoding.EncodeToString(data) |
|||
} |
|||
|
|||
// 初始响应
|
|||
res := libs.APIResponse{Code: 0, Message: "success", Data: content} |
|||
|
|||
json.NewEncoder(w).Encode(res) |
|||
} |
|||
|
|||
// 设置文件密码
|
|||
func HandleSetFilePwd(w http.ResponseWriter, r *http.Request) { |
|||
fPwd := r.Header.Get("filepPwd") |
|||
salt := r.Header.Get("salt") |
|||
// 服务端再hash加密
|
|||
hashPwd := libs.HashPassword(fPwd, salt) |
|||
|
|||
// 服务端存储
|
|||
req := libs.ReqBody{ |
|||
Name: "filePwd", |
|||
Value: hashPwd, |
|||
} |
|||
libs.SetConfig(req) |
|||
|
|||
// salt值存储
|
|||
reqSalt := libs.ReqBody{ |
|||
Name: "salt", |
|||
Value: salt, |
|||
} |
|||
libs.SetConfig(reqSalt) |
|||
res := libs.APIResponse{Message: "密码设置成功"} |
|||
json.NewEncoder(w).Encode(res) |
|||
} |
|||
|
|||
// 更改文件密码
|
|||
func HandleChangeFilePwd(w http.ResponseWriter, r *http.Request) { |
|||
filePwd := r.Header.Get("filePwd") |
|||
salt := r.Header.Get("salt") |
|||
if filePwd == "" || salt == "" { |
|||
libs.ErrorMsg(w, "密码为空") |
|||
return |
|||
} |
|||
newPwd := libs.HashPassword(filePwd, salt) |
|||
pwdReq := libs.ReqBody{ |
|||
Name: "filePwd", |
|||
Value: newPwd, |
|||
} |
|||
libs.SetConfig(pwdReq) |
|||
libs.SuccessMsg(w, "success", "The file password change success!") |
|||
} |
Loading…
Reference in new issue