Browse Source

fix:前端文件bug修复

master
prr 7 months ago
parent
commit
5c7d8dd671
  1. 437
      frontend/src/components/builtin/MarkDown.vue
  2. 182
      frontend/src/components/oa/ShareFiles.vue
  3. 171
      frontend/src/components/setting/SetFilePwd.vue
  4. 5
      frontend/src/components/window/IframeFile.vue
  5. 1
      frontend/src/system/core/FileOs.ts
  6. 2
      godo/cmd/serve.go

437
frontend/src/components/builtin/MarkDown.vue

@ -1,204 +1,259 @@
<script lang="ts" setup> <script lang="ts" setup>
import { BrowserWindow, System } from "@/system"; import { useHistoryStore } from "@/stores/history";
import { inject, onMounted, ref, toRaw, onUnmounted } from "vue"; import { BrowserWindow, System } from "@/system";
import { notifyError, notifySuccess } from "@/util/msg"; import { getSplit, getSystemConfig } from "@/system/config";
import Vditor from "vditor"; import { decodeBase64, isBase64 } from "@/util/file";
import "vditor/dist/index.css"; import { notifyError, notifySuccess } from "@/util/msg";
import { getMdOption } from "@/util/vditor"; import { getMdOption } from "@/util/vditor";
import { isBase64, decodeBase64 } from "@/util/file"; import { saveAs } from "file-saver";
import moment from "moment"; import moment from "moment";
import { useHistoryStore } from "@/stores/history"; import Vditor from "vditor";
import { getSplit } from "@/system/config"; import "vditor/dist/index.css";
import { saveAs } from "file-saver"; import { inject, onMounted, onUnmounted, ref, toRaw } from "vue";
const historyStore = useHistoryStore(); const historyStore = useHistoryStore();
const drawerBox = ref(false); const drawerBox = ref(false);
const baseTitle = ref(""); const baseTitle = ref("");
const content = ref(""); const content = ref("");
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 isSaveing = ref(false); const isSaveing = ref(false);
const vditor = ref(); const vditor = ref();
const filepath: any = ref(""); const filepath: any = ref("");
const fileInput: any = ref(null); const fileInput: any = ref(null);
const SP = getSplit(); const SP = getSplit();
console.log(SP); console.log(SP);
const debouncedHandleKeyDown = (event: KeyboardEvent) => { const debouncedHandleKeyDown = (event: KeyboardEvent) => {
// //
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "s") { if (
event.stopPropagation(); // (event.metaKey || event.ctrlKey) &&
event.preventDefault(); // event.key.toLowerCase() === "s"
if (!isSaveing.value) { ) {
saveData(); event.stopPropagation(); //
} event.preventDefault(); //
} if (!isSaveing.value) {
}; saveData();
}
}
};
const getDateTime = (t: any) => { const getDateTime = (t: any) => {
return moment(t).format("MM-DD HH:mm"); return moment(t).format("MM-DD HH:mm");
}; };
function getTitle() { function getTitle() {
let title = win.getTitle(); let title = win.getTitle();
console.log(title); console.log(title);
if (title.indexOf(SP) > -1) { if (title.indexOf(SP) > -1) {
title = title.split(SP).pop(); title = title.split(SP).pop();
title = title.split("."); title = title.split(".");
title.pop(); title.pop();
return title.join("."); return title.join(".");
} else { } else {
return ""; return "";
} }
} }
onMounted(async () => { onMounted(async () => {
const editorOptions: any = getMdOption(); const editorOptions: any = getMdOption();
editorOptions.input = (val: any) => { editorOptions.input = (val: any) => {
content.value = val; content.value = val;
}; };
vditor.value = new Vditor("vditorContainer", editorOptions); vditor.value = new Vditor("vditorContainer", editorOptions);
baseTitle.value = getTitle(); baseTitle.value = getTitle();
if (win.config && win.config.content) { if (win.config && win.config.content) {
let winContent = toRaw(win.config.content); let winContent = toRaw(win.config.content);
if (winContent && isBase64(winContent)) { if (winContent && isBase64(winContent)) {
winContent = decodeBase64(winContent); winContent = decodeBase64(winContent);
} }
//console.log(winContent); //console.log(winContent);
setTimeout(() => { setTimeout(() => {
if (winContent && winContent != "") { if (winContent && winContent != "") {
//console.log(winContent) //console.log(winContent)
vditor.value.setValue(winContent); vditor.value.setValue(winContent);
} }
}, 1000); }, 1000);
} }
document.addEventListener("keydown", debouncedHandleKeyDown); document.addEventListener("keydown", debouncedHandleKeyDown);
}); });
// //
onUnmounted(() => { onUnmounted(() => {
document.removeEventListener("keydown", debouncedHandleKeyDown); document.removeEventListener("keydown", debouncedHandleKeyDown);
}); });
async function saveData() { async function saveData() {
if (isSaveing.value) { if (isSaveing.value) {
return; return;
} }
isSaveing.value = true; isSaveing.value = true;
if (baseTitle.value == "") { if (baseTitle.value == "") {
notifyError("请输入标题"); notifyError("请输入标题");
isSaveing.value = false; isSaveing.value = false;
return; return;
} }
//console.log(win.config.path) //console.log(win.config.path)
if (!filepath.value || filepath.value == "") { if (!filepath.value || filepath.value == "") {
filepath.value = `${SP}C${SP}Users${SP}Desktop${SP}${baseTitle.value}.md`; filepath.value = `${SP}C${SP}Users${SP}Desktop${SP}${baseTitle.value}.md`;
} }
let refreshDesktop = false; let refreshDesktop = false;
if (win.config.path) { if (win.config.path) {
filepath.value = win.config.path; filepath.value = win.config.path;
let fileTitleArr = filepath.value.split(SP).pop().split("."); let fileTitleArr = filepath.value.split(SP).pop().split(".");
fileTitleArr.pop(); fileTitleArr.pop();
const oldTitle = fileTitleArr.join("."); const oldTitle = fileTitleArr.join(".");
if (oldTitle != baseTitle.value) { if (oldTitle != baseTitle.value) {
filepath.value = filepath.value.replace(oldTitle, baseTitle.value); filepath.value = filepath.value.replace(
refreshDesktop = true; oldTitle,
} baseTitle.value
} else { );
refreshDesktop = true; refreshDesktop = true;
} }
//console.log(path) } else {
await sys?.fs.writeFile(filepath.value, vditor.value.getValue()); refreshDesktop = true;
notifySuccess("保存成功!"); }
isSaveing.value = false; const file = await sys?.fs.getShareInfo(filepath.value);
if (refreshDesktop) { const isWrite =
sys.refershAppList(); file.fs.sender === getSystemConfig().userInfo.id
} ? 1
historyStore.addList("markdown", { : file.fs.is_write;
title: toRaw(baseTitle.value), //console.log(path)
path: filepath.value, const res = file.fi.isShare
time: Date.now(), ? await sys?.fs.writeShareFile(
}); filepath.value,
} vditor.value.getValue(),
function uploadFile(event: any) { isWrite
const file = event.target.files[0]; )
if (!file) { : await sys?.fs.writeFile(filepath.value, vditor.value.getValue());
return; if (res.success) {
} notifySuccess(res.message || "保存成功!");
const reader = new FileReader(); } else {
reader.onload = (e: any) => { notifyError(res.message || "保存失败");
baseTitle.value = file.name.substring(0, file.name.lastIndexOf(".")); }
vditor.value.setValue(e.target.result);
}; isSaveing.value = false;
reader.readAsText(file); if (refreshDesktop) {
} sys.refershAppList();
function importMd() { }
fileInput.value.click(); historyStore.addList("markdown", {
} title: toRaw(baseTitle.value),
function download() { path: filepath.value,
if (baseTitle.value == "") { time: Date.now(),
notifyError("标题不能为空"); });
return; }
} function uploadFile(event: any) {
const contentData = vditor.value.getValue(); const file = event.target.files[0];
if (contentData == "") { if (!file) {
notifyError("内容不能为空"); return;
return; }
} const reader = new FileReader();
let blob = new Blob([contentData], { type: "text/plain;charset=utf-8" }); reader.onload = (e: any) => {
saveAs(blob, baseTitle.value + ".md"); baseTitle.value = file.name.substring(
} 0,
file.name.lastIndexOf(".")
);
vditor.value.setValue(e.target.result);
};
reader.readAsText(file);
}
function importMd() {
fileInput.value.click();
}
function download() {
if (baseTitle.value == "") {
notifyError("标题不能为空");
return;
}
const contentData = vditor.value.getValue();
if (contentData == "") {
notifyError("内容不能为空");
return;
}
let blob = new Blob([contentData], {
type: "text/plain;charset=utf-8",
});
saveAs(blob, baseTitle.value + ".md");
}
</script> </script>
<template> <template>
<el-drawer <el-drawer
v-model="drawerBox" v-model="drawerBox"
direction="ltr" direction="ltr"
style="height: 100vh" style="height: 100vh"
:show-close="false" :show-close="false"
:with-header="false" :with-header="false"
> >
<div <div
class="list-item" class="list-item"
v-for="(item, index) in historyStore.getList('markdown')" v-for="(item, index) in historyStore.getList('markdown')"
:key="index" :key="index"
> >
<div class="list-title"> <div class="list-title">
<el-tooltip <el-tooltip
class="box-item" class="box-item"
effect="dark" effect="dark"
:content="item.path" :content="item.path"
placement="top-start" placement="top-start"
> >
{{ item.title }} {{ item.title }}
</el-tooltip> </el-tooltip>
</div> </div>
<div class="list-time"> <div class="list-time">
{{ getDateTime(item.time) }} {{ getDateTime(item.time) }}
</div> </div>
</div> </div>
</el-drawer> </el-drawer>
<el-row justify="space-between" :gutter="20" :span="24" style="margin: 10px 20px"> <el-row
<el-col :span="5"> justify="space-between"
<el-button @click.stop="drawerBox = !drawerBox" icon="Menu" circle /> :gutter="20"
<el-button @click.stop="importMd" icon="Upload" circle /> :span="24"
style="margin: 10px 20px"
>
<el-col :span="5">
<el-button
@click.stop="drawerBox = !drawerBox"
icon="Menu"
circle
/>
<el-button
@click.stop="importMd"
icon="Upload"
circle
/>
<el-button @click.stop="download" icon="Download" circle /> <el-button
<input @click.stop="download"
type="file" icon="Download"
ref="fileInput" circle
accept=".md" />
style="display: none" <input
@change="uploadFile" type="file"
/> ref="fileInput"
</el-col> accept=".md"
<el-col :span="15"> style="display: none"
<el-input v-model="baseTitle" placeholder="输入标题" /> @change="uploadFile"
</el-col> />
<el-col :span="2"> </el-col>
<el-button @click.stop="saveData()" icon="Finished" :loading="isSaveing" circle /> <el-col :span="15">
</el-col> <el-input
</el-row> v-model="baseTitle"
<div id="vditorContainer" style="margin: 10px 20px"></div> placeholder="输入标题"
/>
</el-col>
<el-col :span="2">
<el-button
@click.stop="saveData()"
icon="Finished"
:loading="isSaveing"
circle
/>
</el-col>
</el-row>
<div
id="vditorContainer"
style="margin: 10px 20px"
></div>
</template> </template>
<style scoped> <style scoped>
@import "@/assets/left.scss"; @import "@/assets/left.scss";
</style> </style>

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

