1
0
mirror of https://gitee.com/Doocs/md synced 2025-04-29 09:32:27 +08:00

feat: add new functions for mp image upload (#637)

This commit is contained in:
Honwhy Wang 2025-04-19 21:52:34 +08:00 committed by GitHub
parent e4b989b8a7
commit 365816970b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 1439 additions and 11 deletions

3
.gitignore vendored
View File

@ -55,4 +55,5 @@ components.d.ts
.wxt
.output
web-ext.config.ts
web-ext.config.ts
.wrangler

View File

@ -17,6 +17,7 @@ export default defineConfig({
define: {
process,
},
envPrefix: [`VITE_`, `CF_`], // 允许 VITE_ 和 CF_ 前缀的变量
plugins: [
vue(),
UnoCSS(),

View File

@ -0,0 +1,16 @@
import { parseFormDataRequest } from '../../../parseFormDataRequest'
import { jsonResponse, MP_HOST } from '../../../utils'
export const onRequestPost: PagesFunction = async (context) => {
const formData = (await parseFormDataRequest(context.request)) as FormData
const url = new URL(context.request.url)
const response = await fetch(
`${MP_HOST}${context.functionPath}${url.search}`,
{
method: `POST`,
body: formData,
},
)
const json = await response.json()
return jsonResponse(json)
}

View File

@ -0,0 +1,5 @@
import { onRequestPost as post } from '../../material/add_material/index'
export const onRequestPost: PagesFunction = async (context) => {
return post(context)
}

View File

@ -0,0 +1,13 @@
import { jsonResponse, MP_HOST } from '../utils'
export const onRequestPost: PagesFunction = async (context) => {
const response = await fetch(
`${MP_HOST}${context.functionPath}`,
{
method: `POST`,
body: context.request.body,
},
)
const json = await response.json()
return jsonResponse(json)
}

View File

@ -0,0 +1,40 @@
// eslint-disable-next-line ts/ban-ts-comment
// @ts-nocheck
// @see https://github.com/cloudflare/images.pages.dev/blob/main/functions/utils/parseFormDataRequest.ts
import { parseMultipart } from '@ssttevee/multipart-parser'
const RE_MULTIPART
= /^multipart\/form-data;\s*boundary=(?:"((?:[^"]|\\")+)"|([^\s;]+))$/
function getBoundary(request: Request): string | undefined {
const contentType = request.headers.get(`Content-Type`)
if (!contentType)
return
const matches = RE_MULTIPART.exec(contentType)
if (!matches)
return
return matches[1] || matches[2]
}
export async function parseFormDataRequest(request: Request): Promise<FormData | undefined> {
const boundary = getBoundary(request)
if (!boundary || !request.body)
return
const parts = await parseMultipart(request.body, boundary)
const formData = new FormData()
for (const { name, data, filename, contentType } of parts) {
formData.append(
name,
filename
? new File([data], filename, { type: contentType })
: new TextDecoder().decode(data),
)
}
return formData
}

8
functions/tsconfig.json Normal file
View File

@ -0,0 +1,8 @@
{
"compilerOptions": {
"target": "esnext",
"lib": ["esnext"],
"module": "esnext",
"types": ["@cloudflare/workers-types"]
}
}

8
functions/utils.ts Normal file
View File

@ -0,0 +1,8 @@
export const MP_HOST = `https://api.weixin.qq.com`
export function jsonResponse(value: any, init: ResponseInit = {}) {
return new Response(JSON.stringify(value), {
headers: { 'Content-Type': `application/json`, ...init.headers },
...init,
})
}

1309
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,7 @@
"build:cli": "npm run build && npx shx rm -rf md-cli/dist && npx shx rm -rf dist/**/*.map && npx shx cp -r dist md-cli/ && cd md-cli && npm pack",
"build:analyze": "cross-env ANALYZE=true vite build",
"preview": "npm run build && vite preview",
"preview:pages": "npm run build:h5-netlify && wrangler pages dev ./dist",
"release:cli": "node ./scripts/release.js",
"ext:dev": "wxt",
"ext:zip": "wxt zip",
@ -25,6 +26,7 @@
"dependencies": {
"@aws-sdk/client-s3": "^3.777.0",
"@aws-sdk/s3-request-presigner": "^3.777.0",
"@ssttevee/multipart-parser": "^0.1.9",
"@vee-validate/yup": "^4.15.0",
"@vueuse/core": "^12.5.0",
"axios": "^1.8.4",
@ -62,6 +64,7 @@
},
"devDependencies": {
"@antfu/eslint-config": "3.11.0",
"@cloudflare/workers-types": "^4.20250419.0",
"@types/buffer-from": "^1.1.3",
"@types/codemirror": "^5.60.15",
"@types/crypto-js": "^4.2.2",
@ -90,6 +93,7 @@
"vite-plugin-radar": "^0.10.0",
"vite-plugin-vue-devtools": "^7.7.2",
"vue-tsc": "^2.2.0",
"wrangler": "^4.12.0",
"wxt": "^0.19.29"
},
"simple-git-hooks": {

View File

@ -138,13 +138,35 @@ function minioOSSSubmit(formValues: any) {
}
//
const isWebsite = ref(window.location.href.startsWith(`http`))
// http/https
const isWebsite = window.location.protocol.startsWith(`http`)
const mpSchema = toTypedSchema(yup.object({
proxyOrigin: isWebsite.value ? yup.string().required(`代理域名不能为空`) : yup.string().optional(),
appID: yup.string().required(`AppID 不能为空`),
appsecret: yup.string().required(`AppSecret 不能为空`),
}))
// Cloudflare Pages
const isCfPage = import.meta.env.CF_PAGES === `1`
// chrome-extension://
const isPluginMode = !isWebsite
// proxyOrigin CF
const isProxyRequired = computed(() => {
return !isPluginMode && !isCfPage
})
const mpPlaceholder = computed(() => {
if (isProxyRequired.value) {
return `http://proxy.example.com`
}
return `可不填`
})
const mpSchema = computed(() =>
toTypedSchema(yup.object({
proxyOrigin: isProxyRequired.value
? yup.string().required(`代理域名不能为空`)
: yup.string().optional(),
appID: yup.string().required(`AppID 不能为空`),
appsecret: yup.string().required(`AppSecret 不能为空`),
})),
)
const mpConfig = ref(localStorage.getItem(`mpConfig`)
? JSON.parse(localStorage.getItem(`mpConfig`)!)
@ -738,7 +760,7 @@ function onDrop(e: DragEvent) {
<Input
v-bind="field"
v-model="field.value"
placeholder="如http://proxy.example.com使用插件时可不填"
:placeholder="mpPlaceholder"
/>
</FormItem>
</Field>
@ -778,7 +800,7 @@ function onDrop(e: DragEvent) {
variant="link"
class="p-0"
as="a"
href="https://mpmd.pages.dev/tutorial/"
href="https://mp.honwhy.wang/tutorial/"
target="_blank"
>
如何在浏览器插件中使用公众号图床

View File

@ -10,7 +10,7 @@ export default defineBackground({
return
}
if (detail.reason === `install`) {
browser.tabs.create({ url: `https://mpmd.pages.dev/welcome` })
browser.tabs.create({ url: `https://mp.honwhy.wang/welcome` })
}
else if (detail.reason === `update`) {
browser.runtime.openOptionsPage()

View File

@ -33,7 +33,7 @@ function onOpenOption() {
>查看文档</a></span>
</div>
<div>
2.配置IP白名单<span><a href="https://mpmd.pages.dev/tutorial" target="_blank">使用教程</a></span>
2.配置IP白名单<span><a href="https://mp.honwhy.wang/tutorial" target="_blank">使用教程</a></span>
</div>
<div>
<button class="button" @click="onOpenOption">

View File

@ -17,6 +17,7 @@ export default defineConfig({
define: {
process,
},
envPrefix: [`VITE_`, `CF_`], // 允许 VITE_ 和 CF_ 前缀的变量
plugins: [
vue(),
UnoCSS(),