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
@@ -0,0 +1 @@
"use strict";var _constant=require("../../utils/constant"),_times=require("../../utils/times"),_reservationService=require("../../services/reservation-service"),_featureProcess=require("../../utils/feature-process"),_theme=require("../../utils/theme"),_utils=require("../../utils/utils"),pad=function(e){return e.toString().padStart(2,"0")};Component({options:{styleIsolation:"apply-shared"},properties:{sdkInstance:{type:Object,value:null},isLandscape:{type:Boolean,value:!1}},data:{show:!1,showReservationEntry:!1,isReserved:!1,modalVisible:!1,isReservationSmsEnable:0,countdown:null,isDarkTheme:!1},observers:{sdkInstance:function(e){if(e){var t=e.store,s=this;this._unsubscribe&&(this._unsubscribe(),this._unsubscribe=null),this._unsubscribe=t.get({liveInfo:function(e){if(null!=e&&e.Basic){var t=e.Basic,i=t.IsCountdownEnable,n=t.IsReservationEnable,o=t.Status,r=t.Countdown,a=1===i&&o===_constant.LIVE_STATUS.预告&&Number(r)>0,u={show:a,showReservationEntry:a&&1===n,isDarkTheme:(0,_theme.isUseDarkTheme)(e.Basic)};if(a){var l=(0,_times.getCurrentServerTimeSecond)()+Number(r);s._startCountdown(l)}else s._stopCountdown(),u.countdown=null;(0,_utils.setDataIfChanged)(s,u)}},"reservation.isReserved":function(e){(0,_utils.setDataIfChanged)(s,{isReserved:e||!1})},"reservation.modalVisible":function(e){(0,_utils.setDataIfChanged)(s,{modalVisible:e||!1})},"reservation.isReservationSmsEnable":function(e){(0,_utils.setDataIfChanged)(s,{isReservationSmsEnable:e||0})},"reservation.autoReservationWindowEnable":function(){s._tryAutoPopup(e)},"reservation.statusLoaded":function(t){t&&s._tryAutoPopup(e)}})}}},lifetimes:{detached:function(){this._unsubscribe&&(this._unsubscribe(),this._unsubscribe=null),this._stopCountdown()}},methods:{_timer:null,_targetTime:null,_finishEmitted:!1,_startCountdown:function(e){var t=this;if(e){var s=e;if(13===String(Math.floor(s)).length&&(s=Math.floor(s/1e3)),!(this._timer&&this._targetTime&&Math.abs(this._targetTime-s)<=1)){this._targetTime=s,this._finishEmitted=!1,this._stopCountdown();var i=function(){var e=Math.ceil(t._targetTime-(0,_times.getCurrentServerTimeSecond)());if(e<=0)return t.setData({countdown:null,show:!1}),t._stopCountdown(),void t._emitCountdownFinish();var s={d:Math.floor(e/86400),h:pad(Math.floor(e%86400/3600)),m:pad(Math.floor(e%3600/60)),s:pad(e%60)};t.data.countdown&&s.d===t.data.countdown.d&&s.h===t.data.countdown.h&&s.m===t.data.countdown.m&&s.s===t.data.countdown.s||t.setData({countdown:s})};i(),this._timer=setInterval(i,1e3)}}else this._stopCountdown()},_stopCountdown:function(){this._timer&&(clearInterval(this._timer),this._timer=null)},_emitCountdownFinish:function(){var e,t;if(!this._finishEmitted){this._finishEmitted=!0;var s=this.properties.sdkInstance;null!=s&&s.emitEvent&&null!==(e=s.EVENTS)&&void 0!==e&&null!==(t=e.countdown)&&void 0!==t&&t.finish&&s.emitEvent(s.EVENTS.countdown.finish,{})}},_tryAutoPopup:function(e){var t,s;if(this.data.showReservationEntry){var i,n=e.store.get("reservation")||{},o=e.store.get("mainInfo")||{};n.statusLoaded&&(1!==n.autoReservationWindowEnable||n.isReserved||null!==(t=o.options)&&void 0!==t&&t.disableReservationCell||null!==(s=o.options)&&void 0!==s&&s.isReserved||(e.store.set("reservation.modalVisible",!0),null===(i=e.reportTea)||void 0===i||i.call(e,"appointment_click",{isAuto:!0,evModule:"RESERVATION"})))}},onReservationTap:function(){var e=this.properties.sdkInstance;e&&this.data.showReservationEntry&&(this.data.isReserved||(0,_featureProcess.lockFeatureProcess)(e,_featureProcess.LockFeatureMap.Reservation)||(e.emitEvent(e.EVENTS.reservation.click,{}),this._openReservation()))},_openReservation:function(){var e=this,t=this.properties.sdkInstance;if(t&&this.data.showReservationEntry){var s=this.data.isReservationSmsEnable,i=(0,_reservationService.getReservationService)(t);1===s?null==i||i.showReservationModal():(t.store.get("userInfo")||{}).userId?null==i||i.submitReservationLogin(function(t){t&&e.setData({isReserved:!0})}):this.triggerEvent("commentCheck")}},onReservationSuccess:function(){this.setData({isReserved:!0})},onModalClose:function(){var e,t=this.properties.sdkInstance;null===(e=(0,_reservationService.getReservationService)(t))||void 0===e||e.hideReservationModal()}}});
@@ -0,0 +1 @@
{"component":true,"usingComponents":{"reservation-modal":"../reservation-modal/reservation-modal"}}
@@ -0,0 +1,60 @@
<view wx:if="{{show}}" class="live-countdown-container {{isDarkTheme ? 'live-countdown-container-dark' : ''}}">
<block wx:if="{{isLandscape}}">
<view class="live-countdown-container-landscape {{showReservationEntry ? '' : 'live-countdown-container-landscape-only'}}">
<view class="live-countdown-panel {{showReservationEntry ? '' : 'live-countdown-panel-only'}}">
<text class="live-countdown-label">距离直播开始还有</text>
<view class="live-countdown-time-box">
<text wx:if="{{countdown.d > 0}}" class="live-countdown-num">{{countdown.d}}</text>
<text wx:if="{{countdown.d > 0}}" class="live-countdown-unit">天</text>
<text class="live-countdown-num">{{countdown.h}}</text>
<text class="live-countdown-unit">时</text>
<text class="live-countdown-num">{{countdown.m}}</text>
<text class="live-countdown-unit">分</text>
<text class="live-countdown-num">{{countdown.s}}</text>
<text class="live-countdown-unit">秒</text>
</view>
</view>
<view
wx:if="{{showReservationEntry}}"
class="live-countdown-btn-landscape {{isReserved ? 'live-countdown-btn-done' : ''}}"
bindtap="onReservationTap"
>
<text wx:if="{{isReserved}}">已预约</text>
<text wx:else>立即预约</text>
</view>
</view>
</block>
<view wx:else class="live-countdown-portrait-container {{showReservationEntry ? '' : 'live-countdown-portrait-container-only'}}">
<view class="live-countdown-portrait-left">
<text class="live-countdown-portrait-label">距离直播开始还有</text>
<view class="live-countdown-portrait-time">
<text wx:if="{{countdown.d > 0}}" class="live-countdown-portrait-num">{{countdown.d}}</text>
<text wx:if="{{countdown.d > 0}}" class="live-countdown-portrait-unit">天</text>
<text class="live-countdown-portrait-num">{{countdown.h}}</text>
<text class="live-countdown-portrait-unit">时</text>
<text class="live-countdown-portrait-num">{{countdown.m}}</text>
<text class="live-countdown-portrait-unit">分</text>
<text class="live-countdown-portrait-num">{{countdown.s}}</text>
<text class="live-countdown-portrait-unit">秒</text>
</view>
</view>
<view wx:if="{{showReservationEntry}}" class="live-countdown-portrait-right">
<view
class="live-countdown-portrait-btn {{isReserved ? 'live-countdown-portrait-btn-done' : ''}}"
bindtap="onReservationTap"
>
<text wx:if="{{isReserved}}">已预约</text>
<text wx:else>立即预约</text>
</view>
</view>
</view>
<reservation-modal
sdkInstance="{{sdkInstance}}"
visible="{{modalVisible}}"
bind:success="onReservationSuccess"
bind:close="onModalClose"
/>
</view>
@@ -0,0 +1 @@
.live-countdown-container-landscape{width:100%;height:140rpx;display:flex;align-items:center;justify-content:flex-end;padding:20rpx 32rpx;box-sizing:border-box;z-index:100;border-bottom:1rpx solid rgba(0,0,0,.1)}.live-countdown-container-dark .live-countdown-container-landscape{border-bottom-color:rgba(255,255,255,.16)}.live-countdown-container-landscape-only{justify-content:center}.live-countdown-panel{display:flex;flex-direction:column;align-items:flex-start;margin-right:auto}.live-countdown-panel-only{margin-right:0;align-items:center}.live-countdown-label{font-size:calc(24rpx + .5 * (1rem - 16px));color:#86909c;margin-bottom:4rpx}.live-countdown-container-dark .live-countdown-label{color:rgba(255,255,255,.72)}.live-countdown-time-box{display:flex;align-items:baseline}.live-countdown-num{font-size:calc(36rpx + .5 * (1rem - 16px));color:#1d2129;font-weight:600;font-family:DINAlternate-Bold,'Helvetica Neue',Helvetica,sans-serif;margin-right:4rpx}.live-countdown-container-dark .live-countdown-num{color:#f2f3f5}.live-countdown-unit{font-size:calc(24rpx + .5 * (1rem - 16px));color:#1d2129;font-weight:400;margin-right:12rpx}.live-countdown-container-dark .live-countdown-unit{color:rgba(255,255,255,.86)}.live-countdown-unit:last-child{margin-right:0}.live-countdown-btn-landscape{display:flex;align-items:center;justify-content:center;height:calc(64rpx + .5 * (1rem - 16px));padding:0 32rpx;background:rgba(254,44,85,.08);color:#fe2c55;font-size:calc(28rpx + .5 * (1rem - 16px));font-weight:500;border-radius:32rpx;opacity:.9}.live-countdown-container-dark .live-countdown-btn-landscape{background:rgba(254,44,85,.18);color:#ff6175}.live-countdown-btn-done{background:0 0;color:#86909c;border:1rpx solid #e5e6eb;opacity:1}.live-countdown-container-dark .live-countdown-btn-done{background:0 0;color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.24)}.live-countdown-portrait-container{display:flex;align-items:center;justify-content:space-between;height:130rpx;background:rgba(0,0,0,.2);border-radius:32rpx;padding:16rpx 24rpx;box-sizing:border-box;margin:0 28rpx 6rpx;width:fit-content;min-width:400rpx}.live-countdown-portrait-container-only{min-width:0;justify-content:center}.live-countdown-portrait-container-only .live-countdown-portrait-left{margin-right:0}.live-countdown-portrait-left{display:flex;flex-direction:column;justify-content:center;margin-right:16rpx}.live-countdown-portrait-label{font-size:calc(26rpx + .5 * (1rem - 16px));line-height:calc(36rpx + .5 * (1rem - 16px));color:#fff;text-align:left;margin-bottom:4rpx}.live-countdown-portrait-time{display:flex;align-items:baseline;color:#fff}.live-countdown-portrait-num{font-size:calc(40rpx + .5 * (1rem - 16px));font-weight:600;margin-right:4rpx;font-family:DINAlternate-Bold,'Helvetica Neue',Helvetica,sans-serif}.live-countdown-portrait-unit{font-size:calc(22rpx + .5 * (1rem - 16px));margin-right:8rpx}.live-countdown-portrait-unit:last-child{margin-right:0}.live-countdown-portrait-right{display:flex;align-items:center;margin-left:16rpx}.live-countdown-portrait-btn{display:flex;align-items:center;justify-content:center;min-width:164rpx;height:calc(56rpx + .5 * (1rem - 16px));border-radius:28rpx;background:rgba(255,255,255,.15);color:#fff;font-size:calc(24rpx + .5 * (1rem - 16px));font-weight:500}.live-countdown-portrait-btn-done{border:1px solid #fff;background:0 0;opacity:.5;box-shadow:0 2rpx 20rpx rgba(21,39,83,.1)}