diff --git a/apps/web/src/components/editor/UploadImgDialog.vue b/apps/web/src/components/editor/UploadImgDialog.vue index 77178ede9..a5875592d 100644 --- a/apps/web/src/components/editor/UploadImgDialog.vue +++ b/apps/web/src/components/editor/UploadImgDialog.vue @@ -352,6 +352,15 @@ onBeforeMount(() => { } }) +// 当弹窗打开,且 imgHost 设为 mp 时,默认切换到公众号图床 Tab +watch(() => displayStore.isShowUploadImgDialog, (open) => { + if (open) { + const host = localStorage.getItem(`imgHost`) || imgHost.value + if (host === `mp`) + activeName.value = `mp` + } +}, { immediate: false }) + function changeImgHost() { localStorage.setItem(`imgHost`, imgHost.value) toast.success(`图床已切换`) diff --git a/apps/web/src/components/editor/editor-header/WeChatPublish.vue b/apps/web/src/components/editor/editor-header/WeChatPublish.vue new file mode 100644 index 000000000..d83c9524e --- /dev/null +++ b/apps/web/src/components/editor/editor-header/WeChatPublish.vue @@ -0,0 +1,485 @@ + + + + + + {{ wechatPublishing ? '发布中...' : '发布到公众号' }} + + + + + + 发布到微信公众号 + + + + + 需要先配置公众号图床 + + 请先完成 appID 与 appsecret 的配置。 + + + 打开配置 + + + 我已配置,重新检测 + + + + + + + + 标题 + + + + + + + 作者 + + + + + + + 摘要 + + + + + {{ wechatForm.digest.length }}/120 + + + + + + + 封面链接 + + + + + + + + {{ uploadingThumb ? '自动上传中…' : (wechatForm.thumbMediaId ? '已上传微信后台' : '将自动上传到微信后台') }} + + + + + + + + + + + {{ uploadingThumb ? '上传中…' : '上传图片' }} + + 未提取到封面,请上传本地图片或在上方输入图片地址 + + + + + + 原文链接 + + + + + + + 评论设置 + + + + + 开启评论 + + + + 仅粉丝可评论 + + + + + + + 取 消 + + + {{ wechatPublishing ? '发布中...' : '确 定' }} + + + + + + + + + 发布成功 + + + + + + 文章已成功发布到微信公众号 + + + + 打开微信公众号管理后台 + + + + + + + + + diff --git a/apps/web/src/components/editor/editor-header/index.vue b/apps/web/src/components/editor/editor-header/index.vue index 50d5ec9ce..01ba4f189 100644 --- a/apps/web/src/components/editor/editor-header/index.vue +++ b/apps/web/src/components/editor/editor-header/index.vue @@ -182,6 +182,9 @@ async function copy() { + + + (url, requestOptions) @@ -335,6 +338,7 @@ async function getMpToken(appID: string, appsecret: string, proxyOrigin: string) } // Cloudflare Pages 环境 const isCfPage = import.meta.env.CF_PAGES === `1` +const isDev = import.meta.env.DEV async function mpFileUpload(file: File) { let { appID, appsecret, proxyOrigin } = JSON.parse( localStorage.getItem(`mpConfig`)!, @@ -362,6 +366,10 @@ async function mpFileUpload(file: File) { if (fileSizeInMB < 1 && (fileType === `image/jpeg` || fileType === `image/png`)) { url = `https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=${access_token}` } + // 本地代理转发 + if (isDev && !isInExtension) { + url = url.replace(`https://api.weixin.qq.com`, ``) + } if (proxyOrigin) { url = url.replace(`https://api.weixin.qq.com`, proxyOrigin) } diff --git a/apps/web/src/utils/index.ts b/apps/web/src/utils/index.ts index a0475c133..3bab581ff 100644 --- a/apps/web/src/utils/index.ts +++ b/apps/web/src/utils/index.ts @@ -337,4 +337,6 @@ export async function processClipboardContent(primaryColor: string) { /]*)>/g, ``, ) + // 新增返回值,公众号发布组件使用 + return clipboardDiv.innerHTML } diff --git a/apps/web/src/utils/wechat-publish.ts b/apps/web/src/utils/wechat-publish.ts new file mode 100644 index 000000000..28a5185ea --- /dev/null +++ b/apps/web/src/utils/wechat-publish.ts @@ -0,0 +1,110 @@ +import { getMpToken } from '@/utils/file' +import { isInExtension } from '../sidepanel' + +const isCfPage = import.meta.env.CF_PAGES === `1` +const isDev = import.meta.env.DEV +export async function getMpAccessToken() { + let { appID, appsecret, proxyOrigin } = JSON.parse( + localStorage.getItem(`mpConfig`)!, + ) + // 未填写代理域名且是cfpages环境 + if (!proxyOrigin && isCfPage) { + proxyOrigin = window.location.origin + } + // 开发环境,走本地代理配置 + if (isDev) { + proxyOrigin = `` + } + const access_token = await getMpToken(appID, appsecret, proxyOrigin) + return access_token +} + +interface MpCoverMediaId { + url: string + media_id: string +} +export async function getMpCoverMediaId(file: File): Promise<{ url: string, media_id: string, errmsg?: string }> { + let { appID, appsecret, proxyOrigin } = JSON.parse( + localStorage.getItem(`mpConfig`)!, + ) + // 未填写代理域名且是cfpages环境 + if (!proxyOrigin && isCfPage) { + proxyOrigin = window.location.origin + } + + // 开发环境,走本地代理配置 + if (isDev) { + proxyOrigin = `` + } + const access_token = await getMpToken(appID, appsecret, proxyOrigin) + + const formdata = new FormData() + formdata.append(`media`, file, file.name) + + const requestOptions = { + method: `POST`, + body: formdata, + } + + let url = `https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=${access_token}&type=image` + if (proxyOrigin !== null && proxyOrigin !== undefined && !isInExtension) { + url = url.replace(`https://api.weixin.qq.com`, proxyOrigin) + } + + const res = await (await fetch(url, requestOptions)).json() as MpCoverMediaId + + if (!res.url || !res.media_id) { + throw new Error(`上传失败,未获取到URL`) + } + + return res +} + +interface MpArticleDraft { + title: string + author?: string + digest?: string + content_source_url?: string + thumb_media_id: string + content: string + need_open_comment?: number + only_fans_can_comment?: number +} + +export async function addMpArticleDraft(params: MpArticleDraft) { + let { appID, appsecret, proxyOrigin } = JSON.parse( + localStorage.getItem(`mpConfig`)!, + ) + // 未填写代理域名且是cfpages环境 + if (!proxyOrigin && isCfPage) { + proxyOrigin = window.location.origin + } + + // 开发环境,走本地代理配置 + if (isDev) { + proxyOrigin = `` + } + const access_token = await getMpToken(appID, appsecret, proxyOrigin) + + let url = `https://api.weixin.qq.com/cgi-bin/draft/add?access_token=${access_token}` + if (proxyOrigin !== null && proxyOrigin !== undefined && !isInExtension) { + url = url.replace(`https://api.weixin.qq.com`, proxyOrigin) + } + + const response = await fetch(url, { + method: `POST`, + headers: { 'Content-Type': `application/json` }, + body: JSON.stringify({ + articles: [ + { + article_type: `news`, + ...params, + }, + ], + }), + }) + + const result = await response.json() + + return result +} diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index ac61c5f19..ab87e2a4e 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -21,6 +21,17 @@ export default defineConfig(({ mode }) => { base, define: { process }, envPrefix: [`VITE_`, `CF_`], + // Support local dev, resolve cross-origin issues + server: { + proxy: { + '/cgi-bin': { + target: `https://api.weixin.qq.com`, + changeOrigin: true, + secure: true, + rewrite: path => path.replace(/^\/cgi-bin/, `/cgi-bin`), + }, + }, + }, plugins: [ vue(), tailwindcss(),
+ 文章已成功发布到微信公众号 +
+ + 打开微信公众号管理后台 + + +