Skip to content

Commit 7e48301

Browse files
YangFongyanglbme
andauthored
feat: optimize the insertion of mp card (#985)
* feat: optimize the insertion of mp card * fix: config type * feat: update insert mp card dialog * fix: style --------- Co-authored-by: Libin YANG <[email protected]>
1 parent d3c645b commit 7e48301

File tree

8 files changed

+186
-48
lines changed

8 files changed

+186
-48
lines changed

apps/web/src/assets/example/markdown.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,6 @@ Foo -> Foo7: To queue
237237
[你好世界]{nǐ・hǎo・shì・jiè}
238238
[小夜時雨]^(さ・よ・しぐれ)
239239

240-
241240
当字符串数量与分隔符数量不匹配时,会自动匹配到最合适的分隔符。
242241

243242
```md
@@ -252,7 +251,6 @@ Foo -> Foo7: To queue
252251
[小夜]{さ・よ・しぐれ}
253252
[小夜時雨]{さ・よ・しぐれ・extra}
254253

255-
256254
## 结语
257255

258256
Markdown 是一种简单、强大且易于掌握的标记语言,通过学习基础和进阶语法,你可以快速创作内容并有效传达信息。无论是技术文档、个人博客还是项目说明,Markdown 都是你的得力助手。希望这篇内容能够带你全面了解 Markdown 的潜力,让你的写作更加丰富多彩!

apps/web/src/components/CodemirrorEditor/InsertMpCardDialog.vue

Lines changed: 67 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<script setup lang="ts">
22
import { toTypedSchema } from '@vee-validate/yup'
3-
import { Info } from 'lucide-vue-next'
43
import { Field, Form } from 'vee-validate'
54
import * as yup from 'yup'
65
import { addPrefix } from '@/utils'
@@ -15,6 +14,17 @@ interface Config {
1514
name: string
1615
logo: string
1716
desc: string
17+
/**
18+
* 1: 公众号
19+
* 2: 服务号
20+
*/
21+
serviceType: `1` | `2`
22+
/**
23+
* 0: 无标识
24+
* 1: 个人认证
25+
* 2: 企业认证
26+
*/
27+
verify: `0` | `1` | `2`
1828
}
1929
2030
/** 表单字段 */
@@ -23,42 +33,17 @@ const config = useStorage<Config>(addPrefix(`mp-profile`), {
2333
name: ``,
2434
logo: ``,
2535
desc: ``,
26-
})
27-
28-
/**
29-
* @deprecated 更换为对象形式,后续版本可移除该兼容写法
30-
*/
31-
const mpId = useStorage(`mpId`, ``)
32-
/**
33-
* @deprecated 更换为对象形式,后续版本可移除该兼容写法
34-
*/
35-
const mpName = useStorage(`mpName`, ``)
36-
/**
37-
* @deprecated 更换为对象形式,后续版本可移除该兼容写法
38-
*/
39-
const mpLogo = useStorage(`mpLogo`, ``)
40-
/**
41-
* @deprecated 更换为对象形式,后续版本可移除该兼容写法
42-
*/
43-
const mpDesc = useStorage(`mpDesc`, ``)
44-
45-
onMounted(() => {
46-
config.value.id = mpId.value || config.value.id
47-
config.value.name = mpName.value || config.value.name
48-
config.value.logo = mpLogo.value || config.value.logo
49-
config.value.desc = mpDesc.value || config.value.desc
50-
51-
mpId.value = ``
52-
mpName.value = ``
53-
mpLogo.value = ``
54-
mpDesc.value = ``
36+
serviceType: `1`,
37+
verify: `0`,
5538
})
5639
5740
const schema = toTypedSchema(yup.object({
5841
id: yup.string().required(`公众号 ID 不能为空`),
5942
name: yup.string().required(`公众号名称 不能为空`),
6043
logo: yup.string().optional().url(`公众号 Logo 必须是一个有效的 URL`),
6144
desc: yup.string().optional(),
45+
serviceType: yup.string().required(),
46+
verify: yup.string().required(),
6247
}))
6348
6449
/** 组装 HTML 片段 */
@@ -70,8 +55,8 @@ function buildMpHtml(config: Config) {
7055
`data-nickname="${config.name}"`,
7156
`data-headimg="${logo}"`,
7257
config.desc && `data-signature="${config.desc}"`,
73-
`data-service_type="1"`,
74-
`data-verify_status="1"`,
58+
`data-service_type="${config.serviceType || `1`}"`,
59+
`data-verify_status="${config.verify || `0`}"`,
7560
].filter(Boolean).join(` `)
7661
7762
return `<section class="mp_profile_iframe_wrp custom_select_card_wrp" nodeleaf="">
@@ -96,17 +81,9 @@ function submit(formValues: any) {
9681
<DialogTitle>插入公众号名片</DialogTitle>
9782
</DialogHeader>
9883

99-
<Alert>
100-
<Info class="h-4 w-4" />
101-
<AlertTitle>提示</AlertTitle>
102-
<AlertDescription>
103-
此功能用于插入微信公众号名片,数据会缓存至本地,可长期使用。
104-
</AlertDescription>
105-
</Alert>
106-
10784
<Form :validation-schema="schema" :initial-values="config" @submit="submit">
10885
<Field v-slot="{ field, errorMessage }" name="id">
109-
<FormItem label="公众号 ID" required :error="errorMessage">
86+
<FormItem label="公众号 ID" required :error="errorMessage" :width="90">
11087
<Input
11188
v-bind="field"
11289
v-model.trim="field.value"
@@ -116,7 +93,7 @@ function submit(formValues: any) {
11693
</Field>
11794

11895
<Field v-slot="{ field, errorMessage }" name="name">
119-
<FormItem label="公众号名称" required :error="errorMessage">
96+
<FormItem label="公众号名称" required :error="errorMessage" :width="90">
12097
<Input
12198
v-bind="field"
12299
v-model.trim="field.value"
@@ -126,7 +103,7 @@ function submit(formValues: any) {
126103
</Field>
127104

128105
<Field v-slot="{ field, errorMessage }" name="logo">
129-
<FormItem label="公众号 Logo" :error="errorMessage">
106+
<FormItem label="公众号 Logo" :error="errorMessage" :width="90">
130107
<Input
131108
v-bind="field"
132109
v-model.trim="field.value"
@@ -136,7 +113,7 @@ function submit(formValues: any) {
136113
</Field>
137114

138115
<Field v-slot="{ field, errorMessage }" name="desc">
139-
<FormItem label="公众号描述" :error="errorMessage">
116+
<FormItem label="公众号描述" :error="errorMessage" :width="90">
140117
<Textarea
141118
v-bind="field"
142119
v-model.trim="field.value"
@@ -146,6 +123,52 @@ function submit(formValues: any) {
146123
</FormItem>
147124
</Field>
148125

126+
<Field v-slot="{ field, errorMessage }" name="serviceType">
127+
<FormItem label="公众号类型" required :error="errorMessage" :width="90">
128+
<RadioGroup class="flex gap-5" v-bind="field" :default-value="field.value">
129+
<div class="inline-flex items-center space-x-2 w-20">
130+
<RadioGroupItem id="option-one" value="1" />
131+
<Label for="option-one">公众号</Label>
132+
</div>
133+
<div class="inline-flex items-center space-x-2 w-20">
134+
<RadioGroupItem id="option-two" value="2" />
135+
<Label for="option-two">服务号</Label>
136+
</div>
137+
</RadioGroup>
138+
</FormItem>
139+
</Field>
140+
141+
<Field v-slot="{ field, errorMessage }" name="verify">
142+
<FormItem label="认证" required :error="errorMessage" :width="90">
143+
<RadioGroup class="flex gap-5" v-bind="field" :default-value="field.value">
144+
<div class="inline-flex items-center space-x-2 w-20">
145+
<RadioGroupItem id="service-type-option-one" value="0" />
146+
<Label for="service-type-option-one">无</Label>
147+
</div>
148+
<div class="inline-flex items-center space-x-2 w-20">
149+
<RadioGroupItem id="service-type-option-two" value="1" />
150+
<Label for="service-type-option-two">个人</Label>
151+
</div>
152+
<div class="inline-flex items-center space-x-2 w-20">
153+
<RadioGroupItem id="service-type-option-three" value="2" />
154+
<Label for="service-type-option-three">企业</Label>
155+
</div>
156+
</RadioGroup>
157+
</FormItem>
158+
</Field>
159+
160+
<FormItem>
161+
<Button
162+
variant="link"
163+
class="p-0 h-auto text-left whitespace-normal"
164+
as="a"
165+
href="https://github.com/doocs/md/blob/main/docs/mp-card.md"
166+
target="_blank"
167+
>
168+
如何获取公众号 ID?
169+
</Button>
170+
</FormItem>
171+
149172
<FormItem>
150173
<Button type="submit">
151174
确认

apps/web/src/components/FormItem.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const props = defineProps<{
33
label?: string
44
required?: boolean
55
error?: string
6+
width?: number
67
}>()
78
</script>
89

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script setup lang="ts">
2+
import type { RadioGroupRootEmits, RadioGroupRootProps } from 'reka-ui'
3+
import type { HTMLAttributes } from 'vue'
4+
import { reactiveOmit } from '@vueuse/core'
5+
import { RadioGroupRoot, useForwardPropsEmits } from 'reka-ui'
6+
import { cn } from '@/lib/utils'
7+
8+
const props = defineProps<RadioGroupRootProps & { class?: HTMLAttributes[`class`] }>()
9+
const emits = defineEmits<RadioGroupRootEmits>()
10+
11+
const delegatedProps = reactiveOmit(props, `class`)
12+
13+
const forwarded = useForwardPropsEmits(delegatedProps, emits)
14+
</script>
15+
16+
<template>
17+
<RadioGroupRoot
18+
data-slot="radio-group"
19+
:class="cn('grid gap-3', props.class)"
20+
v-bind="forwarded"
21+
>
22+
<slot />
23+
</RadioGroupRoot>
24+
</template>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<script setup lang="ts">
2+
import type { RadioGroupItemProps } from 'reka-ui'
3+
import type { HTMLAttributes } from 'vue'
4+
import { reactiveOmit } from '@vueuse/core'
5+
import { CircleIcon } from 'lucide-vue-next'
6+
import {
7+
RadioGroupIndicator,
8+
RadioGroupItem,
9+
10+
useForwardProps,
11+
} from 'reka-ui'
12+
import { cn } from '@/lib/utils'
13+
14+
const props = defineProps<RadioGroupItemProps & { class?: HTMLAttributes[`class`] }>()
15+
16+
const delegatedProps = reactiveOmit(props, `class`)
17+
18+
const forwardedProps = useForwardProps(delegatedProps)
19+
</script>
20+
21+
<template>
22+
<RadioGroupItem
23+
data-slot="radio-group-item"
24+
v-bind="forwardedProps"
25+
:class="
26+
cn(
27+
'border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
28+
props.class,
29+
)
30+
"
31+
>
32+
<RadioGroupIndicator
33+
data-slot="radio-group-indicator"
34+
class="relative flex items-center justify-center"
35+
>
36+
<CircleIcon class="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
37+
</RadioGroupIndicator>
38+
</RadioGroupItem>
39+
</template>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default as RadioGroup } from './RadioGroup.vue'
2+
export { default as RadioGroupItem } from './RadioGroupItem.vue'

apps/web/src/utils/setup-components.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class MpCommonProfile extends HTMLElement {
88
const nickname = this.dataset.nickname || ``
99
const headimg = this.dataset.headimg || ``
1010
const signature = this.dataset.signature || ``
11+
const serviceType = this.dataset.service_type || `1`
1112
const verifyStatus = this.dataset.verify_status || `0`
1213

1314
this.shadowRoot!.innerHTML = `
@@ -33,7 +34,7 @@ class MpCommonProfile extends HTMLElement {
3334
<div class="weui-flex__item">
3435
<div class="wx_profile_nickname_wrp">
3536
<strong id="js_a11y_wx_profile_nickname" class="wx_profile_nickname">${nickname}</strong>
36-
<span class="wx_follow_verify ${verifyStatus === `1` ? `show-verify-personal` : ``}"></span>
37+
<span class="wx_follow_verify ${verifyStatus === `1` ? `show-verify-personal` : verifyStatus === `2` ? `show-verify-company` : ``}"></span>
3738
</div>
3839
<div id="js_a11y_wx_profile_desc" class="wx_profile_desc">${signature}</div>
3940
</div>
@@ -42,7 +43,7 @@ class MpCommonProfile extends HTMLElement {
4243
</div>
4344
</div>
4445
<div id="js_a11y_wx_profile_logo" aria-hidden="true" class="wx_profile_card_ft">
45-
公众号
46+
${serviceType === `1` ? `公众号` : `服务号`}
4647
</div>
4748
</div>
4849
<span aria-hidden="true" id="js_a11y_comma" class="weui-a11y_ref" style="display: none;">,</span>

docs/mp-card.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# 微信公众号 ID 获取说明
2+
3+
## 为什么需要公众号 ID
4+
5+
在开发或运营过程中,有时需要获取某个公众号的唯一标识(即 **fakeid**),比如用于文章抓取、接口调用或做账号绑定。
6+
7+
## 获取公众号 ID 的方法
8+
9+
### 1. 打开公众号后台
10+
11+
进入 [微信公众平台](https://mp.weixin.qq.com),用管理员账号登录。
12+
13+
### 2. 进入文章编辑器
14+
15+
点击【素材管理】→【新建图文素材】,进入文章编辑页面。
16+
17+
### 3. 添加公众号名片
18+
19+
在编辑器里点击【账号名片】,输入你要查询的公众号名称(如 **Doocs**),并插入到正文中。
20+
21+
### 4. 抓取网络请求
22+
23+
按下 `F12` 打开浏览器开发者工具,切换到 **Network(网络)** 标签。
24+
在插入名片时,后台会发起一个接口请求,通常类似:
25+
26+
```
27+
https://mp.weixin.qq.com/cgi-bin/searchbiz?action=search_biz&scene=1&begin=0...
28+
```
29+
30+
### 5. 查找 fakeid
31+
32+
点击该请求,切换到 **Response(响应)**,可以看到返回的 JSON 数据。
33+
其中会包含类似:
34+
35+
```json
36+
{
37+
"list": [
38+
{
39+
"fakeid": "MzIxNjA5ODQ0OQ==",
40+
"nickname": "Doocs",
41+
"alias": "idoocs",
42+
"service_type": 1,
43+
"signature": "GitHub 开源组织 @Doocs 旗下唯一公众号,专注分享技术领域相关知识及行业最新资讯。",
44+
"verify_status": 1
45+
}
46+
]
47+
}
48+
```
49+
50+
这里的 `fakeid` 就是该公众号的唯一标识。将获取到的公众号 ID(fakeid)保存下来,就可以在工具中使用啦。

0 commit comments

Comments
 (0)