feat: 电子药箱小程序 - 4Tab药品管理

- 电子药箱: 药品库存管理 + 手动录入 + 今日用药打卡
- 药品百科: 搜索 + 分类筛选 + 20种药品静态数据
- 惠教中心: 4条药品使用指南课程
- 我的: 家庭成员信息管理
- 自定义TabBar + navigation-bar组件
- SVG药品分类插图
This commit is contained in:
陈誉午
2026-07-29 11:20:52 +08:00
commit 994b267f5c
683 changed files with 43849 additions and 0 deletions
+206
View File
@@ -0,0 +1,206 @@
interface PlayerProperties {
isPlayback: boolean;
isLiving: boolean;
pullUrlInfo: {
rtmpUrl: string;
rtmpOriaacUrl: string;
hlsOriaacUrl: string;
hlsUrl: string;
};
vodInfo: {
state: number;
pullUrl: string;
};
}
interface PlayerData {
liveUrl: string;
vodUrl: string;
isPlaying: boolean;
showVideo: boolean;
fullScreen: boolean;
height: number;
retryCount: number;
maxRetryCount: number;
}
interface PlayerComponent extends WechatMiniprogram.Component.TrivialInstance {
data: PlayerData;
properties: PlayerProperties;
videoContext: WechatMiniprogram.VideoContext | null;
}
Component({
properties: {
isPlayback: {
type: Boolean,
value: false,
},
isLiving: {
type: Boolean,
value: false,
},
pullUrlInfo: {
type: Object,
value: {
rtmpUrl: "",
rtmpOriaacUrl: "",
hlsOriaacUrl: "",
hlsUrl: "",
},
},
vodInfo: {
type: Object,
value: {
state: 0,
pullUrl: "",
},
},
},
data: {
liveUrl: "",
vodUrl: "",
isPlaying: false,
fullScreen: false,
height: 0,
showVideo: true,
retryCount: 0,
maxRetryCount: 3,
},
lifetimes: {
attached(this: PlayerComponent) {
this.initPlayer();
},
detached(this: PlayerComponent) {
this.cleanup();
},
},
observers: {
"isLiving, pullUrlInfo": function (
this: PlayerComponent,
isLiving: boolean,
pullUrlInfo: PlayerProperties["pullUrlInfo"]
) {
if (isLiving && pullUrlInfo.rtmpUrl) {
this.setData({ liveUrl: pullUrlInfo.rtmpUrl });
} else {
this.setData({ liveUrl: "" });
}
},
vodInfo: function (
this: PlayerComponent,
data: PlayerProperties["vodInfo"]
) {
if (data && data.pullUrl) {
this.setData({
vodUrl: data.pullUrl,
isPlaying: true,
showVideo: true,
});
this.playVideo();
}
},
},
methods: {
playVideo(this: PlayerComponent) {
if (!this.videoContext || !this.data.showVideo) return;
setTimeout(() => {
try {
this.videoContext?.play();
} catch (error) {
this.handlePlayError();
}
}, 500);
},
handlePlayError(this: PlayerComponent) {
const { retryCount, maxRetryCount } = this.data;
if (retryCount < maxRetryCount) {
this.setData({ retryCount: retryCount + 1 });
setTimeout(() => {
this.playVideo();
}, 2000);
} else {
this.setData({
showVideo: false,
retryCount: 0,
});
wx.showToast({
title: "播放失败,请检查网络连接",
icon: "none",
});
}
},
initPlayer(this: PlayerComponent) {
try {
const sysInfo = wx.getSystemInfoSync();
this.setData({ height: sysInfo.screenHeight });
this.videoContext = wx.createVideoContext("vodVideo", this);
} catch (err) {
console.error("初始化播放器失败:", err);
wx.showToast({ title: "播放器初始化失败", icon: "none" });
}
},
onLiveStateChange(
this: PlayerComponent,
event: WechatMiniprogram.CustomEvent
) {
const code = event.detail.code;
const stateMap: Record<number, string> = {
2001: "已连接",
2002: "已断开",
2003: "缓冲中",
2004: "播放开始",
2005: "播放结束",
2006: "加载中",
};
console.log("直播状态:", stateMap[code] || `未知(${code})`);
},
onLiveError(this: PlayerComponent, event: WechatMiniprogram.CustomEvent) {
const errCode = event.detail.errCode;
const errorMap: Record<number, string> = {
10001: "系统错误",
10002: "网络错误",
10003: "解码错误",
10004: "直播流不存在",
};
const msg = errorMap[errCode] || `直播错误: ${event.detail.errMsg}`;
wx.showToast({ title: msg, icon: "none" });
},
onVideoPlay(this: PlayerComponent) {
this.setData({ isPlaying: true, retryCount: 0, showVideo: true });
},
onVideoPause(this: PlayerComponent) {
this.setData({ isPlaying: false });
},
onVideoEnded(this: PlayerComponent) {
this.setData({ isPlaying: false });
},
onVideoError(this: PlayerComponent, err: WechatMiniprogram.CustomEvent) {
if (err) {
this.setData({ isPlaying: false, showVideo: false });
this.triggerEvent("controlstoggle", { state: 2 });
}
},
cleanup(this: PlayerComponent) {
this.videoContext = null;
this.setData({
liveUrl: "",
vodUrl: "",
isPlaying: false,
fullScreen: false,
showVideo: true,
retryCount: 0,
});
},
},
});