diff --git a/src/components/MainEditor.vue b/src/components/MainEditor.vue index e8b35d1..9eed338 100644 --- a/src/components/MainEditor.vue +++ b/src/components/MainEditor.vue @@ -20,7 +20,7 @@ - + @@ -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: `

确认使用《${title}》作为文章标题将其同步到云端。
点击确认之后,会同步文章,并修改第一行嵌入文章 ID,最后将当前内容保存操作到本地。

`, + 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({ diff --git a/src/utils/userHandler.js b/src/utils/userHandler.js index 7ca2f21..9c3811b 100644 --- a/src/utils/userHandler.js +++ b/src/utils/userHandler.js @@ -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, }; \ No newline at end of file