diff --git a/apps/web/src/utils/file.ts b/apps/web/src/utils/file.ts
index 4ff0bff3d..97021ebc7 100644
--- a/apps/web/src/utils/file.ts
+++ b/apps/web/src/utils/file.ts
@@ -320,7 +320,8 @@ export async function getMpToken(appID: string, appsecret: string, proxyOrigin:
}
let url = `https://api.weixin.qq.com/cgi-bin/stable_token`
// 兼容空字符串情况,本地代理时不需要传入域名
- if (proxyOrigin !== null && proxyOrigin !== undefined) {
+ // 兼容浏览器插件环境 proxyOrigin 为空情况
+ if (proxyOrigin !== null && proxyOrigin !== undefined && !(chrome.runtime)) {
url = `${proxyOrigin}/cgi-bin/stable_token`
}
const res = await fetch
(url, requestOptions)
diff --git a/apps/web/src/utils/wechat-publish.ts b/apps/web/src/utils/wechat-publish.ts
index 8063f5b4b..f8862144c 100644
--- a/apps/web/src/utils/wechat-publish.ts
+++ b/apps/web/src/utils/wechat-publish.ts
@@ -46,7 +46,7 @@ export async function getMpCoverMediaId(file: File): Promise<{ url: string, medi
}
let url = `https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=${access_token}&type=image`
- if (proxyOrigin !== null && proxyOrigin !== undefined) {
+ if (proxyOrigin !== null && proxyOrigin !== undefined && !(chrome.runtime)) {
url = url.replace(`https://api.weixin.qq.com`, proxyOrigin)
}
@@ -86,7 +86,7 @@ export async function addMpArticleDraft(params: MpArticleDraft) {
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) {
+ if (proxyOrigin !== null && proxyOrigin !== undefined && !(chrome.runtime)) {
url = url.replace(`https://api.weixin.qq.com`, proxyOrigin)
}
From 0977bb903aa2680e67fe0e4e06e32725a68a0e95 Mon Sep 17 00:00:00 2001
From: simonzhangs <2863389578@qq.com>
Date: Mon, 29 Sep 2025 00:37:51 +0800
Subject: [PATCH 3/3] feat: support chorme extension publish wxmp articles
---
.../editor/editor-header/WeChatPublish.vue | 43 ++++++++++++-------
apps/web/src/sidepanel.ts | 2 +-
apps/web/src/utils/file.ts | 8 +++-
apps/web/src/utils/wechat-publish.ts | 5 ++-
4 files changed, 39 insertions(+), 19 deletions(-)
diff --git a/apps/web/src/components/editor/editor-header/WeChatPublish.vue b/apps/web/src/components/editor/editor-header/WeChatPublish.vue
index 857dcb148..d83c9524e 100644
--- a/apps/web/src/components/editor/editor-header/WeChatPublish.vue
+++ b/apps/web/src/components/editor/editor-header/WeChatPublish.vue
@@ -26,6 +26,9 @@ const wechatPublishing = ref(false)
const wechatConfigDialogVisible = ref(false)
const wechatSuccessDialogVisible = ref(false)
+const mpConfigured = ref(false)
+recheckMpConfig()
+
const disabledBtn = computed(() => {
const content = output.value || ``
return wechatPublishing.value || content.trim() === ``
@@ -38,7 +41,7 @@ let coverUrlDebounceTimer: number | undefined
function extractTitleAndDesc() {
try {
// 优先从当前选中文章的标题中提取
- const currentPostTitleEl = document.querySelector(`a.bg-primary.text-primary-foreground.shadow span.line-clamp-1`) as HTMLElement | null
+ const currentPostTitleEl = document.querySelector(`a.bg-primary.text-primary-foreground.shadow-sm span.line-clamp-1`) as HTMLElement | null
let derivedTitle = currentPostTitleEl?.textContent?.trim() || ``
// 如果没找到当前文章标题,再从 #output 的 h1-h6 中提取
@@ -77,21 +80,26 @@ watch(
{ immediate: false },
)
-// 封面链接变化时,清空已得的 media_id,等待重新上传
+// 观察 coverUrl 和 mpConfigured.value 为true时,触发上传
watch(
- () => wechatForm.value.coverUrl,
- (val) => {
- wechatForm.value.thumbMediaId = ``
- const url = (val || ``).trim()
- if (!url)
+ [() => wechatForm.value.coverUrl, () => mpConfigured.value],
+ ([coverUrl, configured], [prevCoverUrl]) => {
+ const url = (coverUrl || ``).trim()
+ if (!url || !configured)
return
if (uploadingThumb.value)
return
+
+ // 如果封面链接发生变化,清空旧的 thumbMediaId
+ if (prevCoverUrl !== coverUrl) {
+ wechatForm.value.thumbMediaId = ``
+ }
+
if (coverUrlDebounceTimer)
clearTimeout(coverUrlDebounceTimer)
coverUrlDebounceTimer = window.setTimeout(() => {
- // 若期间用户又清空了,跳过
- if (!wechatForm.value.coverUrl?.trim())
+ // 若期间用户又清空了或配置失效,跳过
+ if (!wechatForm.value.coverUrl?.trim() || !mpConfigured.value)
return
uploadThumbIfNeeded().catch(() => {})
}, 600)
@@ -106,14 +114,15 @@ function openWechatConfig() {
}
// 打开弹窗后提示是否缺少配置
extractTitleAndDesc()
- // 预取并上传封面图,获取 thumb_media_id
- uploadThumbIfNeeded().catch((err) => {
- console.warn(`uploadThumbIfNeeded error`, err)
- })
+ if (mpConfigured.value) {
+ // 预取并上传封面图,获取 thumb_media_id
+ uploadThumbIfNeeded().catch((err) => {
+ console.warn(`uploadThumbIfNeeded error`, err)
+ })
+ }
wechatConfigDialogVisible.value = true
}
-const mpConfigured = ref(true)
function isMpConfigured(): boolean {
try {
const mpConfigStr = localStorage.getItem(`mpConfig`)
@@ -229,7 +238,7 @@ async function uploadThumbIfNeeded(): Promise {
return wechatForm.value.thumbMediaId
const sourceUrl = (wechatForm.value.coverUrl || ``).trim()
- const imgSrc = sourceUrl || (document.querySelector(`#output img`) as HTMLImageElement | null)?.src || ``
+ let imgSrc = sourceUrl || (document.querySelector(`#output img`) as HTMLImageElement | null)?.src || ``
if (!imgSrc)
return
@@ -240,6 +249,10 @@ async function uploadThumbIfNeeded(): Promise {
}
uploadingThumb.value = true
+ // 兼容浏览器插件直接下载微信图片无法成功问题
+ if (imgSrc.startsWith(`http://mmbiz.qpic.cn`) || imgSrc.startsWith(`https://mmbiz.qpic.cn`)) {
+ imgSrc = `https://wsrv.nl?url=${encodeURIComponent(imgSrc)}`
+ }
const res = await fetch(imgSrc)
const blob = await res.blob()
diff --git a/apps/web/src/sidepanel.ts b/apps/web/src/sidepanel.ts
index d2e2d9a45..c233b39fb 100644
--- a/apps/web/src/sidepanel.ts
+++ b/apps/web/src/sidepanel.ts
@@ -14,7 +14,7 @@ declare namespace chrome {
}
}
-const isInExtension = typeof chrome !== `undefined` && chrome.runtime && chrome.runtime.id
+export const isInExtension = typeof chrome !== `undefined` && chrome.runtime && chrome.runtime.id
async function getCurrentTab() {
const queryOptions = { active: true, lastFocusedWindow: true }
diff --git a/apps/web/src/utils/file.ts b/apps/web/src/utils/file.ts
index 97021ebc7..c7a99ead5 100644
--- a/apps/web/src/utils/file.ts
+++ b/apps/web/src/utils/file.ts
@@ -11,6 +11,7 @@ import CryptoJS from 'crypto-js'
import * as qiniu from 'qiniu-js'
import OSS from 'tiny-oss'
import { v4 as uuidv4 } from 'uuid'
+import { isInExtension } from '../sidepanel'
function getConfig(useDefault: boolean, platform: string) {
if (useDefault) {
@@ -321,7 +322,7 @@ export async function getMpToken(appID: string, appsecret: string, proxyOrigin:
let url = `https://api.weixin.qq.com/cgi-bin/stable_token`
// 兼容空字符串情况,本地代理时不需要传入域名
// 兼容浏览器插件环境 proxyOrigin 为空情况
- if (proxyOrigin !== null && proxyOrigin !== undefined && !(chrome.runtime)) {
+ if (proxyOrigin !== null && proxyOrigin !== undefined && !isInExtension) {
url = `${proxyOrigin}/cgi-bin/stable_token`
}
const res = await fetch(url, requestOptions)
@@ -337,6 +338,7 @@ export async function getMpToken(appID: string, appsecret: string, proxyOrigin:
}
// 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`)!,
@@ -364,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/wechat-publish.ts b/apps/web/src/utils/wechat-publish.ts
index f8862144c..28a5185ea 100644
--- a/apps/web/src/utils/wechat-publish.ts
+++ b/apps/web/src/utils/wechat-publish.ts
@@ -1,4 +1,5 @@
import { getMpToken } from '@/utils/file'
+import { isInExtension } from '../sidepanel'
const isCfPage = import.meta.env.CF_PAGES === `1`
const isDev = import.meta.env.DEV
@@ -46,7 +47,7 @@ export async function getMpCoverMediaId(file: File): Promise<{ url: string, medi
}
let url = `https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=${access_token}&type=image`
- if (proxyOrigin !== null && proxyOrigin !== undefined && !(chrome.runtime)) {
+ if (proxyOrigin !== null && proxyOrigin !== undefined && !isInExtension) {
url = url.replace(`https://api.weixin.qq.com`, proxyOrigin)
}
@@ -86,7 +87,7 @@ export async function addMpArticleDraft(params: MpArticleDraft) {
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 && !(chrome.runtime)) {
+ if (proxyOrigin !== null && proxyOrigin !== undefined && !isInExtension) {
url = url.replace(`https://api.weixin.qq.com`, proxyOrigin)
}