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. 29
      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 = ""
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

9
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 <=

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 { 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>("system");
const win: any = inject<BrowserWindow>("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<HTMLIFrameElement | null>(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);
});
</script>
<style scoped>
.setiframe {
width: 100%;
height: 100%;
border: none;
width: 100%;
height: 100%;
border: none;
}
</style>

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

@ -16,13 +16,15 @@ import { UnwrapNestedRefs, ref } from "vue";
const props = defineProps<{
browserWindow: UnwrapNestedRefs<BrowserWindow>;
}>();
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()
}
</script>

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

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

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

@ -52,7 +52,7 @@
@touchstart.stop.passive="startScale($event, border.type)"
></div>
<div class="wintmp_footer" v-if="browserWindow.windowInfo.footer">
<MenuFooter :browser-window="browserWindow"></MenuFooter>
<MenuFooter :browser-window="browserWindow" @translateSavePath="translateSavePath"></MenuFooter>
</div>
</div>
</template>
@ -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);

20
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<any[]>([])
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

5
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<WindowInfo, keyof BrowserWindowConstructorOptions> = {
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() {

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