feat: 支持同步文章到云端
This commit is contained in:
parent
991ca62c68
commit
58012dbbd3
@ -20,7 +20,7 @@
|
|||||||
</NormalToolbar>
|
</NormalToolbar>
|
||||||
<ExportPDF :modelValue="editorState.text" :customize="customizePDF"
|
<ExportPDF :modelValue="editorState.text" :customize="customizePDF"
|
||||||
@onProgress="handleExportProgress" />
|
@onProgress="handleExportProgress" />
|
||||||
<NormalToolbar title="发布文章" @onClick="publish">
|
<NormalToolbar title="同步到云端" @onClick="uploadCloud">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<Icon class="md-editor-icon" type="md-cloud-upload" size="22" />
|
<Icon class="md-editor-icon" type="md-cloud-upload" size="22" />
|
||||||
</template>
|
</template>
|
||||||
@ -55,8 +55,9 @@ import { ThemeSwitch, PreviewThemeSwitch, ExportPDF } from '@vavt/v3-extension';
|
|||||||
import { lineNumbers } from '@codemirror/view';
|
import { lineNumbers } from '@codemirror/view';
|
||||||
import LinkAttr from 'markdown-it-link-attributes';
|
import LinkAttr from 'markdown-it-link-attributes';
|
||||||
import { ref, reactive, watch, nextTick, onMounted } from "vue";
|
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 { encode as plantumlEncoder } from 'plantuml-encoder';
|
||||||
|
import { SubmitArticle, UpdateArticle } from '/src/utils/userHandler';
|
||||||
|
|
||||||
// fetchScript 用于将其他 JS 脚本加载进来
|
// fetchScript 用于将其他 JS 脚本加载进来
|
||||||
const fetchScript = (url) => new Promise((resolve) => scriptjs(url, () => resolve()));
|
const fetchScript = (url) => new Promise((resolve) => scriptjs(url, () => resolve()));
|
||||||
@ -317,9 +318,69 @@ const handleExportProgress = (progress) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const publish = () => {
|
const uploadCloud = () => {
|
||||||
// TODO 调用接口将 markdown 源码或者 HTML 代码发布到云端
|
// 找到 markdown 代码第一行,第一行前面的空行都剔除掉
|
||||||
Message.warning('抱歉,该功能暂未开放');
|
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({
|
const uploadImgForm = reactive({
|
||||||
|
|||||||
@ -3,7 +3,9 @@ import md5 from 'js-md5';
|
|||||||
// 由于是跨域登录,需要手动设置并携带 Cookie
|
// 由于是跨域登录,需要手动设置并携带 Cookie
|
||||||
const setPHPSessionToCookie = (sessionID) => {
|
const setPHPSessionToCookie = (sessionID) => {
|
||||||
if (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 {
|
export {
|
||||||
SignIn,
|
SignIn,
|
||||||
SignUp,
|
SignUp,
|
||||||
SendSignUpEmail,
|
SendSignUpEmail,
|
||||||
CheckLoginStatus,
|
CheckLoginStatus,
|
||||||
Logout,
|
Logout,
|
||||||
|
SubmitArticle,
|
||||||
|
UpdateArticle,
|
||||||
};
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user