godo 8 months ago
parent
commit
813ebce269
  1. 4
      frontend/auto-imports.d.ts
  2. 1
      frontend/components.d.ts
  3. 4
      frontend/src/components/builtin/FileList.vue
  4. 1
      frontend/src/components/builtin/FileProps.vue
  5. 175
      frontend/src/components/chat/Chat.vue
  6. 62
      frontend/src/components/chat/ChatBox.vue
  7. 11
      frontend/src/components/chat/ChatMenu.vue
  8. 151
      frontend/src/components/chat/ChatMessage.vue
  9. 127
      frontend/src/components/chat/ChatMsgList.vue
  10. 91
      frontend/src/components/chat/ChatUserList.vue
  11. 94
      frontend/src/components/chat/ChatUserSetting.vue
  12. 6
      frontend/src/components/chat/chatUserInfo.vue
  13. 11
      frontend/src/components/computer/Computer.vue
  14. 1
      frontend/src/components/desktop/LockDesktop.vue
  15. 9
      frontend/src/components/oa/ShareFiles.vue
  16. 40
      frontend/src/hook/useComputer.ts
  17. 837
      frontend/src/stores/chat.ts
  18. 42
      frontend/src/stores/db.ts
  19. 36
      frontend/src/stores/file.ts
  20. 170
      frontend/src/stores/notify.ts
  21. 22
      frontend/src/stores/upgrade.ts
  22. 31
      frontend/src/system/core/FileOs.ts
  23. 1
      frontend/src/system/core/FileSystem.ts
  24. 1
      frontend/src/system/index.ts
  25. 5
      frontend/src/util/sharePath.ts
  26. 6
      godo/files/os.go

4
frontend/auto-imports.d.ts

