@tbox.cn/app-module-member 0.2.0 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +16 -0
- package/README.md +99 -11
- package/dist/chunk-EPQEF43P.js +1581 -0
- package/dist/chunk-QWGRWD5C.js +766 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.js +12 -2
- package/dist/member-372B74DY.css +1740 -0
- package/dist/server/index.d.ts +657 -286
- package/dist/server/index.js +11 -1
- package/package.json +25 -16
- package/skills/member/SKILL.md +141 -0
- package/skills/member/references/enrollment.md +34 -0
- package/skills/member/references/points-and-card.md +24 -0
- package/src/client/cards/index.ts +10 -0
- package/src/client/cards/member-card-summary/index.tsx +375 -0
- package/src/client/cards/member-enrollment-cta/index.tsx +61 -0
- package/src/client/cards/member-enrollment-form/index.tsx +181 -0
- package/src/client/cards/member-enrollment-status/index.tsx +65 -0
- package/src/client/cards/member-info/index.tsx +60 -0
- package/src/client/cards/member-login-cta/index.tsx +81 -0
- package/src/client/cards/member-point-usage-list/index.tsx +53 -0
- package/src/client/cards/view.ts +39 -0
- package/src/client/components/ImageWithFallback.tsx +38 -0
- package/src/client/index.ts +6 -4
- package/src/client/styles/member.css +1740 -0
- package/src/client/types/css.d.ts +2 -0
- package/src/server/action.ts +348 -0
- package/src/server/cards/index.ts +7 -7
- package/src/server/cards/member-card-summary/meta.ts +26 -5
- package/src/server/cards/member-card-summary/samples.ts +272 -0
- package/src/server/cards/member-enrollment-cta/meta.ts +19 -0
- package/src/server/cards/member-enrollment-form/meta.ts +10 -6
- package/src/server/cards/member-enrollment-status/meta.ts +5 -6
- package/src/server/cards/member-info/meta.ts +1 -1
- package/src/server/cards/member-login-cta/meta.ts +16 -0
- package/src/server/cards/member-point-usage-list/meta.ts +2 -3
- package/src/server/handler.ts +159 -119
- package/src/server/index.ts +129 -50
- package/src/server/ports.ts +66 -0
- package/src/server/service.ts +94 -80
- package/src/server/status.ts +87 -0
- package/src/server/subject-binding.ts +19 -0
- package/src/server/tool.ts +469 -99
- package/tbox.module.json +124 -0
- package/tests/cards-render.test.tsx +526 -0
- package/tests/enrollment.test.ts +121 -0
- package/tests/ports-resolve.test.ts +95 -0
- package/tests/preference-memory.test.ts +86 -0
- package/tests/samples.test.ts +61 -0
- package/tests/service.test.ts +593 -35
- package/tests/skills.test.ts +65 -0
- package/tests/snapshot-service.test.ts +75 -0
- package/tests/status.test.ts +127 -0
- package/tests/view.test.ts +33 -0
- package/tsup.config.ts +9 -1
- package/dist/chunk-JGZGLFO6.js +0 -111
- package/dist/chunk-ZV6B36AO.js +0 -613
- package/src/client/cards/index.tsx +0 -135
- package/src/server/cards/member-coupon-detail/meta.ts +0 -19
- package/src/server/cards/member-coupon-list/meta.ts +0 -18
- package/tbox.component.json +0 -28
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* member-enrollment-status 富卡(0.4.0 D6/D10):四态变体 + pending 刷新。
|
|
3
|
+
*/
|
|
4
|
+
import { useRef, useState } from 'react';
|
|
5
|
+
import { ArrowClockwise, CheckCircle, Clock, WarningCircle } from '@phosphor-icons/react';
|
|
6
|
+
import { sendCardAction, markSelfRendering } from '@tbox.cn/app-sdk/client';
|
|
7
|
+
import { enrollmentStateText, enrollmentTone } from '../view';
|
|
8
|
+
import type { MemberEnrollmentStatusCardData } from '@tbox.cn/app-contracts-mall';
|
|
9
|
+
|
|
10
|
+
const ICONS = { success: CheckCircle, warning: Clock, neutral: WarningCircle } as const;
|
|
11
|
+
|
|
12
|
+
export function MemberEnrollmentStatusCard(props: {
|
|
13
|
+
data: MemberEnrollmentStatusCardData;
|
|
14
|
+
cardId: string;
|
|
15
|
+
isHistory: boolean;
|
|
16
|
+
actionTokens?: Record<string, string>;
|
|
17
|
+
}) {
|
|
18
|
+
const { data, cardId, isHistory, actionTokens } = props;
|
|
19
|
+
const tone = enrollmentTone(data.state);
|
|
20
|
+
const Icon = ICONS[tone];
|
|
21
|
+
const refreshToken = actionTokens?.['member.query-enrollment-status'];
|
|
22
|
+
const [refreshing, setRefreshing] = useState(false);
|
|
23
|
+
const refreshingRef = useRef(false);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<section className={`member-card member-es member-es--${data.state}`}>
|
|
27
|
+
<span className="member-es__eyebrow">入会申请</span>
|
|
28
|
+
<div className={`member-es__icon member-es__icon--${tone}`}>
|
|
29
|
+
<Icon size={30} weight="duotone" />
|
|
30
|
+
</div>
|
|
31
|
+
<h4>{enrollmentStateText(data.state)}</h4>
|
|
32
|
+
{data.message && <p className="member-es__message">{data.message}</p>}
|
|
33
|
+
{data.state === 'active' && <p className="member-es__support">会员状态已更新,可继续查询会员卡或积分</p>}
|
|
34
|
+
{(data.state === 'failed' || data.state === 'confirmation_timeout') && (
|
|
35
|
+
<p className="member-es__support">本次未确认成功,请根据提示重新发起或稍后再试</p>
|
|
36
|
+
)}
|
|
37
|
+
{data.state === 'pending_confirmation' && data.attemptRef && (
|
|
38
|
+
<button
|
|
39
|
+
type="button"
|
|
40
|
+
className="member-es__refresh"
|
|
41
|
+
disabled={isHistory || !refreshToken || refreshing}
|
|
42
|
+
onClick={() => {
|
|
43
|
+
if (!refreshToken || isHistory || refreshingRef.current) return;
|
|
44
|
+
refreshingRef.current = true;
|
|
45
|
+
setRefreshing(true);
|
|
46
|
+
sendCardAction(
|
|
47
|
+
cardId,
|
|
48
|
+
{ type: 'moduleAction', actionId: 'member.query-enrollment-status', contextToken: refreshToken },
|
|
49
|
+
{ attemptRef: data.attemptRef },
|
|
50
|
+
);
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<ArrowClockwise size={16} weight="bold" />
|
|
54
|
+
{refreshing ? '正在刷新…' : '刷新状态'}
|
|
55
|
+
</button>
|
|
56
|
+
)}
|
|
57
|
+
{isHistory && data.state === 'pending_confirmation' && (
|
|
58
|
+
<p className="member-es__support">历史申请不可刷新,请重新查询当前会员状态</p>
|
|
59
|
+
)}
|
|
60
|
+
</section>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 0.4.0 D10 评审补位:卡内"刷新状态"按钮(attemptRef 依赖卡数据)自持动作,跳过 SDK 默认按钮条
|
|
65
|
+
export default markSelfRendering(MemberEnrollmentStatusCard);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** member-info:账户状态与基础资料,不暴露厂商内部会员标识。 */
|
|
2
|
+
import { CalendarBlank, Phone, Tag, UserCircle } from '@phosphor-icons/react';
|
|
3
|
+
import { ImageWithFallback } from '../../components/ImageWithFallback';
|
|
4
|
+
import { formatMemberDate, memberStateText } from '../view';
|
|
5
|
+
import type { MemberInfoCardData } from '@tbox.cn/app-contracts-mall';
|
|
6
|
+
|
|
7
|
+
export function MemberInfoCard(props: { data: MemberInfoCardData }) {
|
|
8
|
+
const { data } = props;
|
|
9
|
+
return (
|
|
10
|
+
<section className="member-card member-info">
|
|
11
|
+
<div className="member-info__head">
|
|
12
|
+
{data.avatarUrl ? (
|
|
13
|
+
<ImageWithFallback src={data.avatarUrl} alt={data.displayName ?? '会员头像'} className="member-info__avatar" size={48} />
|
|
14
|
+
) : (
|
|
15
|
+
<div className="member-info__avatar member-info__avatar--fallback" aria-hidden="true">
|
|
16
|
+
<UserCircle size={34} weight="duotone" />
|
|
17
|
+
</div>
|
|
18
|
+
)}
|
|
19
|
+
<div className="member-info__body">
|
|
20
|
+
<span className="member-info__eyebrow">会员资料</span>
|
|
21
|
+
<div className="member-info__name-row">
|
|
22
|
+
<strong>{data.displayName ?? '会员'}</strong>
|
|
23
|
+
<span className={`member-status member-status--${data.state === 'active' ? 'active' : 'inactive'}`}>
|
|
24
|
+
{memberStateText(data.state, data.authState)}
|
|
25
|
+
</span>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
{(data.contactDisplay || data.registeredAt) && (
|
|
31
|
+
<dl className="member-info__details">
|
|
32
|
+
{data.contactDisplay && (
|
|
33
|
+
<div>
|
|
34
|
+
<dt><Phone size={16} weight="duotone" />联系方式</dt>
|
|
35
|
+
<dd>{data.contactDisplay}</dd>
|
|
36
|
+
</div>
|
|
37
|
+
)}
|
|
38
|
+
{data.registeredAt && (
|
|
39
|
+
<div>
|
|
40
|
+
<dt><CalendarBlank size={16} weight="duotone" />入会时间</dt>
|
|
41
|
+
<dd>{formatMemberDate(data.registeredAt)}</dd>
|
|
42
|
+
</div>
|
|
43
|
+
)}
|
|
44
|
+
</dl>
|
|
45
|
+
)}
|
|
46
|
+
{data.labels.length > 0 && (
|
|
47
|
+
<div className="member-info__labels">
|
|
48
|
+
<div className="member-info__section-title"><Tag size={16} weight="duotone" />会员标签</div>
|
|
49
|
+
<div className="member-tags">
|
|
50
|
+
{data.labels.map((l) => (
|
|
51
|
+
<span key={l.labelRef}>{l.name}</span>
|
|
52
|
+
))}
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
)}
|
|
56
|
+
</section>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default MemberInfoCard;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* member-login-cta:未登录引导卡。
|
|
3
|
+
*
|
|
4
|
+
* 舞台形态:上半是商圈吉祥物站台(顶部水彩天光 + 米色纸底 + 地面光斑),撕纸边分隔,
|
|
5
|
+
* 下半留给标题与登录按钮。视觉语言取自首页活动卡——同一个角色、同一套纸质涂鸦。
|
|
6
|
+
*
|
|
7
|
+
* 只做一件事——把用户送去商场小程序的登录页。**不承诺登录之后有什么**:
|
|
8
|
+
* 会员权益要等登录后由厂商返回才知道,此刻列出来就是编造。
|
|
9
|
+
*/
|
|
10
|
+
import { useRef, useState } from 'react';
|
|
11
|
+
import { ArrowSquareOut, WarningCircle } from '@phosphor-icons/react';
|
|
12
|
+
import { sendCardAction } from '@tbox.cn/app-sdk/client';
|
|
13
|
+
import type { MemberLoginCtaCardData } from '@tbox.cn/app-contracts-mall';
|
|
14
|
+
|
|
15
|
+
export function MemberLoginCtaCard(props: {
|
|
16
|
+
data: MemberLoginCtaCardData;
|
|
17
|
+
cardId: string;
|
|
18
|
+
isHistory: boolean;
|
|
19
|
+
}) {
|
|
20
|
+
const { data, cardId, isHistory } = props;
|
|
21
|
+
const [opening, setOpening] = useState(false);
|
|
22
|
+
const openingRef = useRef(false);
|
|
23
|
+
|
|
24
|
+
function handleLogin() {
|
|
25
|
+
// 深链为可选透传素材(schema optional);无 URL 时不发 openLink(壳能力/门禁接管)
|
|
26
|
+
if (isHistory || openingRef.current || !data.loginUrl) return;
|
|
27
|
+
openingRef.current = true;
|
|
28
|
+
setOpening(true);
|
|
29
|
+
sendCardAction(cardId, { type: 'openLink', url: data.loginUrl });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<section className="member-card member-login-cta">
|
|
34
|
+
<div className="member-login-cta__stage">
|
|
35
|
+
{/* 天光只铺顶部:吉祥物图自带米色底,渐变穿过它会露出矩形边界 */}
|
|
36
|
+
<span className="member-login-cta__sky" aria-hidden="true" />
|
|
37
|
+
<svg className="member-login-cta__doodle" viewBox="0 0 390 170" aria-hidden="true">
|
|
38
|
+
<path d="M50 40 l5,11 12,2 -9,9 3,12 -11,-6 -11,6 3,-12 -9,-9 12,-2 Z" />
|
|
39
|
+
<path d="M318 56 c10,-12 23,-11 29,-1 c6,10 -3,20 -12,17" />
|
|
40
|
+
<path d="M40 122 c12,-8 20,2 11,9" />
|
|
41
|
+
</svg>
|
|
42
|
+
{/* 地面光斑:把角色钉在台面上,否则它像浮在纸上 */}
|
|
43
|
+
<span className="member-login-cta__ground" aria-hidden="true" />
|
|
44
|
+
{/* 素材变量链(主题轨 T-2.3):装饰主视觉走 CSS background,主题包经 --tbox-asset-member-mascot 覆写 */}
|
|
45
|
+
<span className="member-login-cta__mascot" aria-hidden="true" />
|
|
46
|
+
<span className="member-login-cta__grain" aria-hidden="true" />
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
{/* 撕纸边:与活动卡同一种分隔手法 */}
|
|
50
|
+
<svg className="member-login-cta__tear" viewBox="0 0 390 16" preserveAspectRatio="none" aria-hidden="true">
|
|
51
|
+
<path d="M0,16 L390,16 L390,6 L358,10 L330,4 L298,11 L266,5 L236,12 L204,6 L174,12 L144,6 L112,13 L82,7 L52,14 L24,8 L0,12 Z" />
|
|
52
|
+
</svg>
|
|
53
|
+
|
|
54
|
+
<div className="member-login-cta__body">
|
|
55
|
+
<h4>{data.title ?? '登录后继续'}</h4>
|
|
56
|
+
{/* 说明文案统一:各触发场景的理由大同小异,按场景注入只会变成没人写的字段 */}
|
|
57
|
+
<p className="member-login-cta__reason">登录后可解锁全部功能</p>
|
|
58
|
+
|
|
59
|
+
<button
|
|
60
|
+
type="button"
|
|
61
|
+
className="member-login-cta__btn"
|
|
62
|
+
disabled={isHistory || opening || !data.loginUrl}
|
|
63
|
+
onClick={handleLogin}
|
|
64
|
+
aria-label={data.loginUrl ? '前往登录' : '登录暂不可用(请联系商场客服)'}
|
|
65
|
+
>
|
|
66
|
+
{opening ? '正在打开商场小程序…' : data.loginUrl ? '立即登录' : '暂不可用(请联系商场客服)'}
|
|
67
|
+
{/* 有 URL 才暗示可跳转;无 URL(壳能力接管/未配置深链)用警示图标传达“不可点” */}
|
|
68
|
+
{data.loginUrl ? (
|
|
69
|
+
<ArrowSquareOut size={18} weight="bold" aria-hidden="true" />
|
|
70
|
+
) : (
|
|
71
|
+
<WarningCircle size={18} weight="fill" aria-hidden="true" />
|
|
72
|
+
)}
|
|
73
|
+
</button>
|
|
74
|
+
<p className="member-login-cta__hint">登录在商场小程序内完成,完成后回到这里继续</p>
|
|
75
|
+
{isHistory && <p className="member-login-cta__history">历史卡片不可重复操作</p>}
|
|
76
|
+
</div>
|
|
77
|
+
</section>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default MemberLoginCtaCard;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** member-point-usage-list:积分账户余额与真实流水。 */
|
|
2
|
+
import { ArrowDownRight, ArrowUpRight, Coins } from '@phosphor-icons/react';
|
|
3
|
+
import { formatMemberDate, pointAmountClass } from '../view';
|
|
4
|
+
import type { MemberPointUsageListCardData } from '@tbox.cn/app-contracts-mall';
|
|
5
|
+
|
|
6
|
+
export function MemberPointUsageListCard(props: { data: MemberPointUsageListCardData }) {
|
|
7
|
+
const { data } = props;
|
|
8
|
+
return (
|
|
9
|
+
<section className="member-card member-point-usage">
|
|
10
|
+
<header className="member-pu__head">
|
|
11
|
+
<div className="member-pu__head-icon"><Coins size={22} weight="duotone" /></div>
|
|
12
|
+
<div>
|
|
13
|
+
<span>积分账户</span>
|
|
14
|
+
<strong>我的积分</strong>
|
|
15
|
+
</div>
|
|
16
|
+
{data.membershipLabel && <em>{data.membershipLabel}</em>}
|
|
17
|
+
</header>
|
|
18
|
+
<div className="member-pu__metric">
|
|
19
|
+
<b>{String(data.balance)}</b>
|
|
20
|
+
<span>积分</span>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div className="member-pu__section-title">
|
|
24
|
+
<strong>最近积分记录</strong>
|
|
25
|
+
<span>共 {data.total ?? data.items.length} 条</span>
|
|
26
|
+
</div>
|
|
27
|
+
{data.items.length > 0 ? (
|
|
28
|
+
<ul className="member-pu__list">
|
|
29
|
+
{data.items.map((u) => {
|
|
30
|
+
const isSpend = u.amount.startsWith('-');
|
|
31
|
+
const Icon = isSpend ? ArrowUpRight : ArrowDownRight;
|
|
32
|
+
return (
|
|
33
|
+
<li key={u.usageRecordRef} className="member-pu__row">
|
|
34
|
+
<span className={`member-pu__flow-icon member-pu__flow-icon--${isSpend ? 'spend' : 'income'}`}>
|
|
35
|
+
<Icon size={16} weight="bold" />
|
|
36
|
+
</span>
|
|
37
|
+
<span className="member-pu__copy">
|
|
38
|
+
<strong>{u.title}</strong>
|
|
39
|
+
{u.usedAt && <small>{formatMemberDate(u.usedAt)}</small>}
|
|
40
|
+
</span>
|
|
41
|
+
<b className={pointAmountClass(u.amount)}>{u.amount}</b>
|
|
42
|
+
</li>
|
|
43
|
+
);
|
|
44
|
+
})}
|
|
45
|
+
</ul>
|
|
46
|
+
) : (
|
|
47
|
+
<p className="member-pu__empty">暂无积分记录</p>
|
|
48
|
+
)}
|
|
49
|
+
</section>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default MemberPointUsageListCard;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* member 展示纯函数(0.4.0 D6:状态文案/金额色/图标映射,可单测;券面函数 0.4.0 净删——promotion 承接)。
|
|
3
|
+
*/
|
|
4
|
+
/** 积分流水金额类:负支出 → 红(--tbox-primary),正收入 → 绿(--tbox-success) */
|
|
5
|
+
export function pointAmountClass(amount: string): 'member-pu__amount--spend' | 'member-pu__amount--income' {
|
|
6
|
+
return amount.startsWith('-') ? 'member-pu__amount--spend' : 'member-pu__amount--income';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function formatMemberDate(value?: string): string {
|
|
10
|
+
if (!value) return '';
|
|
11
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})/u.exec(value);
|
|
12
|
+
return match ? `${match[1]}.${match[2]}.${match[3]}` : value;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function enrollmentStateText(state: string): string {
|
|
16
|
+
switch (state) {
|
|
17
|
+
case 'active':
|
|
18
|
+
return '入会成功';
|
|
19
|
+
case 'pending_confirmation':
|
|
20
|
+
return '厂商确认中';
|
|
21
|
+
case 'confirmation_timeout':
|
|
22
|
+
return '确认超时';
|
|
23
|
+
default:
|
|
24
|
+
return '未完成';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function enrollmentTone(state: string): 'success' | 'warning' | 'neutral' {
|
|
29
|
+
if (state === 'active') return 'success';
|
|
30
|
+
if (state === 'pending_confirmation') return 'warning';
|
|
31
|
+
return 'neutral';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function memberStateText(state: string, authState?: string): string {
|
|
35
|
+
if (state === 'active') return '已入会';
|
|
36
|
+
if (state === 'closed') return '已注销';
|
|
37
|
+
if (state === 'unknown') return authState === 'unauthenticated' ? '未登录' : '状态待确认';
|
|
38
|
+
return '未入会';
|
|
39
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 图片 + 加载失败占位(0.4.0 D6:模块自持 ~20 行,禁跨模块依赖/基元封顶不破)。
|
|
3
|
+
* 源:POC shopping-guide 占位语义。src 缺省或加载失败 → 图标占位。
|
|
4
|
+
*/
|
|
5
|
+
import { useState } from 'react';
|
|
6
|
+
import type { ReactNode } from 'react';
|
|
7
|
+
import { ImageSquare } from '@phosphor-icons/react';
|
|
8
|
+
|
|
9
|
+
export function ImageWithFallback(props: {
|
|
10
|
+
src?: string;
|
|
11
|
+
alt: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
/** 占位区尺寸(px,图标随比例缩小) */
|
|
14
|
+
size?: number;
|
|
15
|
+
loading?: 'eager' | 'lazy';
|
|
16
|
+
/** 业务域可传入更贴合场景的正式图标;缺省仍使用通用图片占位。 */
|
|
17
|
+
fallback?: ReactNode;
|
|
18
|
+
}) {
|
|
19
|
+
const { src, alt, className, size = 40, loading = 'lazy', fallback } = props;
|
|
20
|
+
const [failed, setFailed] = useState(false);
|
|
21
|
+
if (!src || failed) {
|
|
22
|
+
return (
|
|
23
|
+
<div className={`img-fallback ${className ?? ''}`.trim()} aria-label={alt} role="img">
|
|
24
|
+
{fallback ?? <ImageSquare weight="duotone" size={Math.round(size * 0.45)} />}
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return (
|
|
29
|
+
<img
|
|
30
|
+
className={className}
|
|
31
|
+
src={src}
|
|
32
|
+
alt={alt}
|
|
33
|
+
loading={loading}
|
|
34
|
+
referrerPolicy="no-referrer"
|
|
35
|
+
onError={() => setFailed(true)}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
}
|
package/src/client/index.ts
CHANGED
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* module-member 客户端入口(与服务端 serverModule 对称)。
|
|
3
3
|
*/
|
|
4
|
+
import './styles/member.css'; // 0.4.0 D1:模块自持 CSS(副作用 import,首行保证先行加载)
|
|
5
|
+
|
|
4
6
|
import type { CardComponent } from '@tbox.cn/app-contracts';
|
|
5
7
|
import type { ClientContext, ClientModule } from '@tbox.cn/app-sdk/client';
|
|
6
8
|
import {
|
|
7
9
|
MemberInfoCard,
|
|
8
10
|
MemberCardSummaryCard,
|
|
9
|
-
MemberCouponListCard,
|
|
10
|
-
MemberCouponDetailCard,
|
|
11
11
|
MemberPointUsageListCard,
|
|
12
12
|
MemberEnrollmentFormCard,
|
|
13
13
|
MemberEnrollmentStatusCard,
|
|
14
|
+
MemberEnrollmentCtaCard,
|
|
15
|
+
MemberLoginCtaCard,
|
|
14
16
|
} from './cards';
|
|
15
17
|
|
|
16
18
|
const cards = {
|
|
17
19
|
'member-info': MemberInfoCard as CardComponent,
|
|
18
20
|
'member-card-summary': MemberCardSummaryCard as CardComponent,
|
|
19
|
-
'member-coupon-list': MemberCouponListCard as CardComponent,
|
|
20
|
-
'member-coupon-detail': MemberCouponDetailCard as CardComponent,
|
|
21
21
|
'member-point-usage-list': MemberPointUsageListCard as CardComponent,
|
|
22
22
|
'member-enrollment-form': MemberEnrollmentFormCard as CardComponent,
|
|
23
23
|
'member-enrollment-status': MemberEnrollmentStatusCard as CardComponent,
|
|
24
|
+
'member-enrollment-cta': MemberEnrollmentCtaCard as CardComponent,
|
|
25
|
+
'member-login-cta': MemberLoginCtaCard as CardComponent,
|
|
24
26
|
} as const;
|
|
25
27
|
|
|
26
28
|
export const clientModule = {
|