prr 7 months ago
parent
commit
8d2422172d
  1. 2
      frontend/components.d.ts
  2. 89
      frontend/src/components/chat/Chat.vue
  3. 126
      frontend/src/components/chat/ChatMenu.vue
  4. 354
      frontend/src/components/chat/ChatMessage.vue
  5. 10
      frontend/src/components/chat/ChatMsgList.vue
  6. 47
      frontend/src/components/chat/ChatUserList.vue
  7. 27
      frontend/src/components/window/WindowTemplate.vue
  8. 313
      frontend/src/stores/chat.ts
  9. 1
      frontend/src/stores/localchat.ts
  10. 317
      frontend/src/stores/upgrade.ts
  11. 66
      frontend/src/system/index.ts
  12. 1
      frontend/tsconfig.json
  13. 2
      godo/cmd/main.go
  14. 23
      godo/files/fs.go
  15. 16
      godo/files/os.go
  16. 56
      godo/files/pwdfile.go

2
frontend/components.d.ts

@ -51,6 +51,7 @@ declare module 'vue' {
ElAside: typeof import('element-plus/es')['ElAside']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBadge: typeof import('element-plus/es')['ElBadge']
ElBu: typeof import('element-plus/es')['ElBu']
ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
ElCarousel: typeof import('element-plus/es')['ElCarousel']
@ -84,6 +85,7 @@ declare module 'vue' {
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElText: typeof import('element-plus/es')['ElText']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTransfer: typeof import('element-plus/es')['ElTransfer']
Error: typeof import('./src/components/taskbar/Error.vue')['default']
FileIcon: typeof import('./src/components/builtin/FileIcon.vue')['default']
FileIconImg: typeof import('./src/components/builtin/FileIconImg.vue')['default']

89
frontend/src/components/chat/Chat.vue

@ -6,8 +6,22 @@
const workUrl = getWorkflowUrl();
onMounted(() => {
store.initChat();
// store.initSSE();
});
const generateData = () => {
const data = [];
for (let i = 1; i <= 15; i++) {
data.push({
key: i,
label: ` ${i}`,
disabled: i % 4 === 0,
});
}
return data;
};
const data = generateData();
const value = ref([]);
</script>
<template>
<el-container class="container">
@ -30,6 +44,13 @@
class="search-input"
v-model="store.search"
/>
<!-- 邀请群聊 -->
<button
class="inviteGroupChats"
@click="store.setGroupChatDialogVisible(true)"
>
<el-icon><Plus /></el-icon>
</button>
</el-header>
<!--好友列表-->
<el-main class="list">
@ -42,7 +63,7 @@
</el-container>
<el-container class="chat-box">
<chat-box v-if="store.currentNavId < 1" />
<chat-user-info v-if="store.currentNavId ==1"></chat-user-info>
<chat-user-info v-if="store.currentNavId == 1"></chat-user-info>
</el-container>
<el-container
class="chat-setting"
@ -60,6 +81,28 @@
<ChatUserSetting />
</el-container>
</el-container>
<!-- 群聊弹窗 -->
<el-dialog
v-model="store.groupChatDialogVisible"
title="发起群聊"
width="600px"
>
<div class="transfer">
<el-transfer class="transfer-box" v-model="value" :data="data" />
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="store.groupChatDialogVisible = false"
>取消</el-button
>
<el-button
type="primary"
@click="createGroupChat"
>确定</el-button
>
</span>
</template>
</el-dialog>
</template>
<style scoped>
.container {
@ -73,7 +116,7 @@
.menu {
width: 55px;
background-color: white;
background-color: #f0f0f0;
overflow-y: hidden;
overflow-x: hidden;
-webkit-app-region: drag;
@ -86,24 +129,42 @@
border-right: 1px solid #edebeb;
overflow-y: hidden;
overflow-x: hidden;
background-color: #f7f7f7;
}
.search {
width: 100%;
display: flex;
align-items: center;
justify-content: space-evenly;
width: 90%;
/* 占据整个宽度 */
height: 50px;
padding: 0;
-webkit-app-region: drag;
}
.inviteGroupChats {
width: 40px;
height: 30px;
border: none;
border-radius: 4px;
background-color: #f0f0f0;
}
.transfer-box {
height: 220px;
display: flex;
justify-content: center;
align-items: center;
}
.search-input {
width: calc(100% - 20px);
/* 减去左右边距 */
margin: 10px;
height: 32px;
-webkit-app-region: no-drag;
--el-input-placeholder-color: #818181 !important;
--el-input-icon-color: #5d5d5d !important;
--el-input-placeholder-color: #bfbfbf !important;
--el-input-icon-color: #bfbfbf !important;
}
.list {
@ -134,11 +195,11 @@
border: none;
}
.no-message-container {
height: 100%;
margin: 120px auto;
text-align: center;
font-size:14px;
justify-content: center;
}
.no-message-container {
height: 100%;
margin: 120px auto;
text-align: center;
font-size: 14px;
justify-content: center;
}
</style>

126
frontend/src/components/chat/ChatMenu.vue

@ -1,70 +1,116 @@
<script setup>
import {ref} from "vue";
import { useChatStore } from "@/stores/chat";
import {Setting as SettingIcon} from "@element-plus/icons-vue";
const store = useChatStore()
const getOnline = () => {
store.getOnlineUsers()
store.setCurrentNavId(1)
}
import { Setting as SettingIcon } from "@element-plus/icons-vue";
const store = useChatStore();
</script>
<template>
<el-row>
<el-avatar shape="square" :size="40" class="userAvatar" :src="store.userInfo.avatar"/>
<el-avatar
shape="square"
:size="40"
class="userAvatar"
:src="store.userInfo.avatar"
/>
</el-row>
<el-row @click="store.setCurrentNavId(0)">
<el-icon v-if="store.currentNavId === 0" class="menu-icon-on">
<ChatLineRound />
</el-icon>
<el-icon v-else class="menu-icon">
<ChatRound />
</el-icon>
<div class="menu-icon-box">
<el-icon
v-if="store.currentNavId === 0"
class="menu-icon-on"
>
<ChatLineRound />
</el-icon>
<el-icon
v-else
class="menu-icon"
>
<ChatRound />
</el-icon>
</div>
</el-row>
<el-row @click="getOnline">
<el-icon v-if="store.currentNavId === 1" class="menu-icon-on">
<UserFilled />
</el-icon>
<el-icon v-else class="menu-icon">
<User />
</el-icon>
<el-row @click="store.setCurrentNavId(1)">
<div class="menu-icon-box">
<el-icon
v-if="store.currentNavId === 1"
class="menu-icon-on"
>
<UserFilled />
</el-icon>
<el-icon
v-else
class="menu-icon"
>
<User />
</el-icon>
</div>
</el-row>
<el-row @click="store.setCurrentNavId(2)">
<el-icon v-if="store.currentNavId === 2" class="menu-icon-on">
<Platform />
</el-icon>
<el-icon v-else class="menu-icon">
<Monitor />
</el-icon>
<div class="menu-icon-box">
<el-icon
v-if="store.currentNavId === 2"
class="menu-icon-on"
>
<Platform />
</el-icon>
<el-icon
v-else
class="menu-icon"
>
<Monitor />
</el-icon>
</div>
</el-row>
<el-row @click="store.setCurrentNavId(5)">
<el-icon v-if="store.currentNavId === 5" class="menu-icon-on">
<SettingIcon />
</el-icon>
<el-icon v-else class="menu-icon">
<SettingIcon />
</el-icon>
<div class="menu-icon-box">
<el-icon
v-if="store.currentNavId === 5"
class="menu-icon-on"
>
<SettingIcon />
</el-icon>
<el-icon
v-else
class="menu-icon"
>
<SettingIcon />
</el-icon>
</div>
</el-row>
</template>
<style scoped>
.userAvatar {
margin: 30px auto 10px;
-webkit-app-region: no-drag
-webkit-app-region: no-drag;
}
.menu-icon-box {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
margin: 10px auto;
border-radius: 15%;
/* background-color: #bae7ff; */
transition: all 0.5s;
}
.menu-icon-box:hover {
background-color: #d9d9d9;
}
.menu-icon {
margin: 20px auto;
margin: 0px auto;
font-size: 25px;
color: #8F8F8F;
cursor: pointer;
}
.menu-icon-on {
margin: 20px auto;
margin: 0px auto;
font-size: 25px;
color: #0078d4;
color: #1890ff;
cursor: pointer;
}
</style>
</style>

354
frontend/src/components/chat/ChatMessage.vue

@ -1,158 +1,210 @@
<script setup lang="ts">
import { useChatStore } from '@/stores/chat';
const store = useChatStore();
import { useChatStore } from "@/stores/chat";
const chatHistory = computed(() => store.chatHistory as any);
const store = useChatStore();
</script>
<template>
<div v-for="item in store.chatHistory" :key="item.id">
<div v-if="!item.isme" class="chat-item">
<el-row>
<el-col :span="8" />
<el-col :span="14">
<el-row>
<el-col :span="24">
<div class="chat-name-me">{{ item.userInfo.username }}</div>
</el-col>
</el-row>
<div class="bubble-me" @contextmenu.prevent="store.showContextMenu($event, item.id)">
<div class="chat-font">
{{ item.content }}
</div>
</div>
</el-col>
<el-col :span="2">
<div class="chat-avatar">
<el-avatar shape="square" style="margin: 0;float: left" :size="32" class="userAvatar"
:src="item.userInfo.avatar" />
</div>
</el-col>
</el-row>
</div>
<div v-else class="chat-item">
<el-row>
<el-col :span="2">
<div class="chat-avatar">
<el-avatar shape="square" style="margin: 0;float: right" :size="32" class="userAvatar"
:src="item.userInfo.avatar" />
</div>
</el-col>
<el-col :span="14">
<el-row>
<el-col :span="24">
<div class="chat-name-other">{{ item.userInfo.username }}</div>
</el-col>
</el-row>
<div class="bubble-other">
<div class="chat-font">
{{ item.content }}
</div>
</div>
</el-col>
<el-col :span="8" />
</el-row>
</div>
<div v-if="item.type === 1" class="withdraw">
{{ item.userInfo.id === store.targetUserId ? "你" : item.userInfo.username }}撤回了一条消息
</div>
</div>
<!--悬浮菜单-->
<div class="context-menu" v-if="store.contextMenu.visible"
:style="{ top: `${store.contextMenu.y}px`, left: `${store.contextMenu.x}px` }">
<div v-for="contextItem in store.contextMenu.list" :key="contextItem.id" class="context-menu-item">
<div class="context-menu-item-font" @click="store.handleContextMenu(contextItem)">
{{ contextItem.label }}
</div>
</div>
</div>
<div
v-for="item in chatHistory"
:key="item.id"
>
<div
v-if="!item.isme"
class="chat-item"
>
<el-row>
<el-col :span="8" />
<el-col :span="14">
<el-row>
<el-col :span="24">
<div class="chat-name-me">
{{ item.userInfo.username }}
</div>
</el-col>
</el-row>
<div
class="bubble-me"
@contextmenu.prevent="
store.showContextMenu($event, item.id)
"
>
<div class="chat-font">
{{ item.content }}
</div>
</div>
</el-col>
<el-col :span="2">
<div class="chat-avatar">
<el-avatar
shape="square"
style="margin: 0; float: left"
:size="32"
class="userAvatar"
:src="item.userInfo.avatar"
/>
</div>
</el-col>
</el-row>
</div>
<div
v-else
class="chat-item"
>
<el-row>
<el-col :span="2">
<div class="chat-avatar">
<el-avatar
shape="square"
style="margin: 0; float: right"
:size="32"
class="userAvatar"
:src="item.userInfo.avatar"
/>
</div>
</el-col>
<el-col :span="14">
<el-row>
<el-col :span="24">
<div class="chat-name-other">
{{ item.userInfo.username }}
</div>
</el-col>
</el-row>
<div class="bubble-other">
<div class="chat-font">
{{ item.content }}
</div>
</div>
</el-col>
<el-col :span="8" />
</el-row>
</div>
<div
v-if="item.type === 1"
class="withdraw"
>
{{
item.userInfo.id === store.targetUserId
? "你"
: item.userInfo.username
}}撤回了一条消息
</div>
</div>
<!--悬浮菜单-->
<div
class="context-menu"
v-if="store.contextMenu.visible"
:style="{
top: `${store.contextMenu.y}px`,
left: `${store.contextMenu.x}px`,
}"
>
<div
v-for="contextItem in store.contextMenu.list"
:key="contextItem.id"
class="context-menu-item"
>
<div
class="context-menu-item-font"
@click="store.handleContextMenu()"
>
{{ contextItem.label }}
</div>
</div>
</div>
</template>
<style scoped>
.bubble-me {
background-color: #95EC69;
float: right;
border-radius: 4px;
margin-right: 5px;
margin-top: 5px;
}
.bubble-me:hover {
background-color: #89D961;
}
.chat-name-me {
font-size: 14px;
font-family: Arial, sans-serif;
line-height: 1.5;
color: #B2B2B2;
float: right;
margin-right: 5px;
}
.bubble-other {
background-color: #FFFFFF;
float: left;
border-radius: 4px;
margin-left: 5px;
margin-top: 5px;
}
.bubble-other:hover {
background-color: #EBEBEB;
}
.chat-name-other {
font-size: 14px;
font-family: Arial, sans-serif;
line-height: 1.5;
color: #B2B2B2;
float: left;
margin-left: 5px;
}
.chat-font {
margin: 8px;
font-size: 15px;
font-family: Arial, sans-serif;
line-height: 1.5;
}
.chat-avatar {
margin: 5px;
}
.chat-item {
margin: 5px;
}
.withdraw {
text-align: center;
font-size: 13px;
font-family: Arial, sans-serif;
color: #999999;
line-height: 3.2;
}
.context-menu {
position: fixed;
background-color: white;
z-index: 9999;
border: 1px solid #cccc;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.context-menu-item {
width: 80px;
height: 30px;
}
.context-menu-item:hover {
background-color: #E2E2E2;
}
.context-menu-item-font {
font-size: 14px;
text-align: center;
font-family: Arial, sans-serif;
line-height: 2.2;
}
</style>
.bubble-me {
background-color: #95ec69;
float: right;
border-radius: 4px;
margin-right: 5px;
margin-top: 5px;
}
.bubble-me:hover {
background-color: #89d961;
}
.chat-name-me {
font-size: 14px;
font-family: Arial, sans-serif;
line-height: 1.5;
color: #b2b2b2;
float: right;
margin-right: 5px;
}
.bubble-other {
background-color: #ffffff;
float: left;
border-radius: 4px;
margin-left: 5px;
margin-top: 5px;
}
.bubble-other:hover {
background-color: #ebebeb;
}
.chat-name-other {
font-size: 14px;
font-family: Arial, sans-serif;
line-height: 1.5;
color: #b2b2b2;
float: left;
margin-left: 5px;
}
.chat-font {
margin: 8px;
font-size: 15px;
font-family: Arial, sans-serif;
line-height: 1.5;
}
.chat-avatar {
margin: 5px;
}
.chat-item {
margin: 5px;
}
.withdraw {
text-align: center;
font-size: 13px;
font-family: Arial, sans-serif;
color: #999999;
line-height: 3.2;
}
.context-menu {
position: fixed;
background-color: white;
z-index: 9999;
border: 1px solid #cccc;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.context-menu-item {
width: 80px;
height: 30px;
}
.context-menu-item:hover {
background-color: #e2e2e2;
}
.context-menu-item-font {
font-size: 14px;
text-align: center;
font-family: Arial, sans-serif;
line-height: 2.2;
}
</style>

10
frontend/src/components/chat/ChatMsgList.vue

@ -4,7 +4,7 @@
class="list-item"
@click="store.changeChatList(item.id)"
:style="{
backgroundColor: item.id === store.targetUserId ? '#C4C4C4' : '',
backgroundColor: item.id === store.targetUserId ? '#bae7ff' : '',
}"
>
<el-row>
@ -60,13 +60,17 @@ const id = ref("1");
<style scoped>
.list-item {
width: 100%;
width: 94%;
height: 60px;
display: flex;
margin: 0 auto;
border-radius: 4px;
transition: all 0.5s;
margin-top: 5px;
}
.list-item:hover {
background-color: #d0d0d0;
background-color: #bae7ff;
}
.avatar {

47
frontend/src/components/chat/ChatUserList.vue

@ -11,14 +11,19 @@
</script>
<template>
<el-collapse
v-model="store.activeNames"
@change="handleChange"
>
<el-collapse v-model="store.activeNames">
<el-collapse-item name="1">
<template #title>
<span v-if="store.userList.length > 0" class="title">同事{{store.userList.length}}</span>
<span v-else class="title">同事</span>
<span
v-if="store.userList.length > 0"
class="title"
>同事{{ store.userList.length }}</span
>
<span
v-else
class="title"
>同事</span
>
</template>
<div v-if="store.userList.length > 0">
<div
@ -30,7 +35,7 @@
@click="store.changeChatList(item.id)"
:style="{
backgroundColor:
item.id === store.targetUserId ? '#C4C4C4' : '',
item.id === store.targetUserId ? '#bae7ff' : '',
}"
>
<el-row>
@ -47,7 +52,10 @@
<el-col :span="18">
<div class="previewName">
{{ item.nickname }}
<el-icon class="online-icon" v-if="item.isOnline">
<el-icon
class="online-icon"
v-if="item.isOnline"
>
<CircleCheckFilled />
</el-icon>
</div>
@ -72,8 +80,16 @@
</el-collapse-item>
<el-collapse-item name="2">
<template #title>
<span v-if="store.groupList.length > 0" class="title">部门{{store.groupList.length}}</span>
<span v-else class="title">部门</span>
<span
v-if="store.groupList.length > 0"
class="title"
>部门{{ store.groupList.length }}</span
>
<span
v-else
class="title"
>部门</span
>
</template>
<div v-if="store.groupList.length > 0">
<div
@ -147,13 +163,16 @@
padding-left: 10px;
}
.list-item {
width: 100%;
width: 94%;
height: 60px;
border: 0.5px solid #d0d0d0;
margin: 0 auto;
border-radius: 4px;
transition: all 0.5s;
margin-bottom: 5px;
}
.list-item:hover {
background-color: #d0d0d0;
background-color: #bae7ff;
}
.avatar {
@ -218,4 +237,4 @@
text-align: center;
color: #999999;
}
</style>
</style>

