feat: 支持同步文章到云端

This commit is contained in:
Frankie Huang 2025-05-05 16:46:12 +08:00
parent 991ca62c68
commit 58012dbbd3
2 changed files with 122 additions and 6 deletions

View File

@ -20,7 +20,7 @@
</NormalToolbar>
<ExportPDF :modelValue="editorState.text" :customize="customizePDF"
@onProgress="handleExportProgress" />
<NormalToolbar title="发布文章" @onClick="publish">
<NormalToolbar title="同步到云端" @onClick="uploadCloud">
<template #trigger>
<Icon class="md-editor-icon" type="md-cloud-upload" size="22" />
</template>
@ -55,8 +55,9 @@ import { ThemeSwitch, PreviewThemeSwitch, ExportPDF } from '@vavt/v3-extension';
import { lineNumbers } from '@codemirror/view';
import LinkAttr from 'markdown-it-link-attributes';
import { ref, reactive, watch, nextTick, onMounted } from "vue";
import { Message } from 'view-ui-plus'
import { Message, Modal } from 'view-ui-plus'
import { encode as plantumlEncoder } from 'plantuml-encoder';
import { SubmitArticle, UpdateArticle } from '/src/utils/userHandler';
// fetchScript JS
const fetchScript = (url) => new Promise((resolve) => scriptjs(url, () => resolve()));
@ -317,9 +318,69 @@ const handleExportProgress = (progress) => {
}
};
const publish = () => {
// TODO markdown HTML
Message.warning('抱歉,该功能暂未开放');
const uploadCloud = () => {
// markdown
const markdownLines = editorState.text.split('\n');
let firstLine = 0;
for (let index = 0; index < markdownLines.length; index++) {
if (markdownLines[index].trim().length > 0) {
firstLine = index;
break;
}
}
for (let index = 0; index < firstLine; index++) {
markdownLines.shift();
}
const firstLineText = markdownLines[0].trim();
if (!firstLineText.startsWith('# ')) {
Message.warning('第一行请以 “# 文章标题” 作为开头');
return;
}
// ID
let title = firstLineText.slice(2).trim();
let articleID = '';
const match = title.match(/^\[(.*?)\]\((.*?)\)$/);
if (match) {
title = match[1].trim(); // ""
articleID = match[2].trim(); // " https://github.com"
}
// ID ID
if (articleID.length > 0 && !isNaN(Number(articleID, 10))) {
editorState.text = markdownLines.join('\n');
//
UpdateArticle(parseInt(articleID, 10), title, editorState.text)
.then((data) => {
Modal.remove();
Message.success('同步成功');
onSave(editorState.text);
})
.catch((error) => {
Message.error(`同步异常: ${error}`);
});
} else {
// title
Modal.confirm({
title: '发布前确认',
content: `<p>确认使用《${title}》作为文章标题将其同步到云端。<br/>点击确认之后,会同步文章,并修改第一行嵌入文章 ID最后将当前内容保存操作到本地。</p>`,
loading: true,
onOk: () => {
SubmitArticle(title, markdownLines.join('\n'))
.then((data) => {
articleID = data.id;
markdownLines[0] = '# [' + title + '](' + articleID + ')';
editorState.text = markdownLines.join('\n');
Modal.remove();
Message.success('同步成功');
onSave(editorState.text);
})
.catch((error) => {
Message.error(`同步异常: ${error}`);
});
},
});
}
}
const uploadImgForm = reactive({

View File

@ -3,7 +3,9 @@ import md5 from 'js-md5';
// 由于是跨域登录,需要手动设置并携带 Cookie
const setPHPSessionToCookie = (sessionID) => {
if (sessionID) {
document.cookie = `PHPSESSID=${sessionID}; max-age=604800; SameSite=None; secure; path=/`;
// 使用 SameSite=None 和 secure 属性,在 tauri 环境会设置失败
// document.cookie = `PHPSESSID=${sessionID}; max-age=604800; SameSite=None; secure; path=/`;
document.cookie = `PHPSESSID=${sessionID}; max-age=604800; path=/`;
}
}
@ -149,10 +151,63 @@ const Logout = () => {
});
}
const SubmitArticle = (title, mdCode) => {
return new Promise((resolve, reject) => {
const PHPSESSID = getPHPSessionFromCookie();
fetch('https://myafei.cn/php/ajax.php?PHPSESSID=' + PHPSESSID, {
method: 'POST',
body: JSON.stringify({
'func': 'submit_article',
'title': title,
'mdCode': mdCode,
}),
}).then(response => {
if (!response.ok) throw new Error(`HTTP 错误: ${response.status}`);
return response.json();
}).then(data => {
if (data.status == 0) {
resolve(data);
} else {
reject(new Error(data.error));
}
}).catch(error => {
reject(error);
});
});
}
const UpdateArticle = (id, title, mdCode) => {
return new Promise((resolve, reject) => {
const PHPSESSID = getPHPSessionFromCookie();
fetch('https://myafei.cn/php/ajax.php?PHPSESSID=' + PHPSESSID, {
method: 'POST',
body: JSON.stringify({
'func': 'update_article',
'id': id,
'title': title,
'mdCode': mdCode,
}),
}).then(response => {
if (!response.ok) throw new Error(`HTTP 错误: ${response.status}`);
return response.json();
}).then(data => {
if (data.status == 0) {
resolve(data);
} else {
reject(new Error(data.error));
}
}).catch(error => {
reject(error);
});
});
}
export {
SignIn,
SignUp,
SendSignUpEmail,
CheckLoginStatus,
Logout,
SubmitArticle,
UpdateArticle,
};