@@ -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