Browse Source

test:文件分享接口对接

master
prr 7 months ago
parent
commit
939565dddd
  1. 3
      frontend/components.d.ts
  2. 4
      frontend/src/components/builtin/FileList.vue
  3. 19
      frontend/src/components/builtin/FileProps.vue
  4. 29
      frontend/src/components/builtin/FileTree.vue
  5. 239
      frontend/src/components/builtin/ShareFileTree.vue
  6. 11
      frontend/src/components/computer/Computer.vue
  7. 4
      frontend/src/components/oa/ShareFiles.vue
  8. 30
      frontend/src/components/setting/SetFilePwd.vue
  9. 1
      frontend/src/components/setting/SetSystem.vue
  10. 4
      frontend/src/hook/useComputer.ts
  11. 4
      frontend/src/hook/useContextMenu.ts
  12. 1
      frontend/src/i18n/lang/zh.json
  13. 51
      frontend/src/system/core/FileOs.ts
  14. 1
      frontend/src/system/core/FileSystem.ts
  15. 4
      frontend/src/system/index.ts
  16. 11
      frontend/src/util/sharePath.ts

3
frontend/components.d.ts

@ -55,7 +55,6 @@ declare module 'vue' {
ElCarousel: typeof import('element-plus/es')['ElCarousel']
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCion: typeof import('element-plus/es')['ElCion']
ElCol: typeof import('element-plus/es')['ElCol']
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
ElContainer: typeof import('element-plus/es')['ElContainer']
@ -130,12 +129,12 @@ declare module 'vue' {
Screenshort: typeof import('./src/components/taskbar/Screenshort.vue')['default']
SetAccount: typeof import('./src/components/setting/SetAccount.vue')['default']
SetCustom: typeof import('./src/components/setting/SetCustom.vue')['default']
SetFilePwd: typeof import('./src/components/setting/SetFilePwd.vue')['default']
SetLang: typeof import('./src/components/setting/SetLang.vue')['default']
SetSystem: typeof import('./src/components/setting/SetSystem.vue')['default']
Setting: typeof import('./src/components/setting/Setting.vue')['default']
SetUpdate: typeof import('./src/components/setting/SetUpdate.vue')['default']
ShareFiles: typeof import('./src/components/oa/ShareFiles.vue')['default']
ShareFileTree: typeof import('./src/components/builtin/ShareFileTree.vue')['default']
ShowNews: typeof import('./src/components/taskbar/ShowNews.vue')['default']
StartMenu: typeof import('./src/components/taskbar/StartMenu.vue')['default']
StartOption: typeof import('./src/components/taskbar/StartOption.vue')['default']

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

@ -34,7 +34,7 @@
@dragleave="handleDragLeave()" @dragstart.stop="startDragApp($event, item)" @click="handleClick(index)"
@mousedown.stop :ref="(ref: any) => {
if (ref) {
appPositions[indeíx] = markRaw(ref as Element);
appPositions[index] = markRaw(ref as Element);
}
}
">
@ -196,8 +196,6 @@ function handleClick(index: number) {
chosenIndexs.value = [index];
}
onMounted(() => {
console.log('filelist:',props.fileList)
chosenIndexs.value = [];
props.onChosen(
throttle((rect: Rect) => {

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

@ -29,7 +29,7 @@
</div>
<div class="propitem">
<div class="propname">{{ t("location") }}</div>
<div class="propvalue">{{ file?.path }}</div>
<div class="propvalue">{{ localName(file?.path) }}</div>
</div>
<div class="propitem">
<div class="propname">{{ t("size") }}</div>
@ -72,10 +72,25 @@ import {
t,
} from "@/system";
import { dealSize } from "@/util/file";
import { isShareFile } from "@/util/sharePath";
const window: BrowserWindow | undefined = inject("browserWindow");
const file = ref<OsFileWithoutContent | null>();
file.value = await useSystem()?.fs.stat(window?.config.content);
const path = window?.config.content
if(path.indexOf('/F') === 0) {
file.value = (await useSystem()?.fs.getShareInfo(path)).fi
} else {
file.value = await useSystem()?.fs.stat(path);
}
// file.value = await useSystem()?.fs.stat(window?.config.content);
function localName<T>(currentPath:T){
if(isShareFile(path)) {
const arr = path.split('/')
const url = '/' + arr[1] + '/' + arr[2] + '/' + arr[arr.length-1]
return arr.length >3 ? url : currentPath
}
return currentPath
}
function confirm() {
window?.close();
}

29
frontend/src/components/builtin/FileTree.vue

@ -51,9 +51,8 @@
import { useSystem,OsFileWithoutContent,basename } from '@/system/index.ts';
import { onMounted, ref } from 'vue';
import { dealSystemName } from '@/i18n';
//
// import { getSystemConfig } from "@/system/config";
// const config = ref(getSystemConfig())
import { getSystemConfig } from "@/system/config";
import { isShareFile } from '@/util/sharePath';
const sys = useSystem();
type FileWithOpen = OsFileWithoutContent & {
@ -113,9 +112,15 @@ function onSubOpen(path: string) {
}
async function onSubRefresh(item: FileWithOpen) {
item.subFileList = (await sys.fs.readdir(item.path)).filter((file:any) => {
return file.isDirectory;
});
if(isShareFile(item.path)) {
item.subFileList = (await sys.fs.sharedir(getSystemConfig().userInfo.id, item?.path)).filter((file:any) => {
return file.isDirectory;
});
} else {
item.subFileList = (await sys.fs.readdir(item.path)).filter((file:any) => {
return file.isDirectory;
});
}
}
async function onOpenArrow(item: FileWithOpen) {
@ -123,9 +128,15 @@ async function onOpenArrow(item: FileWithOpen) {
return;
}
item.isOpen = !item.isOpen;
item.subFileList = (await sys.fs.readdir(item.path)).filter((file:any) => {
return file.isDirectory;
});
if(isShareFile(item.path)) {
item.subFileList = (await sys.fs.sharedir(getSystemConfig().userInfo.id, item?.path)).filter((file:any) => {
return file.isDirectory;
});
} else {
item.subFileList = (await sys.fs.readdir(item.path)).filter((file:any) => {
return file.isDirectory;
});
}
}
</script>
<style lang="scss" scoped>

239
frontend/src/components/builtin/ShareFileTree.vue

@ -1,239 +0,0 @@
<template>
<div
class="item-group"
v-for="(item, index) in fileList"
:key="item.path + item.isOpen"
>
<div
class="file-item"
:class="{
chosen: chosenPath === item.path,
// 'no-chosen': !chosenIndexs.includes(index),
'mode-icon': mode === 'icon',
'mode-list': mode === 'list',
}"
:style="{
'padding-left': level * 12 + 'px',
}"
@click="handleClick(item, index)"
@mousedown.stop
>
<div
class="iconfont"
:class="{
'open-arrow': item.isOpen,
'hide-arrow': item.isOpen && !item.subFileList?.length,
}"
@click.stop="onOpenArrow(item)"
>
<div class="icon-arrow-down"></div>
</div>
<div class="file-item_img">
<FileIcon :file="item" />
</div>
<span class="file-item_title">{{ getName(item) }}</span>
</div>
<div class="sub-tree">
<ShareFileTree
v-if="item.isOpen"
:level="level + 1"
mode="list"
:chosen-path="chosenPath"
:on-refresh="() => onSubRefresh(item)"
:on-open="onSubOpen"
:file-list="item.subFileList"
>
</ShareFileTree>
</div>
</div>
</template>
<script lang="ts" setup>
import { useSystem,OsFileWithoutContent,basename } from '@/system/index.ts';
import { onMounted, ref } from 'vue';
import { dealSystemName } from '@/i18n';
const sys = useSystem();
type FileWithOpen = OsFileWithoutContent & {
isOpen?: boolean;
subFileList?: FileWithOpen[];
};
const props = defineProps({
level: {
type: Number,
default: 0,
},
onOpen: {
type: Function,
default: () => {
//
},
},
onRefresh: {
type: Function,
default: () => {
//
},
},
chosenPath: {
type: String,
default: '',
},
fileList: {
type: Array<FileWithOpen>,
default: () => [],
},
mode: {
type: String,
default: 'icon',
},
});
const chosenIndexs = ref<Array<number>>([]);
function handleClick(item: FileWithOpen, index: number) {
chosenIndexs.value = [index];
props.onOpen(item.path);
}
function getName(item:any){
const name = dealSystemName(basename(item.path))
return name
}
onMounted(() => {
chosenIndexs.value = [];
props.fileList.forEach((item) => {
item.isOpen = false;
});
});
function onSubOpen(path: string) {
props.onOpen(path);
}
async function onSubRefresh(item: FileWithOpen) {
item.subFileList = (await sys.fs.sharedir(sys.getConfig('userInfo')?.id, item?.path)).filter((file:any) => {
return file.isDirectory;
});
}
async function onOpenArrow(item: FileWithOpen) {
if (item.isOpen && !item.subFileList?.length) {
return;
}
item.isOpen = !item.isOpen;
item.subFileList = (await sys.fs.sharedir(sys.getConfig('userInfo')?.id, item?.path)).filter((file:any) => {
return file.isDirectory;
});
}
</script>
<style lang="scss" scoped>
.icon-arrow-down {
display: block;
width: 4px;
height: 4px;
margin: 7px;
transform: translateY(0px) rotate(-45deg);
border: 2px solid rgba(0, 0, 0, 0.465);
border-left: none;
border-top: none;
transition: all 0.1s;
}
.hide-arrow {
border-color: transparent;
}
.open-arrow {
transform: translateY(-2px) translateX(2px) rotate(90deg);
}
.file-item {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
color: var(--icon-title-color);
font-size: var(--ui-font-size);
border: 1px solid transparent;
margin: 2px;
user-select: none;
}
.file-item:hover {
background-color: #b1f1ff4c;
}
.chosen {
border: 1px dashed #3bdbff3d;
background-color: #9595956b;
.file-item_title {
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
// background-color: var(--theme-color);
}
.chosen:hover {
background-color: #9595956b;
}
.no-chosen {
.file-item_title {
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
}
.mode-icon {
.file-item_img {
width: 60%;
height: calc(0.6 * var(--desk-item-size));
margin: 0px auto;
user-select: none;
flex-shrink: 0;
}
.file-item_title {
// color: var(--color-ui-desk-item-title);
height: calc(0.4 * var(--desk-item-size));
display: block;
text-align: center;
word-break: break-all;
flex-grow: 0;
}
}
.mode-list {
display: flex;
flex-direction: row;
justify-content: flex-start;
height: calc(0.8 * var(--menulist-item-height));
width: 100%;
.file-item_img {
width: var(--menulist-item-height);
height: calc(0.6 * var(--menulist-item-height));
// margin: 0px auto;
user-select: none;
flex-shrink: 0;
svg {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.file-item_title {
height: min-content;
word-break: break-all;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
}
</style>

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

@ -43,7 +43,7 @@
>
</FileTree>
<div class="showName" v-if="shareShow">{{ t("share") }}</div>
<ShareFileTree
<FileTree
v-if="shareShow"
:chosen-path="chosenTreePath"
mode="list"
@ -52,7 +52,7 @@
:file-list="shareFileList"
:key="random"
>
</ShareFileTree>
</FileTree>
<QuickLink :on-open="onTreeOpen"></QuickLink>
<div class="left-handle" @mousedown="leftHandleDown"></div>
</div>
@ -105,6 +105,7 @@ import { emitEvent, mountEvent } from "@/system/event";
import { useFileDrag } from "@/hook/useFileDrag";
import { useComputer } from "@/hook/useComputer";
import { Rect, useRectChosen } from "@/hook/useRectChosen";
import { getSystemConfig } from "@/system/config";
const { choseStart, chosing, choseEnd, getRect, Chosen } = useRectChosen();
@ -136,7 +137,7 @@ const { refersh, createFolder, backFolder, openFolder, onComputerMount } = useCo
return router_url.value;
},
setFileList(list) {
console.log('list:',list)
// console.log('list:',list)
//currentList.value = list;
if(config.ext && config.ext instanceof Array && config.ext.length > 0) {
const res:any = []
@ -164,7 +165,7 @@ const { refersh, createFolder, backFolder, openFolder, onComputerMount } = useCo
return system.fs.readdir(path);
},
sharedir(path) {
const val:number = system.getConfig('userInfo')?.id
const val:number = getSystemConfig().userInfo.id
return system.fs.sharedir(val,path)
},
exists(path) {
@ -269,6 +270,8 @@ onMounted(() => {
}
});
shareShow.value = system.getConfig('userType') === 'member' ? true : false
// console.log('', system.getConfig('userInfo').id);
});
function handleOuterClick() {

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

@ -61,9 +61,7 @@ const onSubmit = async () => {
const temp = {...form.value}
temp.senderid = temp.senderid.toString()
temp.receverid = temp.receverid.map((item:any) => item.toString())
const res = await fetchPost(apiUrl, new URLSearchParams(temp))
console.log('分享文件:',res)
await fetchPost(apiUrl, new URLSearchParams(temp))
}
</script>
<style scoped>

30
frontend/src/components/setting/SetFilePwd.vue

@ -0,0 +1,30 @@
<template>
<div class="file-pwd-box">
<div class="setting-item" >
<label>文件密码</label>
<el-input v-model="filePwd" placeholder="请输入文件加密密码" />
</div>
<div class="setting-item">
<label></label>
<el-button @click="toSetFilePwd" type="primary">{{ t("setFilePwd") }}</el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { t } from "@/system";
const filePwd = ref('')
const toSetFilePwd = ()=> {}
</script>
<style scoped>
@import "./setStyle.css";
.file-pwd-box {
padding-top: 20px;
}
.setting-item {
display: flex;
align-items: center;
}
</style>

1
frontend/src/components/setting/SetSystem.vue

@ -47,6 +47,7 @@
{{ t("confirm") }}
</el-button>
</div>
<SetFilePwd></SetFilePwd>
</div>
<div v-if="2 === activeIndex">

4
frontend/src/hook/useComputer.ts

@ -40,7 +40,7 @@ export const useComputer = (adpater: {
}
if (!(await isVia(currentPath))) return;
console.log('use computer refresh:', currentPath);
// console.log('use computer refresh:', currentPath);
let result
if (currentPath.substring(0,2) == '/F') {
result = await adpater.sharedir(currentPath)
@ -67,8 +67,6 @@ export const useComputer = (adpater: {
refersh();
};
const openFolder = (file: OsFileWithoutContent) => {
console.log('use computer openFolder 打开:', file);
if (adpater.isDirectory(file)) {
adpater.setRouter(file.path);
refersh();

4
frontend/src/hook/useContextMenu.ts

@ -268,8 +268,6 @@ function useContextMenu() {
if (file.isDirectory) {
return system?.fs.rmdir(file.path);
} else {
console.log('删除文件:',file);
return system?.fs.unlink(file.path);
}
}
@ -277,8 +275,6 @@ function useContextMenu() {
if (file.isDirectory) {
return system?.fs.rmdir(file.path);
} else {
console.log('删除文件:',file);
return system?.fs.unlink(file.path);
}
}

1
frontend/src/i18n/lang/zh.json

@ -10,6 +10,7 @@
"share": "分享",
"myshare": "我的分享",
"othershare": "接收的分享",
"setFilePwd": "设置文件密码",
"favorite": "我的收藏",
"desktop": "桌面",
"personalization": "个性化",

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

@ -1,7 +1,9 @@
import { getFileUrl,fetchGet,fetchPost } from "../config.ts";
const API_BASE_URL = getFileUrl()
import { OsFileMode } from '../core/FileMode';
// import { getSystemConfig } from "@/system/config";
import { getSystemConfig } from "@/system/config";
import { turnServePath, turnLocalPath } from "@/util/sharePath.ts";
import { OsFile } from "./FileSystem.ts";
export async function handleReadDir(path: any): Promise<any> {
const res = await fetchGet(`${API_BASE_URL}/read?path=${encodeURIComponent(path)}`);
@ -11,9 +13,9 @@ export async function handleReadDir(path: any): Promise<any> {
return await res.json();
}
// 查看分享文件
export async function handleReadShareDir(val: number,path: string): Promise<any> {
export async function handleReadShareDir(id: number,path: string): Promise<any> {
const url = path.indexOf('/F/myshare') !== -1 ? 'sharemylist' : 'sharelist'
const res = await fetchGet(`${API_BASE_URL}/${url}?id=${val}`);
const res = await fetchGet(`${API_BASE_URL}/${url}?id=${id}`);
if (!res.ok) {
return false;
}
@ -21,6 +23,7 @@ export async function handleReadShareDir(val: number,path: string): Promise<any>
}
// 查看分享文件
export async function handleReadShareFile(path: string): Promise<any> {
path = turnServePath(path)
const res = await fetchGet(`${API_BASE_URL}/shareread?path=${path}`);
if (!res.ok) {
return false;
@ -29,18 +32,21 @@ export async function handleReadShareFile(path: string): Promise<any> {
}
// 删除分享文件
export async function handleShareUnlink(path: string): Promise<any> {
const file = await handleShareDetail(path)
const res = await fetchGet(`${API_BASE_URL}/sharedelete?path=${path}`);
const config = getSystemConfig()
const file = await handleShareDetail(path,config.userInfo.id)
path = turnServePath(path)
const res = await fetchGet(`${API_BASE_URL}/sharedelete?senderid=${file.data.fs.sender}&path=${path}&receverid=${file.data.fs.recever}`);
if (!res.ok) {
return false;
}
return await res.json();
}
// 查看文件信息
export async function handleShareDetail(path: string): Promise<any> {
const res = await fetchGet(`${API_BASE_URL}/shareinfo?path=${path}`);
console.log('文件详情:', res);
export async function handleShareDetail(path: string, id: number): Promise<any> {
const sig = path.indexOf('/F/myshare') === 0 ? 0 : 1
path = turnServePath(path)
const res = await fetchGet(`${API_BASE_URL}/shareinfo?path=${path}&id=${id}&sig=${sig}`);
if (!res.ok) {
return false;
}
@ -137,7 +143,6 @@ export async function handleRmdir(dirPath: string): Promise<any> {
return await res.json();
}
export async function handleCopyFile(srcPath: string, dstPath: string): Promise<any> {
const res = await fetchGet(`${API_BASE_URL}/copyfile?srcPath=${encodeURIComponent(srcPath)}&dstPath=${encodeURIComponent(dstPath)}`);
if (!res.ok) {
@ -230,14 +235,12 @@ export async function handleUnZip(path: string): Promise<any> {
export const useOsFile = () => {
return {
// 分享
async sharedir(val: number, path: string) {
const response = await handleReadShareDir(val, path);
async sharedir(id: number, path: string) {
const response = await handleReadShareDir(id, path);
if (response && response.data) {
// return response.data;
console.log('文件列表:',response.data.map(item => item.fi));
return response.data.map(item => {
return response.data.map((item: {[key: string]: OsFile}) => {
item.fi.isShare = true
item.fi.path = turnLocalPath(item.fi.path ,path)
return item.fi
})
}
@ -250,11 +253,14 @@ export const useOsFile = () => {
}
return [];
},
async getShareInfo(path: string) {
const response = await handleShareDetail(path, getSystemConfig().userInfo.id);
if (response && response.data) {
return response.data;
}
return [];
},
async readdir(path: string) {
// console.log('raeddir path:',path,path.substring(0,2))
// const api = path.substring(0,2) == '/F' ? handleReadShareDir : handleReadDir
// const temp = path.substring(0,2) == '/F' ? getSystemConfig().userInfo.id : path
// const response = await api(temp);
const response = await handleReadDir(path);
if (response && response.data) {
return response.data;
@ -282,12 +288,8 @@ export const useOsFile = () => {
return response.data;
}
return false;
//分享
// return true
},
async readFile(path: string) {
console.log('读文件:',path);
// 注意:handleReadFile返回的是JSON,但通常readFile期望返回Buffer或字符串
const response = await handleReadFile(path);
if (response && response.data) {
@ -296,8 +298,7 @@ export const useOsFile = () => {
return false;
},
async unlink(path: string) {
const fun = path.indexOf('data/userData') === 0 ? handleShareUnlink : handleUnlink
console.log('删除路径:',path,fun);
const fun = path.indexOf('/F') === 0 ? handleShareUnlink : handleUnlink
const response = await fun(path);
if (response) {
return response;

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

@ -101,6 +101,7 @@ class OsFile extends OsFileInfo {
title?: string; // 文件名(不包含扩展名)
id?: number; // 文件ID(可选)
isSys?: number; // 文件是否是系统文件(可选)
isShare?: boolean; // 文件是否为共享文件
/**
* OsFile

4
frontend/src/system/index.ts

@ -27,6 +27,7 @@ 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 = {
@ -427,8 +428,7 @@ export class System {
/**打开os 文件系统的文件 */
async openFile(path: string) {
//判断是否是共享文件
const pos = path.indexOf('data/userData')
if (pos !== -1) {
if (isShareFile(path)) {
const arr = path.split('/')
const fileContent = await this.fs.readShareFile(path)
const fileName = extname(arr[arr.length-1] || '') || 'link'

11
frontend/src/util/sharePath.ts

@ -0,0 +1,11 @@
export function turnServePath(path: string): string {
const replaceUrl = path.indexOf('/F/myshare') === 0 ? '/F/myshare' : '/F/othershare'
return path.replace(replaceUrl, 'data/userData')
}
export function turnLocalPath(path: string, newTemp: string): string {
return path.replace('data/userData', newTemp)
}
export function isShareFile(path: string) : boolean {
// console.log('是否是共享文件:',path,path.indexOf('/F/myshare') === 0 || path.indexOf('/F/othershare') === 0);
return path.indexOf('/F/myshare') === 0 || path.indexOf('/F/othershare') === 0
}
Loading…
Cancel
Save