Browse Source

add:markdown写文件选择地址

master
prr 6 months ago
parent
commit
de9693bf5a
  1. 4
      frontend/public/markdown/scripts/index.js
  2. 9
      frontend/src/components/computer/Computer.vue
  3. 438
      frontend/src/components/window/IframeFile.vue
  4. 6
      frontend/src/components/window/MenuFooter.vue
  5. 3
      frontend/src/components/window/WindowInner.vue
  6. 27
      frontend/src/components/window/WindowTemplate.vue
  7. 20
      frontend/src/stores/choose.ts
  8. 5
      frontend/src/system/window/BrowserWindow.ts
  9. 17
      frontend/src/util/eventBus.ts

4
frontend/public/markdown/scripts/index.js

@ -1,5 +1,6 @@
var markdownTitle = "" var markdownTitle = ""
let aiSelected = "" let aiSelected = ""
let componentID = ""
var CustomHookA = Cherry.createSyntaxHook('codeBlock', Cherry.constants.HOOKS_TYPE_LIST.PAR, { var CustomHookA = Cherry.createSyntaxHook('codeBlock', Cherry.constants.HOOKS_TYPE_LIST.PAR, {
makeHtml(str) { makeHtml(str) {
console.warn('custom hook', 'hello'); console.warn('custom hook', 'hello');
@ -441,7 +442,7 @@ const saveData = () => {
markdownTitle = window.prompt("请输入文稿标题"); markdownTitle = window.prompt("请输入文稿标题");
} }
const postData = { title: markdownTitle, content: cherry.getMarkdown() } 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('保存', { var saveMenu = Cherry.createMenuHook('保存', {
onClick: function () { onClick: function () {
@ -701,6 +702,7 @@ function decodeBase64(base64String) {
} }
const eventHandler = (e) => { const eventHandler = (e) => {
const eventData = e.data const eventData = e.data
componentID = eventData.componentID ? eventData.componentID : ''
if (eventData.type === 'start') { if (eventData.type === 'start') {
markdownTitle = eventData.title || '未命名文稿' markdownTitle = eventData.title || '未命名文稿'
return return

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

@ -167,7 +167,16 @@
const system = useSystem(); const system = useSystem();
const { dragFileToDrop } = useFileDrag(system); const { dragFileToDrop } = useFileDrag(system);
const { createDesktopContextMenu } = useContextMenu(); const { createDesktopContextMenu } = useContextMenu();
//
const props = defineProps({
translateSavePath: {
type: Function
}
})
const setRouter = function (path: string) { const setRouter = function (path: string) {
if (props.translateSavePath) {
props.translateSavePath(path)
}
router_url.value = path; router_url.value = path;
if ( if (
router_url_history_index.value <= router_url_history_index.value <=

438
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 { inject, onMounted, onUnmounted, ref, toRaw } from "vue";
import { askAi } from "@/hook/useAi"; import { askAi } from "@/hook/useAi";
import { useChooseStore } from "@/stores/choose"; import { useChooseStore } from "@/stores/choose";
import { nanoid } from "nanoid";
import eventBus from "@/util/eventBus";
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(props);
//let path = win?.config?.path;
// let currentPath = ref('')
const storeRef = ref<HTMLIFrameElement | null>(null); const storeRef = ref<HTMLIFrameElement | null>(null);
let hasInit = false; let hasInit = false;
const choose = useChooseStore(); const choose = useChooseStore();
const eventHandler = async (e: MessageEvent) => { const componentID = nanoid();
const eventData = e.data; // console.log("ID", componentID);
if (eventData.type == props.eventType) { const saveFile = async (e: any) => {
let data = JSON.parse(eventData.data); if (e.componentID !== componentID) return;
let title = data.title; let data = JSON.parse(e.eventData.data);
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; }
} let path:string
if (title.indexOf('.' + ext) > -1) { e.filePath !== ""
title = title.replace('.' + ext, ""); ? (path = `${e.filePath}/${e.fileName}.${ext}`)
} : (path = `${SP}C${SP}Users${SP}Desktop${SP}${e.fileName}.${ext}`);
if (win.config && win.config.path) { // console.log('',path);
path = win.config.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)
}
}
//1 const res = isShare.value
let fileTitleArr = path.split(SP).pop().split("."); ? await sys?.fs.writeShareFile(path, data.content, isWrite.value)
let oldExt = fileTitleArr.pop(); : await sys?.fs.writeFile(path, data.content);
let fileTitle = fileTitleArr.join("."); // console.log("", res, isShare);
if (fileTitle != title) { new Notify({
path = path.replace(fileTitle, title); title: "提示",
} content: res.message,
if (oldExt != ext) { // content: res.code === 0 ? "" : res.message,
path = path.replace("." + oldExt, "." + ext); });
} sys.refershAppList();
} else { };
choose.saveFile('选择地址','*') const eventHandler = async (e: MessageEvent) => {
path = `${SP}C${SP}Users${SP}Desktop${SP}${title}.${ext}`; const eventData = e.data;
} // console.log('', componentID == eventData.componentID);
// if (eventData.type == props.eventType) {
const isShare = ref(false); // if (eventData.componentID !== componentID) return;
const isWrite = ref(0); let data = JSON.parse(eventData.data);
if (isShareFile(path)) { let title = data.title;
const file = await sys?.fs.getShareInfo(path); let path;
isShare.value = true; let ext: any = props.ext;
isWrite.value = file.fs.sender === getSystemConfig().userInfo.id ? 1 : file.fs.is_write; if (ext instanceof Array) {
if ( ext = ext[0];
!isWrite.value && }
file.fs.sender !== getSystemConfig().userInfo.id if (data.ext) {
) { ext = data.ext;
new Notify({ }
title: "提示", if (title.indexOf("." + ext) > -1) {
content: "该文件没有编辑权限", title = title.replace("." + ext, "");
}); }
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 if (win.config && win.config.path) {
? await sys?.fs.writeShareFile( path = win.config.path;
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 (!content && win?.config.path) { //1
// const header = { let fileTitleArr = path.split(SP).pop().split(".");
// pwd: '' let oldExt = fileTitleArr.pop();
// }; let fileTitle = fileTitleArr.join(".");
// const filePwd = getSystemConfig().fileInputPwd if (fileTitle != title) {
// const pos = filePwd.findIndex((item: any) => item.path == win?.config.path) path = path.replace(fileTitle, title);
// //console.log('', win?.config.path, pos, filePwd); }
// const userType = getSystemConfig().userType if (oldExt != ext) {
// if (pos !== -1) { path = path.replace("." + oldExt, "." + ext);
// header.pwd = userType == 'person' ? md5(filePwd[pos].pwd) : filePwd[pos].pwd }
// } } else {
// content = await sys?.fs.readFile(win?.config.path, header); choose.saveFile("选择地址", "*", componentID, eventData);
// } return;
content = toRaw(content); // path = `${SP}C${SP}Users${SP}Desktop${SP}${title}.${ext}`;
if (content && content !== "") { }
storeRef.value?.contentWindow?.postMessage( writeFile(path, data, title);
{ } else if (eventData.type == "initSuccess") {
type: "init", if (hasInit) {
data: { content, title }, return;
}, }
"*" hasInit = true;
); let content = win?.config?.content;
} else { let title = win.getTitle();
storeRef.value?.contentWindow?.postMessage( // console.log("win.config;", win?.config);
{ // console.log(title);
type: "start", title = title.split(SP).pop();
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()
} // if (!content && win?.config.path) {
else if (eventData.type == 'aiCreater') { // const header = {
console.log('传递内容: ', eventData) // pwd: ''
let postData: any = {} // };
if (eventData.data) { // const filePwd = getSystemConfig().fileInputPwd
postData.content = eventData.data // const pos = filePwd.findIndex((item: any) => item.path == win?.config.path)
} // //console.log('', win?.config.path, pos, filePwd);
if (eventData.title) { // const userType = getSystemConfig().userType
postData.title = eventData.title // if (pos !== -1) {
} // header.pwd = userType == 'person' ? md5(filePwd[pos].pwd) : filePwd[pos].pwd
if (eventData.category) { // }
postData.category = eventData.category // content = await sys?.fs.readFile(win?.config.path, header);
} // }
//console.log(postData,eventData.action) content = toRaw(content);
// AI if (content && content !== "") {
const res: any = await askAi(postData, eventData.action); storeRef.value?.contentWindow?.postMessage(
storeRef.value?.contentWindow?.postMessage( {
{ type: "init",
type: 'aiReciver', data: { content, title },
data: res, componentID,
action: eventData.action },
}, "*"
"*" );
); } 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 () => { const delFileInputPwd = async () => {
let fileInputPwd = getSystemConfig().fileInputPwd; let fileInputPwd = getSystemConfig().fileInputPwd;
const currentPath = win.config.path; const currentPath = win.config.path;
const temp = fileInputPwd.filter( const temp = fileInputPwd.filter(
(item: any) => item.path !== currentPath (item: any) => item.path !== currentPath
); );
setSystemKey("fileInputPwd", temp); setSystemKey("fileInputPwd", temp);
}; };
onMounted(() => { onMounted(() => {
window.addEventListener("message", eventHandler); window.addEventListener("message", eventHandler);
}); });
onUnmounted(async () => { onUnmounted(async () => {
await delFileInputPwd(); await delFileInputPwd();
window.removeEventListener("message", eventHandler); 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>

6
frontend/src/components/window/MenuFooter.vue

@ -16,13 +16,15 @@ import { UnwrapNestedRefs, ref } from "vue";
const props = defineProps<{ const props = defineProps<{
browserWindow: UnwrapNestedRefs<BrowserWindow>; browserWindow: UnwrapNestedRefs<BrowserWindow>;
}>(); }>();
const emit = defineEmits(['translateSavePath'])
let fileName = ref('未命名文件') let fileName = ref('未命名文件')
//console.log('', props.browserWindow);
function cancleSave() { function cancleSave() {
props.browserWindow.close() props.browserWindow.close()
} }
function saveFile() { function saveFile() {
emit('translateSavePath','',fileName.value)
props.browserWindow.close()
} }
</script> </script>

3
frontend/src/components/window/WindowInner.vue

@ -1,7 +1,7 @@
<template> <template>
<IframeFile v-if="win.url" :src="win.url" :ext="win.ext" :eventType="win.eventType" /> <IframeFile v-if="win.url" :src="win.url" :ext="win.ext" :eventType="win.eventType" />
<Suspense v-else> <Suspense v-else>
<component v-if="win.content" :is="stepComponent(win.content)"></component> <component v-if="win.content" :is="stepComponent(win.content)" :translateSavePath="translateSavePath"></component>
<RouterView v-else /> <RouterView v-else />
</Suspense> </Suspense>
<!-- <component :is="window.content"></component> --> <!-- <component :is="window.content"></component> -->
@ -14,6 +14,7 @@ const props = defineProps<{
win: any; win: any;
}>(); }>();
const win = ref(props.win) const win = ref(props.win)
const translateSavePath = inject('translateSavePath')
if (props.win.path) { if (props.win.path) {
router.push(props.win.path); router.push(props.win.path);
} }

27
frontend/src/components/window/WindowTemplate.vue

@ -52,7 +52,7 @@
@touchstart.stop.passive="startScale($event, border.type)" @touchstart.stop.passive="startScale($event, border.type)"
></div> ></div>
<div class="wintmp_footer" v-if="browserWindow.windowInfo.footer"> <div class="wintmp_footer" v-if="browserWindow.windowInfo.footer">
<MenuFooter :browser-window="browserWindow"></MenuFooter> <MenuFooter :browser-window="browserWindow" @translateSavePath="translateSavePath"></MenuFooter>
</div> </div>
</div> </div>
</template> </template>
@ -73,6 +73,8 @@
ref, ref,
UnwrapNestedRefs, UnwrapNestedRefs,
} from "vue"; } from "vue";
import { useChooseStore } from "@/stores/choose";
import eventBus from '@/util/eventBus'
const sys = useSystem(); const sys = useSystem();
const props = defineProps<{ const props = defineProps<{
@ -81,15 +83,28 @@
const browserWindow = props.browserWindow; const browserWindow = props.browserWindow;
// console.log('', browserWindow);
const windowInfo = browserWindow.windowInfo; const windowInfo = browserWindow.windowInfo;
// const temp = reactive(browserWindow)
provide("browserWindow", browserWindow); provide("browserWindow", browserWindow);
provide("system", sys); provide("system", sys);
// let filePath = ref(inject('saveFilePath')) const choose = useChooseStore()
// watch(filePath, (newVal) => {
// console.log('', newVal); 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() { function predown() {
browserWindow.moveTop(); browserWindow.moveTop();
emitEvent("window.content.click", browserWindow); emitEvent("window.content.click", browserWindow);

20
frontend/src/stores/choose.ts

@ -5,7 +5,11 @@ export const useChooseStore = defineStore('chooseStore', () => {
const win:any = ref() const win:any = ref()
const path:any = ref([]) const path:any = ref([])
const ifShow = ref(false) const ifShow = ref(false)
//const savePath:any = ref('') let savePath = ref({
path: '',
name: ''
})
const saveFileContent = ref<any[]>([])
const select = (title = '选择文件', fileExt:any) => { const select = (title = '选择文件', fileExt:any) => {
win.value = new BrowserWindow({ win.value = new BrowserWindow({
@ -27,7 +31,7 @@ export const useChooseStore = defineStore('chooseStore', () => {
win.value.show() win.value.show()
ifShow.value = true ifShow.value = true
} }
const saveFile = (title: string, fileExt: any) => { const saveFile = (title: string, fileExt: any, componentID: string, eventData: any) => {
// console.log('保存文件'); // console.log('保存文件');
win.value = new BrowserWindow({ win.value = new BrowserWindow({
title, title,
@ -44,9 +48,17 @@ export const useChooseStore = defineStore('chooseStore', () => {
center: true, center: true,
minimizable: false, minimizable: false,
resizable: true, resizable: true,
footer: true footer: true,
componentID
}); });
win.value.show() win.value.show()
saveFileContent.value.push({
componentID,
eventData,
filePath: '',
fileName: ''
})
return savePath
// ifShow.value = true // ifShow.value = true
} }
const close = () => { const close = () => {
@ -58,6 +70,8 @@ export const useChooseStore = defineStore('chooseStore', () => {
win, win,
path, path,
ifShow, ifShow,
savePath,
saveFileContent,
select, select,
close, close,
saveFile saveFile

5
frontend/src/system/window/BrowserWindow.ts

@ -33,6 +33,7 @@ export interface BrowserWindowConstructorOptions {
skipTaskbar: boolean; skipTaskbar: boolean;
backgroundColor: string; backgroundColor: string;
footer: boolean; footer: boolean;
componentID: string;
} }
export interface WindowInfo extends BrowserWindowConstructorOptions { export interface WindowInfo extends BrowserWindowConstructorOptions {
state: WindowStateEnum; state: WindowStateEnum;
@ -61,7 +62,8 @@ class BrowserWindow {
alwaysOnTop: false, alwaysOnTop: false,
skipTaskbar: false, skipTaskbar: false,
backgroundColor: '#fff', backgroundColor: '#fff',
footer: false footer: false,
componentID: ''
}; };
public static defaultInfo: Omit<WindowInfo, keyof BrowserWindowConstructorOptions> = { public static defaultInfo: Omit<WindowInfo, keyof BrowserWindowConstructorOptions> = {
state: WindowStateEnum.normal, state: WindowStateEnum.normal,
@ -115,6 +117,7 @@ class BrowserWindow {
previousState: this.windowInfo.state, previousState: this.windowInfo.state,
}; };
this.windowInfo.footer = option?.footer || false this.windowInfo.footer = option?.footer || false
this.windowInfo.componentID = option?.componentID || ''
} }
_setZindex() { _setZindex() {

17
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;
Loading…
Cancel
Save