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. 76
      frontend/src/components/oa/FilePwd.vue
  6. 2
      frontend/src/components/setting/SetFilePwd.vue
  7. 330
      frontend/src/components/window/IframeFile.vue
  8. 533
      frontend/src/system/config.ts
  9. 785
      frontend/src/system/core/FileOs.ts
  10. 8
      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 { useSystem,OsFileWithoutContent,basename } from '@/system/index.ts';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import { dealSystemName } from '@/i18n'; import { dealSystemName } from '@/i18n';
import { getSystemConfig } from "@/system/config";
import { isShareFile } from '@/util/sharePath'; import { isShareFile } from '@/util/sharePath';
const sys = useSystem(); const sys = useSystem();
@ -113,7 +112,7 @@ function onSubOpen(path: string) {
async function onSubRefresh(item: FileWithOpen) { async function onSubRefresh(item: FileWithOpen) {
if(isShareFile(item.path)) { 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; return file.isDirectory;
}); });
} else { } else {
@ -135,7 +134,7 @@ async function onOpenArrow(item: FileWithOpen) {
// }); // });
// } else // } else
if(isShareFile(item.path)) { 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; return file.isDirectory;
}); });
} else { } 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> <template>
<div class="uper_nav"> <div class="uper_nav">
<div class="uper_nav_button" @click="changeHistory(-1)"> <div
<svg class="uper_nav_button"
t="1632984723698" @click="changeHistory(-1)"
class="icon" >
viewBox="0 0 1024 1024" <svg
version="1.1" t="1632984723698"
xmlns="http://www.w3.org/2000/svg" class="icon"
p-id="10100" viewBox="0 0 1024 1024"
> version="1.1"
<path xmlns="http://www.w3.org/2000/svg"
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="10100"
p-id="10101" >
/> <path
</svg> 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"
</div> p-id="10101"
<div class="uper_nav_button" @click="changeHistory(1)"> />
<svg </svg>
t="1632984737821" </div>
class="icon" <div
viewBox="0 0 1024 1024" class="uper_nav_button"
version="1.1" @click="changeHistory(1)"
xmlns="http://www.w3.org/2000/svg" >
p-id="10249" <svg
> t="1632984737821"
<path class="icon"
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" viewBox="0 0 1024 1024"
p-id="10250" version="1.1"
/> xmlns="http://www.w3.org/2000/svg"
</svg> p-id="10249"
</div> >
<div class="uper_nav_button" @click="backFolder()"> <path
<svg 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"
t="1639145815176" p-id="10250"
class="icon" />
viewBox="0 0 1024 1024" </svg>
version="1.1" </div>
xmlns="http://www.w3.org/2000/svg" <div
p-id="3860" class="uper_nav_button"
> @click="backFolder()"
<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" <svg
fill="#444444" t="1639145815176"
p-id="3861" class="icon"
/> viewBox="0 0 1024 1024"
</svg> version="1.1"
</div> 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"> <div
<template v-if="modelValue?.startsWith('search:')"> @click="startInput()"
<span>{{ modelValue }}</span> v-if="path_state == 'pendding'"
</template> class="path"
<template v-else> >
<span <template v-if="modelValue?.startsWith('search:')">
class="path-p" <span>{{ modelValue }}</span>
:key="p" </template>
v-for="(p, index) in modelValue?.split('/').slice(1)" <template v-else>
@click.stop="handlePathPClick(index)" <span
> class="path-p"
{{ p }}<span class="iconfont icon-arrow-down"></span :key="p"
></span> v-for="(p, index) in modelValue?.split('/').slice(1)"
</template> @click.stop="handlePathPClick(index)"
</div> >
<div @focusout="endInput()" v-show="path_state == 'inputing'" class="path_inputing nav-path"> {{ p }}<span class="iconfont icon-arrow-down"></span
<input ref="myinput" v-model="inputStr" @keyup.enter="endInput()" /> ></span>
</div> </template>
<div class="search path_inputing"> </div>
<input placeholder="search" v-model="searchStr" @keyup.enter="endSearch" @blur="endSearch" /> <div
</div> @focusout="endInput()"
</div> 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> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, nextTick } from 'vue'; import { nextTick, ref } from "vue";
const props = defineProps<{ const props = defineProps<{
modelValue?: string; modelValue?: string;
}>(); }>();
const emit = defineEmits(['update:modelValue', 'backFolder', 'changeHistory', 'refresh', 'search']); const emit = defineEmits([
"update:modelValue",
"backFolder",
"changeHistory",
"refresh",
"search",
]);
function backFolder() { function backFolder() {
emit('backFolder'); emit("backFolder");
} }
function changeHistory(num: number) { function changeHistory(num: number) {
emit('changeHistory', num); emit("changeHistory", num);
} }
/* ------------ 路径输入框 ------------*/ /* ------------ 路径输入框 ------------*/
const myinput = ref<HTMLElement | null>(null); const myinput = ref<HTMLElement | null>(null);
const inputStr = ref(props.modelValue); const inputStr = ref(props.modelValue);
const path_state = ref('pendding'); const path_state = ref("pendding");
function startInput() { function startInput() {
path_state.value = 'inputing'; path_state.value = "inputing";
inputStr.value = props.modelValue; inputStr.value = props.modelValue;
nextTick(() => { nextTick(() => {
myinput.value?.focus(); myinput.value?.focus();
}); });
} }
function endInput() { function endInput() {
path_state.value = 'pendding'; path_state.value = "pendding";
emit('refresh', inputStr.value); emit("refresh", inputStr.value);
} }
/* ------------ 路径输入框end ---------*/ /* ------------ 路径输入框end ---------*/
/* ------------ 搜索框 ------------*/ /* ------------ 搜索框 ------------*/
const searchStr = ref(''); const searchStr = ref("");
function endSearch() { function endSearch() {
if (searchStr.value == '') return; if (searchStr.value == "") return;
emit('search', searchStr.value); emit("search", searchStr.value);
searchStr.value = ''; searchStr.value = "";
} }
function handlePathPClick(index: number) { function handlePathPClick(index: number) {
const path = props.modelValue const path = props.modelValue
?.split('/') ?.split("/")
.slice(0, index + 2) .slice(0, index + 2)
.join('/'); .join("/");
if (path === undefined) return; if (path === undefined) return;
if (path === props.modelValue) return; if (path === props.modelValue) return;
emit('refresh', path); emit("refresh", path);
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.icon-arrow-down { .icon-arrow-down {
display: inline-block; display: inline-block;
width: 4px; width: 4px;
height: 4px; height: 4px;
transform: translateY(-1px) rotate(-45deg); transform: translateY(-1px) rotate(-45deg);
border: 2px solid rgba(0, 0, 0, 0.465); border: 2px solid rgba(0, 0, 0, 0.465);
border-left: none; border-left: none;
border-top: none; border-top: none;
transition: all 0.1s; transition: all 0.1s;
margin: 0 2px; margin: 0 2px;
} }
.uper_nav { .uper_nav {
height: var(--button-item-height); height: var(--button-item-height);
display: flex; display: flex;
margin-top:5px; margin-top: 5px;
} }
.uper_nav_button { .uper_nav_button {
width: calc(var(--button-item-height) - 10px); width: calc(var(--button-item-height) - 10px);
height: var(--button-item-height); height: var(--button-item-height);
line-height: var(--button-item-height); line-height: var(--button-item-height);
padding: 0px 4px; padding: 0px 4px;
margin: 0 auto; margin: 0 auto;
flex-shrink: 0; flex-shrink: 0;
text-align: center; text-align: center;
filter: brightness(230%); filter: brightness(230%);
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.uper_nav_button_small { .uper_nav_button_small {
width: calc(var(--button-item-height) - 16px); width: calc(var(--button-item-height) - 16px);
} }
.uper_nav_button svg { .uper_nav_button svg {
width: calc(var(--button-item-height) - 16px); width: calc(var(--button-item-height) - 16px);
height: calc(var(--button-item-height) - 16px); height: calc(var(--button-item-height) - 16px);
} }
.path { .path {
height: calc(var(--button-item-height)); height: calc(var(--button-item-height));
width: 100%; width: 100%;
line-height: calc(var(--button-item-height) - 6px); line-height: calc(var(--button-item-height) - 6px);
padding: 0px 5px; padding: 0px 5px;
margin: 0px 2px; margin: 0px 2px;
border: 1px solid rgba(134, 134, 134, 0.267); border: 1px solid rgba(134, 134, 134, 0.267);
transition: all 0.1s; transition: all 0.1s;
/* text-align: center; */ /* text-align: center; */
overflow: auto; overflow: auto;
user-select: none; user-select: none;
display: flex; display: flex;
align-items: center; align-items: center;
.path-p { .path-p {
padding: 0; padding: 0;
margin: 0; margin: 0;
margin-right: 2px; margin-right: 2px;
transition: all 0.1s; transition: all 0.1s;
border: 1px solid transparent; border: 1px solid transparent;
} }
.path-p:hover { .path-p:hover {
background-color: #b1f1ff4c; background-color: #b1f1ff4c;
border: 1px solid rgba(0, 102, 255, 0.138); border: 1px solid rgba(0, 102, 255, 0.138);
cursor: pointer; cursor: pointer;
} }
.path span { .path span {
height: var(--button-item-height); height: var(--button-item-height);
/* text-align: center; */ /* text-align: center; */
line-height: var(--button-item-height); line-height: var(--button-item-height);
} }
} }
.path_inputing { .path_inputing {
height: calc(var(--button-item-height)); height: calc(var(--button-item-height));
width: 100%; width: 100%;
line-height: calc(var(--button-item-height) - 6px); line-height: calc(var(--button-item-height) - 6px);
padding: 0px 5px; padding: 0px 5px;
margin: 0px 2px; margin: 0px 2px;
border: 1px solid rgba(134, 134, 134, 0.267); border: 1px solid rgba(134, 134, 134, 0.267);
transition: all 0.1s; transition: all 0.1s;
user-select: text; user-select: text;
} }
.path_inputing input { .path_inputing input {
height: 100%; height: 100%;
width: 100%; width: 100%;
/* padding: 1px 5px; */ /* padding: 1px 5px; */
/* text-align: center; */ /* text-align: center; */
line-height: var(--button-item-height); line-height: var(--button-item-height);
background: none; background: none;
border: none; border: none;
outline: none; outline: none;
user-select: none; user-select: none;
} }
.nav-path { .nav-path {
} }
.search { .search {
width: 200px; width: 200px;
} }
.path:hover { .path:hover {
border: 1px solid rgb(0, 102, 255); border: 1px solid rgb(0, 102, 255);
} }
</style> </style>

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

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

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

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

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

@ -1,162 +1,188 @@
<template> <template>
<iframe class="setiframe" allow="fullscreen" ref="storeRef" :src="src"></iframe> <iframe
class="setiframe"
allow="fullscreen"
ref="storeRef"
:src="src"
></iframe>
</template> </template>
<script lang="ts" setup name="IframeFile"> <script lang="ts" setup name="IframeFile">
//@ts-ignore //@ts-ignore
import { BrowserWindow, Notify, System, Dialog } from "@/system"; import { BrowserWindow, Dialog, Notify, System } from "@/system";
import { ref, onMounted, inject, onUnmounted, toRaw } from "vue"; import { getSplit, getSystemConfig, setSystemKey } from "@/system/config";
import { isBase64, base64ToBuffer } from "@/util/file"; import { base64ToBuffer, isBase64 } from "@/util/file";
import { getSplit, getSystemConfig } from "@/system/config"; import { isShareFile } from "@/util/sharePath.ts";
import { isShareFile } from "@/util/sharePath.ts"; import { inject, onMounted, onUnmounted, ref, toRaw } from "vue";
const SP = getSplit(); const SP = getSplit();
const sys: any = inject<System>("system"); const sys: any = inject<System>("system");
const win: any = inject<BrowserWindow>("browserWindow"); const win: any = inject<BrowserWindow>("browserWindow");
const props = defineProps({ const props = defineProps({
src: { src: {
type: String, type: String,
default: "", default: "",
}, },
eventType: { eventType: {
type: String, type: String,
default: "", default: "",
}, },
ext: { ext: {
type: String, type: String,
default: "md", default: "md",
}, },
}); });
//console.log('iframe: ', props); //console.log('iframe: ', props);
//console.log(props); //console.log(props);
//let path = win?.config?.path; //let path = win?.config?.path;
const storeRef = ref<HTMLIFrameElement | null>(null); // let currentPath = ref('')
let hasInit = false; const storeRef = ref<HTMLIFrameElement | null>(null);
const eventHandler = async (e: MessageEvent) => { let hasInit = false;
const eventData = e.data; const eventHandler = async (e: MessageEvent) => {
const eventData = e.data;
if (eventData.type == props.eventType) { if (eventData.type == props.eventType) {
let data = JSON.parse(eventData.data); let data = JSON.parse(eventData.data);
let title = data.title; let title = data.title;
let path; let path;
let ext: any = props.ext; let ext: any = props.ext;
if (ext instanceof Array) { if (ext instanceof Array) {
ext = ext[0]; ext = ext[0];
} }
if (data.ext) { if (data.ext) {
ext = data.ext; ext = data.ext;
} }
// console.log(ext) // console.log(ext)
// console.log(data) // console.log(data)
if (win.config && win.config.path) { if (win.config && win.config.path) {
path = win.config.path; path = win.config.path;
let fileTitleArr = path.split(SP).pop().split("."); //1
let oldExt = fileTitleArr.pop(); // let fileTitleArr = path.split(SP).pop().split(".");
let fileTitle = fileTitleArr.join("."); // let oldExt = fileTitleArr.pop();
if (fileTitle != title) { // let fileTitle = fileTitleArr.join(".");
path = path.replace(fileTitle, title); // if (fileTitle != title) {
} // path = path.replace(fileTitle, title);
if (oldExt != ext) { // }
path = path.replace("." + oldExt, "." + ext); // if (oldExt != ext) {
} // path = path.replace("." + oldExt, "." + ext);
} else { // }
path = `${SP}C${SP}Users${SP}Desktop${SP}${title}.${ext}`; } else {
} path = `${SP}C${SP}Users${SP}Desktop${SP}${title}.${ext}`;
// }
const isShare = ref(false) //
const isWrite = ref(0) const isShare = ref(false);
if (isShareFile(path)) { const isWrite = ref(0);
const file = await sys?.fs.getShareInfo(path) if (isShareFile(path)) {
isShare.value = true const file = await sys?.fs.getShareInfo(path);
isWrite.value = file.fs.is_write isShare.value = true;
if (!isWrite.value) { isWrite.value = file.fs.is_write;
new Notify({ if (
title: "提示", !isWrite.value &&
content: "该文件没有编辑权限", file.fs.sender !== getSystemConfig().userInfo.id
}); ) {
return; new Notify({
} title: "提示",
}else if (await sys?.fs.exists(path)) { content: "该文件没有编辑权限",
let res = await Dialog.showMessageBox({ });
type: "info", return;
title: "提示", }
message: "存在相同的文件名-" + title, } else if (await sys?.fs.exists(path)) {
buttons: ["覆盖文件?", "取消"], let res = await Dialog.showMessageBox({
}); type: "info",
//console.log(res) title: "提示",
if (res.response > 0) { message: "存在相同的文件名-" + title,
return; buttons: ["覆盖文件?", "取消"],
} });
} //console.log(res)
if (typeof data.content === "string") { if (res.response > 0) {
if (data.content.indexOf(";base64,") > -1) { return;
const parts = data.content.split(";base64,"); }
data.content = parts[1]; }
} if (typeof data.content === "string") {
if (isBase64(data.content)) { if (data.content.indexOf(";base64,") > -1) {
data.content = base64ToBuffer(data.content); const parts = data.content.split(";base64,");
//console.log(data.content) data.content = parts[1];
} }
} if (isBase64(data.content)) {
const res = isShare ? await sys?.fs.writeShareFile(path, data.content, isWrite.value) : await sys?.fs.writeFile(path, data.content); data.content = base64ToBuffer(data.content);
console.log('编写文件:', res); //console.log(data.content)
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);
});
onUnmounted(() => { const res = isShare.value
window.removeEventListener("message", eventHandler); ? 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> </script>
<style scoped> <style scoped>
.setiframe { .setiframe {
width: 100%; width: 100%;
height: 100%; height: 100%;
border: none; border: none;
} }
</style> </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'; export const configStoreType = localStorage.getItem('GodoOS-storeType') || 'local';
/** /**
* *
@ -7,298 +7,305 @@ export const configStoreType = localStorage.getItem('GodoOS-storeType') || 'loca
* @returns * @returns
*/ */
export const getSystemConfig = (ifset = false) => { export const getSystemConfig = (ifset = false) => {
// 从本地存储中尝试获取配置信息,若不存在则使用默认空对象 // 从本地存储中尝试获取配置信息,若不存在则使用默认空对象
const configSetting = localStorage.getItem('GodoOS-config') || '{}'; const configSetting = localStorage.getItem('GodoOS-config') || '{}';
// 解析配置信息为JSON对象 // 解析配置信息为JSON对象
const config = JSON.parse(configSetting); const config = JSON.parse(configSetting);
// 初始化配置对象的各项属性,若本地存储中已存在则不进行覆盖 // 初始化配置对象的各项属性,若本地存储中已存在则不进行覆盖
if (!config.version) { if (!config.version) {
config.version = '1.0.2'; config.version = '1.0.2';
} }
if (!config.isFirstRun) { if (!config.isFirstRun) {
config.isFirstRun = false; config.isFirstRun = false;
} }
if (!config.lang) { if (!config.lang) {
config.lang = ''; config.lang = '';
} }
// 初始化API相关URL,若本地存储中已存在则不进行覆盖 // 初始化API相关URL,若本地存储中已存在则不进行覆盖
if (!config.apiUrl) { if (!config.apiUrl) {
config.apiUrl = 'http://localhost:56780'; config.apiUrl = 'http://localhost:56780';
} }
if (!config.userType) { if (!config.userType) {
config.userType = 'person' config.userType = 'person'
} }
if (!config.file) { if (!config.file) {
config.file = { config.file = {
isPwd: 0, isPwd: 0,
pwd: '', pwd: '',
salt: 'vIf_wIUedciAd0nTm6qjJA==' salt: 'vIf_wIUedciAd0nTm6qjJA=='
} }
} }
// 初始化用户信息,若本地存储中已存在则不进行覆盖 if (!config.fileInputPwd) {
if (!config.userInfo) { config.fileInputPwd = []
config.userInfo = { }
url: '', // 初始化用户信息,若本地存储中已存在则不进行覆盖
username: '', if (!config.userInfo) {
password: '', config.userInfo = {
id: 0, url: '',
nickname: '', username: '',
avatar: '', password: '',
email: '', id: 0,
phone: '', nickname: '',
desc: '', avatar: '',
job_number: '', email: '',
work_place: '', phone: '',
hired_date: '', desc: '',
ding_id: '', job_number: '',
role_id: 0, work_place: '',
roleName: '', hired_date: '',
dept_id: 0, ding_id: '',
deptName: '', role_id: 0,
token: '', roleName: '',
user_auths: '', dept_id: 0,
user_shares: '' deptName: '',
}; token: '',
} user_auths: '',
user_shares: '',
isPwd: false
};
}
config.isApp = (window as any).go ? true : false; config.isApp = (window as any).go ? true : false;
// 初始化系统相关信息,若本地存储中已存在则不进行覆盖 // 初始化系统相关信息,若本地存储中已存在则不进行覆盖
//system //system
if (!config.systemInfo) { if (!config.systemInfo) {
config.systemInfo = {}; config.systemInfo = {};
} }
if (!config.theme) { if (!config.theme) {
config.theme = 'light'; config.theme = 'light';
} }
if (!config.storeType) { if (!config.storeType) {
config.storeType = configStoreType; config.storeType = configStoreType;
} }
if (!config.storePath) { if (!config.storePath) {
config.storePath = ""; config.storePath = "";
} }
if (!config.userType) { if (!config.userType) {
config.userType = 'person'; config.userType = 'person';
} }
// 初始化背景设置,若本地存储中已存在则不进行覆盖 // 初始化背景设置,若本地存储中已存在则不进行覆盖
if (!config.background) { if (!config.background) {
config.background = { config.background = {
url: '/image/bg/bg6.jpg', url: '/image/bg/bg6.jpg',
type: 'image', type: 'image',
color: 'rgba(30, 144, 255, 1)', color: 'rgba(30, 144, 255, 1)',
imageList: [ imageList: [
'/image/bg/bg1.jpg', '/image/bg/bg1.jpg',
'/image/bg/bg2.jpg', '/image/bg/bg2.jpg',
'/image/bg/bg3.jpg', '/image/bg/bg3.jpg',
'/image/bg/bg4.jpg', '/image/bg/bg4.jpg',
'/image/bg/bg5.jpg', '/image/bg/bg5.jpg',
'/image/bg/bg6.jpg', '/image/bg/bg6.jpg',
'/image/bg/bg7.jpg', '/image/bg/bg7.jpg',
'/image/bg/bg8.jpg', '/image/bg/bg8.jpg',
'/image/bg/bg9.jpg', '/image/bg/bg9.jpg',
] ]
} }
} }
// 初始化账户信息,若本地存储中已存在则不进行覆盖 // 初始化账户信息,若本地存储中已存在则不进行覆盖
if (!config.account) { if (!config.account) {
config.account = { config.account = {
ad: true, ad: true,
username: '', username: '',
password: '', password: '',
}; };
} }
if(config.userType == 'member'){ if (config.userType == 'member') {
config.account.ad = false config.account.ad = false
} }
if (!config.storenet) { if (!config.storenet) {
config.storenet = { config.storenet = {
url: '', url: '',
username: '', username: '',
password: '', password: '',
}; };
} }
if (!config.webdavClient) { if (!config.webdavClient) {
config.webdavClient = { config.webdavClient = {
url: '', url: '',
username: '', username: '',
password: '', password: '',
}; };
} }
if (!config.dbInfo) { if (!config.dbInfo) {
config.dbInfo = { config.dbInfo = {
url: '', url: '',
username: '', username: '',
password: '', password: '',
dbname: '' dbname: ''
}; };
} }
if (!config.chatConf) { if (!config.chatConf) {
config.chatConf = { config.chatConf = {
'checkTime': '15', 'checkTime': '15',
'first': '192', 'first': '192',
'second': '168', 'second': '168',
'thirdStart': '1', 'thirdStart': '1',
'thirdEnd': '1', 'thirdEnd': '1',
'fourthStart': '2', 'fourthStart': '2',
'fourthEnd': '254' 'fourthEnd': '254'
} }
} }
// 初始化桌面快捷方式列表,若本地存储中已存在则不进行覆盖 // 初始化桌面快捷方式列表,若本地存储中已存在则不进行覆盖
if (!config.desktopList) { if (!config.desktopList) {
config.desktopList = []; config.desktopList = [];
} }
// 初始化菜单列表,若本地存储中已存在则不进行覆盖 // 初始化菜单列表,若本地存储中已存在则不进行覆盖
if (!config.menuList) { if (!config.menuList) {
config.menuList = []; config.menuList = [];
} }
// 生成新的会话ID,若本地存储中不存在 // 生成新的会话ID,若本地存储中不存在
if (!config.token) { if (!config.token) {
config.token = generateRandomString(16); config.token = generateRandomString(16);
} }
// 根据参数决定是否更新本地存储中的配置信息 // 根据参数决定是否更新本地存储中的配置信息
if (ifset) { if (ifset) {
setSystemConfig(config) setSystemConfig(config)
} }
// 返回配置对象 // 返回配置对象
return config; return config;
}; };
export function getApiUrl() { export function getApiUrl() {
const config = getSystemConfig(); const config = getSystemConfig();
if (config.userType == 'person') { if (config.userType == 'person') {
return config.apiUrl return config.apiUrl
}else{ } else {
return config.userInfo.url return config.userInfo.url
} }
} }
export function getFileUrl() { export function getFileUrl() {
const config = getSystemConfig(); const config = getSystemConfig();
if (config.userType == 'person') { if (config.userType == 'person') {
if (config.storeType == 'net') { if (config.storeType == 'net') {
return config.storenet.url + '/file' return config.storenet.url + '/file'
} }
else if (config.storeType == 'webdav') { else if (config.storeType == 'webdav') {
return config.apiUrl + '/webdav' return config.apiUrl + '/webdav'
} else {
return config.apiUrl + '/file'
}
} else { } else {
return config.userInfo.url + '/files' return config.apiUrl + '/file'
} }
} else {
return config.userInfo.url + '/files'
}
} }
export function getChatUrl() { export function getChatUrl() {
const config = getSystemConfig(); const config = getSystemConfig();
if (config.userType == 'person') { if (config.userType == 'person') {
return config.apiUrl + '/localchat' return config.apiUrl + '/localchat'
} else { } else {
return config.userInfo.url + '/chat' return config.userInfo.url + '/chat'
} }
} }
export function getUrl(url: string, islast = true) { export function getUrl(url: string, islast = true) {
const config = getSystemConfig(); const config = getSystemConfig();
if (config.userType == 'person') { if (config.userType == 'person') {
return config.apiUrl + url return config.apiUrl + url
} else {
if (islast) {
return config.userInfo.url + url + '&uuid=' + getClientId() + '&token=' + config.userInfo.token
} else { } else {
if(islast){ return config.userInfo.url + url + '?uuid=' + getClientId() + '&token=' + config.userInfo.token
return config.userInfo.url + url + '&uuid=' + getClientId() + '&token=' + config.userInfo.token
}else{
return config.userInfo.url + url + '?uuid=' + getClientId() + '&token=' + config.userInfo.token
}
} }
}
} }
export function getWorkflowUrl(){ export function getWorkflowUrl() {
const config = getSystemConfig(); const config = getSystemConfig();
if (config.userType == 'member') { if (config.userType == 'member') {
return config.userInfo.url + '/views/desktop/index.html' + '?uuid=' + getClientId() + '&token=' + config.userInfo.token return config.userInfo.url + '/views/desktop/index.html' + '?uuid=' + getClientId() + '&token=' + config.userInfo.token
} }
} }
export function fetchGet(url: string, headerConfig?: {[key: string]: string}) { export function fetchGet(url: string, headerConfig?: { [key: string]: string }) {
const config = getSystemConfig(); // console.log('请求头部;', headerConfig);
if (config.userType == 'person') {
return fetch(url, { const config = getSystemConfig();
method: 'GET', if (config.userType == 'person') {
headers: headerConfig return fetch(url, {
}) method: 'GET',
} else { headers: headerConfig
return fetch(url, { })
method: 'GET', } else {
credentials: 'include', return fetch(url, {
headers: { method: 'GET',
//'Content-Type': 'application/json', credentials: 'include',
'ClientID': getClientId(), headers: {
'Authorization': config.userInfo.token //'Content-Type': 'application/json',
} 'ClientID': getClientId(),
}) 'Authorization': config.userInfo.token,
} ...headerConfig
}
})
}
} }
export function fetchPost(url: string, data: any, headerConfig?: {[key: string]: string}) { export function fetchPost(url: string, data: any, headerConfig?: { [key: string]: string }) {
const config = getSystemConfig(); const config = getSystemConfig();
if (config.userType == 'person') { if (config.userType == 'person') {
return fetch(url, { return fetch(url, {
method: 'POST', method: 'POST',
body: data body: data
}) })
} else { } else {
return fetch(url, { return fetch(url, {
method: 'POST', method: 'POST',
credentials: 'include', credentials: 'include',
body: data, body: data,
headers: { headers: {
'ClientID': getClientId(), 'ClientID': getClientId(),
'Authorization': config.userInfo.token, 'Authorization': config.userInfo.token,
...headerConfig ...headerConfig
} }
}) })
} }
} }
export function isWindowsOS() { 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) { export function parseJson(str: string) {
try { try {
return JSON.parse(str); return JSON.parse(str);
} catch (e) { } catch (e) {
return undefined; return undefined;
} }
}; };
export function getSplit() { export function getSplit() {
if (isWindowsOS()) { if (isWindowsOS()) {
return "\\" return "\\"
} else { } else {
return "/" return "/"
} }
} }
export const getSystemKey = (key: string, ifset = false) => { export const getSystemKey = (key: string, ifset = false) => {
const config = getSystemConfig(ifset); const config = getSystemConfig(ifset);
if (key.indexOf('.') > -1) { if (key.indexOf('.') > -1) {
const keys = key.split('.'); const keys = key.split('.');
return config[keys[0]][keys[1]]; return config[keys[0]][keys[1]];
} else { } else {
return config[key]; return config[key];
} }
} }
export const setSystemKey = (key: string, val: any) => { export const setSystemKey = (key: string, val: any) => {
const config = getSystemConfig(); const config = getSystemConfig();
config[key] = val; config[key] = val;
localStorage.setItem('GodoOS-config', JSON.stringify(config)); localStorage.setItem('GodoOS-config', JSON.stringify(config));
localStorage.setItem('GodoOS-storeType', config.storeType); localStorage.setItem('GodoOS-storeType', config.storeType);
}; };
export const setSystemConfig = (config: any) => { export const setSystemConfig = (config: any) => {
localStorage.setItem('GodoOS-config', JSON.stringify(config)); localStorage.setItem('GodoOS-config', JSON.stringify(config));
localStorage.setItem('GodoOS-storeType', config.storeType); localStorage.setItem('GodoOS-storeType', config.storeType);
}; };
export const clearSystemConfig = () => { export const clearSystemConfig = () => {
const storetype = localStorage.getItem('GodoOS-storeType') || 'local'; const storetype = localStorage.getItem('GodoOS-storeType') || 'local';
localStorage.clear() localStorage.clear()
localStorage.setItem('GodoOS-storeType', storetype) localStorage.setItem('GodoOS-storeType', storetype)
//localStorage.removeItem('GodoOS-config'); //localStorage.removeItem('GodoOS-config');
}; };
// function bin2hex(s: string) { // function bin2hex(s: string) {
// s = encodeURI(s);//只会有0-127的ascii不转化 // s = encodeURI(s);//只会有0-127的ascii不转化
@ -331,12 +338,12 @@ export const clearSystemConfig = () => {
// return uuid; // return uuid;
// } // }
export const getClientId = () => { export const getClientId = () => {
let uuid: any = localStorage.getItem("godoosClientId"); let uuid: any = localStorage.getItem("godoosClientId");
if (!uuid) { if (!uuid) {
const timestamp = new Date().getTime(); const timestamp = new Date().getTime();
const random = Math.floor(Math.random() * 1000000); const random = Math.floor(Math.random() * 1000000);
uuid = `${timestamp}${random}`; uuid = `${timestamp}${random}`;
localStorage.setItem("godoosClientId", uuid); localStorage.setItem("godoosClientId", uuid);
} }
return uuid; return uuid;
} }

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

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

@ -1,10 +1,10 @@
import * as fspath from './Path'; import JSZip from "jszip";
import { OsFileInterface } from './FIleInterface';
import { SystemOptions } from '../type/type'; import { SystemOptions } from '../type/type';
import { InitSystemFile, InitUserFile } from './SystemFileConfig';
import { createInitFile } from './createInitFile'; import { createInitFile } from './createInitFile';
import { OsFileInterface } from './FIleInterface';
import { OsFileMode } from './FileMode'; import { OsFileMode } from './FileMode';
import JSZip from "jszip"; import * as fspath from './Path';
import { InitSystemFile, InitUserFile } from './SystemFileConfig';
type DateLike = Date | string | number; type DateLike = Date | string | number;
// Os文件模式枚举 // Os文件模式枚举
class OsFileInfo { class OsFileInfo {

22
frontend/src/system/index.ts

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

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

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

Loading…
Cancel
Save