feat: 电子药箱小程序 - 4Tab药品管理
- 电子药箱: 药品库存管理 + 手动录入 + 今日用药打卡 - 药品百科: 搜索 + 分类筛选 + 20种药品静态数据 - 惠教中心: 4条药品使用指南课程 - 我的: 家庭成员信息管理 - 自定义TabBar + navigation-bar组件 - SVG药品分类插图
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
// components/my-video/index.ts
|
||||
import { AES_KEY, AES_IV } from "../../env";
|
||||
import { request } from "../../utils/request";
|
||||
import { aesEncrypt } from "../../utils/crypto";
|
||||
|
||||
interface VideoData {
|
||||
screen: boolean;
|
||||
playing: boolean;
|
||||
currentTime: number;
|
||||
isReady: boolean;
|
||||
sendDurationTimer: number | null;
|
||||
lastUpdateTime: number;
|
||||
isConnected: boolean; // 新增网络连接状态字段
|
||||
}
|
||||
interface MyVideoComponent {
|
||||
data: VideoData;
|
||||
videoContext: WechatMiniprogram.VideoContext | null;
|
||||
pauseVideoHandler?: () => void;
|
||||
resumeVideoHandler?: () => void;
|
||||
setData: (d: Partial<VideoData>, cb?: () => void) => void;
|
||||
initNetworkListener: () => void;
|
||||
startSendProgress: () => void;
|
||||
clearSendProgressTimer: () => void;
|
||||
sendProgress: () => Promise<void>;
|
||||
}
|
||||
|
||||
Component({
|
||||
properties: {
|
||||
src: String,
|
||||
backgroundUrl: String,
|
||||
},
|
||||
|
||||
data: {
|
||||
screen: false,
|
||||
playing: false,
|
||||
currentTime: 0,
|
||||
isReady: false,
|
||||
isConnected: false,
|
||||
sendDurationTimer: 0,
|
||||
lastUpdateTime: 0,
|
||||
} as VideoData,
|
||||
|
||||
lifetimes: {
|
||||
attached(this: MyVideoComponent) {
|
||||
this.initNetworkListener();
|
||||
|
||||
// 获取 videoContext 并初始化
|
||||
this.videoContext = wx.createVideoContext("videoPlayer", this as any);
|
||||
|
||||
const pauseVideo = () => {
|
||||
if (this.data.playing) {
|
||||
wx.setStorageSync("interruptedTime", this.data.currentTime);
|
||||
this.videoContext?.pause();
|
||||
this.setData({ playing: false });
|
||||
this.clearSendProgressTimer();
|
||||
}
|
||||
};
|
||||
|
||||
const resumeVideo = () => {
|
||||
if (!this.videoContext) {
|
||||
this.videoContext = wx.createVideoContext("videoPlayer", this as any);
|
||||
}
|
||||
this.videoContext.pause();
|
||||
};
|
||||
|
||||
this.pauseVideoHandler = pauseVideo;
|
||||
this.resumeVideoHandler = resumeVideo;
|
||||
|
||||
wx.onAudioInterruptionBegin(this.pauseVideoHandler);
|
||||
wx.onAudioInterruptionEnd(this.resumeVideoHandler);
|
||||
wx.onAppHide(this.pauseVideoHandler);
|
||||
wx.onAppShow(this.resumeVideoHandler);
|
||||
},
|
||||
|
||||
detached(this: MyVideoComponent) {
|
||||
if (this.pauseVideoHandler) {
|
||||
wx.offAudioInterruptionBegin(this.pauseVideoHandler);
|
||||
wx.offAppHide(this.pauseVideoHandler);
|
||||
}
|
||||
if (this.resumeVideoHandler) {
|
||||
wx.offAudioInterruptionEnd(this.resumeVideoHandler);
|
||||
wx.offAppShow(this.resumeVideoHandler);
|
||||
}
|
||||
this.clearSendProgressTimer();
|
||||
this.videoContext = null;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
initNetworkListener(this: MyVideoComponent) {
|
||||
// 首先获取当前网络状态
|
||||
wx.getNetworkType({
|
||||
success: (res) => {
|
||||
this.setData({
|
||||
isConnected: res.networkType !== "none",
|
||||
});
|
||||
},
|
||||
});
|
||||
wx.onNetworkStatusChange(
|
||||
(res: WechatMiniprogram.OnNetworkStatusChangeCallbackResult) => {
|
||||
this.setData({
|
||||
isConnected: res.isConnected,
|
||||
});
|
||||
if (!res.isConnected && this.data.playing) {
|
||||
this.videoContext?.pause();
|
||||
this.setData({ playing: false });
|
||||
wx.showToast({
|
||||
title: "网络连接已断开",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
}
|
||||
if (res.isConnected) {
|
||||
wx.showToast({
|
||||
title: "网络已连接",
|
||||
icon: "success",
|
||||
duration: 1500,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
handleLoadedMetadata(this: MyVideoComponent) {
|
||||
this.setData({ isReady: true });
|
||||
},
|
||||
|
||||
handlePosterTap(this: MyVideoComponent) {
|
||||
if (!this.videoContext || !this.data.isReady) return;
|
||||
if (!this.data.isConnected) {
|
||||
wx.showToast({
|
||||
title: "网络连接异常,请检查网络设置",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const newPlaying = !this.data.playing;
|
||||
const resumeTime =
|
||||
(wx.getStorageSync("interruptedTime") as number) ||
|
||||
this.data.currentTime ||
|
||||
(wx.getStorageSync("currentTime") as number) ||
|
||||
0;
|
||||
|
||||
if (newPlaying) {
|
||||
if (resumeTime > 0) {
|
||||
this.videoContext.seek(resumeTime);
|
||||
}
|
||||
this.videoContext.play();
|
||||
if (!this.data.sendDurationTimer) {
|
||||
this.startSendProgress();
|
||||
}
|
||||
} else {
|
||||
this.videoContext.pause();
|
||||
this.clearSendProgressTimer();
|
||||
}
|
||||
|
||||
this.setData({ playing: newPlaying });
|
||||
wx.removeStorageSync("interruptedTime");
|
||||
},
|
||||
|
||||
handlePause(this: MyVideoComponent) {
|
||||
wx.setStorageSync("interruptedTime", this.data.currentTime);
|
||||
this.setData({ playing: false });
|
||||
this.clearSendProgressTimer();
|
||||
},
|
||||
|
||||
handleTimeUpdate(
|
||||
this: MyVideoComponent,
|
||||
e: WechatMiniprogram.VideoTimeUpdate
|
||||
) {
|
||||
const now = Date.now();
|
||||
const currentTime = Math.floor(e.detail.currentTime ?? 0);
|
||||
if (now - this.data.lastUpdateTime >= 1000) {
|
||||
this.setData({ currentTime });
|
||||
(this.data as VideoData).lastUpdateTime = now;
|
||||
wx.setStorageSync("currentTime", currentTime);
|
||||
}
|
||||
},
|
||||
|
||||
handleEnded(this: MyVideoComponent) {
|
||||
this.sendProgress();
|
||||
wx.setStorageSync("ended", true);
|
||||
this.setData({ playing: false, currentTime: 0 });
|
||||
wx.removeStorageSync("currentTime");
|
||||
wx.removeStorageSync("interruptedTime");
|
||||
this.clearSendProgressTimer();
|
||||
},
|
||||
|
||||
handleFullscreenChange(this: MyVideoComponent) {
|
||||
const newScreen = !this.data.screen;
|
||||
if (newScreen) {
|
||||
this.videoContext?.requestFullScreen({ direction: 90 });
|
||||
} else {
|
||||
this.videoContext?.exitFullScreen();
|
||||
}
|
||||
this.setData({ screen: newScreen });
|
||||
},
|
||||
|
||||
handleError(this: MyVideoComponent, e: WechatMiniprogram.VideoError) {
|
||||
console.error("播放错误:", e.detail.errMsg);
|
||||
this.setData({ playing: false });
|
||||
},
|
||||
|
||||
startSendProgress(this: MyVideoComponent) {
|
||||
this.clearSendProgressTimer();
|
||||
const timer = setInterval(() => {
|
||||
this.sendProgress();
|
||||
}, 15000) as unknown as number;
|
||||
this.setData({ sendDurationTimer: timer });
|
||||
},
|
||||
|
||||
clearSendProgressTimer(this: MyVideoComponent) {
|
||||
const t = this.data.sendDurationTimer;
|
||||
if (t) {
|
||||
clearInterval(t);
|
||||
this.setData({ sendDurationTimer: 0 });
|
||||
}
|
||||
},
|
||||
|
||||
async sendProgress(this: MyVideoComponent) {
|
||||
try {
|
||||
const openId = wx.getStorageSync("openId");
|
||||
const code = wx.getStorageSync("code");
|
||||
const state = wx.getStorageSync("state");
|
||||
const seeId = wx.getStorageSync("seeId");
|
||||
const duration = this.data.currentTime + 1;
|
||||
if (code) {
|
||||
const params = {
|
||||
openId,
|
||||
code,
|
||||
duration
|
||||
};
|
||||
await request({
|
||||
options: {
|
||||
url: `/app/video-watch/inspect`,
|
||||
data: aesEncrypt(JSON.stringify(params), AES_KEY, AES_IV),
|
||||
},
|
||||
isLoading: false,
|
||||
});
|
||||
} else {
|
||||
const params = {
|
||||
openId,
|
||||
state,
|
||||
seeId,
|
||||
duration
|
||||
};
|
||||
await request({
|
||||
options: {
|
||||
url: `/app/watch/inspect`,
|
||||
data: aesEncrypt(JSON.stringify(params), AES_KEY, AES_IV),
|
||||
},
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("上报观看进度失败:", err);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user