diff --git a/frontend/public/markdown/scripts/index.js b/frontend/public/markdown/scripts/index.js index 976b945..7ed7b6d 100644 --- a/frontend/public/markdown/scripts/index.js +++ b/frontend/public/markdown/scripts/index.js @@ -1,5 +1,6 @@ var markdownTitle = "" let aiSelected = "" +let componentID = "" var CustomHookA = Cherry.createSyntaxHook('codeBlock', Cherry.constants.HOOKS_TYPE_LIST.PAR, { makeHtml(str) { console.warn('custom hook', 'hello'); @@ -441,7 +442,7 @@ const saveData = () => { markdownTitle = window.prompt("请输入文稿标题"); } const postData = { title: markdownTitle, content: cherry.getMarkdown() } - window.parent.postMessage({ type: 'exportMd', data: JSON.stringify(postData) }, '*') + window.parent.postMessage({ type: 'exportMd', data: JSON.stringify(postData),componentID }, '*') } var saveMenu = Cherry.createMenuHook('保存', { onClick: function () { @@ -701,6 +702,7 @@ function decodeBase64(base64String) { } const eventHandler = (e) => { const eventData = e.data + componentID = eventData.componentID ? eventData.componentID : '' if (eventData.type === 'start') { markdownTitle = eventData.title || '未命名文稿' return diff --git a/frontend/src/components/computer/Computer.vue b/frontend/src/components/computer/Computer.vue index be9566c..77fabff 100644 --- a/frontend/src/components/computer/Computer.vue +++ b/frontend/src/components/computer/Computer.vue @@ -167,7 +167,16 @@ const system = useSystem(); const { dragFileToDrop } = useFileDrag(system); const { createDesktopContextMenu } = useContextMenu(); + // 选择保存文件路径时,传递选择路径 + const props = defineProps({ + translateSavePath: { + type: Function + } + }) const setRouter = function (path: string) { + if (props.translateSavePath) { + props.translateSavePath(path) + } router_url.value = path; if ( router_url_history_index.value <= diff --git a/frontend/src/components/window/IframeFile.vue b/frontend/src/components/window/IframeFile.vue index aa1874a..223374d 100644 --- a/frontend/src/components/window/IframeFile.vue +++ b/frontend/src/components/window/IframeFile.vue @@ -10,240 +10,260 @@ import { isShareFile } from "@/util/sharePath.ts"; import { inject, onMounted, onUnmounted, ref, toRaw } from "vue"; import { askAi } from "@/hook/useAi"; import { useChooseStore } from "@/stores/choose"; +import { nanoid } from "nanoid"; +import eventBus from "@/util/eventBus"; const SP = getSplit(); const sys: any = inject("system"); const win: any = inject("browserWindow"); const props = defineProps({ - src: { - type: String, - default: "", - }, - eventType: { - type: String, - default: "", - }, - ext: { - type: String, - default: "md", - }, + 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; -// let currentPath = ref('') const storeRef = ref(null); let hasInit = false; const choose = useChooseStore(); +const componentID = nanoid(); +// console.log("唯一ID:", componentID); +const saveFile = async (e: any) => { + if (e.componentID !== componentID) return; + let data = JSON.parse(e.eventData.data); + let ext: any = props.ext; + if (ext instanceof Array) { + ext = ext[0]; + } + if (data.ext) { + ext = data.ext; + } + let path:string + e.filePath !== "" + ? (path = `${e.filePath}/${e.fileName}.${ext}`) + : (path = `${SP}C${SP}Users${SP}Desktop${SP}${e.fileName}.${ext}`); + // console.log('路径:',path); + await writeFile(path, data, e.fileName); +}; +eventBus.on("saveFile", saveFile); +const writeFile = async (path: string, data: any, title: string) => { + 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.sender === getSystemConfig().userInfo.id + ? 1 + : 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.message, + // content: res.code === 0 ? "文件已保存" : res.message, + }); + sys.refershAppList(); +}; 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; - } - if (title.indexOf('.' + ext) > -1) { - title = title.replace('.' + ext, ""); - } - 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 { - choose.saveFile('选择地址','*') - 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.sender === getSystemConfig().userInfo.id ? 1 : 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 eventData = e.data; + // console.log('是否同一个:', componentID == eventData.componentID); + if (eventData.type == props.eventType) { + // if (eventData.componentID !== componentID) return; + 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; + } + if (title.indexOf("." + ext) > -1) { + title = title.replace("." + ext, ""); + } - 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.message - // content: res.code === 0 ? "文件已保存" : res.message, - }); - 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 (win.config && win.config.path) { + path = win.config.path; - // if (!content && win?.config.path) { - // const header = { - // pwd: '' - // }; - // const filePwd = getSystemConfig().fileInputPwd - // const pos = filePwd.findIndex((item: any) => item.path == win?.config.path) - // //console.log('路径:', win?.config.path, pos, filePwd); - // const userType = getSystemConfig().userType - // if (pos !== -1) { - // header.pwd = userType == 'person' ? md5(filePwd[pos].pwd) : filePwd[pos].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, - }, - "*" - ); - } - } - else if (eventData.type == "close") { - // console.log("关闭"); - win.close(); - } - else if (eventData.type == "saveMind") { - // console.log("保存"); - const data = eventData.data; - const path = win?.config?.path; - //console.log(path,data) - const winMind = new BrowserWindow({ - title: data.title, - url: "/mind/index.html", - frame: true, - config: { - ext: 'mind', - path: path, - content: data.content - }, - icon: "gallery", - width: 700, - height: 500, - x: 100, - y: 100, - //center: true, - minimizable: false, - resizable: true, - }); - winMind.show() + //去除重复文件名后的(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 { + choose.saveFile("选择地址", "*", componentID, eventData); + return; + // path = `${SP}C${SP}Users${SP}Desktop${SP}${title}.${ext}`; + } + writeFile(path, data, title); + } 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(); - } - else if (eventData.type == 'aiCreater') { - console.log('传递内容: ', eventData) - let postData: any = {} - if (eventData.data) { - postData.content = eventData.data - } - if (eventData.title) { - postData.title = eventData.title - } - if (eventData.category) { - postData.category = eventData.category - } - //console.log(postData,eventData.action) - // 模拟AI返回数据 - const res: any = await askAi(postData, eventData.action); - storeRef.value?.contentWindow?.postMessage( - { - type: 'aiReciver', - data: res, - action: eventData.action - }, - "*" - ); - } + // if (!content && win?.config.path) { + // const header = { + // pwd: '' + // }; + // const filePwd = getSystemConfig().fileInputPwd + // const pos = filePwd.findIndex((item: any) => item.path == win?.config.path) + // //console.log('路径:', win?.config.path, pos, filePwd); + // const userType = getSystemConfig().userType + // if (pos !== -1) { + // header.pwd = userType == 'person' ? md5(filePwd[pos].pwd) : filePwd[pos].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 }, + componentID, + }, + "*" + ); + } else { + storeRef.value?.contentWindow?.postMessage( + { + type: "start", + title, + componentID, + }, + "*" + ); + } + } else if (eventData.type == "close") { + // console.log("关闭"); + win.close(); + } else if (eventData.type == "saveMind") { + // console.log("保存"); + const data = eventData.data; + const path = win?.config?.path; + //console.log(path,data) + const winMind = new BrowserWindow({ + title: data.title, + url: "/mind/index.html", + frame: true, + config: { + ext: "mind", + path: path, + content: data.content, + }, + icon: "gallery", + width: 700, + height: 500, + x: 100, + y: 100, + //center: true, + minimizable: false, + resizable: true, + }); + winMind.show(); + } else if (eventData.type == "aiCreater") { + console.log("传递内容: ", eventData); + let postData: any = {}; + if (eventData.data) { + postData.content = eventData.data; + } + if (eventData.title) { + postData.title = eventData.title; + } + if (eventData.category) { + postData.category = eventData.category; + } + //console.log(postData,eventData.action) + // 模拟AI返回数据 + const res: any = await askAi(postData, eventData.action); + storeRef.value?.contentWindow?.postMessage( + { + type: "aiReciver", + data: res, + action: eventData.action, + }, + "*" + ); + } }; //删除本地暂存的文件密码 const delFileInputPwd = async () => { - let fileInputPwd = getSystemConfig().fileInputPwd; - const currentPath = win.config.path; - const temp = fileInputPwd.filter( - (item: any) => item.path !== currentPath - ); - setSystemKey("fileInputPwd", temp); + 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); + window.addEventListener("message", eventHandler); }); onUnmounted(async () => { - await delFileInputPwd(); - window.removeEventListener("message", eventHandler); + await delFileInputPwd(); + window.removeEventListener("message", eventHandler); }); diff --git a/frontend/src/components/window/MenuFooter.vue b/frontend/src/components/window/MenuFooter.vue index e4083b8..0d5487c 100644 --- a/frontend/src/components/window/MenuFooter.vue +++ b/frontend/src/components/window/MenuFooter.vue @@ -16,13 +16,15 @@ import { UnwrapNestedRefs, ref } from "vue"; const props = defineProps<{ browserWindow: UnwrapNestedRefs; }>(); +const emit = defineEmits(['translateSavePath']) let fileName = ref('未命名文件') -//console.log('传递消息:', props.browserWindow); + function cancleSave() { props.browserWindow.close() } function saveFile() { - + emit('translateSavePath','',fileName.value) + props.browserWindow.close() } diff --git a/frontend/src/components/window/WindowInner.vue b/frontend/src/components/window/WindowInner.vue index 107875b..8ed2529 100644 --- a/frontend/src/components/window/WindowInner.vue +++ b/frontend/src/components/window/WindowInner.vue @@ -1,7 +1,7 @@ @@ -73,6 +73,8 @@ ref, UnwrapNestedRefs, } from "vue"; + import { useChooseStore } from "@/stores/choose"; + import eventBus from '@/util/eventBus' const sys = useSystem(); const props = defineProps<{ @@ -81,15 +83,28 @@ const browserWindow = props.browserWindow; - // console.log('窗口配置:', browserWindow); const windowInfo = browserWindow.windowInfo; + // const temp = reactive(browserWindow) provide("browserWindow", browserWindow); provide("system", sys); - // let filePath = ref(inject('saveFilePath')) - // watch(filePath, (newVal) => { - // console.log('改变路径:', newVal); - - // }) + const choose = useChooseStore() + + function translateSavePath (path: string, name?: string) { + if (browserWindow.windowInfo.footer) { + const pos = choose.saveFileContent.findIndex((item) => { + return item.componentID == browserWindow.windowInfo.componentID + }) + if (pos == -1) return + if (path && path !== '') { + choose.saveFileContent[pos].filePath = path + } else if (name && name !== '') { + choose.saveFileContent[pos].fileName = name + eventBus.emit('saveFile', choose.saveFileContent[pos] ) + } + } + } + provide('translateSavePath', translateSavePath) + function predown() { browserWindow.moveTop(); emitEvent("window.content.click", browserWindow); diff --git a/frontend/src/stores/choose.ts b/frontend/src/stores/choose.ts index 17c2bb9..b19a9e5 100644 --- a/frontend/src/stores/choose.ts +++ b/frontend/src/stores/choose.ts @@ -5,7 +5,11 @@ export const useChooseStore = defineStore('chooseStore', () => { const win:any = ref() const path:any = ref([]) const ifShow = ref(false) - //const savePath:any = ref('') + let savePath = ref({ + path: '', + name: '' + }) + const saveFileContent = ref([]) const select = (title = '选择文件', fileExt:any) => { win.value = new BrowserWindow({ @@ -27,7 +31,7 @@ export const useChooseStore = defineStore('chooseStore', () => { win.value.show() ifShow.value = true } - const saveFile = (title: string, fileExt: any) => { + const saveFile = (title: string, fileExt: any, componentID: string, eventData: any) => { // console.log('保存文件'); win.value = new BrowserWindow({ title, @@ -44,9 +48,17 @@ export const useChooseStore = defineStore('chooseStore', () => { center: true, minimizable: false, resizable: true, - footer: true + footer: true, + componentID }); win.value.show() + saveFileContent.value.push({ + componentID, + eventData, + filePath: '', + fileName: '' + }) + return savePath // ifShow.value = true } const close = () => { @@ -58,6 +70,8 @@ export const useChooseStore = defineStore('chooseStore', () => { win, path, ifShow, + savePath, + saveFileContent, select, close, saveFile diff --git a/frontend/src/system/window/BrowserWindow.ts b/frontend/src/system/window/BrowserWindow.ts index 9d342fc..e735875 100644 --- a/frontend/src/system/window/BrowserWindow.ts +++ b/frontend/src/system/window/BrowserWindow.ts @@ -33,6 +33,7 @@ export interface BrowserWindowConstructorOptions { skipTaskbar: boolean; backgroundColor: string; footer: boolean; + componentID: string; } export interface WindowInfo extends BrowserWindowConstructorOptions { state: WindowStateEnum; @@ -61,7 +62,8 @@ class BrowserWindow { alwaysOnTop: false, skipTaskbar: false, backgroundColor: '#fff', - footer: false + footer: false, + componentID: '' }; public static defaultInfo: Omit = { state: WindowStateEnum.normal, @@ -115,6 +117,7 @@ class BrowserWindow { previousState: this.windowInfo.state, }; this.windowInfo.footer = option?.footer || false + this.windowInfo.componentID = option?.componentID || '' } _setZindex() { diff --git a/frontend/src/util/eventBus.ts b/frontend/src/util/eventBus.ts new file mode 100644 index 0000000..9022c18 --- /dev/null +++ b/frontend/src/util/eventBus.ts @@ -0,0 +1,17 @@ +let eventBus = { + events: {} as { [key: string]: Function[]}, + on: function (eventName: string, callback: Function) { + if (!this.events[eventName]) { + this.events[eventName] = []; + } + this.events[eventName].push(callback); + }, + emit: function (eventName:string, ...args: any[]) { + if (this.events[eventName]) { + this.events[eventName].forEach((callback) => { + callback(...args); + }); + } + } +}; +export default eventBus; \ No newline at end of file