refactor: update match configuration and user matching logic

- Changed the daily free match limit to a lifetime limit, aligning with backend configurations.
- Updated the match price display to include original pricing for better user clarity.
- Refactored match quota handling to sync with the server, ensuring accurate match counts and purchase statuses.
- Enhanced UI messages to reflect changes in match availability and pricing.
- Removed deprecated logic related to daily match counts, streamlining the matching process.
This commit is contained in:
Alex-larget
2026-04-01 17:09:45 +08:00
parent bdd0795434
commit 360bba697b
26 changed files with 374 additions and 781 deletions

View File

@@ -37,7 +37,7 @@ export interface LinkTagItem {
label: string
aliases?: string
url: string
type: 'url' | 'miniprogram' | 'ckb' | 'wxlink'
type: 'url' | 'miniprogram' | 'ckb' | 'wxlink' | 'internal'
appId?: string
pagePath?: string
/** 管理端列表用:库内是否已存目标小程序 AppSecret接口不下发明文 */

View File

@@ -308,7 +308,7 @@ export function ContentPage() {
label: '',
aliases: '',
url: '',
type: 'url' as 'url' | 'miniprogram' | 'ckb' | 'wxlink',
type: 'url' as 'url' | 'miniprogram' | 'ckb' | 'wxlink' | 'internal',
appId: '',
appSecret: '',
pagePath: '',
@@ -663,7 +663,7 @@ export function ContentPage() {
id: t.tagId,
label: t.label,
url: t.url,
type: (t.type || 'url') as 'url' | 'miniprogram' | 'ckb' | 'wxlink',
type: (t.type || 'url') as 'url' | 'miniprogram' | 'ckb' | 'wxlink' | 'internal',
appId: t.appId || '',
pagePath: t.pagePath || '',
hasAppSecret: !!t.hasAppSecret,
@@ -750,7 +750,7 @@ export function ContentPage() {
label: t.label,
aliases: t.aliases || '',
url: t.url,
type: (t.type || 'url') as 'url' | 'miniprogram' | 'ckb' | 'wxlink',
type: (t.type || 'url') as 'url' | 'miniprogram' | 'ckb' | 'wxlink' | 'internal',
appId: t.appId || '',
pagePath: t.pagePath || '',
hasAppSecret: !!t.hasAppSecret,
@@ -3063,9 +3063,9 @@ export function ContentPage() {
<CardHeader className="pb-3">
<CardTitle className="text-white text-base flex items-center gap-2">
<Hash className="w-4 h-4 text-amber-400" />
# //
# ///
</CardTitle>
<p className="text-xs text-gray-500 mt-1"> # </p>
<p className="text-xs text-gray-500 mt-1"> # </p>
</CardHeader>
<CardContent className="space-y-3">
<div className="flex items-end justify-between gap-3 flex-wrap">
@@ -3174,16 +3174,30 @@ export function ContentPage() {
className={`text-[10px] ${
t.type === 'ckb'
? 'bg-green-500/20 text-green-300 border-green-500/30'
: t.type === 'miniprogram' || t.type === 'wxlink'
? 'bg-[#38bdac]/20 text-[#38bdac] border-[#38bdac]/30'
: 'bg-gray-700 text-gray-300'
: t.type === 'internal'
? 'bg-sky-500/20 text-sky-200 border-sky-500/30'
: t.type === 'miniprogram' || t.type === 'wxlink'
? 'bg-[#38bdac]/20 text-[#38bdac] border-[#38bdac]/30'
: 'bg-gray-700 text-gray-300'
}`}
>
{t.type === 'url' ? '网页' : t.type === 'ckb' ? '存客宝' : t.type === 'wxlink' ? '小程序链接' : '小程序'}
{t.type === 'url'
? '网页'
: t.type === 'internal'
? '本小程序'
: t.type === 'ckb'
? '存客宝'
: t.type === 'wxlink'
? '小程序链接'
: '小程序'}
</Badge>
</td>
<td className="px-3 py-2 text-gray-300">
{t.type === 'miniprogram' ? (
{t.type === 'internal' ? (
<div className="text-xs font-mono text-sky-300 truncate max-w-[420px]" title={t.pagePath || ''}>
{t.pagePath || '—'}
</div>
) : t.type === 'miniprogram' ? (
<div className="space-y-0.5">
{(() => {
const mp = linkedMps.find(m => m.key === t.appId)
@@ -3301,7 +3315,7 @@ export function ContentPage() {
<DialogHeader className="gap-1">
<DialogTitle className="text-base">{linkTagEditing ? '编辑链接标签' : '添加链接标签'}</DialogTitle>
<DialogDescription className="text-gray-400 text-xs">
# mpKey AppIDAppSecret 使
# API mpKey AppIDAppSecret 使
</DialogDescription>
</DialogHeader>
@@ -3343,7 +3357,7 @@ export function ContentPage() {
<Select
value={linkTagForm.type}
onValueChange={(v) =>
setLinkTagForm((p) => ({ ...p, type: v as 'url' | 'miniprogram' | 'ckb' | 'wxlink' }))
setLinkTagForm((p) => ({ ...p, type: v as 'url' | 'miniprogram' | 'ckb' | 'wxlink' | 'internal' }))
}
>
<SelectTrigger className="bg-[#0a1628] border-gray-700 text-white h-8">
@@ -3351,6 +3365,7 @@ export function ContentPage() {
</SelectTrigger>
<SelectContent className="bg-[#0f2137] border-gray-700 text-white">
<SelectItem value="url"></SelectItem>
<SelectItem value="internal"></SelectItem>
<SelectItem value="miniprogram">API跳转</SelectItem>
<SelectItem value="wxlink"></SelectItem>
<SelectItem value="ckb"></SelectItem>
@@ -3365,9 +3380,18 @@ export function ContentPage() {
? '存客宝计划URL'
: linkTagForm.type === 'wxlink'
? '小程序链接'
: '小程序 mpKey / 微信 AppID'}
: linkTagForm.type === 'internal'
? '页面路径'
: '小程序 mpKey / 微信 AppID'}
</Label>
{linkTagForm.type === 'wxlink' ? (
{linkTagForm.type === 'internal' ? (
<Input
className="bg-[#0a1628] border-gray-700 text-white h-8 text-sm font-mono"
placeholder="/pages/index/index 或带参数 ?id=1"
value={linkTagForm.pagePath}
onChange={(e) => setLinkTagForm((p) => ({ ...p, pagePath: e.target.value }))}
/>
) : linkTagForm.type === 'wxlink' ? (
<Input
className="bg-[#0a1628] border-gray-700 text-white h-8 text-sm"
placeholder="粘贴小程序右上角 ... → 复制链接 得到的 URL"
@@ -3506,6 +3530,22 @@ export function ContentPage() {
return
}
if (payload.type === 'miniprogram') payload.url = ''
if (payload.type === 'internal') {
payload.url = ''
payload.appId = ''
payload.appSecret = ''
let p = payload.pagePath.trim()
if (!p) {
toast.error('请填写本小程序页面路径')
return
}
if (!p.startsWith('/')) p = '/' + p.replace(/^\/+/, '')
if (!/^\/pages\//.test(p)) {
toast.error('路径需以 /pages/ 开头')
return
}
payload.pagePath = p
}
if (payload.type === 'wxlink') { payload.appId = ''; payload.pagePath = '' }
setLinkTagSaving(true)
try {