27
frontend/src/components/window/WindowTemplate.vue

@ -54,12 +54,12 @@
import { onUnmounted, provide, ref } from "vue";
import { onMounted, computed, UnwrapNestedRefs } from "vue";
import { WindowStateEnum } from "@/system/window/BrowserWindow";
import { ScaleElement } from "@/system/window/dom/ScaleElement";
import { BrowserWindow } from "@/system/window/BrowserWindow";
import { emitEvent } from "@/system/event";
import { useSystem } from "@/system";
import { vDragable } from "@/system/window/MakeDragable";
const sys = useSystem();
const props = defineProps<{
browserWindow: UnwrapNestedRefs<BrowserWindow>;
@ -67,7 +67,6 @@ const props = defineProps<{
const browserWindow = props.browserWindow;
const windowInfo = browserWindow.windowInfo;
// windowid
provide("browserWindow", browserWindow);
provide("system", sys);
@ -96,7 +95,6 @@ onMounted(() => {
height: computed(() => windowInfo.height + "px"),
left: computed(() => windowInfo.x + "px"),
top: computed(() => windowInfo.y + "px"),
zIndex: computed(() => {
if (windowInfo.alwaysOnTop) {
return 9999;
@ -107,12 +105,10 @@ onMounted(() => {
};
});
/*
挂载缩放事件
*/
const resizable = ref(windowInfo.resizable);
const resizemode = ref("null");
let scaleAble: ScaleElement;
onMounted(() => {
scaleAble = new ScaleElement(
resizemode,
@ -129,6 +125,7 @@ onMounted(() => {
browserWindow.emit("resize", windowInfo.width, windowInfo.height);
});
});
function startScale(e: MouseEvent | TouchEvent, dire: string) {
console.log(e);
if (windowInfo.disable) {
@ -146,19 +143,17 @@ function startScale(e: MouseEvent | TouchEvent, dire: string) {
onUnmounted(() => {
scaleAble.unMount();
// dragAble.unMount();
});
//
const dragBorders = [
{ type: 'r', class: 'right_border' },
{ type: 'b', class: 'bottom_border' },
{ type: 'l', class: 'left_border' },
{ type: 't', class: 'top_border' },
{ type: 'rb', class: 'right_bottom_border' },
{ type: 'lb', class: 'left_bottom_border' },
{ type: 'lt', class: 'left_top_border' },
{ type: 'rt', class: 'right_top_border' },
{ type: 'r', class: 'right_border', cursorClass: 'ew-resize' },
{ type: 'b', class: 'bottom_border', cursorClass: 'ns-resize' },
{ type: 'l', class: 'left_border', cursorClass: 'ew-resize' },
{ type: 't', class: 'top_border', cursorClass: 'ns-resize' },
{ type: 'rb', class: 'right_bottom_border', cursorClass: 'nwse-resize' },
{ type: 'lb', class: 'left_bottom_border', cursorClass: 'nesw-resize' },
{ type: 'lt', class: 'left_top_border', cursorClass: 'nwse-resize' },
{ type: 'rt', class: 'right_top_border', cursorClass: 'nesw-resize' },
];
</script>
<style>

313
frontend/src/stores/chat.ts

@ -1,10 +1,33 @@
import emojiList from "@/assets/emoji.json";
import { fetchGet, fetchPost, getSystemConfig } from '@/system/config';
import { fetchPost, getSystemConfig } from '@/system/config';
import { notifyError } from "@/util/msg";
import { defineStore } from 'pinia';
import { db } from "./db";
import { useMessageStore } from "./message";
interface ChatMessage {
type: string;
createdAt: number;
content: any;
targetUserId: any;
previewType: 0 | 1; // 消息类型,0表示正常消息,1表示撤回消息
previewMessage: any;
isMe: boolean;
isRead: boolean;
userInfo: {
id: any;
username: any;
avatar: any;
};
}
// 发起群聊对话框显示
const groupChatDialogVisible = ref(false);
// 设置发起群聊对话框状态
const setGroupChatDialogVisible = (visible: boolean) => {
groupChatDialogVisible.value = visible;
};
export const useChatStore = defineStore('chatStore', () => {
// 用户列表
const userList: any = ref([]);
@ -29,10 +52,19 @@ export const useChatStore = defineStore('chatStore', () => {
previewType: 1,
previewMessage: "测试消息",
},
{
id: 3,
nickname: '朋友2',
avatar: '/logo.png',
previewTimeFormat: "昨天",
previewType: 1,
previewMessage: "测试消息",
},
]);
// 模拟数据 - 聊天消息列表
const chatHistory = ref([]);
const chatHistory = ref<ChatMessage[]>([]);
// 群组数据
const groupList = ref([
@ -82,10 +114,8 @@ export const useChatStore = defineStore('chatStore', () => {
visible: false,
chatMessageId: 0,
list: [
{
id: 2,
label: '撤回',
}
{ id: 1, label: '复制' },
{ id: 2, label: '删除' },
],
x: 0,
y: 0
@ -96,6 +126,10 @@ export const useChatStore = defineStore('chatStore', () => {
config.userInfo.avatar = '/logo.png';
}
userInfo.value = config.userInfo;
getUserList()
initUserList()
initOnlineUserList()
console.log(userList.value);
};
const setCurrentNavId = (id: number) => {
@ -104,7 +138,7 @@ export const useChatStore = defineStore('chatStore', () => {
const sendMessage = async () => {
const chatSendUrl = apiUrl + '/chat/send';
const messageHistory = {
const messageHistory: ChatMessage = {
type: 'text',
createdAt: Date.now(),
content: message.value,
@ -165,7 +199,7 @@ export const useChatStore = defineStore('chatStore', () => {
}
} else {
const targetUser = await db.getOne('workbenchusers', id);
const lastMessage = messageHistory;
const lastMessage: any = messageStore;
const targetUserInfo = {
id: targetUser.id,
@ -177,7 +211,7 @@ export const useChatStore = defineStore('chatStore', () => {
const now = new Date();
const createdAt = new Date(lastMessage.createdAt);
const diffTime = Math.abs(now.getTime() - createdAt.getTime());
console.log(diffTime);
// 根据时间差格式化时间
const previewTimeFormat = formatTime(Date.now());
@ -220,40 +254,192 @@ export const useChatStore = defineStore('chatStore', () => {
message.value = '';
};
const initSSE = async () => {
console.log('initSSE');
const source = new EventSource(`${apiUrl}/chat/message`);
console.log(source);
source.onmessage = function (event) {
const data = JSON.parse(event.data);
console.log(data);
messageStore.handleMessage(data);
};
const setScrollToBottom = async () => {
// await nextTick(); // 确保 DOM 已经更新完毕
// // 检查 innerRef 是否存在
// if (!innerRef.value) {
// console.warn('innerRef is not defined.');
// return;
// }
// // 设置滚动条到底部
// const max = innerRef.value.clientHeight;
// if (scrollbarRef.value) {
// scrollbarRef.value.setScrollTop(max);
// } else {
// console.warn('scrollbarRef is not defined.');
// }
};
source.onerror = function (event) {
console.error('EventSource error:', event);
};
const handleUserData = async (data: any[]) => {
;
// 创建一个用户数组,将所有在线的用户提取出来
const users: any[] = [];
// 遍历每个数据项
data.forEach((item: any) => {
if (item.id && item.login_ip) {
users.push({
id: item.id,
ip: item.login_ip,
avatar: item.avatar,
username: item.username,
nickname: item.nickname
});
}
});
console.log(users);
// 将提取到的用户数据传递给 setUserList
if (users.length > 0) {
await setUserList(users);
}
};
const setScrollToBottom = async () => {
await nextTick(); // 确保 DOM 已经更新完毕
// 检查 innerRef 是否存在
if (!innerRef.value) {
console.warn('innerRef is not defined.');
const setUserList = async (data: any[]) => {
if (data.length < 1) {
return;
}
// 设置滚动条到底部
const max = innerRef.value.clientHeight;
if (scrollbarRef.value) {
scrollbarRef.value.setScrollTop(max);
} else {
console.warn('scrollbarRef is not defined.');
// 从当前用户列表中获取已有用户的 IP 和完整用户映射
const existingIps = new Set(userList.value.map((d: any) => d.ip));
const userMap = new Map(
userList.value.map((user: any) => [user.ip, user])
);
const updates: any[] = [];
const newEntries: any[] = [];
// 遍历传入的 data,每个用户根据是否存在来更新或添加
data.forEach((d: any) => {
const existingUser = userMap.get(d.ip);
if (existingUser && existingIps.has(d.ip)) {
// 若用户已存在,添加到更新列表
updates.push({
key: existingUser.id,
changes: {
isOnline: true,
nickname: d.nickname,
username: d.usernmae,
updatedAt: Date.now()
}
});
} else {
// 若用户不存在,添加到新条目列表
newEntries.push({
id: d.id,
ip: d.ip,
isOnline: true,
nickname: d.nickname,
username: d.usernmae,
createdAt: Date.now(),
updatedAt: Date.now()
});
}
});
console.log(updates);
console.log(newEntries);
// 批量更新和添加用户数据
if (updates.length > 0) {
await db.table('workbenchusers').bulkUpdate(updates);
}
if (newEntries.length > 0) {
await db.table('workbenchusers').bulkPut(newEntries);
}
// 刷新用户列表
await getUserList();
};
const getUserList = async () => {
try {
// 从数据库中获取所有用户信息
const list = await db.getAll("workbenchusers");
// 创建一个 Map,用于存储每个用户的唯一 ID 地址
let uniqueIdMap = new Map<string, any>();
// 遍历用户列表,将每个用户添加到 Map 中(基于 ID 去重)
list.forEach((item: any) => {
uniqueIdMap.set(item.id, item); // 使用 ID 作为键,用户对象作为值
});
// 将 Map 的值转换为数组(去重后的用户列表)
const uniqueIdList = Array.from(uniqueIdMap.values());
// 按照 updatedAt 时间进行升序排序
uniqueIdList.sort((a: any, b: any) => a.updatedAt - b.updatedAt);
// 更新用户列表
userList.value = uniqueIdList;
} catch (error) {
console.error("获取用户列表失败:", error);
}
};
// 初始化统一用户列表状态
const initUserList = async () => {
// 检查用户列表是否为空
if (userList.value.length > 0) {
// 收集需要更新的用户数据
const updates = userList.value
.filter((d: any) => d.isOnline) // 过滤出在线的用户
.map((d: any) => ({
key: d.id,
changes: {
isOnline: false
}
}));
// 批量更新用户状态
if (updates.length > 0) {
await db.table('workbenchusers').bulkUpdate(updates);
}
}
};
const initOnlineUserList = async () => {
const msgAll = await db.getAll('workbenchusers');
const list = msgAll.reduce((acc: any, msg: any) => {
if (!msg.isMe) {
const targetId = msg.targetId;
if (!acc[targetId]) {
acc[targetId] = { chatArr: [], readNum: 0 };
}
acc[targetId].chatArr.push(msg);
// 计算未读消息数量
if (!msg.isRead) {
acc[targetId].readNum++;
}
}
return acc;
}, {});
const res = Object.keys(list).map(targetId => {
const { chatArr, readNum } = list[targetId];
const lastMessage = chatArr[chatArr.length - 1];
if (lastMessage) {
lastMessage.readNum = readNum;
return lastMessage;
}
return null; // 防止返回空值
}).filter(Boolean); // 过滤掉空值
userList.value = res.sort((a, b) => b.createdAt - a.createdAt);
};
const changeChatList = async (id: number) => {
// 设置 targetUserId
targetUserId.value = id;
@ -274,59 +460,6 @@ export const useChatStore = defineStore('chatStore', () => {
contextMenu.value.visible = false;
};
const getOnlineUsers = async () => {
const res = await fetchGet(apiUrl + '/chat/online?page=1');
if (!res.ok) {
notifyError("获取在线用户失败");
return;
}
const data = await res.json();
console.log(data);
const onlineUsers = data.data.list.map((item: any) => ({
id: item.id,
username: item.username,
nickname: item.nickname,
email: item.email,
phone: item.phone,
desc: item.desc,
jobNumber: item.job_number,
workPlace: item.work_place,
hiredDate: item.hired_date,
avatar: item.avatar || '/logo.png',
isOnline: true,
ip: item.login_ip,
updatedAt: item.updated_at,
createdAt: item.add_time,
}));
// 更新或添加用户
const existingUserIds = await db.getAll('workbenchusers').then(users => users.map(user => user.id));
const newUserIds = onlineUsers.filter(user => !existingUserIds.includes(user.id)).map(user => user.id);
// 更新现有用户的状态
const updatePromises = onlineUsers.filter(user => existingUserIds.includes(user.id)).map(user => {
return db.update('workbenchusers', user.id, {
isOnline: true,
updatedAt: user.updatedAt,
ip: user.ip,
});
});
// 添加新用户
const addPromises = onlineUsers.filter((user: { id: any }) => newUserIds.includes(user.id)).map((user: any) => {
return db.addOne('workbenchusers', user);
});
await Promise.all([...updatePromises, ...addPromises]);
// 更新 userList
userList.value = await db.getAll('workbenchusers');
console.log(userList.value);
};
const showContextMenu = (event: any, id: number) => {
contextMenu.value.visible = true;
@ -354,14 +487,16 @@ export const useChatStore = defineStore('chatStore', () => {
message,
contextMenu,
activeNames,
groupChatDialogVisible,
initChat,
initSSE,
showContextMenu,
setCurrentNavId,
sendMessage,
changeChatList,
handleContextMenu,
showContextMenu,
getOnlineUsers,
updateConversationList
updateConversationList,
handleUserData,
initUserList,
setGroupChatDialogVisible
};
});

1
frontend/src/stores/localchat.ts

@ -26,7 +26,6 @@ export const useLocalChatStore = defineStore('localChatStore', () => {
const chatTargetIp = ref("")
const showAddUser = ref(false)
const handlerMessage = (data : any) => {
//console.log(data)
if(data.onlines){
const ips = []
for(let ip in data.onlines){

317
frontend/src/stores/upgrade.ts

@ -1,162 +1,185 @@
import { t } from '@/i18n';
import { getSystemConfig, getUrl, parseJson, setSystemKey } from '@/system/config';
import { RestartApp } from '@/util/goutil';
import { ElMessage } from 'element-plus';
import { defineStore } from "pinia";
import { ref } from "vue";
import { setSystemKey, parseJson, getSystemConfig } from '@/system/config'
import { RestartApp } from '@/util/goutil';
import { ElMessage } from 'element-plus'
import { t } from '@/i18n';
import { useChatStore } from "./chat";
import { useLocalChatStore } from "./localchat";
export const useUpgradeStore = defineStore('upgradeStore', () => {
const hasUpgrade = ref(false);
const hasNotice = ref(false);
const hasAd = ref(false);
const updateUrl = ref('');
const versionTag = ref('')
const upgradeDesc = ref('')
const currentVersion = ref('')
const progress = ref(0)
const noticeList:any = ref([])
const adList:any = ref([])
const localChatStore = useLocalChatStore()
function compareVersions(version1:string, version2:string) {
// 将版本号字符串按"."分割成数组
const parts1 = version1.split('.').map(Number);
const parts2 = version2.split('.').map(Number);
// 确保两个数组长度相同
const maxLength = Math.max(parts1.length, parts2.length);
while (parts1.length < maxLength) parts1.push(0);
while (parts2.length < maxLength) parts2.push(0);
// 比较每个部分
for (let i = 0; i < maxLength; i++) {
if (parts1[i] > parts2[i]) return 1;
if (parts1[i] < parts2[i]) return -1;
}
// 如果所有部分都相等,则返回0
return 0;
const hasUpgrade = ref(false);
const hasNotice = ref(false);
const hasAd = ref(false);
const updateUrl = ref('');
const versionTag = ref('')
const upgradeDesc = ref('')
const currentVersion = ref('')
const progress = ref(0)
const noticeList: any = ref([])
const adList: any = ref([])
const localChatStore = useLocalChatStore()
const chatChatStore = useChatStore()
function compareVersions(version1: string, version2: string) {
// 将版本号字符串按"."分割成数组
const parts1 = version1.split('.').map(Number);
const parts2 = version2.split('.').map(Number);
// 确保两个数组长度相同
const maxLength = Math.max(parts1.length, parts2.length);
while (parts1.length < maxLength) parts1.push(0);
while (parts2.length < maxLength) parts2.push(0);
// 比较每个部分
for (let i = 0; i < maxLength; i++) {
if (parts1[i] > parts2[i]) return 1;
if (parts1[i] < parts2[i]) return -1;
}
function systemMessage(){
const config = getSystemConfig();
const source = new EventSource(`${config.apiUrl}/system/message`);
source.onmessage = function(event) {
const data = JSON.parse(event.data);
//console.log(data)
handleMessage(data);
};
source.onerror = function(event) {
console.error('EventSource error:', event);
};
// 如果所有部分都相等,则返回0
return 0;
}
function systemMessage() {
const config = getSystemConfig();
const source = new EventSource(`${config.apiUrl}/system/message`);
source.onmessage = function (event) {
const data = JSON.parse(event.data);
//console.log(data)
handleMessage(data);
};
source.onerror = function (event) {
console.error('EventSource error:', event);
};
}
// 获取在线消息
function onlineMessage() {
const url = getUrl('/chat/message', false)
const source = new EventSource(url);
source.onmessage = function (event) {
const data = JSON.parse(event.data);
handleMessage(data);
};
source.onerror = function (event) {
console.error('EventSource error:', event);
};
}
async function handleMessage(message: any) {
switch (message.type) {
case 'update':
checkUpdate(message.data)
break;
case 'localchat':
localChatStore.handlerMessage(message.data)
break;
case 'online':
chatChatStore.handleUserData(message.data)
break;
default:
console.warn('Unknown message type:', message.type);
}
async function handleMessage(message:any) {
switch (message.type) {
case 'update':
checkUpdate(message.data)
break;
case 'localchat':
localChatStore.handlerMessage(message.data)
break;
default:
console.warn('Unknown message type:', message.type);
}
}
async function checkUpdate(res: any) {
//console.log(res)
if (!res) return
const config = getSystemConfig();
if (!config.account.ad) return;
currentVersion.value = config.version;
let bottomList: any = []
let centerList: any = []
if (res.adlist && res.adlist.length > 0) {
bottomList = res.adlist[0]['bottom']
centerList = res.adlist[0]['center']
}
async function checkUpdate(res:any) {
//console.log(res)
if(!res)return
const config = getSystemConfig();
if(!config.account.ad)return;
currentVersion.value = config.version;
let bottomList:any = []
let centerList:any = []
if (res.adlist && res.adlist.length > 0) {
bottomList = res.adlist[0]['bottom']
centerList = res.adlist[0]['center']
}
if(bottomList && bottomList.length > 0){
hasNotice.value = true
noticeList.value = [...noticeList.value, ...changeUrl(bottomList)]
}
//console.log(noticeList)
//console.log(centerList)
if(centerList && centerList.length > 0){
hasAd.value = true
adList.value = [...adList.value, ...changeUrl(centerList)]
}
//console.log(adList.value)
if (bottomList && bottomList.length > 0) {
hasNotice.value = true
noticeList.value = [...noticeList.value, ...changeUrl(bottomList)]
}
//console.log(noticeList)
//console.log(centerList)
if (centerList && centerList.length > 0) {
hasAd.value = true
adList.value = [...adList.value, ...changeUrl(centerList)]
}
//console.log(adList.value)
if(!res.version || res.version == ""){
return
}
versionTag.value = res.version
if (compareVersions(versionTag.value, config.version) > 0) {
upgradeDesc.value = res.desc ?? t('upgrade.msg')
hasUpgrade.value = true
updateUrl.value = res.url
}
if (!res.version || res.version == "") {
return
}
versionTag.value = res.version
if (compareVersions(versionTag.value, config.version) > 0) {
upgradeDesc.value = res.desc ?? t('upgrade.msg')
hasUpgrade.value = true
updateUrl.value = res.url
}
function changeUrl(list : any){
list.forEach((item:any) => {
if(item.img && item.img.indexOf('http') == -1){
item.img = `https://godoos.com${item.img}`
}
});
return list
}
function changeUrl(list: any) {
list.forEach((item: any) => {
if (item.img && item.img.indexOf('http') == -1) {
item.img = `https://godoos.com${item.img}`
}
});
return list
}
async function update() {
const config = getSystemConfig();
const upUrl = `${config.apiUrl}/system/update?url=${updateUrl.value}`
const upRes = await fetch(upUrl)
if (!upRes.ok) return;
const reader: any = upRes.body?.getReader();
if (!reader) {
ElMessage({
type: 'error',
message: "the system has not stream!"
})
}
async function update() {
const config = getSystemConfig();
const upUrl = `${config.apiUrl}/system/update?url=${updateUrl.value}`
const upRes = await fetch(upUrl)
if (!upRes.ok) return;
const reader: any = upRes.body?.getReader();
if (!reader) {
ElMessage({
type: 'error',
message: "the system has not stream!"
})
while (true) {
const { done, value } = await reader.read();
if (done) {
reader.releaseLock();
break;
}
const rawjson = new TextDecoder().decode(value);
const json = parseJson(rawjson);
//console.log(json)
if (json) {
if (json.progress) {
progress.value = json.progress
}
while (true) {
const { done, value } = await reader.read();
if (done) {
reader.releaseLock();
break;
}
const rawjson = new TextDecoder().decode(value);
const json = parseJson(rawjson);
//console.log(json)
if (json) {
if (json.progress) {
progress.value = json.progress
}
if (json.updateCompleted) {
hasUpgrade.value = false
progress.value = 0
ElMessage({
type: 'success',
message: "update completed!"
})
setSystemKey('version', versionTag.value)
currentVersion.value = versionTag.value
RestartApp()
break;
}
}
if (json.updateCompleted) {
hasUpgrade.value = false
progress.value = 0
ElMessage({
type: 'success',
message: "update completed!"
})
setSystemKey('version', versionTag.value)
currentVersion.value = versionTag.value
RestartApp()
break;
}
}
}
return {
hasUpgrade,
hasNotice,
hasAd,
versionTag,
upgradeDesc,
updateUrl,
noticeList,
adList,
progress,
checkUpdate,
systemMessage,
update
}
}
return {
hasUpgrade,
hasNotice,
hasAd,
versionTag,
upgradeDesc,
updateUrl,
noticeList,
adList,
progress,
checkUpdate,
systemMessage,
onlineMessage,
update
}
})

66
frontend/src/system/index.ts

@ -1,6 +1,10 @@
import { markRaw, nextTick } from 'vue';
import { version } from '../../package.json';
import { useOsFile } from './core/FileOs';
import { OsFileSystem } from './core/FileSystem';
import { Eventer, initEventer, initEventListener } from './event';
import { initRootState, RootState } from './root';
import { SystemStateEnum } from './type/enum';
import { markRaw, nextTick } from 'vue';
import {
Saveablekey,
Setting,
@ -8,26 +12,22 @@ import {
SystemOptionsCertainly,
WinAppOptions,
} from './type/type';
import { initEventer, Eventer, initEventListener } from './event';
import { OsFileSystem } from './core/FileSystem';
import { useOsFile } from './core/FileOs';
import { version } from '../../package.json';
import { BrowserWindow, BrowserWindowOption } from './window/BrowserWindow';
import { useMessageStore } from '@/stores/message';
import { useUpgradeStore } from '@/stores/upgrade';
import { RestartApp } from '@/util/goutil';
import { notifyError } from '@/util/msg';
import { isShareFile } from '@/util/sharePath';
import { pick } from '../util/modash';
import { clearSystemConfig, fetchGet, getClientId, getFileUrl, getSystemConfig, getSystemKey, setSystemConfig, setSystemKey } from './config';
import { OsFileInterface } from './core/FIleInterface';
import { extname } from './core/Path';
import { initBuiltinApp, initBuiltinFileOpener } from './initBuiltin';
import { defaultConfig } from './initConfig';
import { OsFileInterface } from './core/FIleInterface';
import { Tray, TrayOptions } from './menu/Tary';
import { Notify, NotifyConstructorOptions } from './notification/Notification';
import { Dialog } from './window/Dialog';
import { pick } from '../util/modash';
import { Tray, TrayOptions } from './menu/Tary';
import { getSystemConfig, getSystemKey, setSystemKey, setSystemConfig, clearSystemConfig, getFileUrl, fetchGet, getClientId } from './config'
import { useUpgradeStore } from '@/stores/upgrade';
import { useMessageStore } from '@/stores/message';
import { RestartApp } from '@/util/goutil';
import { notifyError } from '@/util/msg';
import { isShareFile } from '@/util/sharePath';
export type OsPlugin = (system: System) => void;
export type FileOpener = {
@ -113,17 +113,19 @@ export class System {
}
private checkMessages() {
const config = getSystemConfig();
const upgradeStore = useUpgradeStore();
if (config.userType == 'member') {
setTimeout(() => {
const messageStore = useMessageStore();
messageStore.systemMessage()
// const messageStore = useMessageStore();
// messageStore.systemMessage()
upgradeStore.onlineMessage();
}, 3000);
}
setTimeout(() => {
const upgradeStore = useUpgradeStore();
upgradeStore.systemMessage()
// upgradeStore.systemMessage()
}, 6000);
}
/**
* @description:
@ -431,6 +433,7 @@ export class System {
if (isShareFile(path)) {
const arr = path.split('/')
const fileContent = await this.fs.readShareFile(path)
<<<<<<< HEAD
// console.log('阅读:', fileContent);
if (fileContent !== false) {
const fileName = extname(arr[arr.length-1] || '') || 'link'
@ -438,6 +441,12 @@ export class System {
.get(fileName)
?.func.call(this, path, fileContent || '');
}
=======
const fileName = extname(arr[arr.length - 1] || '') || 'link'
this._flieOpenerMap
.get(fileName)
?.func.call(this, path, fileContent || '');
>>>>>>> 89f84204e655e3df0824fe91c9b17bc8a9d6ad87
} else {
const fileStat = await this.fs.stat(path)
if (!fileStat) {
@ -517,16 +526,17 @@ export function useSystem() {
return System.GLOBAL_SYSTEM!;
}
export * from './core/Path';
export { t } from '../i18n';
export { dealIcon } from '../util/Icon';
export type { OsFileInterface } from './core/FIleInterface';
export * from './core/FileSystem';
export { BrowserWindow } from './window/BrowserWindow';
export * from './core/Path';
export { Menu } from './menu/Menu';
export { MenuItem } from './menu/MenuItem';
export { Tray } from './menu/Tary';
export { Notify } from './notification/Notification';
export { Dialog } from './window/Dialog';
export type { SystemOptions, WinApp } from './type/type';
export { BrowserWindow } from './window/BrowserWindow';
export { Dialog } from './window/Dialog';
export { vDragable } from './window/MakeDragable';
export type { OsFileInterface } from './core/FIleInterface';
export { t } from '../i18n';
export { Tray } from './menu/Tary';
export { dealIcon } from '../util/Icon';
export { Menu } from './menu/Menu';
export { MenuItem } from './menu/MenuItem';

1
frontend/tsconfig.json

@ -1,6 +1,7 @@
{
"compilerOptions": {
"target": "ES2020",
"noEmitOnError": false,
//"target": "esnext",
"useDefineForClassFields": true,
"module": "ESNext",

2
godo/cmd/main.go

@ -101,6 +101,8 @@ func OsStart() {
fileRouter.HandleFunc("/unzip", files.HandleUnZip).Methods(http.MethodGet)
fileRouter.HandleFunc("/watch", files.WatchHandler).Methods(http.MethodGet)
fileRouter.HandleFunc("/setfilepwd", files.HandleSetFilePwd).Methods(http.MethodGet)
fileRouter.HandleFunc("/changefilepwd", files.HandleChangeFilePwd).Methods(http.MethodGet)
fileRouter.HandleFunc("/changeisPwd", files.HandleSetIsPwd).Methods(http.MethodGet)
localchatRouter := router.PathPrefix("/localchat").Subrouter()
localchatRouter.HandleFunc("/message", localchat.HandleMessage).Methods(http.MethodPost)

23
godo/files/fs.go

@ -315,9 +315,8 @@ func HandleCopyFile(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(res)
}
// HandleWriteFile writes content to a file
// 带加密写
func HandleWriteFile(w http.ResponseWriter, r *http.Request) {
// basepath = "/Users/sujia/.godoos/os"
filePath := r.URL.Query().Get("filePath")
basePath, err := libs.GetOsDir()
if err != nil {
@ -346,12 +345,27 @@ func HandleWriteFile(w http.ResponseWriter, r *http.Request) {
}
defer file.Close()
// 内容为空直接返回,不为空则加密
// 内容为空直接返回
if len(filedata) == 0 {
CheckAddDesktop(filePath)
libs.SuccessMsg(w, "", "success")
return
}
// 判读是否加密
ispwd := GetPwdFlag()
// 没有加密写入明文
if ispwd == 0 {
_, err := io.Copy(file, fileContent)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
CheckAddDesktop(filePath)
libs.SuccessMsg(w, "", "success")
return
}
// 加密
data, err := libs.EncryptData(filedata, libs.EncryptionKey)
if err != nil {
@ -365,8 +379,7 @@ func HandleWriteFile(w http.ResponseWriter, r *http.Request) {
}
// 判断下是否添加到桌面上
CheckAddDesktop(filePath)
res := libs.APIResponse{Message: fmt.Sprintf("File '%s' successfully written.", filePath)}
json.NewEncoder(w).Encode(res)
libs.SuccessMsg(w, "", "success")
}
// HandleAppendFile appends content to a file

16
godo/files/os.go

@ -339,7 +339,7 @@ func CheckDeleteDesktop(filePath string) error {
// 校验文件密码
func CheckFilePwd(fpwd, salt string) bool {
pwd := libs.HashPassword(fpwd, salt)
oldpwd, err := libs.GetConfig("filepwd")
oldpwd, err := libs.GetConfig("filePwd")
if !err {
return false
}
@ -365,3 +365,17 @@ func GetSalt(r *http.Request) string {
return salt
}
}
// 获取密码标识位,没有添加上
func GetPwdFlag() int {
isPwd, has := libs.GetConfig("isPwd")
if !has {
req := libs.ReqBody{
Name: "isPwd",
Value: 0,
}
libs.SetConfig(req)
libs.SaveConfig()
}
return isPwd.(int)
}

56
godo/files/pwdfile.go

@ -5,33 +5,24 @@ import (
"encoding/json"
"godo/libs"
"net/http"
"strconv"
"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)
hasPwd := GetPwdFlag()
// 校验文件路径
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 {
@ -45,14 +36,31 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
return
}
// 解密
data, err := libs.DecryptData(fileContent, libs.EncryptionKey)
// 没有加密 base64明文传输
if hasPwd == 0 {
data := string(fileContent)
if !strings.HasPrefix(data, "link::") {
data = base64.StdEncoding.EncodeToString(fileContent)
resp := libs.APIResponse{Message: "success", Data: data}
json.NewEncoder(w).Encode(resp)
return
}
}
// 有加密,先校验密码,再解密
if !CheckFilePwd(fPwd, salt) {
libs.HTTPError(w, http.StatusBadRequest, "密码错误")
return
}
var data []byte
fileContent, err = libs.DecryptData(fileContent, libs.EncryptionKey)
if err != nil {
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
return
}
content := string(data)
content := string(fileContent)
// 检查文件内容是否以"link::"开头
if !strings.HasPrefix(content, "link::") {
content = base64.StdEncoding.EncodeToString(data)
@ -60,7 +68,6 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
// 初始响应
res := libs.APIResponse{Code: 0, Message: "success", Data: content}
json.NewEncoder(w).Encode(res)
}
@ -68,6 +75,7 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
func HandleSetFilePwd(w http.ResponseWriter, r *http.Request) {
fPwd := r.Header.Get("filepPwd")
salt := r.Header.Get("salt")
// 服务端再hash加密
hashPwd := libs.HashPassword(fPwd, salt)
@ -104,3 +112,17 @@ func HandleChangeFilePwd(w http.ResponseWriter, r *http.Request) {
libs.SetConfig(pwdReq)
libs.SuccessMsg(w, "success", "The file password change success!")
}
// 更改加密状态
func HandleSetIsPwd(w http.ResponseWriter, r *http.Request) {
isPwd := r.URL.Query().Get("ispwd")
// 0非加密机器 1加密机器
isPwdValue, _ := strconv.Atoi(isPwd)
pwdReq := libs.ReqBody{
Name: "isPwd",
Value: isPwdValue,
}
libs.SetConfig(pwdReq)
libs.SaveConfig()
libs.SuccessMsg(w, "success", "")
}

Loading…
Cancel
Save