@ -1,82 +1,114 @@
<template> <template>
<el-form :model="form" label-width="auto" style="max-width: 560px;margin-top:20px;padding: 20px;"> <el-form
<el-form-item label="分享给"> :model="form"
<el-select v-model="form.receverid" filterable multiple clearable collapse-tags placeholder="选择人员" label-width="auto"
popper-class="custom-header" :max-collapse-tags="1" value-key="id" style="width: 240px" @change="checkUsers"> style="max-width: 560px; margin-top: 20px; padding: 20px"
<template #header> >
<el-checkbox v-model="checkAll" @change="handleCheckAll"> <el-form-item label="分享给">
全选 <el-select
</el-checkbox> v-model="form.receverid"
</template> filterable
<el-option v-for="item in userList" :key="item.id" :label="item.nickname" :value="item.id" /> multiple
</el-select> clearable
</el-form-item> collapse-tags
<el-form-item label="编辑权限"> placeholder="选择人员"
<el-switch v-model="form.iswrite" active-value="1" inactive-value="0" /> popper-class="custom-header"
</el-form-item> :max-collapse-tags="1"
<div class="btn-group"> value-key="id"
<el-button type="primary" @click="onSubmit">发布分享</el-button> style="width: 240px"
</div> @change="checkUsers"
</el-form> >
<template #header>
<el-checkbox
v-model="checkAll"
@change="handleCheckAll"
>
全选
</el-checkbox>
</template>
<el-option
v-for="item in userList"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="编辑权限">
<el-switch
v-model="form.iswrite"
active-value="1"
inactive-value="0"
/>
</el-form-item>
<div class="btn-group">
<el-button
type="primary"
@click="onSubmit"
>发布分享</el-button
>
</div>
</el-form>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, inject, onMounted } from 'vue'; import { BrowserWindow, useSystem } from "@/system";
import { useSystem, BrowserWindow } from '@/system'; import { fetchPost, getSystemConfig } from "@/system/config";
import { getSystemConfig, fetchPost } from "@/system/config"; import { notifyError, notifySuccess } from "@/util/msg";
import { notifySuccess, notifyError } from "@/util/msg"; import { inject, onMounted, ref } from "vue";
const window: BrowserWindow | undefined = inject("browserWindow"); const window: BrowserWindow | undefined = inject("browserWindow");
const sys = useSystem() const sys = useSystem();
const userInfo: any = sys.getConfig('userInfo') const userInfo: any = sys.getConfig("userInfo");
let userList = ref(userInfo.user_shares) let userList = ref(userInfo.user_shares);
const checkAll = ref(false) const checkAll = ref(false);
const form: any = ref({ const form: any = ref({
senderid: '', senderid: "",
receverid: [], receverid: [],
path: '', path: "",
iswrite: '0' iswrite: "0",
}) });
const config = ref(getSystemConfig()) const config = ref(getSystemConfig());
const handleCheckAll = (val: any) => { const handleCheckAll = (val: any) => {
if (val) { if (val) {
form.value.receverid = userList.value.map((d: any) => d.value) form.value.receverid = userList.value.map((d: any) => d.value);
} else { } else {
form.value.receverid.value = [] form.value.receverid.value = [];
} }
} };
const checkUsers = (val: any) => { const checkUsers = (val: any) => {
const res:any = [] const res: any = [];
val.forEach((item: any) => { val.forEach((item: any) => {
if(item){ if (item) {
res.push(item) res.push(item);
} }
}) });
form.value.receverid = res form.value.receverid = res;
} };
const onSubmit = async () => { const onSubmit = async () => {
const apiUrl = config.value.userInfo.url + '/files/share' const apiUrl = config.value.userInfo.url + "/files/share";
form.value.senderid = config.value.userInfo.id form.value.senderid = config.value.userInfo.id;
form.value.path = window?.config.path || '' form.value.path = window?.config.path || "";
const temp = {...form.value} const temp = { ...form.value };
temp.senderid = temp.senderid.toString() temp.senderid = temp.senderid.toString();
temp.receverid = temp.receverid.map((item:any) => item.toString()) temp.receverid = temp.receverid.map((item: any) => item.toString());
const res = await fetchPost(apiUrl, new URLSearchParams(temp)) const res = await fetchPost(apiUrl, new URLSearchParams(temp));
if (res.ok) { const result = await res.json();
notifySuccess("分享文件成功") if (res.ok) {
} else { notifySuccess(result.message || "分享文件成功");
notifyError("分享文件失败") } else {
} notifyError(result.message || "分享文件失败");
} }
onMounted(() => { };
userList.value = userList.value.filter((item: any)=> { onMounted(() => {
return item?.id !== config.value.userInfo.id userList.value = userList.value.filter((item: any) => {
}) return item?.id !== config.value.userInfo.id;
}) });
});
</script> </script>
<style scoped> <style scoped>
.btn-group{ .btn-group {
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
</style> </style>

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

@ -1,81 +1,106 @@
<template> <template>
<div class="file-pwd-box"> <div class="file-pwd-box">
<div v-if="setPwd"> <div v-if="setPwd">
<div class="setting-item" > <div class="setting-item">
<label>文件密码</label> <label>文件密码</label>
<el-input v-model="filePwd" placeholder="请设置6-10位的密码" type="password" show-password/> <el-input
</div> v-model="filePwd"
<div class="setting-item"> placeholder="请设置6-10位的密码"
<label></label> type="password"
<el-button @click="toSetFilePwd" type="primary">{{ t("setFilePwd") }}</el-button> show-password
<el-button @click="clearPwd" type="primary">取消文件加密</el-button> />
</div> </div>
</div> <div class="setting-item">
<div v-else class="setting-item"> <label></label>
<label></label> <el-button
<el-button @click="setPwd = true" type="primary">设置文件密码</el-button> @click="toSetFilePwd"
</div> type="primary"
</div> >{{ t("setFilePwd") }}</el-button
>
<el-button
@click="clearPwd"
type="primary"
>取消文件加密</el-button
>
</div>
</div>
<div
v-else
class="setting-item"
>
<label></label>
<el-button
@click="setPwd = true"
type="primary"
>设置文件密码</el-button
>
</div>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { md5 } from "js-md5"; import { t } from "@/system";
import { ref, onMounted } from "vue"; import {
import { t } from "@/system"; fetchGet,
import { fetchGet, getApiUrl, setSystemKey, getSystemConfig } from "@/system/config"; getApiUrl,
import { notifySuccess, notifyError } from "@/util/msg"; getSystemConfig,
const filePwd = ref('') setSystemKey,
const setPwd = ref(false) } from "@/system/config";
const config = getSystemConfig() import { notifyError, notifySuccess } from "@/util/msg";
const params = { import { md5 } from "js-md5";
isPwd: 1, import { onMounted, ref } from "vue";
pwd: '', const filePwd = ref("");
salt: getSystemConfig().file.salt const setPwd = ref(false);
} const config = getSystemConfig();
// const params = {
async function toSetFilePwd() { isPwd: 1,
if (filePwd.value.length < 6 || filePwd.value.length > 10) { pwd: "",
notifyError("密码长度应该在6-10位之间") salt: getSystemConfig().file.salt,
return };
} //
params.pwd = md5(filePwd.value) async function toSetFilePwd() {
params.isPwd = filePwd.value === '' ? 0 : 1 if (filePwd.value.length < 6 || filePwd.value.length > 10) {
const url = getApiUrl() + '/file/setfilepwd' notifyError("密码长度应该在6-10位之间");
const header = { return;
'Salt': params.salt ? params.salt : 'vIf_wIUedciAd0nTm6qjJA==', }
'FilePwd': params.pwd params.pwd = md5(filePwd.value);
} params.isPwd = filePwd.value === "" ? 0 : 1;
await fetchGet(`${getApiUrl()}/file/changeispwd?ispwd=${params.isPwd}`) const url = getApiUrl() + "/file/setfilepwd";
const res = await fetchGet(url, header) const header = {
if (res.ok){ salt: params.salt ? params.salt : "vIf_wIUedciAd0nTm6qjJA==",
notifySuccess("设置文件密码成功"); pwd: params.pwd,
} else { };
params.isPwd = 0 await fetchGet(`${getApiUrl()}/file/changeispwd?ispwd=${params.isPwd}`);
params.pwd = '' const res = await fetchGet(url, header);
notifyError("设置文件密码失败") if (res.ok) {
} notifySuccess("设置文件密码成功");
setSystemKey('file',params) } else {
} params.isPwd = 0;
async function clearPwd() { params.pwd = "";
setPwd.value = false notifyError("设置文件密码失败");
filePwd.value = '' }
params.isPwd = 0 setSystemKey("file", params);
await fetchGet(`${getApiUrl()}/file/changeispwd?ispwd=0`) }
setSystemKey('file',params) async function clearPwd() {
} setPwd.value = false;
onMounted(() => { filePwd.value = "";
params.isPwd = config.file.isPwd params.isPwd = 0;
setPwd.value = params.isPwd ? true : false await fetchGet(`${getApiUrl()}/file/changeispwd?ispwd=0`);
}) setSystemKey("file", params);
}
onMounted(() => {
params.isPwd = config.file.isPwd;
setPwd.value = params.isPwd ? true : false;
});
</script> </script>
<style scoped> <style scoped>
@import "./setStyle.css"; @import "./setStyle.css";
.file-pwd-box { .file-pwd-box {
padding-top: 20px; padding-top: 20px;
} }
.setting-item { .setting-item {
display: flex; display: flex;
align-items: center; align-items: center;
} }
</style> </style>

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

@ -75,7 +75,7 @@
if (isShareFile(path)) { if (isShareFile(path)) {
const file = await sys?.fs.getShareInfo(path); const file = await sys?.fs.getShareInfo(path);
isShare.value = true; isShare.value = true;
isWrite.value = file.fs.is_write; isWrite.value = file.fs.sender === getSystemConfig().userInfo.id ? 1 : file.fs.is_write;
if ( if (
!isWrite.value && !isWrite.value &&
file.fs.sender !== getSystemConfig().userInfo.id file.fs.sender !== getSystemConfig().userInfo.id
@ -119,7 +119,8 @@
// console.log("", res, isShare); // console.log("", res, isShare);
new Notify({ new Notify({
title: "提示", title: "提示",
content: res.code === 0 ? "文件已保存" : "文件保存失败", content: res.message
// content: res.code === 0 ? "" : res.message,
}); });
sys.refershAppList(); sys.refershAppList();
} else if (eventData.type == "initSuccess") { } else if (eventData.type == "initSuccess") {

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

@ -427,7 +427,6 @@ export const useOsFile = () => {
} }
} }
} }
//console.log('创建露肩:', path);
const response = await handleWriteFile(path, content, head); const response = await handleWriteFile(path, content, head);
if (response) { if (response) {

2
godo/cmd/serve.go

@ -86,7 +86,7 @@ func (l loggingMiddleware) Middleware(next http.Handler) http.Handler {
// CORS 中间件 // CORS 中间件
func corsMiddleware() mux.MiddlewareFunc { func corsMiddleware() mux.MiddlewareFunc {
allowHeaders := "Content-Type, Accept, Authorization, Origin,filePwd,salt" allowHeaders := "Content-Type, Accept, Authorization, Origin,pwd,salt"
allowMethods := "GET, POST, PUT, DELETE, OPTIONS" allowMethods := "GET, POST, PUT, DELETE, OPTIONS"
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {

Loading…
Cancel
Save