feat: 电子药箱小程序 - 4Tab药品管理
- 电子药箱: 药品库存管理 + 手动录入 + 今日用药打卡 - 药品百科: 搜索 + 分类筛选 + 20种药品静态数据 - 惠教中心: 4条药品使用指南课程 - 我的: 家庭成员信息管理 - 自定义TabBar + navigation-bar组件 - SVG药品分类插图
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
type GuideMenuItem = {
|
||||
key: string;
|
||||
label: string;
|
||||
icon: string;
|
||||
};
|
||||
|
||||
interface GuidePopupProperties {
|
||||
show: boolean;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
images: string[];
|
||||
amount: string;
|
||||
}
|
||||
|
||||
interface GuidePopupData {
|
||||
mounted: boolean;
|
||||
visible: boolean;
|
||||
displayName: string;
|
||||
displaySubtitle: string;
|
||||
avatarUrl: string;
|
||||
avatarLetter: string;
|
||||
balanceLabel: string;
|
||||
withdrawText: string;
|
||||
incomeText: string;
|
||||
menuItems: GuideMenuItem[];
|
||||
}
|
||||
|
||||
interface GuidePopupInstance
|
||||
extends WechatMiniprogram.Component.TrivialInstance {
|
||||
data: GuidePopupData;
|
||||
properties: GuidePopupProperties;
|
||||
_hideTimer?: number | null;
|
||||
}
|
||||
|
||||
const DEFAULT_NAME = "当前用户";
|
||||
const DEFAULT_ENTRY = "个人中心";
|
||||
const DEFAULT_BALANCE_LABEL = "可提现金额";
|
||||
const DEFAULT_WITHDRAW_TEXT = "立即提现";
|
||||
const DEFAULT_INCOME_TEXT = "收益明细";
|
||||
const HIDE_DELAY = 280;
|
||||
|
||||
const DEFAULT_MENU_ITEMS: GuideMenuItem[] = [
|
||||
{
|
||||
key: "orders",
|
||||
label: "我的订单",
|
||||
icon: "./icons/orders.svg",
|
||||
},
|
||||
{
|
||||
key: "prize-records",
|
||||
label: "中奖记录",
|
||||
icon: "./icons/gift.svg",
|
||||
},
|
||||
{
|
||||
key: "coupons",
|
||||
label: "我的优惠券",
|
||||
icon: "./icons/coupon.svg",
|
||||
},
|
||||
{
|
||||
key: "comment-board",
|
||||
label: "评论记录板",
|
||||
icon: "./icons/comment.svg",
|
||||
},
|
||||
{
|
||||
key: "nickname",
|
||||
label: "修改昵称",
|
||||
icon: "./icons/edit.svg",
|
||||
},
|
||||
{
|
||||
key: "complaint",
|
||||
label: "投诉",
|
||||
icon: "./icons/warning.svg",
|
||||
},
|
||||
];
|
||||
|
||||
function normalizeImages(value: unknown): string[] {
|
||||
if (!Array.isArray(value)) return [];
|
||||
|
||||
return value.filter(
|
||||
(item): item is string => typeof item === "string" && item.length > 0,
|
||||
);
|
||||
}
|
||||
|
||||
function syncViewModel(
|
||||
instance: GuidePopupInstance,
|
||||
titleText: string,
|
||||
subtitleText: string,
|
||||
imageList: string[],
|
||||
) {
|
||||
const name = titleText || wx.getStorageSync("userName") || DEFAULT_NAME;
|
||||
const subtitle = subtitleText || DEFAULT_ENTRY;
|
||||
const avatarUrl = imageList.length ? imageList[0] : "";
|
||||
const avatarLetter = String(name).trim().slice(0, 1).toUpperCase() || "U";
|
||||
|
||||
instance.setData({
|
||||
displayName: name,
|
||||
displaySubtitle: subtitle,
|
||||
avatarUrl,
|
||||
avatarLetter,
|
||||
});
|
||||
}
|
||||
|
||||
function clearHideTimer(instance: GuidePopupInstance) {
|
||||
if (!instance._hideTimer) return;
|
||||
|
||||
clearTimeout(instance._hideTimer);
|
||||
instance._hideTimer = null;
|
||||
}
|
||||
|
||||
function togglePopup(instance: GuidePopupInstance, show: boolean) {
|
||||
clearHideTimer(instance);
|
||||
|
||||
if (show) {
|
||||
if (instance.data.mounted) {
|
||||
wx.nextTick(() => {
|
||||
instance.setData({ visible: true });
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
instance.setData(
|
||||
{
|
||||
mounted: true,
|
||||
visible: false,
|
||||
},
|
||||
() => {
|
||||
wx.nextTick(() => {
|
||||
instance.setData({ visible: true });
|
||||
});
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!instance.data.mounted) return;
|
||||
|
||||
instance.setData({ visible: false });
|
||||
instance._hideTimer = setTimeout(() => {
|
||||
instance.setData({ mounted: false });
|
||||
instance._hideTimer = null;
|
||||
}, HIDE_DELAY);
|
||||
}
|
||||
|
||||
Component({
|
||||
properties: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer(this: GuidePopupInstance, nextValue: boolean) {
|
||||
togglePopup(this, !!nextValue);
|
||||
},
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
value: "",
|
||||
observer(this: GuidePopupInstance, nextValue: string) {
|
||||
syncViewModel(
|
||||
this,
|
||||
nextValue || "",
|
||||
this.properties.subtitle || "",
|
||||
normalizeImages(this.properties.images),
|
||||
);
|
||||
},
|
||||
},
|
||||
subtitle: {
|
||||
type: String,
|
||||
value: "",
|
||||
observer(this: GuidePopupInstance, nextValue: string) {
|
||||
syncViewModel(
|
||||
this,
|
||||
this.properties.title || "",
|
||||
nextValue || "",
|
||||
normalizeImages(this.properties.images),
|
||||
);
|
||||
},
|
||||
},
|
||||
images: {
|
||||
type: Array,
|
||||
value: [],
|
||||
observer(this: GuidePopupInstance, nextValue: unknown) {
|
||||
syncViewModel(
|
||||
this,
|
||||
this.properties.title || "",
|
||||
this.properties.subtitle || "",
|
||||
normalizeImages(nextValue),
|
||||
);
|
||||
},
|
||||
},
|
||||
amount: {
|
||||
type: String,
|
||||
value: "0.00",
|
||||
},
|
||||
},
|
||||
|
||||
data: {
|
||||
mounted: false,
|
||||
visible: false,
|
||||
displayName: DEFAULT_NAME,
|
||||
displaySubtitle: DEFAULT_ENTRY,
|
||||
avatarUrl: "",
|
||||
avatarLetter: "U",
|
||||
balanceLabel: DEFAULT_BALANCE_LABEL,
|
||||
withdrawText: DEFAULT_WITHDRAW_TEXT,
|
||||
incomeText: DEFAULT_INCOME_TEXT,
|
||||
menuItems: DEFAULT_MENU_ITEMS,
|
||||
} as GuidePopupData,
|
||||
|
||||
lifetimes: {
|
||||
attached(this: GuidePopupInstance) {
|
||||
syncViewModel(
|
||||
this,
|
||||
this.properties.title || "",
|
||||
this.properties.subtitle || "",
|
||||
normalizeImages(this.properties.images),
|
||||
);
|
||||
togglePopup(this, !!this.properties.show);
|
||||
},
|
||||
|
||||
detached(this: GuidePopupInstance) {
|
||||
clearHideTimer(this);
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
noop() {},
|
||||
|
||||
handleClose(this: GuidePopupInstance) {
|
||||
this.triggerEvent("close");
|
||||
},
|
||||
|
||||
handlePreviewAvatar(this: GuidePopupInstance) {
|
||||
const images = normalizeImages(this.properties.images);
|
||||
if (!images.length) return;
|
||||
|
||||
wx.previewImage({
|
||||
current: images[0],
|
||||
urls: images,
|
||||
});
|
||||
},
|
||||
|
||||
handleQuickAction(
|
||||
this: GuidePopupInstance,
|
||||
e: WechatMiniprogram.CustomEvent,
|
||||
) {
|
||||
const key = (e.currentTarget.dataset as { key?: string }).key || "";
|
||||
if (!key) return;
|
||||
|
||||
this.triggerEvent("action", { key });
|
||||
},
|
||||
|
||||
handleMenuTap(this: GuidePopupInstance, e: WechatMiniprogram.CustomEvent) {
|
||||
const key = (e.currentTarget.dataset as { key?: string }).key || "";
|
||||
if (!key) return;
|
||||
|
||||
this.triggerEvent("action", { key });
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user