@ -3,9 +3,11 @@
// @ts-nocheck // @ts-nocheck
// noinspection JSUnusedGlobalSymbols // noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import // Generated by unplugin-auto-import
// biome-ignore lint: disable
export {} export {}
declare global { declare global {
const EffectScope: typeof import('vue')['EffectScope'] const EffectScope: typeof import('vue')['EffectScope']
const ElMessage: typeof import('element-plus/es')['ElMessage']
const computed: typeof import('vue')['computed'] const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp'] const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef'] const customRef: typeof import('vue')['customRef']
@ -70,6 +72,6 @@ declare global {
// for type re-export // for type re-export
declare global { declare global {
// @ts-ignore // @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue' export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue') import('vue')
} }

1
frontend/components.d.ts

@ -74,6 +74,7 @@ declare module 'vue' {
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTransfer: typeof import('element-plus/es')['ElTransfer'] ElTransfer: typeof import('element-plus/es')['ElTransfer']
ElTree: typeof import('element-plus/es')['ElTree'] ElTree: typeof import('element-plus/es')['ElTree']
ElUpload: typeof import('element-plus/es')['ElUpload']
Error: typeof import('./src/components/taskbar/Error.vue')['default'] Error: typeof import('./src/components/taskbar/Error.vue')['default']
FileIcon: typeof import('./src/components/builtin/FileIcon.vue')['default'] FileIcon: typeof import('./src/components/builtin/FileIcon.vue')['default']
FileIconImg: typeof import('./src/components/builtin/FileIconImg.vue')['default'] FileIconImg: typeof import('./src/components/builtin/FileIconImg.vue')['default']

4
frontend/src/components/builtin/FileList.vue

@ -369,7 +369,7 @@ function handleRightClick(mouse: MouseEvent, item: OsFileWithoutContent, index:
}, },
]; ];
if (item.isShare && item.path.indexOf('/F/othershare') !== 0) { if (!item.isShare || item.path.indexOf('/F/othershare') !== 0) {
fileMenus.push({ fileMenus.push({
label: t('delete'), label: t('delete'),
click: async () => { click: async () => {
@ -385,7 +385,7 @@ function handleRightClick(mouse: MouseEvent, item: OsFileWithoutContent, index:
}) })
} }
const userType = sys.getConfig('userType'); const userType = sys.getConfig('userType');
if (userType == 'member' && !item.isShare) { if (userType == 'member' && !item.isShare && !item.isDirectory) {
menuArr.push( menuArr.push(
{ {

1
frontend/src/components/builtin/FileProps.vue

@ -79,6 +79,7 @@ const file = ref<OsFileWithoutContent | null>();
const path = window?.config.content const path = window?.config.content
if(path.indexOf('/F') === 0) { if(path.indexOf('/F') === 0) {
file.value = (await useSystem()?.fs.getShareInfo(path)).fi file.value = (await useSystem()?.fs.getShareInfo(path)).fi
// file.value.path = file.value.titleName || file.value.path
} else { } else {
file.value = await useSystem()?.fs.stat(path); file.value = await useSystem()?.fs.stat(path);
} }

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

@ -18,13 +18,27 @@
}; };
const data = ref(generateData()); const data = ref(generateData());
const users = ref([]); // users any[]
const users = ref<any[]>([]);
watchEffect(() => { watchEffect(() => {
if (store.allUserList.length > 0) { if (store.allUserList.length > 0) {
data.value = generateData(); data.value = generateData();
} }
}); });
function toggleSelectItem(item: any) {
const index = users.value.indexOf(item.key);
if (index === -1) {
users.value.push(item.key);
} else {
users.value.splice(index, 1);
}
}
function removeItem(userId: string) {
users.value = users.value.filter((user) => user !== userId);
}
</script> </script>
<template> <template>
<el-container class="container"> <el-container class="container">
@ -89,29 +103,78 @@
v-model="store.groupChatInvitedDialogVisible" v-model="store.groupChatInvitedDialogVisible"
title="发起群聊" title="发起群聊"
width="80%" width="80%"
align-center
> >
<div class="dialog-body"> <div class="dialog-body">
<!-- 添加输入部门名的输入框 --> <!-- 添加输入部门名的输入框 -->
<el-input <el-form
v-model="store.departmentName" label-position="top"
placeholder="请输入群聊名称"
></el-input>
<el-transfer
v-model="users"
:data="data"
> >
<!-- 义穿梭框 --> <el-form-item label="群聊名称:">
<template #default="{ option }"> <el-input
<div class="user-item"> style="width: 240px"
<el-avatar class="department-name"
:size="20" v-model="store.departmentName"
:src="option.avatar" placeholder="请输入群聊名称"
class="avatar" ></el-input>
/> </el-form-item>
<span>{{ option.label }}</span>
<el-upload>
</el-upload>
</el-form>
<div class="transfer-container">
<!-- 自定义穿梭框组件 -->
<div class="transfer-box">
<div class="list-box">
<h3>可选项</h3>
<ul>
<li
v-for="item in data"
:key="item.key"
@click="toggleSelectItem(item)"
:class="{ selected: users.includes(item.key) }"
>
<el-avatar
:size="10"
:src="item.avatar"
class="avatar"
/>
<input
type="checkbox"
:checked="users.includes(item.key)"
/>
<span>{{ item.label }}</span>
<span
v-if="users.includes(item.key)"
class="remove-icon"
@click.stop="removeItem(item.key)"
></span
>
</li>
</ul>
</div>
<div class="list-box">
<h3>已选项</h3>
<ul>
<li
v-for="user in users"
:key="user"
>
<span>{{
data.find((item: any) => item.key === user)
?.label
}}</span>
<span
class="remove-icon"
@click="removeItem(user)"
></span
>
</li>
</ul>
</div> </div>
</template> </div>
</el-transfer> </div>
</div> </div>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
@ -135,12 +198,12 @@
width: 100%; width: 100%;
overflow-y: hidden; overflow-y: hidden;
overflow-x: hidden; overflow-x: hidden;
border-top: 1px solid #e8e8e8;
} }
.menu { .menu {
width: 55px; width: 55px;
background-color: #ffffff;
background-color: #f0f0f0;
overflow-y: hidden; overflow-y: hidden;
overflow-x: hidden; overflow-x: hidden;
-webkit-app-region: drag; -webkit-app-region: drag;
@ -159,11 +222,14 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-evenly; justify-content: space-evenly;
width: 90%; width: 100%;
/* 占据整个宽度 */ /* 占据整个宽度 */
height: 50px; height: 50px;
padding: 0; padding: 0;
padding-right: 10px;
-webkit-app-region: drag; -webkit-app-region: drag;
border-bottom: 1px solid #e8e8e8;
border-left: 1px solid #e8e8e8;
} }
.inviteGroupChats { .inviteGroupChats {
width: 40px; width: 40px;
@ -192,27 +258,27 @@
.list { .list {
width: 100%; width: 100%;
height: 100%;
/* 占据整个宽度 */ /* 占据整个宽度 */
padding: 0; padding: 0;
overflow-y: hidden; overflow-y: hidden;
overflow-x: hidden; overflow-x: hidden;
border-left: 1px solid #e8e8e8;
/* border-right: 1px solid #E8E8E8; */
} }
.dialog-body { .dialog-body {
width: 100%; width: 100%;
} }
.transfer-container >>> .el-transfer-panel {
width: 300px;
}
.el-transfer { .el-transfer {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
/* .el-transfer >>> .el-transfer-panel >>> .el-transfer__buttons {
width: 50px;
} */
/* .el-transfer__button {
width: 20px;;
} */
.chat-box { .chat-box {
flex: 3; flex: 3;
/* 占据剩余宽度的三倍 */ /* 占据剩余宽度的三倍 */
@ -240,4 +306,55 @@
font-size: 14px; font-size: 14px;
justify-content: center; justify-content: center;
} }
.transfer-box {
display: flex;
gap: 0px;
}
.list-box {
width: 50%;
border-top: 1px solid #ccc;
margin-top: 10px;
}
.list-box ul {
list-style: none;
padding: 0;
margin: 0;
}
.list-box li {
display: flex;
align-items: center;
padding: 5px 0;
cursor: pointer;
transition: background-color 0.2s;
}
.list-box li:hover {
background-color: #f0f8ff;
}
.list-box li.selected {
background-color: #e6f7ff;
}
input[type="checkbox"] {
margin-right: 8px;
}
.remove-icon {
margin-left: auto;
color: #d32f2f;
cursor: pointer;
font-size: 14px;
}
.remove-icon:hover {
color: #ff5a5a;
}
.department-name {
margin: 10px 0;
}
</style> </style>

62
frontend/src/components/chat/ChatBox.vue

@ -6,12 +6,42 @@
<!--聊天顶部区--> <!--聊天顶部区-->
<el-header class="chat-header"> <el-header class="chat-header">
<div class="header-title"> <div class="header-title">
<span v-if="store.targetUserInfo.displayName">{{ <span
store.targetUserInfo.displayName v-if="store.targetUserInfo.displayName"
}}</span> class="header-title-name"
<span v-else-if="store.targetGroupInfo.displayName">{{ >{{ store.targetUserInfo.displayName }}</span
store.targetGroupInfo.displayName >
}}</span> <span
v-else-if="store.targetGroupInfo.displayName"
class="header-title-name"
>{{ store.targetGroupInfo.displayName }}</span
>
<!-- 更多 -->
<el-dropdown
placement="bottom"
v-if="
store.targetGroupInfo &&
Object.keys(store.targetGroupInfo).length > 0
"
>
<!-- 设置 -->
<el-icon><More /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="store.inviteFriend"
>邀请好友</el-dropdown-item
>
<el-dropdown-item
@click="
store.quitGroup(
store.targetGroupInfo.chatId
)
"
>退出群聊</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</div> </div>
</el-header> </el-header>
@ -96,13 +126,15 @@
const store: any = useChatStore(); const store: any = useChatStore();
const choose = useChooseStore(); const choose = useChooseStore();
const imgExt = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg"]; const imgExt = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg"];
const choosetype = ref("image"); const choosetype = ref("");
function selectImg() { function selectImg() {
choosetype.value = "image"; choosetype.value = "image";
console.log(choosetype.value)
choose.select("选择图片", imgExt); choose.select("选择图片", imgExt);
} }
function selectFile() { function selectFile() {
console.log("selectFile");
choosetype.value = "applyfile"; choosetype.value = "applyfile";
choose.select("选择文件", "*"); choose.select("选择文件", "*");
} }
@ -115,6 +147,7 @@
if (paths.length > 0) { if (paths.length > 0) {
store.sendInfo = paths; store.sendInfo = paths;
choose.path = []; choose.path = [];
console.log(choosetype.value);
store.sendMessage(choosetype.value); store.sendMessage(choosetype.value);
} }
}, },
@ -137,10 +170,17 @@
-webkit-app-region: drag; -webkit-app-region: drag;
} }
header-title { .header-title {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0px 10px;
}
.header-title-name {
height: 50px;
line-height: 50px;
font-size: 20px; font-size: 20px;
text-align: left;
margin-left: 15px;
} }
.msg-main { .msg-main {
@ -156,6 +196,7 @@
border-style: solid; border-style: solid;
} }
.msg-footer { .msg-footer {
width: 100%; width: 100%;
/* 占据整个宽度 */ /* 占据整个宽度 */
@ -237,7 +278,6 @@
} }
.no-message-container { .no-message-container {
height: 100%;
margin: 120px auto; margin: 120px auto;
text-align: center; text-align: center;
justify-content: center; justify-content: center;

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

@ -82,7 +82,7 @@ const store = useChatStore();
<style scoped> <style scoped>
.userAvatar { .userAvatar {
margin: 30px auto 10px; margin: 6px auto;
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
} }
@ -93,13 +93,12 @@ const store = useChatStore();
width: 40px; width: 40px;
height: 40px; height: 40px;
margin: 10px auto; margin: 10px auto;
border-radius: 15%; /* border-radius: 15%; */
/* background-color: #bae7ff; */
transition: all 0.5s; transition: all 0.5s;
} }
.menu-icon-box:hover { /* .menu-icon-box:hover {
background-color: #d9d9d9; background-color: #d9d9d9;
} } */
.menu-icon { .menu-icon {
margin: 0px auto; margin: 0px auto;
@ -110,7 +109,7 @@ const store = useChatStore();
.menu-icon-on { .menu-icon-on {
margin: 0px auto; margin: 0px auto;
font-size: 25px; font-size: 25px;
color: #1890ff; color: #2A6BF2;
cursor: pointer; cursor: pointer;
} }
</style> </style>

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

@ -2,10 +2,10 @@
<div <div
v-if="store.chatHistory && store.chatHistory.length > 0" v-if="store.chatHistory && store.chatHistory.length > 0"
v-for="item in store.chatHistory" v-for="item in store.chatHistory"
:key="item.time" :key="item.chatId"
> >
<div <div
v-if="item.userId == store.userInfo.id" v-if="item.isMe"
class="chat-item" class="chat-item"
> >
<el-row> <el-row>
@ -14,19 +14,54 @@
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<div class="chat-name-me"> <div class="chat-name-me">
{{ item.userInfo.nickname }} {{ store.userInfo.nickname }}
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<div <div
class="bubble-me" class="bubble-me"
@contextmenu.prevent=" @contextmenu.prevent="
store.showContextMenu($event, item.userId) store.showContextMenu($event, item.chatId)
" "
> >
<div class="chat-font"> <!-- 文本消息展示 -->
<div
v-if="item.content_type == 'text'"
class="chat-font"
>
{{ item.message }} {{ item.message }}
</div> </div>
<!-- 文件消息展示 -->
<div
v-else-if="item.content_type == 'file'"
:class="['chat-item-file', 'file-me']"
>
<!-- 文件图标 -->
<div class="chat-item-file-icon">
<el-icon
size="30"
color="#303133"
><Document
/></el-icon>
</div>
<!-- 文件名 -->
<div class="chat-item-file-name">
{{ item.message }}
</div>
</div>
<!-- 图片消息展示 -->
<div
v-else-if="item.content_type == 'image'"
class="chat-item-image"
>
<el-image
fit="cover"
loading="lazy"
:src="item.message"
/>
</div>
</div> </div>
</el-col> </el-col>
<el-col :span="2"> <el-col :span="2">
@ -36,7 +71,7 @@
style="margin: 0; float: left" style="margin: 0; float: left"
:size="32" :size="32"
class="userAvatar" class="userAvatar"
:src="item.userInfo.avatar" :src="item.avatar"
/> />
</div> </div>
</el-col> </el-col>
@ -54,7 +89,7 @@
style="margin: 0; float: right" style="margin: 0; float: right"
:size="32" :size="32"
class="userAvatar" class="userAvatar"
:src="item.userInfo.avatar" :src="item.avatar"
/> />
</div> </div>
</el-col> </el-col>
@ -62,14 +97,49 @@
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<div class="chat-name-other"> <div class="chat-name-other">
{{ item.userInfo.nickname }} {{ item.displayName }}
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<div class="bubble-other"> <div class="bubble-other">
<div class="chat-font"> <!-- 文本消息展示 -->
<div
v-if="item.content_type == 'text'"
class="chat-font"
>
{{ item.message }} {{ item.message }}
</div> </div>
<!-- 文件消息展示 -->
<div
v-else-if="item.content_type == 'file'"
:class="['chat-item-file', 'file-other']"
>
<!-- 文件图标 -->
<div class="chat-item-file-icon">
<el-icon
size="30"
color="#303133"
><Document
/></el-icon>
</div>
<!-- 文件名 -->
<div class="chat-item-file-name">
{{ item.message }}
</div>
</div>
<!-- 图片消息展示 -->
<div
v-else-if="item.content_type == 'image'"
class="chat-item-image"
>
<el-image
fit="cover"
loading="lazy"
:src="item.message"
/>
</div>
</div> </div>
</el-col> </el-col>
<el-col :span="8" /> <el-col :span="8" />
@ -107,22 +177,22 @@
</script> </script>
<style scoped> <style scoped>
.bubble-me { .bubble-me,
background-color: #95ec69;
float: right;
border-radius: 4px;
margin-right: 5px;
margin-top: 5px;
padding: 5px;
}
.bubble-other { .bubble-other {
display: flex;
align-items: center;
background-color: #ffffff; background-color: #ffffff;
float: left; float: left;
border-radius: 4px; border-radius: 4px;
margin-left: 5px; margin-left: 5px;
margin-top: 5px; margin-bottom: 20px;
padding: 5px; }
.bubble-me {
background-color: #95ec69;
float: right;
margin-right: 5px;
margin-left: 0;
} }
.chat-name-me, .chat-name-me,
@ -131,12 +201,51 @@
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
line-height: 1.5; line-height: 1.5;
color: #b2b2b2; color: #b2b2b2;
margin-bottom: 2px;
margin-left: 2px;
}
.chat-name-me {
text-align: right; /* 右对齐昵称 */
margin-right: 2px;
} }
.chat-font { .chat-font {
margin: 8px;
font-size: 15px; font-size: 15px;
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
line-height: 1.5; line-height: 1.5;
margin: 10px;
}
.chat-item-file {
border-radius: 4px;
display: flex;
align-items: center;
justify-content: space-between;
margin: 10px;
}
.file-me {
flex-direction: row; /* 图标在左边 */
}
.file-other {
flex-direction: row-reverse; /* 图标在右边 */
}
.chat-item-file-icon {
width: 40px;
}
.chat-item-file-name {
font-size: 14px;
font-family: Arial, sans-serif;
line-height: 1.5;
color: #409eff;
}
.chat-item-image {
width: 180px;
height: 180px;
margin: 10px;
} }
</style> </style>

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

@ -1,70 +1,89 @@
<template> <template>
<div v-if="store.chatList.length > 0" v-for="item in store.chatList" :key="item.id"> <div
<div v-if="store.chatList.length > 0"
class="list-item" v-for="item in store.chatList"
@click="store.changeChatList(item.chatId,item.type)" :key="item.id"
:style="{ >
backgroundColor: item.userId == store.targetChatId ? '#bae7ff' : '', <div
}" class="list-item"
> @click="store.getSessionInfo(item.chatId, item.type)"
<el-row> :style="{
<el-col :span="6"> backgroundColor:
<el-avatar item.chatId == store.targetChatId ? '#EAF3FC' : '',
shape="square" }"
:size="40" >
class="avatar" <el-row>
:src="item.avatar" <el-col :span="6">
/> <el-avatar
</el-col> shape="square"
<el-col :span="18" class="preview"> :size="40"
<el-row class="preview-content"> class="avatar"
<el-col :span="18" class="preview-left"> :src="item.avatar"
<div class="previewName">{{ item.displayName }}</div> />
<div class="previewChat"> </el-col>
<span>{{ item.previewMessage }}</span> <el-col
:span="18"
</div> class="preview"
</el-col> >
<el-col :span="6" class="preview-right"> <el-row class="preview-content">
<div class="previewTime"> <el-col
{{ item.previewTimeFormat }} :span="18"
</div> class="preview-left"
</el-col> >
</el-row> <div class="previewName">
</el-col> {{ item.displayName }}
</el-row> </div>
</div> <div class="previewChat">
</div> <span>{{ item.previewMessage }}</span>
<div v-else class="emptyChat"> </div>
<el-icon :size="60" class="chat-icon"> </el-col>
<ChatSquare /> <el-col
</el-icon> :span="6"
<p class="empty-message">暂无数据</p> class="preview-right"
</div> >
<div class="previewTime">
{{ item.previewTimeFormat }}
</div>
</el-col>
</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> </template>
<script setup> <script setup>
import { useChatStore } from "@/stores/chat"; import { useChatStore } from "@/stores/chat";
import { ref } from "vue"; import { ref } from "vue";
const store = useChatStore();
const id = ref("1");
const store = useChatStore();
const id = ref("1");
</script> </script>
<style scoped> <style scoped>
.list-item { .list-item {
width: 94%; width: 100%;
height: 60px; height: 60px;
display: flex; display: flex;
margin: 0 auto; margin: 0 auto;
border-radius: 4px; transition: all 0.5s;
transition: all 0.5s; overflow: hidden;
margin-top: 5px;
} }
.list-item:hover { .list-item:hover {
background-color: #bae7ff; background-color: #eaf3fc;
} }
.avatar { .avatar {
@ -106,7 +125,7 @@ const id = ref("1");
} }
.previewChat { .previewChat {
height: 20px; height: 20px;
margin-left: 10px; margin-left: 10px;
font-size: 10px; font-size: 10px;
font-family: Arial, sans-serif; font-family: Arial, sans-serif;

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

@ -49,9 +49,9 @@
<el-collapse-item name="1"> <el-collapse-item name="1">
<template #title> <template #title>
<span <span
v-if="store.userList.length > 0" v-if="store.onlineUserList.length > 0"
class="title" class="title"
>在线{{ store.userList.length }}</span >在线{{ store.onlineUserList.length }}</span
> >
<span <span
v-else v-else
@ -59,15 +59,14 @@
>在线</span >在线</span
> >
</template> </template>
<div v-if="store.userList.length > 0"> <div v-if="store.onlineUserList.length > 0">
<div <div
v-for="item in store.userList" v-for="item in store.onlineUserList"
:key="item.id" :key="item.id"
> >
<div <div
class="list-item" class="list-item"
@click="store.changeChatList(item.id,'user')" @click="store.getSessionInfo(item.chatId, 'user')"
:style="{ :style="{
backgroundColor: backgroundColor:
item.id === store.targetChatId ? '#bae7ff' : '', item.id === store.targetChatId ? '#bae7ff' : '',
@ -109,6 +108,7 @@
</div> </div>
</div> </div>
</div> </div>
<div v-else> <div v-else>
<p class="no-data">暂无数据</p> <p class="no-data">暂无数据</p>
</div> </div>
@ -139,34 +139,7 @@
@node-click="handleNodeClick" @node-click="handleNodeClick"
:default-expand-all="false" :default-expand-all="false"
> >
<!-- <template #default="{ node, data }">
<div
class="list-item"
@click="store.changeGroupList(data)"
:style="{
backgroundColor:
data.dept_id === store.targetGroupId
? '#C4C4C4'
: '',
}"
>
<el-row>
<el-col :span="6">
<el-avatar
shape="square"
:size="40"
class="avatar"
:src="data.avatar || ''"
/>
</el-col>
<el-col :span="18">
<div class="preview-name">
{{ data.dept_name }}
</div>
</el-col>
</el-row>
</div>
</template> -->
</el-tree> </el-tree>
</div> </div>
@ -174,6 +147,54 @@
<p class="no-data">暂无数据</p> <p class="no-data">暂无数据</p>
</div> </div>
</el-collapse-item> </el-collapse-item>
<el-collapse-item name="3">
<template #title>
<span
v-if="store.groupList.length > 0"
class="title"
>群组{{ store.groups.length }}</span
>
<span
v-else
class="title"
>群组</span
>
</template>
<div v-if="store.groupList.length > 0">
<div
v-for="group in store.groups"
:key="group.id"
>
<div
class="list-item"
@click="store.getSessionInfo(group.id, 'group')"
:style="{
backgroundColor:
group.id === store.targetChatId
? '#bae7ff'
: '',
}"
>
<el-row>
<el-col :span="6">
<el-avatar
shape="square"
:size="40"
class="avatar"
:src="group.avatar"
/>
</el-col>
<el-col :span="18">
<div class="previewName">{{ group.name }}</div>
</el-col>
</el-row>
</div>
</div>
</div>
<div v-else>
<p class="no-data">暂无数据</p>
</div>
</el-collapse-item>
</el-collapse> </el-collapse>
</template> </template>
@ -191,7 +212,7 @@
} }
.list-item:hover { .list-item:hover {
/* background-color: #bae7ff; */ background-color: #bae7ff;
} }
.avatar { .avatar {

94
frontend/src/components/chat/ChatUserSetting.vue

@ -2,7 +2,8 @@
import { t } from '@/i18n'; import { t } from '@/i18n';
import { ref, onMounted } from "vue"; import { ref, onMounted } from "vue";
import { useChatStore } from "@/stores/chat"; import { useChatStore } from "@/stores/chat";
import { fetchGet, getSystemConfig } from "@/system/config"; import { notifyError, notifySuccess } from "@/util/msg";
import { fetchGet, getSystemConfig, setSystemKey } from "@/system/config";
const store = useChatStore() const store = useChatStore()
const form = ref({ const form = ref({
nickname: '', nickname: '',
@ -10,37 +11,49 @@ const form = ref({
const userInfo = getSystemConfig().userInfo const userInfo = getSystemConfig().userInfo
const dialogShow = ref(false) const dialogShow = ref(false)
let imgList = reactive([]) let imgList = reactive([])
let pos = ref(0)
const showChange = (val) =>{ const showChange = (val) =>{
dialogShow.value = val dialogShow.value = val
} }
const toChangeHead = ()=>{ const toChangeHead = async ()=>{
console.log('换头像'); let res = await fetchGet(`${userInfo.url}/files/saveavatar?id=${userInfo.id}&name=${imgList[pos.value].name}`)
console.log('submit!:',res)
if (!res.ok) {
notifyError("头像换取失败")
} else {
res = await res.json()
notifySuccess(res.message)
userInfo.avatar = imgList[pos.value].name
store.userInfo.avatar = userInfo.url + '/upload/avatar/' + userInfo.avatar
setSystemKey('userInfo', userInfo)
}
showChange(false)
} }
// //
const getHeadList = async() => { const getHeadList = async () => {
const res = await fetchGet(`${userInfo.url}/files/avatarlist`) let res = await fetchGet (`${userInfo.url}/files/avatarlist`)
// const apiUrl = getSystemConfig().apiUrl + '/upload/avatar/';
const apiUrl = userInfo.url + '/upload/avatar/';
if (res.ok) { if (res.ok) {
imgList = await res.json() res = await res.json()
imgList = imgList.data.map(item => { for (const item of res.data) {
item.isChoose = false imgList.push({
return item url: apiUrl + item,
}) name: item
imgList[0].isChoose = true })
}
} }
console.log('imgList:' , imgList);
} }
let pos = ref(0)
// //
const chooseImg = (index) => { const chooseImg = (index) => {
imgList.forEach(item => item.isChoose = false)
imgList[index].isChoose = true
pos.value = index pos.value = index
} }
const onSubmit = () => { const onSubmit = async () => {
console.log('submit!') console.log('提交');
} }
onMounted(()=>{ onMounted(()=>{
getHeadList() getHeadList()
store.userInfo.avatar = userInfo.url + '/upload/avatar/' + userInfo.avatar
}) })
</script> </script>
<template> <template>
@ -67,13 +80,20 @@ onMounted(()=>{
</el-form> </el-form>
<el-dialog v-model="dialogShow" title="修改头像" width="500px" draggable> <el-dialog v-model="dialogShow" title="修改头像" width="500px" draggable>
<div> <div>
<el-avatar <span
v-for="(item, index) in imgList" v-for="(item, index) in imgList"
:key="item.name" :key="item.name"
:size="90" class="img-box"
:src="item.url" >
:class="{'is-active': item.isChoose}" <el-avatar
@click="chooseImg(index)"/> :size="80"
:src="item.url"
@click="chooseImg(index)"
:class="{'is-active': pos == index}"
>
</el-avatar>
<el-icon v-show="pos == index"><Select /></el-icon>
</span>
</div> </div>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
@ -89,12 +109,28 @@ onMounted(()=>{
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.el-avatar { .img-box {
margin: 10px; position: relative;
} .el-avatar {
.is-active { margin: 10px;
width: 100px; }
height: 100px; .is-active {
border: 2px solid red; width: 90px;
height: 90px;
border: 2px solid green;
box-sizing: border-box;
}
.el-icon {
position: absolute;
bottom: 0;
left: 50%;
width: 25px;
height: 25px;
border-radius: 50%;
color: white;
background-color: green;
transform: translate(-50%,0)
}
} }
</style> </style>

6
frontend/src/components/chat/chatUserInfo.vue

@ -16,7 +16,7 @@
class="user-info-container" class="user-info-container"
> >
<div class="user-details"> <div class="user-details">
<p>昵称: {{ store.targetUserInfo.nickname }}</p> <p>昵称: {{ store.targetUserInfo.displayName }}</p>
<p>邮箱: {{ store.targetUserInfo.email }}</p> <p>邮箱: {{ store.targetUserInfo.email }}</p>
<p>电话: {{ store.targetUserInfo.phone }}</p> <p>电话: {{ store.targetUserInfo.phone }}</p>
<p>描述: {{ store.targetUserInfo.desc }}</p> <p>描述: {{ store.targetUserInfo.desc }}</p>
@ -37,9 +37,9 @@
const store = useChatStore(); const store = useChatStore();
const sendMessage = (userId:number) => { const sendMessage = (chatId: string) => {
store.currentNavId = 0; store.currentNavId = 0;
store.changeChatListAndGetChatHistory(userId) store.addChatListAndGetChatHistory(chatId);
}; };
</script> </script>

11
frontend/src/components/computer/Computer.vue

@ -175,7 +175,16 @@ const { refersh, createFolder, backFolder, openFolder, onComputerMount } = useCo
return file.isDirectory; return file.isDirectory;
}, },
// //
readShareDir(path){ async readShareDir(path){
// let file: OsFileWithoutContent
// if (type === 'path') {
// file = await system.fs.getShareInfo(params)
// file = file.fi
// file.path = turnLocalPath(file.path, currentPath, 1)
// } else {
// file = params
// }
// return system.fs.readShareFileDir(getSystemConfig().userInfo.id, file)
return system.fs.readShareFileDir(getSystemConfig().userInfo.id, path) return system.fs.readShareFileDir(getSystemConfig().userInfo.id, path)
}, },
notify(title, content) { notify(title, content) {

1
frontend/src/components/desktop/LockDesktop.vue

@ -121,6 +121,7 @@ onMounted(() => {
}); });
async function onLogin() { async function onLogin() {
localStorage.removeItem("godoosClientId");
if (loginCallback) { if (loginCallback) {
const res = await loginCallback(userName.value, userPassword.value); const res = await loginCallback(userName.value, userPassword.value);
if (res) { if (res) {

9
frontend/src/components/oa/ShareFiles.vue

@ -21,14 +21,14 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, inject } from 'vue'; import { ref, inject, onMounted } from 'vue';
import { useSystem, BrowserWindow } from '@/system'; import { useSystem, BrowserWindow } from '@/system';
import { getSystemConfig, fetchPost } from "@/system/config"; import { getSystemConfig, fetchPost } from "@/system/config";
import { notifySuccess, notifyError } from "@/util/msg"; import { notifySuccess, notifyError } from "@/util/msg";
const window: BrowserWindow | undefined = inject("browserWindow"); const window: BrowserWindow | undefined = inject("browserWindow");
const sys = useSystem() const sys = useSystem()
const userInfo: any = sys.getConfig('userInfo') const userInfo: any = sys.getConfig('userInfo')
const userList = ref(userInfo.user_shares) let userList = ref(userInfo.user_shares)
const checkAll = ref(false) const checkAll = ref(false)
const form: any = ref({ const form: any = ref({
senderid: '', senderid: '',
@ -68,6 +68,11 @@ const onSubmit = async () => {
notifyError("分享文件失败") notifyError("分享文件失败")
} }
} }
onMounted(() => {
userList.value = userList.value.filter((item: any)=> {
return item?.id !== config.value.userInfo.id
})
})
</script> </script>
<style scoped> <style scoped>
.btn-group{ .btn-group{

40
frontend/src/hook/useComputer.ts

@ -33,6 +33,8 @@ export const useComputer = (adpater: {
}; };
const refersh = async () => { const refersh = async () => {
const currentPath = adpater.getRouter(); const currentPath = adpater.getRouter();
//console.log('refresh:', currentPath);
if (!currentPath) return; if (!currentPath) return;
if (currentPath.startsWith('search:')) { if (currentPath.startsWith('search:')) {
const keyword = currentPath.substr(7); const keyword = currentPath.substr(7);
@ -41,16 +43,37 @@ export const useComputer = (adpater: {
return; return;
} }
if (!(await isVia(currentPath))) return; if (!(await isVia(currentPath))) return;
// console.log('use computer refresh:', currentPath);
let result let result
if (currentPath === '/F/myshare' || currentPath === '/F/othershare') { if (currentPath === '/F/myshare' || currentPath === '/F/othershare') {
result = await adpater.sharedir(currentPath) result = await adpater.sharedir(currentPath)
} else if (currentPath.indexOf('/F') === 0) {
// result = await adpater.readShareDir(file?.path || currentPath)
result = await adpater.readShareDir(currentPath)
} else { } else {
result = await adpater.readdir(currentPath); result = await adpater.readdir(currentPath);
} }
// else if (currentPath.indexOf('/F') === 0) {
// //判断是否是回退
// // console.log('currentPath:', currentPath);
// if (offset && offset === -1) {
// const parentPath = useShareFile().CurrentFile?.parentPath
// //console.log('回退:',parentPath);
// result = await adpater.readShareDir('path', parentPath, currentPath)
// } else {
// result = await adpater.readShareDir('file',file)
// }
// // 查找文件回退的路径
// // const arr = useShareFile().getShareFile()
// // file = arr?.find(item => {
// // return item.titleName === currentPath
// // })
// // console.log('file:',arr,currentPath, file);
// // if (!file) {
// // const parentPath = useShareFile().CurrentFile?.parentPath
// // console.log('回退:',parentPath);
// // result = await adpater.readShareDir('path', parentPath, currentPath)
// // } else {
// // result = await adpater.readShareDir('file',file)
// // }
// }
if (result) adpater.setFileList(result); if (result) adpater.setFileList(result);
}; };
const createFolder = (path: RouterPath) => { const createFolder = (path: RouterPath) => {
@ -72,10 +95,11 @@ export const useComputer = (adpater: {
}; };
const openFolder = (file: OsFileWithoutContent) => { const openFolder = (file: OsFileWithoutContent) => {
if (adpater.isDirectory(file)) { if (adpater.isDirectory(file)) {
// const path = file?.isShare ? file.titleName : file.path // console.log('文件:',file);
const path = file.path // const path = file?.isShare ? turnLocalPath(file.titleName, file.root) : file.path
adpater.setRouter(path); // console.log('路径:', path);
refersh(file); adpater.setRouter(file.path);
refersh();
} else { } else {
adpater.openFile(file.path); adpater.openFile(file.path);
} }

837
frontend/src/stores/chat.ts

File diff suppressed because it is too large

42
frontend/src/stores/db.ts

@ -1,35 +1,37 @@
import Dexie from 'dexie'; import Dexie from 'dexie';
export type ChatTable = 'chatuser' | 'chatmsg' | 'chatmessage' | 'groupmessage' | 'chatRecord' | 'workbenchusers' | 'conversationList' | 'group' | 'groupMembers' | 'groupChatList' | 'groupChatRecord'; export type ChatTable = 'chatuser' | 'chatmsg' | 'workbenchChatRecord' | 'workbenchChatUser' | 'workbenchSessionList' | 'groupSessionList' | 'workbenchGroupChatRecord' | 'workbenchGroupUserList';
export const dbInit: any = new Dexie('GodoOSDatabase'); export const dbInit: any = new Dexie('GodoOSDatabase');
dbInit.version(1).stores({ dbInit.version(1).stores({
// 用户列表 // 用户列表
workbenchusers: '++id,ip,userName,avatar,mobile,phone,nickName,isOnline,updatedAt,createdAt', workbenchChatUser: '++id,ip,userName,chatId,avatar,mobile,phone,nickName,isOnline,updatedAt,createdAt',
// 聊天记录
chatRecord: '++id,toUserId,messages,messageType,time,createdAt,userInfo',
// 会话列表 // 会话列表
conversationList: '++id,avatar,chatId,username,nickname,userId,toUserId,previewMessage,messages,time,createdAt', workbenchSessionList: '++id,avatar,chatId,username,nickname,userId,toUserId,previewMessage,messages,time,createdAt',
// 聊天记录
workbenchChatRecord: '++id,toUserId,messages,messageType,time,createdAt,userInfo',
// 群组会话列表
groupSessionList: '++id,groupId,name,message,previewMessage,avatar,createdAt',
// 群组聊天记录
workbenchGroupChatRecord: '++id,chatId,userId,to_groupid,messageType,userInfo,message,time,type,createdAt',
// 群用户列表
workbenchGroupUserList: '++id, group_id, createdAt, userIdArray',
// 用户列表
chatuser: '++id,ip,hostname,userName,avatar,mobile,nickName,isOnline,updatedAt,createdAt', chatuser: '++id,ip,hostname,userName,avatar,mobile,nickName,isOnline,updatedAt,createdAt',
chatmsg: '++id,toUserId,targetIp,senderInfo,reciperInfo,previewMessage,content,type,status,isRead,isMe,readAt,createdAt', chatmsg: '++id,toUserId,targetIp,senderInfo,reciperInfo,previewMessage,content,type,status,isRead,isMe,readAt,createdAt',
chatmessage: '++id,userId,toUserId,senderInfo,isMe,isRead,content,type,readAt,createdAt',
groupChatRecord: '++id,userId,groupId,messageType,userInfo,message,time,type,createdAt',
// 群组表
group: '++id,avatar,name,groupId,creator,createdAt',
// 群成员表
groupMembers: '++id,userId,groupTableId,groupId,createdAt',
// 群会话列表
groupChatList: '++id,groupId,name,message,previewMessage,avatar,createdAt',
}).upgrade((tx: { }).upgrade((tx: {
conversationList: any; workbenchSessionList: any;
group: any; workbenchChatUser: any;
chatRecord: { addIndex: (arg0: string, arg1: (obj: { toUserId: any; }) => any) => void; }; workbenchGroupChatRecord: any;
workbenchGroupUserList: any;
workbenchChatRecord: { addIndex: (arg0: string, arg1: (obj: { toUserId: any; }) => any) => void; };
}) => { }) => {
// 手动添加索引 // 手动添加索引
tx.conversationList.addIndex('userId', (obj: { userId: any; }) => obj.userId); tx.workbenchSessionList.addIndex('userId', (obj: { userId: any; }) => obj.userId);
tx.chatRecord.addIndex('toUserId', (obj: { toUserId: any; }) => obj.toUserId); tx.workbenchChatRecord.addIndex('toUserId', (obj: { toUserId: any; }) => obj.toUserId);
tx.group.addIndex('groupId', (obj: { groupId: any }) => obj.groupId); // 添加索引: 群主 ID tx.workbenchChatUser.addIndex('chatId', (obj: { chatId: any; }) => obj.chatId);
tx.workbenchGroupChatRecord.addIndex('chatId', (obj: { chatId: any; }) => obj.chatId);
tx.workbenchGroupUserList.addIndex('group_id', (obj: { group_id: any; }) => obj.group_id);
}); });
export const db = { export const db = {

36
frontend/src/stores/file.ts

@ -0,0 +1,36 @@
import { defineStore } from 'pinia'
import { OsFileWithoutContent } from '@/system/core/FileSystem';
export const useShareFile = defineStore('shareFile', () =>{
const currentShareFile = ref<OsFileWithoutContent[]>([]);
let CurrentFile = ref<OsFileWithoutContent>();
const setShareFile = (file: OsFileWithoutContent[]) => {
currentShareFile.value = file
//console.log('存储文件:', currentShareFile);
}
const setCurrentFile = (file: OsFileWithoutContent) => {
CurrentFile.value = file
//console.log('当前文件:', CurrentFile.value);
}
const getShareFile = (): OsFileWithoutContent[] | null =>{
return currentShareFile.value
}
const findServerPath = (titleName: string): OsFileWithoutContent | string => {
//console.log('查找文件:',getShareFile());
let result = currentShareFile.value.find(item =>{
return item.titleName === titleName
})
if (!result) {
//console.log('回退茶砸后:',currentShareFile.value[0]);
return currentShareFile.value[0].parentPath
}
return result
}
return {
setShareFile,
setCurrentFile,
getShareFile,
findServerPath,
currentShareFile,
CurrentFile
}
})

170
frontend/src/stores/notify.ts

@ -1,97 +1,97 @@
import { fetchGet, getSystemConfig } from "@/system/config";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { ref } from "vue"; import { ref } from "vue";
import { getSystemConfig, fetchGet } from "@/system/config";
import { useUpgradeStore } from "./upgrade"; import { useUpgradeStore } from "./upgrade";
export const useNotifyStore = defineStore('notifyStore', () => { export const useNotifyStore = defineStore('notifyStore', () => {
const config = getSystemConfig(); const config = getSystemConfig();
const upgradeStore = useUpgradeStore() const upgradeStore = useUpgradeStore()
const notifyList: any = ref([]); const notifyList: any = ref([]);
const readList: any = ref([]) const readList: any = ref([])
const showNews = ref(false) const showNews = ref(false)
const newsDetail = ref({}) const newsDetail = ref({})
const page = ref({ const page = ref({
current: 1, current: 1,
size: 10, size: 10,
total: 0, total: 0,
pages: 0, pages: 0,
}) })
async function getList() { async function getList() {
if (config.userType == 'person') { if (config.userType == 'person') {
return return
}
const complition = await fetchGet(config.userInfo.url + '/news/list?page=' + page.value.current + '&limit=' + page.value.size)
if (!complition.ok) {
return;
}
const data = await complition.json();
if (data.success) {
page.value.total = data.data.total;
notifyList.value = data.data.list;
page.value.pages = Math.ceil(page.value.total / page.value.size)
checkNotify()
}
} }
const checkNotify = ()=> { const complition = await fetchGet(config.userInfo.url + '/news/list?page=' + page.value.current + '&limit=' + page.value.size)
const list = notifyList.value.filter((item: any) => { if (!complition.ok) {
return readList.value.indexOf(item.id) < 0 return;
})
if(list.length < 1)return;
const centerList = list.filter((item: any) => {
return item.position == 'center'
})
const bottomList = list.filter((item: any) => {
return item.position == 'bottom'
})
if(centerList.length > 0){
upgradeStore.hasAd = true
upgradeStore.adList = [...centerList, ...upgradeStore.adList]
}
if(bottomList.length > 0){
upgradeStore.hasNotice = true
upgradeStore.noticeList = [...bottomList, ...upgradeStore.noticeList]
}
} }
const addRead = (id: number) => { const data = await complition.json();
if (readList.value.indexOf(id) < 0) { if (data.success) {
readList.value.push(id) page.value.total = data.data.total;
} notifyList.value = data.data.list;
page.value.pages = Math.ceil(page.value.total / page.value.size)
checkNotify()
} }
const pageClick = async (pageNum: any) => {
//console.log(pageNum) }
page.value.current = pageNum const checkNotify = () => {
await getList() const list = notifyList.value.filter((item: any) => {
return readList.value.indexOf(item.id) < 0
})
if (list.length < 1) return;
const centerList = list.filter((item: any) => {
return item.position == 'center'
})
const bottomList = list.filter((item: any) => {
return item.position == 'bottom'
})
if (centerList.length > 0) {
upgradeStore.hasAd = true
upgradeStore.adList = [...centerList, ...upgradeStore.adList]
} }
const viewContent = (item :any) =>{ if (bottomList.length > 0) {
const timestamp = item.add_time * 1000; // 将 10 位时间戳转换为 13 位 upgradeStore.hasNotice = true
const date = new Date(timestamp); upgradeStore.noticeList = [...bottomList, ...upgradeStore.noticeList]
item.showtime = date.toLocaleString();
newsDetail.value = item
addRead(item.id)
showNews.value = true
} }
return {
notifyList, }
showNews, const addRead = (id: number) => {
newsDetail, if (readList.value.indexOf(id) < 0) {
getList, readList.value.push(id)
addRead,
page,
pageClick,
readList,
viewContent
} }
}
const pageClick = async (pageNum: any) => {
//console.log(pageNum)
page.value.current = pageNum
await getList()
}
const viewContent = (item: any) => {
const timestamp = item.add_time * 1000; // 将 10 位时间戳转换为 13 位
const date = new Date(timestamp);
item.showtime = date.toLocaleString();
newsDetail.value = item
addRead(item.id)
showNews.value = true
}
return {
notifyList,
showNews,
newsDetail,
getList,
addRead,
page,
pageClick,
readList,
viewContent
}
}, { }, {
persist: { persist: {
enabled: true, enabled: true,
strategies: [ strategies: [
{ {
storage: localStorage, storage: localStorage,
paths: [ paths: [
"readList", "readList",
] ]
}, // name 字段用localstorage存储 }, // name 字段用localstorage存储
], ],
} }
}) })

22
frontend/src/stores/upgrade.ts

@ -68,20 +68,6 @@ export const useUpgradeStore = defineStore('upgradeStore', () => {
}; };
} }
// 获取用户聊天消息
function userChatMessage() {
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) { async function handleMessage(message: any) {
switch (message.type) { switch (message.type) {
@ -92,12 +78,13 @@ export const useUpgradeStore = defineStore('upgradeStore', () => {
localChatStore.handlerMessage(message.data) localChatStore.handlerMessage(message.data)
break; break;
case 'online': case 'online':
chatChatStore.handleUserData(message.data) chatChatStore.onlineUserData(message.data)
break; break;
case 'user': case 'user':
chatChatStore.userChatMessage(message.data) chatChatStore.userChatMessage(message.data)
break break
case 'group': case 'group':
console.log(message)
chatChatStore.groupChatMessage(message.data); chatChatStore.groupChatMessage(message.data);
break; break;
default: default:
@ -105,7 +92,7 @@ export const useUpgradeStore = defineStore('upgradeStore', () => {
} }
} }
async function checkUpdate(res: any) { async function checkUpdate(res: any) {
//console.log(res) console.log(res)
if (!res) return if (!res) return
const config = getSystemConfig(); const config = getSystemConfig();
if (!config.account.ad) return; if (!config.account.ad) return;
@ -142,7 +129,6 @@ export const useUpgradeStore = defineStore('upgradeStore', () => {
list.forEach((item: any) => { list.forEach((item: any) => {
if (item.img && item.img.indexOf('http') == -1) { if (item.img && item.img.indexOf('http') == -1) {
item.img = `https://godoos.com${item.img}` item.img = `https://godoos.com${item.img}`
} }
}); });
return list return list
@ -202,7 +188,7 @@ export const useUpgradeStore = defineStore('upgradeStore', () => {
checkUpdate, checkUpdate,
systemMessage, systemMessage,
onlineMessage, onlineMessage,
userChatMessage, // userChatMessage,
update update
} }
}) })

31
frontend/src/system/core/FileOs.ts

@ -253,16 +253,17 @@ export const useOsFile = () => {
return { return {
// 分享 // 分享
async sharedir(id: number, path: string) { async sharedir(id: number, path: string) {
// console.log('是否是根:', isRootShare(path),path);
const fun = isRootShare(path) ? handleReadShareDir : handleShareDir const fun = isRootShare(path) ? handleReadShareDir : handleShareDir
const response = await fun(id, path); const response = await fun(id, path);
if (response && response.data) { if (response && response.data) {
return response.data.map((item: {[key: string]: OsFile}) => { const result = response.data.map((item: {[key: string]: OsFile}) => {
item.fi.isShare = true item.fi.isShare = true
item.fi.parentPath = turnLocalPath(item.fi.parentPath ,path)
item.fi.path = turnLocalPath(item.fi.path ,path) item.fi.path = turnLocalPath(item.fi.path ,path)
// item.fi.titleName = turnLocalPath(item.fi.titleName, path) //item.fi.titleName = turnLocalPath(item.fi.titleName, path)
return item.fi return item.fi
}) })
return result
} }
return []; return [];
}, },
@ -273,16 +274,26 @@ export const useOsFile = () => {
} }
return []; return [];
}, },
//分享文件夹取消
async readShareFileDir(id: number, path: string) { async readShareFileDir(id: number, path: string) {
const response = await handleShareDir(id,path); const response = await handleShareDir(id, path)
if (response && response.data) { if (response && response.data) {
return response.data.map((item: {[key: string]: OsFile}) => { return response.data
item.fi.isShare = true
item.fi.path = turnLocalPath(item.fi.path ,path,1)
return item.fi
})
} }
return []; return []
// const response = await handleShareDir(id, file.path);
// useShareFile().setCurrentFile(file)
// if (response && response.data) {
// const result = response.data.map((item: {[key: string]: OsFile}) => {
// item.fi.isShare = true
// item.fi.parentPath = turnLocalPath(item.fi.parentPath ,file.path,1)
// item.fi.path = turnLocalPath(item.fi.path ,file.path,1)
// // item.fi.titleName = turnLocalPath(item.fi.titleName, file.path, 1)
// return item.fi
// })
// return result
// }
// return [];
}, },
async getShareInfo(path: string) { async getShareInfo(path: string) {
const response = await handleShareDetail(path, getSystemConfig().userInfo.id); const response = await handleShareDetail(path, getSystemConfig().userInfo.id);

1
frontend/src/system/core/FileSystem.ts

@ -103,6 +103,7 @@ class OsFile extends OsFileInfo {
isSys?: number; // 文件是否是系统文件(可选) isSys?: number; // 文件是否是系统文件(可选)
isShare?: boolean; // 文件是否为共享文件 isShare?: boolean; // 文件是否为共享文件
isPwd?: boolean; //文件是否上锁 isPwd?: boolean; //文件是否上锁
// root?: string; //分享文件的根目录
titleName?: string; // 文件原本路径 titleName?: string; // 文件原本路径
/** /**

1
frontend/src/system/index.ts

@ -118,6 +118,7 @@ export class System {
// const messageStore = useMessageStore(); // const messageStore = useMessageStore();
// messageStore.systemMessage() // messageStore.systemMessage()
upgradeStore.onlineMessage(); upgradeStore.onlineMessage();
// upgradeStore.userChatMessage();
}, 3000); }, 3000);
} }
setTimeout(() => { setTimeout(() => {

5
frontend/src/util/sharePath.ts

@ -25,3 +25,8 @@ export function turnFilePath(file: OsFileWithoutContent) : string {
const arr = file.path.split('/') const arr = file.path.split('/')
return `/${arr[1]}/${arr[2]}/${arr[arr.length - 1]}` return `/${arr[1]}/${arr[2]}/${arr[arr.length - 1]}`
} }
//返回是我的分享还是接收分享的文件路径
export function getFileRootPath(path: string) : string {
const rootPath = path.indexOf('/F/myshare') === 0 ? '/F/myshare' : '/F/othershare'
return rootPath
}

6
godo/files/os.go

@ -364,7 +364,11 @@ func IsHavePwd(pwd string) bool {
func GetSalt(r *http.Request) (string, error) { func GetSalt(r *http.Request) (string, error) {
data, ishas := libs.GetConfig("salt") data, ishas := libs.GetConfig("salt")
if ishas { if ishas {
return data.(string), nil // 断言成功则返回
if salt, ok := data.(string); ok {
return salt, nil
}
return "", fmt.Errorf("类型断言失败,期望类型为 string")
} }
salt := r.Header.Get("salt") salt := r.Header.Get("salt")
if salt != "" { if salt != "" {

Loading…
Cancel
Save