From 4d34248425bbd3282a4bccb3902cc329125e3ca9 Mon Sep 17 00:00:00 2001 From: terwer Date: Sat, 5 Aug 2023 16:03:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B8=B8=E8=A7=84=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=96=87=E7=AB=A0=E6=AF=94=E5=AF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/adaptors/api/base/baseBlogApi.ts | 17 +-- .../api/notion/adaptor/notionApiAdaptor.ts | 117 +++++++++++++++--- .../api/yuque/adaptor/yuqueApiAdaptor.ts | 5 +- .../publish/SinglePublishDoPublish.vue | 47 ++++++- src/utils/appLogger.ts | 12 +- src/utils/constants.ts | 1 + vite.config.ts | 18 +-- 7 files changed, 171 insertions(+), 46 deletions(-) diff --git a/src/adaptors/api/base/baseBlogApi.ts b/src/adaptors/api/base/baseBlogApi.ts index b3e250c8..7b8e0b8b 100644 --- a/src/adaptors/api/base/baseBlogApi.ts +++ b/src/adaptors/api/base/baseBlogApi.ts @@ -22,14 +22,15 @@ * or visit www.terwer.space if you need additional information or have any * questions. */ -import {BlogApi, BlogConfig} from "zhi-blog-api" -import {SiyuanKernelApi} from "zhi-siyuan-api" -import {CommonFetchClient} from "zhi-fetch-middleware" -import {AppInstance} from "~/src/appInstance.ts" -import {createAppLogger, ILogger} from "~/src/utils/appLogger.ts" -import {useSiyuanApi} from "~/src/composables/useSiyuanApi.ts" -import {JsonUtil, ObjectUtil, StrUtil} from "zhi-common" -import {isDev} from "~/src/utils/constants.ts" + +import { BlogApi, BlogConfig } from "zhi-blog-api" +import { SiyuanKernelApi } from "zhi-siyuan-api" +import { CommonFetchClient } from "zhi-fetch-middleware" +import { AppInstance } from "~/src/appInstance.ts" +import { createAppLogger, ILogger } from "~/src/utils/appLogger.ts" +import { useSiyuanApi } from "~/src/composables/useSiyuanApi.ts" +import { JsonUtil, ObjectUtil, StrUtil } from "zhi-common" +import { isDev } from "~/src/utils/constants.ts" /** * API授权统一封装基类 diff --git a/src/adaptors/api/notion/adaptor/notionApiAdaptor.ts b/src/adaptors/api/notion/adaptor/notionApiAdaptor.ts index 0bf96ba4..260387ab 100644 --- a/src/adaptors/api/notion/adaptor/notionApiAdaptor.ts +++ b/src/adaptors/api/notion/adaptor/notionApiAdaptor.ts @@ -23,10 +23,11 @@ * questions. */ -import { UserBlog } from "zhi-blog-api" +import { CategoryInfo, Post, UserBlog } from "zhi-blog-api" import { BaseBlogApi } from "~/src/adaptors/api/base/baseBlogApi.ts" import { NotionConfig } from "~/src/adaptors/api/notion/config/notionConfig.ts" import { createAppLogger } from "~/src/utils/appLogger.ts" +import { ObjectUtil, StrUtil } from "zhi-common" /** * Notion API 适配器 @@ -40,11 +41,67 @@ class NotionApiAdaptor extends BaseBlogApi { public async getUsersBlogs(): Promise { const result: UserBlog[] = [] - // https://developers.notion.com/reference/post-search - const headers = { - Authorization: `Bearer ${this.cfg.password}`, - "Notion-Version": "2022-06-28", + const pages = await this.getPages() + // 数据适配 + pages.forEach((item: any) => { + const userblog: UserBlog = new UserBlog() + userblog.blogid = item.id + const titles = item?.properties?.title?.title ?? [] + userblog.blogName = titles.map((x: any) => x.plain_text).join("") + userblog.url = item.public_url + result.push(userblog) + }) + this.logger.debug("get usersBlogs result=>", result) + + return result + } + + public async newPost(post: Post, publish?: boolean): Promise { + return super.newPost(post) + } + + public async editPost(postid: string, post: Post, publish?: boolean): Promise { + return await super.editPost(postid, post) + } + + public async deletePost(postid: string): Promise { + return await super.deletePost(postid) + } + + public async getPost(postid: string, useSlug?: boolean): Promise { + return await super.getPost(postid) + } + + public async getCategories(): Promise { + const cats = [] as CategoryInfo[] + + const pages: any[] = await this.getPages() + if (pages && pages.length > 0) { + pages.forEach((item: any) => { + const cat = new CategoryInfo() + cat.categoryId = item.id + const titles = item?.properties?.title?.title ?? [] + cat.categoryName = titles.map((x: any) => x.plain_text).join("") + cat.description = cat.categoryName + cat.categoryDescription = cat.categoryName + cat.htmlUrl = item.public_url + cats.push(cat) + }) } + + return cats + } + + public async getPreviewUrl(postid: string): Promise { + const purl = this.cfg.previewUrl ?? "" + const postUrl = purl.replace("[postid]", postid) + return StrUtil.pathJoin(this.cfg.home ?? "", postUrl) + } + + // ================ + // private methods + // ================ + private async getPages(): Promise { const params = { page_size: 10, filter: { @@ -52,7 +109,7 @@ class NotionApiAdaptor extends BaseBlogApi { property: "object", }, } - const searchResp = await this.proxyFetch("/search", [headers], params, "POST", "application/json") + const searchResp = await this.notionRequest("/search", params, "POST") this.logger.debug("notion searchResp=>", searchResp) if (searchResp?.status === 401) { throw new Error(searchResp?.message) @@ -67,18 +124,44 @@ class NotionApiAdaptor extends BaseBlogApi { ) } - // 数据适配 - pages.forEach((item: any) => { - const userblog: UserBlog = new UserBlog() - userblog.blogid = item.id - const titles = item?.properties?.title?.title ?? [] - userblog.blogName = titles.map((x: any) => x.plain_text).join("") - userblog.url = item.public_url - result.push(userblog) - }) - this.logger.debug("get usersBlogs result=>", result) + return pages + } - return result + /** + * 向Notion请求数据 + * + * @param url 请求地址 + * @param params 数据 + * @param method 请求方法 GET | POST | PUT | DELETE + * @private + */ + private async notionRequest( + url: string, + params?: any, + method: "GET" | "POST" | "PUT" | "DELETE" = "POST" + ): Promise { + const contentType = "application/json" + // https://developers.notion.com/reference/post-search + const headers = { + "Content-Type": contentType, + Authorization: `Bearer ${this.cfg.password}`, + "Notion-Version": "2022-06-28", + } + + // 打印日志 + this.logger.debug("向Notion请求数据,url =>", url) + this.logger.debug("向Notion请求数据,params =>", params) + + // 使用兼容的fetch调用并返回统一的JSON数据 + const body = ObjectUtil.isEmptyObject(params) ? {} : params + const resJson = await this.proxyFetch(url, [headers], body, method, contentType) + this.logger.debug("向Notion请求数据,resJson =>", resJson) + + if (resJson?.status === 401) { + throw new Error(resJson?.message) + } + + return resJson } } diff --git a/src/adaptors/api/yuque/adaptor/yuqueApiAdaptor.ts b/src/adaptors/api/yuque/adaptor/yuqueApiAdaptor.ts index 77dd259e..ac00f36e 100644 --- a/src/adaptors/api/yuque/adaptor/yuqueApiAdaptor.ts +++ b/src/adaptors/api/yuque/adaptor/yuqueApiAdaptor.ts @@ -308,10 +308,7 @@ class YuqueApiAdaptor extends BaseBlogApi { this.logger.debug("向语雀请求数据,params =>", params) // 使用兼容的fetch调用并返回统一的JSON数据 - let body = "" - if (!ObjectUtil.isEmptyObject(params)) { - body = JSON.stringify(params) - } + const body = ObjectUtil.isEmptyObject(params) ? "" : JSON.stringify(params); const resJson = await this.proxyFetch(url, [headers], body, method, contentType) this.logger.debug("向语雀请求数据,resJson =>", resJson) diff --git a/src/components/publish/SinglePublishDoPublish.vue b/src/components/publish/SinglePublishDoPublish.vue index f882099f..b6ccc884 100644 --- a/src/components/publish/SinglePublishDoPublish.vue +++ b/src/components/publish/SinglePublishDoPublish.vue @@ -35,6 +35,7 @@ import { useVueI18n } from "~/src/composables/useVueI18n.ts" import { pre } from "~/src/utils/import/pre.ts" import { DynamicConfig } from "~/src/components/set/publish/platform/dynamicConfig.ts" import { useSiyuanApi } from "~/src/composables/useSiyuanApi.ts" +import { ElMessage } from "element-plus" const logger = createAppLogger("single-publish-do-publish") @@ -44,6 +45,7 @@ const route = useRoute() const { doInitPage } = usePublish() const { query } = useRoute() const { kernelApi, blogApi } = useSiyuanApi() +const { doSinglePublish } = usePublish() // datas const sysKeys = pre.systemCfg.map((item) => { @@ -65,10 +67,35 @@ const formData = reactive({ mergedPost: {} as Post, singleFormData: {} as any, + changeTips: { + title: "", + }, + actionEnable: true, }) -const handlePublish = async () => {} +const handlePublish = async () => { + try { + formData.isPublishLoading = true + logger.info("单个常规发布开始") + const processResult = await doSinglePublish(key, id, formData.mergedPost) + + logger.info("normal publish processResult =>", processResult) + logger.info("单个常规发布结束") + + // 刷新页面 + formData.isInit = false + formData.actionEnable = false + await initPage() + // 需要刷新才能继续操作,防止重复提交 + formData.isInit = true + formData.actionEnable = true + } catch (error) { + ElMessage.error(error.message) + } finally { + formData.isPublishLoading = false + } +} const handleDelete = async () => {} @@ -91,15 +118,22 @@ const showChangeTip = (v1: string, v2: string) => { return `系统标题为 [${v1}] , 已在远程平台被修改为 [${v2}]` } -onMounted(async () => { - logger.info("获取到的ID为=>", id) +const refreshChangeTips = () => { + formData.changeTips.title = showChangeTip(formData.siyuanPost.title, formData.platformPost.title) +} + +const initPage = async () => { try { formData.singleFormData = await doInitPage(key, id, method) + // 文章元数据 formData.siyuanPost = formData.singleFormData.siyuanPost formData.platformPost = formData.singleFormData.platformPost formData.mergedPost = formData.singleFormData.mergedPost + // 刷新比对提示 + refreshChangeTips() + logger.debug("formData.platformPost=>", formData.platformPost) } catch (e) { const errMsg = t("main.opt.failure") + "=>" + e @@ -109,7 +143,12 @@ onMounted(async () => { timeout: 7000, }) } +} + +onMounted(async () => { + logger.info("获取到的ID为=>", id) + await initPage() formData.isInit = true }) @@ -132,7 +171,7 @@ onMounted(async () => { diff --git a/src/utils/appLogger.ts b/src/utils/appLogger.ts index 4ce3a17a..995d75cb 100644 --- a/src/utils/appLogger.ts +++ b/src/utils/appLogger.ts @@ -23,13 +23,13 @@ * questions. */ -import { isDev } from "~/src/utils/constants.ts" +import { isDebugMode, isDev } from "~/src/utils/constants.ts" import { simpleLogger } from "zhi-lib-base" /** * 使用 eruda 更好的控制日志 */ -window.console = isDev ? (window as any).eruda.get("console") : window.console +window.console = isDev && isDebugMode ? (window as any).eruda.get("console") : window.console /** * 简单的日志接口 @@ -55,7 +55,7 @@ export const createAppLogger = (name: string): ILogger => { /** * 销毁日志 */ -export const destroyLogger = (): void => { - const win = window as any - win.eruda.destroy() -} +// export const destroyLogger = (): void => { +// const win = window as any +// win.eruda.destroy() +// } diff --git a/src/utils/constants.ts b/src/utils/constants.ts index d1eba5ad..065bd096 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -24,6 +24,7 @@ */ export const isDev = process.env.DEV_MODE === "true" +export const isDebugMode = process.env.DEBUG_MODE === "true" /** * 动态配置key,全系统唯一,请勿更改 diff --git a/vite.config.ts b/vite.config.ts index 417f0791..947c0261 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,6 +10,7 @@ import Components from "unplugin-vue-components/vite" import { ElementPlusResolver } from "unplugin-vue-components/resolvers" import { nodePolyfills } from "vite-plugin-node-polyfills" +// methods start const getAppBase = (isSiyuanBuild: boolean, isWidgetBuild: boolean, isStaticBuild: boolean): string => { if (isSiyuanBuild) { return "/plugins/siyuan-plugin-publisher/" @@ -22,13 +23,14 @@ const getAppBase = (isSiyuanBuild: boolean, isWidgetBuild: boolean, isStaticBuil } } -const getDefineEnv = (isDevMode: boolean) => { +const getDefineEnv = (isDevMode: boolean, debugMode: boolean) => { const mode = process.env.NODE_ENV console.log("isServe=>", isServe) console.log("mode=>", mode) const defaultEnv = { DEV_MODE: `${isDevMode}`, + DEBUG_MODE: `${debugMode}`, APP_BASE: `${appBase}`, NODE_ENV: "development", VITE_DEFAULT_TYPE: `siyuan`, @@ -50,13 +52,15 @@ const getDefineEnv = (isDevMode: boolean) => { return defineEnv } +// methods end +// config const args = minimist(process.argv.slice(2)) -const debugMode = false +// 开启之后可以同eruda接管日志 +const debugMode = process.env.DEBUG_MODE === "true" const isServe = process.env.IS_SERVE const isWatch = args.watch || args.w || false const isDev = isServe || isWatch || debugMode -// const isDev = false const isWindows = process.platform === "win32" let devDistDir = "/Users/terwer/Documents/mydocs/SiYuanWorkspace/test/data/plugins/siyuan-plugin-publisher" // let devDistDir = "/Users/terwer/Documents/mydocs/SiYuanWorkspace/public/data/plugins/siyuan-plugin-publisher" @@ -67,7 +71,7 @@ if (isWindows) { const isSiyuanBuild = process.env.BUILD_TYPE === "siyuan" const isWidgetBuild = process.env.BUILD_TYPE === "widget" const isStaticBuild = process.env.BUILD_TYPE === "static" -const isChromeBuild = process.env.BUILD_TYPE === "chrome" +// const isChromeBuild = process.env.BUILD_TYPE === "chrome" const distDir = isWatch ? devDistDir : isWidgetBuild ? "widget" : "./dist" const appBase = getAppBase(isSiyuanBuild, isWidgetBuild, isStaticBuild) @@ -97,7 +101,7 @@ export default defineConfig({ inject: { // 在 body 标签底部插入指定的 JavaScript 文件 tags: - isDev && !isChromeBuild + isDev && debugMode ? [ { tag: "script", @@ -125,7 +129,7 @@ export default defineConfig({ ], data: { title: "eruda", - injectScript: isDev && !isChromeBuild ? `` : "", + injectScript: isDev && debugMode ? `` : "", }, }, }), @@ -156,7 +160,7 @@ export default defineConfig({ // https://vitejs.dev/guide/env-and-mode.html#env-files // https://github.com/vitejs/vite/discussions/3058#discussioncomment-2115319 // 在这里自定义变量 - define: getDefineEnv(isDev), + define: getDefineEnv(isDev, debugMode), resolve: { alias: {