Browse Source

fix:企业版文件加密

master
18786462055 8 months ago
parent
commit
795d76dd82
  1. 1343
      frontend/src/components/builtin/FileList.vue
  2. 5
      frontend/src/components/builtin/FileTree.vue
  3. 1108
      frontend/src/components/computer/Computer.vue
  4. 448
      frontend/src/components/computer/ComputerNavBar.vue
  5. 78
      frontend/src/components/oa/FilePwd.vue
  6. 2
      frontend/src/components/setting/SetFilePwd.vue
  7. 332
      frontend/src/components/window/IframeFile.vue
  8. 533
      frontend/src/system/config.ts
  9. 787
      frontend/src/system/core/FileOs.ts
  10. 12
      frontend/src/system/core/FileSystem.ts
  11. 22
      frontend/src/system/index.ts
  12. 8
      frontend/src/system/window/Dialog.ts

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

File diff suppressed because it is too large

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

@ -51,7 +51,6 @@
import { useSystem,OsFileWithoutContent,basename } from '@/system/index.ts';
import { onMounted, ref } from 'vue';
import { dealSystemName } from '@/i18n';
import { getSystemConfig } from "@/system/config";
import { isShareFile } from '@/util/sharePath';
const sys = useSystem();
@ -113,7 +112,7 @@ function onSubOpen(path: string) {
async function onSubRefresh(item: FileWithOpen) {
if(isShareFile(item.path)) {
item.subFileList = (await sys.fs.sharedir(getSystemConfig().userInfo.id, item?.path)).filter((file:any) => {
item.subFileList = (await sys.fs.sharedir(item?.path)).filter((file:any) => {
return file.isDirectory;
});
} else {
@ -135,7 +134,7 @@ async function onOpenArrow(item: FileWithOpen) {
// });
// } else
if(isShareFile(item.path)) {
item.subFileList = (await sys.fs.sharedir(getSystemConfig().userInfo.id, item?.path)).filter((file:any) => {
item.subFileList = (await sys.fs.sharedir(item?.path)).filter((file:any) => {
return file.isDirectory;
});
} else {

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

File diff suppressed because it is too large

448
frontend/src/components/computer/ComputerNavBar.vue

@ -1,227 +1,259 @@
<template>
<div class="uper_nav">
<div class="uper_nav_button" @click="changeHistory(-1)">
<svg
t="1632984723698"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="10100"
>
<path
d="M862.485 481.154H234.126l203.3-203.3c12.497-12.497 12.497-32.758 0-45.255s-32.758-12.497-45.255 0L135.397 489.373c-12.497 12.497-12.497 32.758 0 45.254l256.774 256.775c6.249 6.248 14.438 9.372 22.627 9.372s16.379-3.124 22.627-9.372c12.497-12.497 12.497-32.759 0-45.255l-203.3-203.301h628.36c17.036 0 30.846-13.81 30.846-30.846s-13.81-30.846-30.846-30.846z"
p-id="10101"
/>
</svg>
</div>
<div class="uper_nav_button" @click="changeHistory(1)">
<svg
t="1632984737821"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="10249"
>
<path
d="M885.113 489.373L628.338 232.599c-12.496-12.497-32.758-12.497-45.254 0-12.497 12.497-12.497 32.758 0 45.255l203.3 203.3H158.025c-17.036 0-30.846 13.811-30.846 30.846 0 17.036 13.811 30.846 30.846 30.846h628.36L583.084 746.147c-12.497 12.496-12.497 32.758 0 45.255 6.248 6.248 14.438 9.372 22.627 9.372s16.379-3.124 22.627-9.372l256.775-256.775a31.999 31.999 0 0 0 0-45.254z"
p-id="10250"
/>
</svg>
</div>
<div class="uper_nav_button" @click="backFolder()">
<svg
t="1639145815176"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="3860"
>
<path
d="M554.666667 268.8v601.6h-85.333334V268.8L337.066667 401.066667 277.333333 341.333333 512 106.666667 746.666667 341.333333l-59.733334 59.733334L554.666667 268.8z"
fill="#444444"
p-id="3861"
/>
</svg>
</div>
<div class="uper_nav">
<div
class="uper_nav_button"
@click="changeHistory(-1)"
>
<svg
t="1632984723698"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="10100"
>
<path
d="M862.485 481.154H234.126l203.3-203.3c12.497-12.497 12.497-32.758 0-45.255s-32.758-12.497-45.255 0L135.397 489.373c-12.497 12.497-12.497 32.758 0 45.254l256.774 256.775c6.249 6.248 14.438 9.372 22.627 9.372s16.379-3.124 22.627-9.372c12.497-12.497 12.497-32.759 0-45.255l-203.3-203.301h628.36c17.036 0 30.846-13.81 30.846-30.846s-13.81-30.846-30.846-30.846z"
p-id="10101"
/>
</svg>
</div>
<div
class="uper_nav_button"
@click="changeHistory(1)"
>
<svg
t="1632984737821"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="10249"
>
<path
d="M885.113 489.373L628.338 232.599c-12.496-12.497-32.758-12.497-45.254 0-12.497 12.497-12.497 32.758 0 45.255l203.3 203.3H158.025c-17.036 0-30.846 13.811-30.846 30.846 0 17.036 13.811 30.846 30.846 30.846h628.36L583.084 746.147c-12.497 12.496-12.497 32.758 0 45.255 6.248 6.248 14.438 9.372 22.627 9.372s16.379-3.124 22.627-9.372l256.775-256.775a31.999 31.999 0 0 0 0-45.254z"
p-id="10250"
/>
</svg>
</div>
<div
class="uper_nav_button"
@click="backFolder()"
>
<svg
t="1639145815176"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="3860"
>
<path
d="M554.666667 268.8v601.6h-85.333334V268.8L337.066667 401.066667 277.333333 341.333333 512 106.666667 746.666667 341.333333l-59.733334 59.733334L554.666667 268.8z"
fill="#444444"
p-id="3861"
/>
</svg>
</div>
<div @click="startInput()" v-if="path_state == 'pendding'" class="path">
<template v-if="modelValue?.startsWith('search:')">
<span>{{ modelValue }}</span>
</template>
<template v-else>
<span
class="path-p"
:key="p"
v-for="(p, index) in modelValue?.split('/').slice(1)"
@click.stop="handlePathPClick(index)"
>
{{ p }}<span class="iconfont icon-arrow-down"></span
></span>
</template>
</div>
<div @focusout="endInput()" v-show="path_state == 'inputing'" class="path_inputing nav-path">
<input ref="myinput" v-model="inputStr" @keyup.enter="endInput()" />
</div>
<div class="search path_inputing">
<input placeholder="search" v-model="searchStr" @keyup.enter="endSearch" @blur="endSearch" />
</div>
</div>
<div
@click="startInput()"
v-if="path_state == 'pendding'"
class="path"
>
<template v-if="modelValue?.startsWith('search:')">
<span>{{ modelValue }}</span>
</template>
<template v-else>
<span
class="path-p"
:key="p"
v-for="(p, index) in modelValue?.split('/').slice(1)"
@click.stop="handlePathPClick(index)"
>
{{ p }}<span class="iconfont icon-arrow-down"></span
></span>
</template>
</div>
<div
@focusout="endInput()"
v-show="path_state == 'inputing'"
class="path_inputing nav-path"
>
<input
ref="myinput"
v-model="inputStr"
@keyup.enter="endInput()"
/>
</div>
<div class="search path_inputing">
<input
placeholder="search"
v-model="searchStr"
@keyup.enter="endSearch"
@blur="endSearch"
/>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, nextTick } from 'vue';
const props = defineProps<{
modelValue?: string;
}>();
const emit = defineEmits(['update:modelValue', 'backFolder', 'changeHistory', 'refresh', 'search']);
import { nextTick, ref } from "vue";
const props = defineProps<{
modelValue?: string;
}>();
const emit = defineEmits([
"update:modelValue",
"backFolder",
"changeHistory",
"refresh",
"search",
]);
function backFolder() {
emit('backFolder');
}
function changeHistory(num: number) {
emit('changeHistory', num);
}
function backFolder() {
emit("backFolder");
}
function changeHistory(num: number) {
emit("changeHistory", num);
}
/* ------------ 路径输入框 ------------*/
const myinput = ref<HTMLElement | null>(null);
const inputStr = ref(props.modelValue);
/* ------------ 路径输入框 ------------*/
const myinput = ref<HTMLElement | null>(null);
const inputStr = ref(props.modelValue);
const path_state = ref('pendding');
function startInput() {
path_state.value = 'inputing';
inputStr.value = props.modelValue;
nextTick(() => {
myinput.value?.focus();
});
}
function endInput() {
path_state.value = 'pendding';
emit('refresh', inputStr.value);
}
/* ------------ 路径输入框end ---------*/
const path_state = ref("pendding");
function startInput() {
path_state.value = "inputing";
inputStr.value = props.modelValue;
nextTick(() => {
myinput.value?.focus();
});
}
function endInput() {
path_state.value = "pendding";
emit("refresh", inputStr.value);
}
/* ------------ 路径输入框end ---------*/
/* ------------ 搜索框 ------------*/
const searchStr = ref('');
function endSearch() {
if (searchStr.value == '') return;
emit('search', searchStr.value);
searchStr.value = '';
}
/* ------------ 搜索框 ------------*/
const searchStr = ref("");
function endSearch() {
if (searchStr.value == "") return;
emit("search", searchStr.value);
searchStr.value = "";
}
function handlePathPClick(index: number) {
const path = props.modelValue
?.split('/')
.slice(0, index + 2)
.join('/');
if (path === undefined) return;
if (path === props.modelValue) return;
emit('refresh', path);
}
function handlePathPClick(index: number) {
const path = props.modelValue
?.split("/")
.slice(0, index + 2)
.join("/");
if (path === undefined) return;
if (path === props.modelValue) return;
emit("refresh", path);
}
</script>
<style lang="scss" scoped>
.icon-arrow-down {
display: inline-block;
width: 4px;
height: 4px;
transform: translateY(-1px) rotate(-45deg);
border: 2px solid rgba(0, 0, 0, 0.465);
border-left: none;
border-top: none;
transition: all 0.1s;
margin: 0 2px;
}
.uper_nav {
height: var(--button-item-height);
display: flex;
margin-top:5px;
}
.icon-arrow-down {
display: inline-block;
width: 4px;
height: 4px;
transform: translateY(-1px) rotate(-45deg);
border: 2px solid rgba(0, 0, 0, 0.465);
border-left: none;
border-top: none;
transition: all 0.1s;
margin: 0 2px;
}
.uper_nav {
height: var(--button-item-height);
display: flex;
margin-top: 5px;
}
.uper_nav_button {
width: calc(var(--button-item-height) - 10px);
height: var(--button-item-height);
line-height: var(--button-item-height);
padding: 0px 4px;
margin: 0 auto;
flex-shrink: 0;
text-align: center;
filter: brightness(230%);
display: flex;
justify-content: center;
align-items: center;
}
.uper_nav_button {
width: calc(var(--button-item-height) - 10px);
height: var(--button-item-height);
line-height: var(--button-item-height);
padding: 0px 4px;
margin: 0 auto;
flex-shrink: 0;
text-align: center;
filter: brightness(230%);
display: flex;
justify-content: center;
align-items: center;
}
.uper_nav_button_small {
width: calc(var(--button-item-height) - 16px);
}
.uper_nav_button_small {
width: calc(var(--button-item-height) - 16px);
}
.uper_nav_button svg {
width: calc(var(--button-item-height) - 16px);
height: calc(var(--button-item-height) - 16px);
}
.uper_nav_button svg {
width: calc(var(--button-item-height) - 16px);
height: calc(var(--button-item-height) - 16px);
}
.path {
height: calc(var(--button-item-height));
width: 100%;
line-height: calc(var(--button-item-height) - 6px);
padding: 0px 5px;
margin: 0px 2px;
border: 1px solid rgba(134, 134, 134, 0.267);
transition: all 0.1s;
/* text-align: center; */
overflow: auto;
user-select: none;
.path {
height: calc(var(--button-item-height));
width: 100%;
line-height: calc(var(--button-item-height) - 6px);
padding: 0px 5px;
margin: 0px 2px;
border: 1px solid rgba(134, 134, 134, 0.267);
transition: all 0.1s;
/* text-align: center; */
overflow: auto;
user-select: none;
display: flex;
align-items: center;
.path-p {
padding: 0;
margin: 0;
margin-right: 2px;
transition: all 0.1s;
border: 1px solid transparent;
}
.path-p:hover {
background-color: #b1f1ff4c;
border: 1px solid rgba(0, 102, 255, 0.138);
cursor: pointer;
}
.path span {
height: var(--button-item-height);
/* text-align: center; */
line-height: var(--button-item-height);
}
}
display: flex;
align-items: center;
.path-p {
padding: 0;
margin: 0;
margin-right: 2px;
transition: all 0.1s;
border: 1px solid transparent;
}
.path-p:hover {
background-color: #b1f1ff4c;
border: 1px solid rgba(0, 102, 255, 0.138);
cursor: pointer;
}
.path span {
height: var(--button-item-height);
/* text-align: center; */
line-height: var(--button-item-height);
}
}
.path_inputing {
height: calc(var(--button-item-height));
width: 100%;
line-height: calc(var(--button-item-height) - 6px);
padding: 0px 5px;
margin: 0px 2px;
border: 1px solid rgba(134, 134, 134, 0.267);
transition: all 0.1s;
user-select: text;
}
.path_inputing {
height: calc(var(--button-item-height));
width: 100%;
line-height: calc(var(--button-item-height) - 6px);
padding: 0px 5px;
margin: 0px 2px;
border: 1px solid rgba(134, 134, 134, 0.267);
transition: all 0.1s;
user-select: text;
}
.path_inputing input {
height: 100%;
width: 100%;
/* padding: 1px 5px; */
/* text-align: center; */
line-height: var(--button-item-height);
background: none;
border: none;
outline: none;
user-select: none;
}
.nav-path {
}
.search {
width: 200px;
}
.path:hover {
border: 1px solid rgb(0, 102, 255);
}
.path_inputing input {
height: 100%;
width: 100%;
/* padding: 1px 5px; */
/* text-align: center; */
line-height: var(--button-item-height);
background: none;
border: none;
outline: none;
user-select: none;
}
.nav-path {
}
.search {
width: 200px;
}
.path:hover {
border: 1px solid rgb(0, 102, 255);
}
</style>

78
frontend/src/components/oa/FilePwd.vue

@ -1,33 +1,57 @@
<template>
<el-form label-width="auto" style="max-width: 560px;margin-top:20px;padding: 20px;">
<el-form-item label="文件密码">
<el-input v-model="filePwd" type="password" show-password/>
</el-form-item>
<div class="btn-group">
<el-button type="primary" @click="setFilePwd">提交</el-button>
</div>
</el-form>
<el-form
label-width="auto"
style="max-width: 560px; margin-top: 20px; padding: 20px"
>
<el-form-item label="文件密码">
<el-input
v-model="filePwd"
type="password"
show-password
/>
</el-form-item>
<div class="btn-group">
<el-button
type="primary"
@click="setFilePwd"
>提交</el-button
>
</div>
</el-form>
</template>
<script lang="ts" setup>
import { fetchPost } from '@/system/config';
import { ref } from 'vue'
import { getSystemConfig } from "@/system/config";
import { BrowserWindow } from '@/system';
const window: BrowserWindow | undefined = inject("browserWindow");
const filePwd = ref('')
const userInfo = getSystemConfig().userInfo
async function setFilePwd() {
if (filePwd.value !== '' && filePwd.value.length >= 6 && filePwd.value.length <= 10) {
const path = window?.config.path || ''
const res = await fetchPost(`${userInfo.url}`, filePwd.value)
console.log('路径:', res, path);
}
}
import { BrowserWindow, useSystem } from "@/system";
import { notifyError, notifySuccess } from "@/util/msg";
import { ref } from "vue";
const window: BrowserWindow | undefined = inject("browserWindow");
const filePwd = ref("");
const sys = useSystem();
async function setFilePwd() {
if (
filePwd.value !== "" &&
filePwd.value.length >= 6 &&
filePwd.value.length <= 10
) {
const path = window?.config.path || "";
const header = {
pwd: filePwd.value,
};
const file = await sys.fs.readFile(path);
if (file === false) return;
const res = await sys.fs.writeFile(path, file, header);
if (res && res.success) {
notifySuccess("文件密码设置成功");
} else {
notifyError("文件密码设置失败");
}
//console.log("", res, path);
}
}
</script>
<style scoped>
.btn-group{
display: flex;
justify-content: center;
}
</style>
.btn-group {
display: flex;
justify-content: center;
}
</style>

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

@ -63,7 +63,7 @@ async function clearPwd() {
await fetchGet(`${getApiUrl()}/file/changeispwd?ispwd=0`)
setSystemKey('file',params)
}
onMounted(()=>{
onMounted(() => {
params.isPwd = config.file.isPwd
setPwd.value = params.isPwd ? true : false
})

332
frontend/src/components/window/IframeFile.vue

@ -1,162 +1,188 @@
<template>
<iframe class="setiframe" allow="fullscreen" ref="storeRef" :src="src"></iframe>
<iframe
class="setiframe"
allow="fullscreen"
ref="storeRef"
:src="src"
></iframe>
</template>
<script lang="ts" setup name="IframeFile">
//@ts-ignore
import { BrowserWindow, Notify, System, Dialog } from "@/system";
import { ref, onMounted, inject, onUnmounted, toRaw } from "vue";
import { isBase64, base64ToBuffer } from "@/util/file";
import { getSplit, getSystemConfig } from "@/system/config";
import { isShareFile } from "@/util/sharePath.ts";
const SP = getSplit();
//@ts-ignore
import { BrowserWindow, Dialog, Notify, System } from "@/system";
import { getSplit, getSystemConfig, setSystemKey } from "@/system/config";
import { base64ToBuffer, isBase64 } from "@/util/file";
import { isShareFile } from "@/util/sharePath.ts";
import { inject, onMounted, onUnmounted, ref, toRaw } from "vue";
const SP = getSplit();
const sys: any = inject<System>("system");
const win: any = inject<BrowserWindow>("browserWindow");
const props = defineProps({
src: {
type: String,
default: "",
},
eventType: {
type: String,
default: "",
},
ext: {
type: String,
default: "md",
},
});
//console.log('iframe: ', props);
const sys: any = inject<System>("system");
const win: any = inject<BrowserWindow>("browserWindow");
const props = defineProps({
src: {
type: String,
default: "",
},
eventType: {
type: String,
default: "",
},
ext: {
type: String,
default: "md",
},
});
//console.log('iframe: ', props);
//console.log(props);
//let path = win?.config?.path;
const storeRef = ref<HTMLIFrameElement | null>(null);
let hasInit = false;
const eventHandler = async (e: MessageEvent) => {
const eventData = e.data;
if (eventData.type == props.eventType) {
let data = JSON.parse(eventData.data);
let title = data.title;
let path;
let ext: any = props.ext;
if (ext instanceof Array) {
ext = ext[0];
}
if (data.ext) {
ext = data.ext;
}
// console.log(ext)
// console.log(data)
if (win.config && win.config.path) {
path = win.config.path;
let fileTitleArr = path.split(SP).pop().split(".");
let oldExt = fileTitleArr.pop();
let fileTitle = fileTitleArr.join(".");
if (fileTitle != title) {
path = path.replace(fileTitle, title);
}
if (oldExt != ext) {
path = path.replace("." + oldExt, "." + ext);
}
} else {
path = `${SP}C${SP}Users${SP}Desktop${SP}${title}.${ext}`;
}
//
const isShare = ref(false)
const isWrite = ref(0)
if (isShareFile(path)) {
const file = await sys?.fs.getShareInfo(path)
isShare.value = true
isWrite.value = file.fs.is_write
if (!isWrite.value) {
new Notify({
title: "提示",
content: "该文件没有编辑权限",
});
return;
}
}else if (await sys?.fs.exists(path)) {
let res = await Dialog.showMessageBox({
type: "info",
title: "提示",
message: "存在相同的文件名-" + title,
buttons: ["覆盖文件?", "取消"],
});
//console.log(res)
if (res.response > 0) {
return;
}
}
if (typeof data.content === "string") {
if (data.content.indexOf(";base64,") > -1) {
const parts = data.content.split(";base64,");
data.content = parts[1];
}
if (isBase64(data.content)) {
data.content = base64ToBuffer(data.content);
//console.log(data.content)
}
}
const res = isShare ? await sys?.fs.writeShareFile(path, data.content, isWrite.value) : await sys?.fs.writeFile(path, data.content);
console.log('编写文件:', res);
new Notify({
title: "提示",
content: res.code === 0 ? '文件已保存' : '文件保存失败',
});
sys.refershAppList();
} else if (eventData.type == "initSuccess") {
if (hasInit) {
return;
}
hasInit = true;
let content = win?.config?.content;
console.log(win?.config);
let title = win.getTitle();
// console.log(title);
title = title.split(SP).pop();
//console.log(title);
if (!content && win?.config.path) {
const file = getSystemConfig().file
const header = {
salt: file.salt,
filePwd: file.pwd
}
content = await sys?.fs.readFile(win?.config.path, header);
}
content = toRaw(content);
// console.log(content);
if (content && content !== "") {
storeRef.value?.contentWindow?.postMessage(
{
type: "init",
data: { content, title },
},
"*"
);
} else {
storeRef.value?.contentWindow?.postMessage(
{
type: "start",
title,
},
"*"
);
}
}
};
onMounted(() => {
window.addEventListener("message", eventHandler);
});
//console.log(props);
//let path = win?.config?.path;
// let currentPath = ref('')
const storeRef = ref<HTMLIFrameElement | null>(null);
let hasInit = false;
const eventHandler = async (e: MessageEvent) => {
const eventData = e.data;
onUnmounted(() => {
window.removeEventListener("message", eventHandler);
});
if (eventData.type == props.eventType) {
let data = JSON.parse(eventData.data);
let title = data.title;
let path;
let ext: any = props.ext;
if (ext instanceof Array) {
ext = ext[0];
}
if (data.ext) {
ext = data.ext;
}
// console.log(ext)
// console.log(data)
if (win.config && win.config.path) {
path = win.config.path;
//1
// let fileTitleArr = path.split(SP).pop().split(".");
// let oldExt = fileTitleArr.pop();
// let fileTitle = fileTitleArr.join(".");
// if (fileTitle != title) {
// path = path.replace(fileTitle, title);
// }
// if (oldExt != ext) {
// path = path.replace("." + oldExt, "." + ext);
// }
} else {
path = `${SP}C${SP}Users${SP}Desktop${SP}${title}.${ext}`;
}
//
const isShare = ref(false);
const isWrite = ref(0);
if (isShareFile(path)) {
const file = await sys?.fs.getShareInfo(path);
isShare.value = true;
isWrite.value = file.fs.is_write;
if (
!isWrite.value &&
file.fs.sender !== getSystemConfig().userInfo.id
) {
new Notify({
title: "提示",
content: "该文件没有编辑权限",
});
return;
}
} else if (await sys?.fs.exists(path)) {
let res = await Dialog.showMessageBox({
type: "info",
title: "提示",
message: "存在相同的文件名-" + title,
buttons: ["覆盖文件?", "取消"],
});
//console.log(res)
if (res.response > 0) {
return;
}
}
if (typeof data.content === "string") {
if (data.content.indexOf(";base64,") > -1) {
const parts = data.content.split(";base64,");
data.content = parts[1];
}
if (isBase64(data.content)) {
data.content = base64ToBuffer(data.content);
//console.log(data.content)
}
}
const res = isShare.value
? await sys?.fs.writeShareFile(
path,
data.content,
isWrite.value
)
: await sys?.fs.writeFile(path, data.content);
// console.log("", res, isShare);
new Notify({
title: "提示",
content: res.code === 0 ? "文件已保存" : "文件保存失败",
});
sys.refershAppList();
} else if (eventData.type == "initSuccess") {
if (hasInit) {
return;
}
hasInit = true;
let content = win?.config?.content;
let title = win.getTitle();
// console.log("win.config;", win?.config);
// console.log(title);
title = title.split(SP).pop();
if (!content && win?.config.path) {
const file = getSystemConfig().file;
const header = {
salt: file.salt,
pwd: file.pwd,
};
content = await sys?.fs.readFile(win?.config.path, header);
}
content = toRaw(content);
if (content && content !== "") {
storeRef.value?.contentWindow?.postMessage(
{
type: "init",
data: { content, title },
},
"*"
);
} else {
storeRef.value?.contentWindow?.postMessage(
{
type: "start",
title,
},
"*"
);
}
}
};
//
const delFileInputPwd = async () => {
let fileInputPwd = getSystemConfig().fileInputPwd;
const currentPath = win.config.path;
const temp = fileInputPwd.filter(
(item: any) => item.path !== currentPath
);
setSystemKey("fileInputPwd", temp);
};
onMounted(() => {
window.addEventListener("message", eventHandler);
});
onUnmounted(async () => {
await delFileInputPwd();
window.removeEventListener("message", eventHandler);
});
</script>
<style scoped>
.setiframe {
width: 100%;
height: 100%;
border: none;
}
.setiframe {
width: 100%;
height: 100%;
border: none;
}
</style>

533
frontend/src/system/config.ts

@ -1,4 +1,4 @@
import { generateRandomString } from "../util/common.ts"
import { generateRandomString } from "../util/common.ts";
export const configStoreType = localStorage.getItem('GodoOS-storeType') || 'local';
/**
*
@ -7,298 +7,305 @@ export const configStoreType = localStorage.getItem('GodoOS-storeType') || 'loca
* @returns
*/
export const getSystemConfig = (ifset = false) => {
// 从本地存储中尝试获取配置信息,若不存在则使用默认空对象
const configSetting = localStorage.getItem('GodoOS-config') || '{}';
// 解析配置信息为JSON对象
const config = JSON.parse(configSetting);
// 从本地存储中尝试获取配置信息,若不存在则使用默认空对象
const configSetting = localStorage.getItem('GodoOS-config') || '{}';
// 解析配置信息为JSON对象
const config = JSON.parse(configSetting);
// 初始化配置对象的各项属性,若本地存储中已存在则不进行覆盖
if (!config.version) {
config.version = '1.0.2';
}
if (!config.isFirstRun) {
config.isFirstRun = false;
}
if (!config.lang) {
config.lang = '';
}
// 初始化API相关URL,若本地存储中已存在则不进行覆盖
if (!config.apiUrl) {
config.apiUrl = 'http://localhost:56780';
}
if (!config.userType) {
config.userType = 'person'
}
if (!config.file) {
config.file = {
isPwd: 0,
pwd: '',
salt: 'vIf_wIUedciAd0nTm6qjJA=='
}
}
// 初始化用户信息,若本地存储中已存在则不进行覆盖
if (!config.userInfo) {
config.userInfo = {
url: '',
username: '',
password: '',
id: 0,
nickname: '',
avatar: '',
email: '',
phone: '',
desc: '',
job_number: '',
work_place: '',
hired_date: '',
ding_id: '',
role_id: 0,
roleName: '',
dept_id: 0,
deptName: '',
token: '',
user_auths: '',
user_shares: ''
};
}
// 初始化配置对象的各项属性,若本地存储中已存在则不进行覆盖
if (!config.version) {
config.version = '1.0.2';
}
if (!config.isFirstRun) {
config.isFirstRun = false;
}
if (!config.lang) {
config.lang = '';
}
// 初始化API相关URL,若本地存储中已存在则不进行覆盖
if (!config.apiUrl) {
config.apiUrl = 'http://localhost:56780';
}
if (!config.userType) {
config.userType = 'person'
}
if (!config.file) {
config.file = {
isPwd: 0,
pwd: '',
salt: 'vIf_wIUedciAd0nTm6qjJA=='
}
}
if (!config.fileInputPwd) {
config.fileInputPwd = []
}
// 初始化用户信息,若本地存储中已存在则不进行覆盖
if (!config.userInfo) {
config.userInfo = {
url: '',
username: '',
password: '',
id: 0,
nickname: '',
avatar: '',
email: '',
phone: '',
desc: '',
job_number: '',
work_place: '',
hired_date: '',
ding_id: '',
role_id: 0,
roleName: '',
dept_id: 0,
deptName: '',
token: '',
user_auths: '',
user_shares: '',
isPwd: false
};
}
config.isApp = (window as any).go ? true : false;
// 初始化系统相关信息,若本地存储中已存在则不进行覆盖
//system
if (!config.systemInfo) {
config.systemInfo = {};
}
if (!config.theme) {
config.theme = 'light';
}
if (!config.storeType) {
config.storeType = configStoreType;
}
if (!config.storePath) {
config.storePath = "";
}
if (!config.userType) {
config.userType = 'person';
}
// 初始化背景设置,若本地存储中已存在则不进行覆盖
if (!config.background) {
config.background = {
url: '/image/bg/bg6.jpg',
type: 'image',
color: 'rgba(30, 144, 255, 1)',
imageList: [
'/image/bg/bg1.jpg',
'/image/bg/bg2.jpg',
'/image/bg/bg3.jpg',
'/image/bg/bg4.jpg',
'/image/bg/bg5.jpg',
'/image/bg/bg6.jpg',
'/image/bg/bg7.jpg',
'/image/bg/bg8.jpg',
'/image/bg/bg9.jpg',
]
}
}
config.isApp = (window as any).go ? true : false;
// 初始化系统相关信息,若本地存储中已存在则不进行覆盖
//system
if (!config.systemInfo) {
config.systemInfo = {};
}
if (!config.theme) {
config.theme = 'light';
}
if (!config.storeType) {
config.storeType = configStoreType;
}
if (!config.storePath) {
config.storePath = "";
}
if (!config.userType) {
config.userType = 'person';
}
// 初始化背景设置,若本地存储中已存在则不进行覆盖
if (!config.background) {
config.background = {
url: '/image/bg/bg6.jpg',
type: 'image',
color: 'rgba(30, 144, 255, 1)',
imageList: [
'/image/bg/bg1.jpg',
'/image/bg/bg2.jpg',
'/image/bg/bg3.jpg',
'/image/bg/bg4.jpg',
'/image/bg/bg5.jpg',
'/image/bg/bg6.jpg',
'/image/bg/bg7.jpg',
'/image/bg/bg8.jpg',
'/image/bg/bg9.jpg',
]
}
}
// 初始化账户信息,若本地存储中已存在则不进行覆盖
if (!config.account) {
config.account = {
ad: true,
username: '',
password: '',
};
}
if(config.userType == 'member'){
config.account.ad = false
}
if (!config.storenet) {
config.storenet = {
url: '',
username: '',
password: '',
};
}
if (!config.webdavClient) {
config.webdavClient = {
url: '',
username: '',
password: '',
};
}
if (!config.dbInfo) {
config.dbInfo = {
url: '',
username: '',
password: '',
dbname: ''
};
}
if (!config.chatConf) {
config.chatConf = {
'checkTime': '15',
'first': '192',
'second': '168',
'thirdStart': '1',
'thirdEnd': '1',
'fourthStart': '2',
'fourthEnd': '254'
}
}
// 初始化桌面快捷方式列表,若本地存储中已存在则不进行覆盖
if (!config.desktopList) {
config.desktopList = [];
}
// 初始化菜单列表,若本地存储中已存在则不进行覆盖
if (!config.menuList) {
config.menuList = [];
}
// 生成新的会话ID,若本地存储中不存在
if (!config.token) {
config.token = generateRandomString(16);
}
// 根据参数决定是否更新本地存储中的配置信息
if (ifset) {
setSystemConfig(config)
}
// 返回配置对象
return config;
// 初始化账户信息,若本地存储中已存在则不进行覆盖
if (!config.account) {
config.account = {
ad: true,
username: '',
password: '',
};
}
if (config.userType == 'member') {
config.account.ad = false
}
if (!config.storenet) {
config.storenet = {
url: '',
username: '',
password: '',
};
}
if (!config.webdavClient) {
config.webdavClient = {
url: '',
username: '',
password: '',
};
}
if (!config.dbInfo) {
config.dbInfo = {
url: '',
username: '',
password: '',
dbname: ''
};
}
if (!config.chatConf) {
config.chatConf = {
'checkTime': '15',
'first': '192',
'second': '168',
'thirdStart': '1',
'thirdEnd': '1',
'fourthStart': '2',
'fourthEnd': '254'
}
}
// 初始化桌面快捷方式列表,若本地存储中已存在则不进行覆盖
if (!config.desktopList) {
config.desktopList = [];
}
// 初始化菜单列表,若本地存储中已存在则不进行覆盖
if (!config.menuList) {
config.menuList = [];
}
// 生成新的会话ID,若本地存储中不存在
if (!config.token) {
config.token = generateRandomString(16);
}
// 根据参数决定是否更新本地存储中的配置信息
if (ifset) {
setSystemConfig(config)
}
// 返回配置对象
return config;
};
export function getApiUrl() {
const config = getSystemConfig();
if (config.userType == 'person') {
return config.apiUrl
}else{
return config.userInfo.url
}
const config = getSystemConfig();
if (config.userType == 'person') {
return config.apiUrl
} else {
return config.userInfo.url
}
}
export function getFileUrl() {
const config = getSystemConfig();
if (config.userType == 'person') {
if (config.storeType == 'net') {
return config.storenet.url + '/file'
}
else if (config.storeType == 'webdav') {
return config.apiUrl + '/webdav'
} else {
return config.apiUrl + '/file'
}
const config = getSystemConfig();
if (config.userType == 'person') {
if (config.storeType == 'net') {
return config.storenet.url + '/file'
}
else if (config.storeType == 'webdav') {
return config.apiUrl + '/webdav'
} else {
return config.userInfo.url + '/files'
return config.apiUrl + '/file'
}
} else {
return config.userInfo.url + '/files'
}
}
export function getChatUrl() {
const config = getSystemConfig();
if (config.userType == 'person') {
return config.apiUrl + '/localchat'
} else {
return config.userInfo.url + '/chat'
}
const config = getSystemConfig();
if (config.userType == 'person') {
return config.apiUrl + '/localchat'
} else {
return config.userInfo.url + '/chat'
}
}
export function getUrl(url: string, islast = true) {
const config = getSystemConfig();
if (config.userType == 'person') {
return config.apiUrl + url
const config = getSystemConfig();
if (config.userType == 'person') {
return config.apiUrl + url
} else {
if (islast) {
return config.userInfo.url + url + '&uuid=' + getClientId() + '&token=' + config.userInfo.token
} else {
if(islast){
return config.userInfo.url + url + '&uuid=' + getClientId() + '&token=' + config.userInfo.token
}else{
return config.userInfo.url + url + '?uuid=' + getClientId() + '&token=' + config.userInfo.token
}
return config.userInfo.url + url + '?uuid=' + getClientId() + '&token=' + config.userInfo.token
}
}
}
export function getWorkflowUrl(){
const config = getSystemConfig();
if (config.userType == 'member') {
return config.userInfo.url + '/views/desktop/index.html' + '?uuid=' + getClientId() + '&token=' + config.userInfo.token
}
export function getWorkflowUrl() {
const config = getSystemConfig();
if (config.userType == 'member') {
return config.userInfo.url + '/views/desktop/index.html' + '?uuid=' + getClientId() + '&token=' + config.userInfo.token
}
}
export function fetchGet(url: string, headerConfig?: {[key: string]: string}) {
const config = getSystemConfig();
if (config.userType == 'person') {
return fetch(url, {
method: 'GET',
headers: headerConfig
})
} else {
return fetch(url, {
method: 'GET',
credentials: 'include',
headers: {
//'Content-Type': 'application/json',
'ClientID': getClientId(),
'Authorization': config.userInfo.token
}
})
}
export function fetchGet(url: string, headerConfig?: { [key: string]: string }) {
// console.log('请求头部;', headerConfig);
const config = getSystemConfig();
if (config.userType == 'person') {
return fetch(url, {
method: 'GET',
headers: headerConfig
})
} else {
return fetch(url, {
method: 'GET',
credentials: 'include',
headers: {
//'Content-Type': 'application/json',
'ClientID': getClientId(),
'Authorization': config.userInfo.token,
...headerConfig
}
})
}
}
export function fetchPost(url: string, data: any, headerConfig?: {[key: string]: string}) {
const config = getSystemConfig();
if (config.userType == 'person') {
return fetch(url, {
method: 'POST',
body: data
})
} else {
return fetch(url, {
method: 'POST',
credentials: 'include',
body: data,
headers: {
'ClientID': getClientId(),
'Authorization': config.userInfo.token,
...headerConfig
}
})
}
export function fetchPost(url: string, data: any, headerConfig?: { [key: string]: string }) {
const config = getSystemConfig();
if (config.userType == 'person') {
return fetch(url, {
method: 'POST',
body: data
})
} else {
return fetch(url, {
method: 'POST',
credentials: 'include',
body: data,
headers: {
'ClientID': getClientId(),
'Authorization': config.userInfo.token,
...headerConfig
}
})
}
}
export function isWindowsOS() {
return /win64|wow64|win32|win16|wow32/i.test(navigator.userAgent);
return /win64|wow64|win32|win16|wow32/i.test(navigator.userAgent);
}
export function parseJson(str: string) {
try {
return JSON.parse(str);
} catch (e) {
return undefined;
}
try {
return JSON.parse(str);
} catch (e) {
return undefined;
}
};
export function getSplit() {
if (isWindowsOS()) {
return "\\"
} else {
return "/"
}
if (isWindowsOS()) {
return "\\"
} else {
return "/"
}
}
export const getSystemKey = (key: string, ifset = false) => {
const config = getSystemConfig(ifset);
if (key.indexOf('.') > -1) {
const keys = key.split('.');
return config[keys[0]][keys[1]];
} else {
return config[key];
}
const config = getSystemConfig(ifset);
if (key.indexOf('.') > -1) {
const keys = key.split('.');
return config[keys[0]][keys[1]];
} else {
return config[key];
}
}
export const setSystemKey = (key: string, val: any) => {
const config = getSystemConfig();
config[key] = val;
localStorage.setItem('GodoOS-config', JSON.stringify(config));
localStorage.setItem('GodoOS-storeType', config.storeType);
const config = getSystemConfig();
config[key] = val;
localStorage.setItem('GodoOS-config', JSON.stringify(config));
localStorage.setItem('GodoOS-storeType', config.storeType);
};
export const setSystemConfig = (config: any) => {
localStorage.setItem('GodoOS-config', JSON.stringify(config));
localStorage.setItem('GodoOS-storeType', config.storeType);
localStorage.setItem('GodoOS-config', JSON.stringify(config));
localStorage.setItem('GodoOS-storeType', config.storeType);
};
export const clearSystemConfig = () => {
const storetype = localStorage.getItem('GodoOS-storeType') || 'local';
localStorage.clear()
localStorage.setItem('GodoOS-storeType', storetype)
//localStorage.removeItem('GodoOS-config');
const storetype = localStorage.getItem('GodoOS-storeType') || 'local';
localStorage.clear()
localStorage.setItem('GodoOS-storeType', storetype)
//localStorage.removeItem('GodoOS-config');
};
// function bin2hex(s: string) {
// s = encodeURI(s);//只会有0-127的ascii不转化
@ -331,12 +338,12 @@ export const clearSystemConfig = () => {
// return uuid;
// }
export const getClientId = () => {
let uuid: any = localStorage.getItem("godoosClientId");
if (!uuid) {
const timestamp = new Date().getTime();
const random = Math.floor(Math.random() * 1000000);
uuid = `${timestamp}${random}`;
localStorage.setItem("godoosClientId", uuid);
}
return uuid;
let uuid: any = localStorage.getItem("godoosClientId");
if (!uuid) {
const timestamp = new Date().getTime();
const random = Math.floor(Math.random() * 1000000);
uuid = `${timestamp}${random}`;
localStorage.setItem("godoosClientId", uuid);
}
return uuid;
}

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

@ -1,445 +1,476 @@
import { getFileUrl,fetchGet,fetchPost } from "../config.ts";
const API_BASE_URL = getFileUrl()
import { OsFileMode } from '../core/FileMode';
import { getSystemConfig } from "@/system/config";
import { turnServePath, turnLocalPath, isRootShare, isShareFile } from "@/util/sharePath.ts";
import { isRootShare, isShareFile, turnLocalPath, turnServePath } from "@/util/sharePath.ts";
import { md5 } from "js-md5";
import { fetchGet, fetchPost, getFileUrl } from "../config.ts";
import { OsFileMode } from '../core/FileMode';
import { OsFile } from "./FileSystem.ts";
const API_BASE_URL = getFileUrl()
// import { notifyError } from "@/util/msg";
export async function handleReadDir(path: any): Promise<any> {
const res = await fetchGet(`${API_BASE_URL}/read?path=${encodeURIComponent(path)}`);
if (!res.ok) {
return false;
}
return await res.json();
const res = await fetchGet(`${API_BASE_URL}/read?path=${encodeURIComponent(path)}`);
if (!res.ok) {
return false;
}
return await res.json();
}
// 查看分享文件
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=${id}`);
if (!res.ok) {
return false;
}
return await res.json();
export async function handleReadShareDir(path: string): Promise<any> {
const url = path.indexOf('/F/myshare') !== -1 ? 'sharemylist' : 'sharelist'
const res = await fetchGet(`${API_BASE_URL}/${url}`);
if (!res.ok) {
return false;
}
return await res.json();
}
// 查看分享文件夹
export async function handleShareDir(id: number,path: string): Promise<any> {
path = turnServePath(path)
const res = await fetchGet(`${API_BASE_URL}/sharedir?id=${id}&dirPath=${path}`);
if (!res.ok) {
return false;
}
return await res.json();
export async function handleShareDir(path: string): Promise<any> {
path = turnServePath(path)
const res = await fetchGet(`${API_BASE_URL}/sharedir?dirPath=${path}`);
if (!res.ok) {
return false;
}
return await res.json();
}
// 读文件
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;
}
return await res.json();
path = turnServePath(path)
const res = await fetchGet(`${API_BASE_URL}/shareread?path=${path}`);
if (!res.ok) {
return false;
}
return await res.json();
}
// 删除分享文件
export async function handleShareUnlink(path: string): Promise<any> {
const file = await handleShareDetail(path,getSystemConfig()?.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();
const file = await handleShareDetail(path)
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, 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;
}
return await res.json();
export async function handleShareDetail(path: string): Promise<any> {
const sig = path.indexOf('/F/myshare') === 0 ? 0 : 1
path = turnServePath(path)
const res = await fetchGet(`${API_BASE_URL}/shareinfo?path=${path}&sig=${sig}`);
if (!res.ok) {
return false;
}
return await res.json();
}
// 编写共享文件
export async function handleWriteShareFile(path: string, content: any, isWrite: number): Promise<any> {
const formData = getFormData(content);
const res = await fetchPost(`${API_BASE_URL}/writewithchmod?path=${path}&iswrite=${isWrite}`, formData);
if (!res.ok) {
return false;
}
return await res.json();
const formData = getFormData(content);
const res = await fetchPost(`${API_BASE_URL}/writewithchmod?path=${path}&iswrite=${isWrite}`, formData);
if (!res.ok) {
return false;
}
return await res.json();
}
export async function handleStat(path: string): Promise<any> {
const res = await fetchGet(`${API_BASE_URL}/stat?path=${encodeURIComponent(path)}`);
if (!res.ok) {
return false;
}
return await res.json();
const res = await fetchGet(`${API_BASE_URL}/stat?path=${encodeURIComponent(path)}`);
if (!res.ok) {
return false;
}
return await res.json();
}
export async function handleChmod(path: string, mode: string): Promise<any> {
const res = await fetchPost(`${API_BASE_URL}/chmod`, JSON.stringify({ path, mode }));
if (!res.ok) {
return false;
}
return await res.json();
const res = await fetchPost(`${API_BASE_URL}/chmod`, JSON.stringify({ path, mode }));
if (!res.ok) {
return false;
}
return await res.json();
}
function osFileModeToOctal(mode: OsFileMode): string {
switch (mode) {
case OsFileMode.Read:
return "400";
case OsFileMode.Write:
return "200";
case OsFileMode.Execute:
return "100";
case OsFileMode.ReadWrite:
return "600";
case OsFileMode.ReadExecute:
return "500";
case OsFileMode.WriteExecute:
return "300";
case OsFileMode.ReadWriteExecute:
return "700";
default:
throw new Error("Invalid OsFileMode");
}
switch (mode) {
case OsFileMode.Read:
return "400";
case OsFileMode.Write:
return "200";
case OsFileMode.Execute:
return "100";
case OsFileMode.ReadWrite:
return "600";
case OsFileMode.ReadExecute:
return "500";
case OsFileMode.WriteExecute:
return "300";
case OsFileMode.ReadWriteExecute:
return "700";
default:
throw new Error("Invalid OsFileMode");
}
}
export async function handleExists(path: string): Promise<any> {
const res = await fetchGet(`${API_BASE_URL}/exists?path=${encodeURIComponent(path)}`);
if (!res.ok) {
return false;
}
return await res.json();
const res = await fetchGet(`${API_BASE_URL}/exists?path=${encodeURIComponent(path)}`);
if (!res.ok) {
return false;
}
return await res.json();
}
export async function handleReadFile(path: string , header?: {[key: string]: string}): Promise<any> {
const res = await fetchGet(`${API_BASE_URL}/readfile?path=${encodeURIComponent(path)}`, header);
if (!res.ok) {
return false;
export async function handleReadFile(path: string, header?: { [key: string]: string }): Promise<any> {
const userType = getSystemConfig().userType
// let head = userType === 'member' ? { pwd: header?.pwd || '' } : { ...header }
let head = {}
if (userType === 'member') {
head = {
pwd: header?.pwd || ''
}
return await res.json();
} else if (getSystemConfig().file.isPwd === 1) {
head = {
pwd: md5(header?.pwd || ''),
salt: header?.salt || ''
}
}
const res = await fetchGet(`${API_BASE_URL}/readfile?path=${encodeURIComponent(path)}`, head);
if (!res.ok) {
return false;
}
return await res.json();
}
export async function handleUnlink(path: string): Promise<any> {
const res = await fetchGet(`${API_BASE_URL}/unlink?path=${encodeURIComponent(path)}`);
if (!res.ok) {
return false;
}
return await res.json();
const res = await fetchGet(`${API_BASE_URL}/unlink?path=${encodeURIComponent(path)}`);
if (!res.ok) {
return false;
}
return await res.json();
}
export async function handleClear(): Promise<any> {
const res = await fetchGet(`${API_BASE_URL}/clear`);
if (!res.ok) {
return false;
}
return await res.json();
const res = await fetchGet(`${API_BASE_URL}/clear`);
if (!res.ok) {
return false;
}
return await res.json();
}
export async function handleRename(oldPath: string, newPath: string): Promise<any> {
const url = isShareFile(oldPath) ? 'sharerename' : 'rename'
let params = ''
if (isShareFile(oldPath)) {
const optionID = oldPath.indexOf('/F/myshare') === 0 ? 0 : 1
oldPath = turnServePath(oldPath)
newPath = turnServePath(newPath)
params = `oldpath=${encodeURIComponent(oldPath)}&newpath=${encodeURIComponent(newPath)}&userID=${getSystemConfig()?.userInfo.id}&optionID=${optionID}`
} else {
params = `oldPath=${encodeURIComponent(oldPath)}&newPath=${encodeURIComponent(newPath)}`
}
const res = await fetchGet(`${API_BASE_URL}/${url}?${params}`);
if (!res.ok) {
return false;
}
return await res.json();
const url = isShareFile(oldPath) ? 'sharerename' : 'rename'
let params = ''
if (isShareFile(oldPath)) {
const optionID = oldPath.indexOf('/F/myshare') === 0 ? 0 : 1
oldPath = turnServePath(oldPath)
newPath = turnServePath(newPath)
params = `oldpath=${encodeURIComponent(oldPath)}&newpath=${encodeURIComponent(newPath)}&userID=${getSystemConfig()?.userInfo.id}&optionID=${optionID}`
} else {
params = `oldPath=${encodeURIComponent(oldPath)}&newPath=${encodeURIComponent(newPath)}`
}
const res = await fetchGet(`${API_BASE_URL}/${url}?${params}`);
if (!res.ok) {
return false;
}
return await res.json();
}
export async function handleMkdir(dirPath: string): Promise<any> {
const res = await fetchPost(`${API_BASE_URL}/mkdir?dirPath=${encodeURIComponent(dirPath)}`, {});
if (!res.ok) {
return false;
}
return await res.json();
const res = await fetchPost(`${API_BASE_URL}/mkdir?dirPath=${encodeURIComponent(dirPath)}`, {});
if (!res.ok) {
return false;
}
return await res.json();
}
export async function handleRmdir(dirPath: string): Promise<any> {
const res = await fetchGet(`${API_BASE_URL}/rmdir?dirPath=${encodeURIComponent(dirPath)}`);
if (!res.ok) {
return false;
}
return await res.json();
const res = await fetchGet(`${API_BASE_URL}/rmdir?dirPath=${encodeURIComponent(dirPath)}`);
if (!res.ok) {
return false;
}
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) {
return false;
}
return await res.json();
const res = await fetchGet(`${API_BASE_URL}/copyfile?srcPath=${encodeURIComponent(srcPath)}&dstPath=${encodeURIComponent(dstPath)}`);
if (!res.ok) {
return false;
}
return await res.json();
}
export function getFormData(content: any) {
let blobContent: Blob;
if (typeof content === 'string') {
// 如果content是字符串,转换为Blob并指定文本类型
blobContent = new Blob([content], { type: 'text/plain;charset=utf-8' });
} else if ('data' in content && Array.isArray(content.data)) {
// 假设data属性是一个字节数组,将其转换为ArrayBuffer
const arrayBuffer = new Uint8Array(content.data).buffer;
//console.log(arrayBuffer)
blobContent = new Blob([arrayBuffer]);
} else if (content instanceof ArrayBuffer) {
// 如果已经是ArrayBuffer,直接使用
blobContent = new Blob([content]);
} else if (content instanceof Blob) {
// 如果是Blob,直接使用
blobContent = content;
}
else if (content instanceof Array || content instanceof Object) {
// 如果是数组
blobContent = new Blob([JSON.stringify(content)], { type: 'text/plain;charset=utf-8' });
} else {
throw new Error('Unsupported content format');
}
let blobContent: Blob;
if (typeof content === 'string') {
// 如果content是字符串,转换为Blob并指定文本类型
blobContent = new Blob([content], { type: 'text/plain;charset=utf-8' });
} else if ('data' in content && Array.isArray(content.data)) {
// 假设data属性是一个字节数组,将其转换为ArrayBuffer
const arrayBuffer = new Uint8Array(content.data).buffer;
//console.log(arrayBuffer)
blobContent = new Blob([arrayBuffer]);
} else if (content instanceof ArrayBuffer) {
// 如果已经是ArrayBuffer,直接使用
blobContent = new Blob([content]);
} else if (content instanceof Blob) {
// 如果是Blob,直接使用
blobContent = content;
}
else if (content instanceof Array || content instanceof Object) {
// 如果是数组
blobContent = new Blob([JSON.stringify(content)], { type: 'text/plain;charset=utf-8' });
} else {
throw new Error('Unsupported content format');
}
const formData = new FormData();
formData.append('content', blobContent);
return formData
const formData = new FormData();
formData.append('content', blobContent);
return formData
}
export async function handleWriteFile(filePath: string, content: any): Promise<any> {
const formData = getFormData(content);
const url = `${API_BASE_URL}/writefile?filePath=${encodeURIComponent(filePath)}`;
const res = await fetchPost(url, formData);
if (!res.ok) {
return false;
}
return await res.json();
export async function handleWriteFile(filePath: string, content: any, header?: { [key: string]: any }): Promise<any> {
const formData = getFormData(content);
const head = header ? { ...header } : {}
const url = `${API_BASE_URL}/writefile?path=${encodeURIComponent(filePath)}`;
// const url = `${API_BASE_URL}/writefile?filePath=${encodeURIComponent(filePath)}`;
const res = await fetchPost(url, formData, head);
if (!res.ok) {
return false;
}
return await res.json();
}
export async function handleAppendFile(filePath: string, content: string | Blob): Promise<any> {
const formData = getFormData(content);
const url = `${API_BASE_URL}/appendfile?filePath=${encodeURIComponent(filePath)}`;
const res = await fetchPost(url, formData);
if (!res.ok) {
return false;
}
return await res.json();
const formData = getFormData(content);
const url = `${API_BASE_URL}/appendfile?filePath=${encodeURIComponent(filePath)}`;
const res = await fetchPost(url, formData);
if (!res.ok) {
return false;
}
return await res.json();
}
export function handleWatch(path: string, callback: any, errback: any) {
if (typeof EventSource !== "undefined") {
const source = new EventSource(`${API_BASE_URL}/watch?path=${encodeURIComponent(path)}`);
source.onmessage = function (event) {
callback(event)
}
// 当与服务器的连接打开时触发
source.onopen = function () {
console.log("Connection opened.");
};
// 当与服务器的连接关闭时触发
source.onerror = function (event) {
console.log("Connection closed.");
errback(event)
};
} else {
errback("Your browser does not support server-sent events.")
if (typeof EventSource !== "undefined") {
const source = new EventSource(`${API_BASE_URL}/watch?path=${encodeURIComponent(path)}`);
source.onmessage = function (event) {
callback(event)
}
// 当与服务器的连接打开时触发
source.onopen = function () {
console.log("Connection opened.");
};
// 当与服务器的连接关闭时触发
source.onerror = function (event) {
console.log("Connection closed.");
errback(event)
};
} else {
errback("Your browser does not support server-sent events.")
}
}
export async function handleZip(path: string, ext: string): Promise<any> {
const res = await fetchGet(`${API_BASE_URL}/zip?path=${encodeURIComponent(path)}&ext=${ext}`);
if (!res.ok) {
return false;
}
return await res.json();
const res = await fetchGet(`${API_BASE_URL}/zip?path=${encodeURIComponent(path)}&ext=${ext}`);
if (!res.ok) {
return false;
}
return await res.json();
}
export async function handleUnZip(path: string): Promise<any> {
const res = await fetchGet(`${API_BASE_URL}/unzip?path=${encodeURIComponent(path)}`);
if (!res.ok) {
return false;
}
return await res.json();
const res = await fetchGet(`${API_BASE_URL}/unzip?path=${encodeURIComponent(path)}`);
if (!res.ok) {
return false;
}
return await res.json();
}
export const useOsFile = () => {
return {
// 分享
async sharedir(id: number, path: string) {
const fun = isRootShare(path) ? handleReadShareDir : handleShareDir
const response = await fun(id, path);
if (response && response.data) {
const result = response.data.map((item: {[key: string]: OsFile}) => {
item.fi.isShare = true
item.fi.parentPath = turnLocalPath(item.fi.parentPath ,path)
item.fi.path = turnLocalPath(item.fi.path ,path)
//item.fi.titleName = turnLocalPath(item.fi.titleName, path)
return item.fi
})
return result
}
return [];
},
async readShareFile(path: string) {
const response = await handleReadShareFile(path);
if (response && response.data) {
return response.data;
}
return [];
},
//分享文件夹取消
async readShareFileDir(id: number, path: string) {
const response = await handleShareDir(id, path)
if (response && response.data) {
return response.data
}
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) {
const response = await handleShareDetail(path, getSystemConfig().userInfo.id);
if (response && response.data) {
response.data.fi.isShare = true
response.data.fi.path = turnLocalPath(response.data.fi.path, path, 1)
return response.data;
}
return [];
},
//编写共享文件
async writeShareFile(path: string, content: any, isWrite: number) {
path = turnServePath(path)
const response = await handleWriteShareFile(path, content, isWrite);
if (response) {
return response;
}
return false;
},
async readdir(path: string) {
const response = await handleReadDir(path);
if (response && response.data) {
return response.data;
}
return [];
},
async stat(path: string) {
const response = await handleStat(path);
if (response && response.data) {
return response.data;
}
return false;
},
async chmod(path: string, mode: OsFileMode) {
const modes = osFileModeToOctal(mode)
const response = await handleChmod(path, modes);
if (response) {
return response;
}
return false;
},
async exists(path: string) {
const response = await handleExists(path);
if (response && response.data) {
return response.data;
return {
// 分享
async sharedir(path: string) {
const fun = isRootShare(path) ? handleReadShareDir : handleShareDir
const response = await fun(path);
if (response && response.data) {
const result = response.data.map((item: { [key: string]: OsFile }) => {
item.fi.isShare = true
item.fi.parentPath = turnLocalPath(item.fi.parentPath, path)
item.fi.path = turnLocalPath(item.fi.path, path)
//item.fi.titleName = turnLocalPath(item.fi.titleName, path)
return item.fi
})
return result
}
return [];
},
async readShareFile(path: string) {
const response = await handleReadShareFile(path);
if (response && response.data) {
return response.data;
}
return [];
},
//分享文件夹取消
async readShareFileDir(path: string) {
const response = await handleShareDir(path)
if (response && response.data) {
return response.data
}
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) {
const response = await handleShareDetail(path);
if (response && response.data) {
response.data.fi.isShare = true
response.data.fi.path = turnLocalPath(response.data.fi.path, path, 1)
return response.data;
}
return [];
},
//编写共享文件
async writeShareFile(path: string, content: any, isWrite: number) {
path = turnServePath(path)
const response = await handleWriteShareFile(path, content, isWrite);
if (response) {
return response;
}
return false;
},
async readdir(path: string) {
const response = await handleReadDir(path);
if (response && response.data) {
return response.data;
}
return [];
},
async stat(path: string) {
const response = await handleStat(path);
if (response && response.data) {
return response.data;
}
return false;
},
async chmod(path: string, mode: OsFileMode) {
const modes = osFileModeToOctal(mode)
const response = await handleChmod(path, modes);
if (response) {
return response;
}
return false;
},
async exists(path: string) {
const response = await handleExists(path);
if (response && response.data) {
return response.data;
}
return false;
},
async readFile(path: string, header?: { [key: string]: string }) {
// 注意:handleReadFile返回的是JSON,但通常readFile期望返回Buffer或字符串
const response = await handleReadFile(path, header);
if (response && response.code === 0) {
return response.data;
}
return false;
},
async unlink(path: string) {
const fun = path.indexOf('/F') === 0 ? handleShareUnlink : handleUnlink
const response = await fun(path);
if (response) {
return response;
}
return false;
},
async rename(oldPath: string, newPath: string) {
const response = await handleRename(oldPath, newPath);
if (response) {
return response;
}
return false;
},
async rmdir(path: string) {
const fun = path.indexOf('/F') === 0 ? handleShareUnlink : handleRmdir
const response = await fun(path);
if (response) {
return response;
}
return false;
},
async mkdir(path: string) {
const response = await handleMkdir(path);
if (response) {
return response;
}
return false;
},
async copyFile(srcPath: string, dstPath: string) {
const response = await handleCopyFile(srcPath, dstPath);
if (response) {
return response;
}
return false;
},
async writeFile(path: string, content: string | Blob, header?: { [key: string]: any }) {
let head = {}
if (getSystemConfig().userType == 'member') {
if (header) {
head = { ...header }
} else {
const filePwd = getSystemConfig().fileInputPwd
const pos = filePwd.findIndex((item: any) => item.path == path)
if (pos !== -1) {
head = {
pwd: filePwd[pos].pwd
}
return false;
},
async readFile(path: string, header?: {[key: string]: string}) {
// 注意:handleReadFile返回的是JSON,但通常readFile期望返回Buffer或字符串
const response = await handleReadFile(path, header);
if (response && response.data) {
return response.data;
}
return false;
},
async unlink(path: string) {
const fun = path.indexOf('/F') === 0 ? handleShareUnlink : handleUnlink
const response = await fun(path);
if (response) {
return response;
}
return false;
},
async rename(oldPath: string, newPath: string) {
const response = await handleRename(oldPath, newPath);
if (response) {
return response;
}
return false;
},
async rmdir(path: string) {
const fun = path.indexOf('/F') === 0 ? handleShareUnlink : handleRmdir
const response = await fun(path);
if (response) {
return response;
}
return false;
},
async mkdir(path: string) {
const response = await handleMkdir(path);
if (response) {
return response;
}
return false;
},
async copyFile(srcPath: string, dstPath: string) {
const response = await handleCopyFile(srcPath, dstPath);
if (response) {
return response;
}
return false;
},
async writeFile(path: string, content: string | Blob) {
const response = await handleWriteFile(path, content);
if (response) {
return response;
}
return false;
},
async appendFile(path: string, content: string | Blob) {
const response = await handleAppendFile(path, content);
if (response) {
return response;
}
return false;
},
async search(path: string, options: any) {
console.log('search:',path, options)
return true;
},
async zip(path: string, ext: string) {
const response = await handleZip(path, ext);
if (response) {
return response;
}
return false;
},
async unzip(path: string) {
const response = await handleUnZip(path);
if (response) {
return response;
}
return false;
},
serializeFileSystem() {
return Promise.reject('fs 不支持序列化');
},
deserializeFileSystem() {
return Promise.reject('fs 不支持序列化');
},
removeFileSystem() {
return handleClear();
},
registerWatcher(path: string, callback: any, errback: any) {
handleWatch(path, callback, errback);
},
}
}
}
}
//console.log('创建露肩:', path);
const response = await handleWriteFile(path, content, head);
if (response) {
return response;
}
return false;
},
async appendFile(path: string, content: string | Blob) {
const response = await handleAppendFile(path, content);
if (response) {
return response;
}
return false;
},
async search(path: string, options: any) {
console.log('search:', path, options)
return true;
},
async zip(path: string, ext: string) {
const response = await handleZip(path, ext);
if (response) {
return response;
}
return false;
},
async unzip(path: string) {
const response = await handleUnZip(path);
if (response) {
return response;
}
return false;
},
serializeFileSystem() {
return Promise.reject('fs 不支持序列化');
},
deserializeFileSystem() {
return Promise.reject('fs 不支持序列化');
},
removeFileSystem() {
return handleClear();
},
registerWatcher(path: string, callback: any, errback: any) {
handleWatch(path, callback, errback);
},
}
};

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

@ -1,10 +1,10 @@
import * as fspath from './Path';
import { OsFileInterface } from './FIleInterface';
import JSZip from "jszip";
import { SystemOptions } from '../type/type';
import { InitSystemFile, InitUserFile } from './SystemFileConfig';
import { createInitFile } from './createInitFile';
import { OsFileInterface } from './FIleInterface';
import { OsFileMode } from './FileMode';
import JSZip from "jszip";
import * as fspath from './Path';
import { InitSystemFile, InitUserFile } from './SystemFileConfig';
type DateLike = Date | string | number;
// Os文件模式枚举
class OsFileInfo {
@ -896,7 +896,7 @@ class OsFileSystem implements OsFileInterface {
const transedPath = fspath.transformPath(path);
// 获取父路径
let parentPath = fspath.dirname(transedPath);
// 如果父路径为空,设置为根路径
if (parentPath === '') parentPath = '/';
// 判断文件是否存在
@ -1120,7 +1120,7 @@ class OsFileSystem implements OsFileInterface {
const ziplibs = new JSZip();
const unziped = await ziplibs.loadAsync(content);
const targetPath = path.substring(0, path.lastIndexOf("."))
if (!await that.exists(targetPath)) {
await that.mkdir(targetPath)
}

22
frontend/src/system/index.ts

@ -452,7 +452,7 @@ export class System {
const filePwd = getSystemConfig()
const header = {
salt: '',
filePwd: ''
pwd: ''
}
//判断文件是否需要输入密码
if (fileStat.isPwd && path.indexOf('.exe') === -1) {
@ -461,14 +461,30 @@ export class System {
return
}
header.salt = filePwd.file.salt || 'vIf_wIUedciAd0nTm6qjJA=='
header.filePwd = temp?.inputPwd || ''
header.pwd = temp?.inputPwd || ''
}
// 读取文件内容
const fileContent = await this.fs.readFile(path, header);
if (!fileContent && fileStat.isPwd) {
// console.log('文件:', fileContent);
if (fileContent === false && fileStat.isPwd) {
notifyError('密码错误')
return
}
//企业用户文件加密密码存储
if (fileStat.isPwd && getSystemConfig().userType === 'member') {
let fileInputPwd = getSystemConfig().fileInputPwd
const pos = fileInputPwd.findIndex((item: any) => item.path == path)
if (pos !== -1) {
fileInputPwd[pos].pwd = header.pwd
} else {
fileInputPwd.push({
path: path,
pwd: header.pwd
})
}
setSystemKey('fileInputPwd', fileInputPwd)
}
// 从_fileOpenerMap中获取文件扩展名对应的函数并调用
const fileName = extname(fileStat?.name || '') || 'link'
this._flieOpenerMap

8
frontend/src/system/window/Dialog.ts

@ -1,6 +1,7 @@
import { ElMessageBox } from 'element-plus'
import {BrowserWindow} from "./BrowserWindow"
import { md5 } from "js-md5"
import { BrowserWindow } from "./BrowserWindow"
// import { setSystemKey } from "@/system/config"
// import { md5 } from "js-md5"
class Dialog {
constructor() {
// static class
@ -120,8 +121,9 @@ class Dialog {
}).then(({value}) => {
promres({
response: 1,
inputPwd: md5(value)
inputPwd: value
});
// setSystemKey('filePwd', value)
}).catch(()=>{
promres({
response: -1,

Loading…
Cancel
Save